]> git.saurik.com Git - wxWidgets.git/blob - src/mgl/region.cpp
Fix [ 1574240 ] wx.RadioButton doesn't navigate correctly
[wxWidgets.git] / src / mgl / region.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/mgl/region.cpp
3 // Purpose: Region handling for wxWidgets/MGL
4 // Author: Vaclav Slavik
5 // RCS-ID: $Id$
6 // Copyright: (c) 2001-2002 SciTech Software, Inc. (www.scitechsoft.com)
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
12
13 #ifdef __BORLANDC__
14 #pragma hdrstop
15 #endif
16
17 #include "wx/region.h"
18
19 #ifndef WX_PRECOMP
20 #include "wx/gdicmn.h"
21 #include "wx/module.h"
22 #endif
23
24 #include "wx/thread.h"
25
26 #include <mgraph.hpp>
27
28 #include "wx/listimpl.cpp"
29 WX_DEFINE_LIST(wxRegionRectList)
30
31 IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject)
32 IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator, wxObject)
33
34 //-----------------------------------------------------------------------------
35 // wxRegionRefData implementation
36 //-----------------------------------------------------------------------------
37
38 class WXDLLEXPORT wxRegionRefData : public wxGDIRefData
39 {
40 public:
41 wxRegionRefData() {}
42
43 wxRegionRefData(const wxRegionRefData& data)
44 {
45 m_region = data.m_region;
46 }
47
48 virtual ~wxRegionRefData() {}
49
50 MGLRegion m_region;
51 };
52
53 #define M_REGION (((wxRegionRefData*)m_refData)->m_region)
54 #define M_REGION_OF(r) (((wxRegionRefData*)(r.m_refData))->m_region)
55
56 //-----------------------------------------------------------------------------
57 // wxRegion
58 //-----------------------------------------------------------------------------
59
60 wxObjectRefData *wxRegion::CreateRefData() const
61 {
62 return new wxRegionRefData;
63 }
64
65 wxObjectRefData *wxRegion::CloneRefData(const wxObjectRefData *data) const
66 {
67 return new wxRegionRefData(*(wxRegionRefData *)data);
68 }
69
70 /*
71 * Create an empty region.
72 */
73 wxRegion::wxRegion()
74 {
75 m_refData = NULL;
76 }
77
78 wxRegion::wxRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
79 {
80 m_refData = new wxRegionRefData;
81 MGLRect rect(x, y, x + w, y + h);
82 M_REGION = rect;
83 }
84
85 wxRegion::wxRegion(const wxPoint& topLeft, const wxPoint& bottomRight)
86 {
87 m_refData = new wxRegionRefData;
88 MGLRect rect(topLeft.x, topLeft.y, bottomRight.x+1, bottomRight.y+1);
89 M_REGION = rect;
90 }
91
92 wxRegion::wxRegion(const wxRect& r)
93 {
94 m_refData = new wxRegionRefData;
95 MGLRect rect(r.GetLeft(), r.GetTop(), r.GetRight()+1, r.GetBottom()+1);
96 M_REGION = rect;
97 }
98
99 wxRegion::wxRegion(const MGLRegion& region)
100 {
101 m_refData = new wxRegionRefData;
102 M_REGION = region;
103 }
104
105 wxRegion::~wxRegion()
106 {
107 // m_refData unrefed in ~wxObject
108 }
109
110 const MGLRegion& wxRegion::GetMGLRegion() const
111 {
112 return M_REGION;
113 }
114
115 //-----------------------------------------------------------------------------
116 // Modify region
117 //-----------------------------------------------------------------------------
118
119 // Clear current region
120 void wxRegion::Clear()
121 {
122 UnRef();
123 }
124
125
126 //-----------------------------------------------------------------------------
127 // Information on region
128 //-----------------------------------------------------------------------------
129
130 bool wxRegion::DoIsEqual(const wxRegion& WXUNUSED(region)) const
131 {
132 wxFAIL_MSG( _T("not implemented") );
133
134 return false;
135 }
136
137 // Outer bounds of region
138 bool wxRegion::DoGetBox(wxCoord& x, wxCoord& y, wxCoord&w, wxCoord &h) const
139 {
140 if (m_refData)
141 {
142 rect_t rect;
143 rect = M_REGION.getBounds();
144 x = rect.left;
145 y = rect.top;
146 w = rect.right - rect.left;
147 h = rect.bottom - rect.top;
148
149 return true;
150 }
151 else
152 {
153 x = y = w = h = 0;
154 return false;
155 }
156 }
157
158 // Is region empty?
159 bool wxRegion::IsEmpty() const
160 {
161 if (!m_refData)
162 return true;
163
164 return (bool)(M_REGION.isEmpty());
165 }
166
167 //-----------------------------------------------------------------------------
168 // Modifications
169 //-----------------------------------------------------------------------------
170
171 bool wxRegion::DoOffset(wxCoord x, wxCoord y)
172 {
173 AllocExclusive();
174 M_REGION.offset(x, y);
175 return true;
176 }
177
178 // Union rectangle or region with this.
179 bool wxRegion::DoUnionWithRect(const wxRect& r)
180 {
181 AllocExclusive();
182 M_REGION += MGLRect(r.x, r.y, r.GetRight() + 1, r.GetHeight() + 1);
183 return true;
184 }
185
186 bool wxRegion::DoUnionWithRegion(const wxRegion& region)
187 {
188 AllocExclusive();
189 M_REGION += M_REGION_OF(region);
190 return true;
191 }
192
193 bool wxRegion::DoIntersect(const wxRegion& region)
194 {
195 AllocExclusive();
196 M_REGION &= M_REGION_OF(region);
197 return true;
198 }
199
200 bool wxRegion::DoSubtract(const wxRegion& region)
201 {
202 AllocExclusive();
203 M_REGION -= M_REGION_OF(region);
204 return true;
205 }
206
207 bool wxRegion::DoXor(const wxRegion& region)
208 {
209 AllocExclusive();
210 MGLRegion rg1 = M_REGION + M_REGION_OF(region),
211 rg2 = M_REGION & M_REGION_OF(region);
212 M_REGION = rg1 - rg2;
213 return true;
214 }
215
216
217 //-----------------------------------------------------------------------------
218 // Tests
219 //-----------------------------------------------------------------------------
220
221 // Does the region contain the point (x,y)?
222 wxRegionContain wxRegion::DoContainsPoint(wxCoord x, wxCoord y) const
223 {
224 if (!m_refData)
225 return wxOutRegion;
226
227 if (M_REGION.includes((int)x, (int)y))
228 return wxInRegion;
229 else
230 return wxOutRegion;
231 }
232
233 // Does the region contain the rectangle (x, y, w, h)?
234 wxRegionContain wxRegion::DoContainsRect(const wxRect& r) const
235 {
236 if (!m_refData)
237 return wxOutRegion;
238
239 MGLRect rect(r.x, r.y, r.GetRight() + 1, r.GetBottom() + 1);
240 MGLRegion rg;
241
242 // 1) is the rectangle entirely covered by the region?
243 rg = MGLRegion(rect) - M_REGION;
244 if (rg.isEmpty())
245 return wxInRegion;
246
247 // 2) is the rectangle completely outside the region?
248 rg = M_REGION & rect; // intersection
249 if (rg.isEmpty())
250 return wxOutRegion;
251
252 // 3) neither case happened => it is partially covered:
253 return wxPartRegion;
254 }
255
256 ///////////////////////////////////////////////////////////////////////////////
257 // wxRegionIterator //
258 ///////////////////////////////////////////////////////////////////////////////
259
260 #if wxUSE_THREADS
261 static wxMutex *gs_mutexIterator;
262
263 class wxMglRegionModule : public wxModule
264 {
265 public:
266 virtual bool OnInit()
267 {
268 gs_mutexIterator = new wxMutex();
269 return true;
270 }
271 virtual void OnExit()
272 {
273 wxDELETE(gs_mutexIterator);
274 }
275
276 DECLARE_DYNAMIC_CLASS(wxMglRegionModule)
277 };
278 IMPLEMENT_DYNAMIC_CLASS(wxMglRegionModule, wxModule)
279 #endif
280
281 /*
282 * Initialize empty iterator
283 */
284 wxRegionIterator::wxRegionIterator() : m_currentNode(NULL)
285 {
286 m_rects.DeleteContents(true);
287 }
288
289 wxRegionIterator::~wxRegionIterator()
290 {
291 }
292
293 /*
294 * Initialize iterator for region
295 */
296 wxRegionIterator::wxRegionIterator(const wxRegion& region)
297 {
298 m_rects.DeleteContents(true);
299 Reset(region);
300 }
301
302 /*
303 * Reset iterator for a new /e region.
304 */
305
306
307 static wxRegionRectList *gs_rectList;
308
309 static void MGLAPI wxMGL_region_callback(const rect_t *r)
310 {
311 gs_rectList->Append(new wxRect(r->left, r->top,
312 r->right - r->left, r->bottom - r->top));
313 }
314
315 void wxRegionIterator::Reset(const wxRegion& region)
316 {
317 m_currentNode = NULL;
318 m_rects.Clear();
319
320 if (!region.Empty())
321 {
322 #if wxUSE_THREADS
323 wxMutexLocker lock(*gs_mutexIterator);
324 #endif
325 gs_rectList = &m_rects;
326 M_REGION_OF(region).traverse(wxMGL_region_callback);
327 m_currentNode = m_rects.GetFirst();
328 }
329 }
330
331 /*
332 * Increment iterator. The rectangle returned is the one after the
333 * incrementation.
334 */
335 void wxRegionIterator::operator ++ ()
336 {
337 if (m_currentNode)
338 m_currentNode = m_currentNode->GetNext();
339 }
340
341 /*
342 * Increment iterator. The rectangle returned is the one before the
343 * incrementation.
344 */
345 void wxRegionIterator::operator ++ (int)
346 {
347 if (m_currentNode)
348 m_currentNode = m_currentNode->GetNext();
349 }
350
351 wxCoord wxRegionIterator::GetX() const
352 {
353 if (m_currentNode)
354 return m_currentNode->GetData()->x;
355 else
356 return 0;
357 }
358
359 wxCoord wxRegionIterator::GetY() const
360 {
361 if (m_currentNode)
362 return m_currentNode->GetData()->y;
363 else
364 return 0;
365 }
366
367 wxCoord wxRegionIterator::GetW() const
368 {
369 if (m_currentNode)
370 return m_currentNode->GetData()->width;
371 else
372 return 0;
373 }
374
375 wxCoord wxRegionIterator::GetH() const
376 {
377 if (m_currentNode)
378 return m_currentNode->GetData()->height;
379 else
380 return 0;
381 }