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