]> git.saurik.com Git - wxWidgets.git/blob - src/mgl/region.cpp
added back 2 extra pixels for the best size under XP
[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 #endif
22
23 #include "wx/thread.h"
24 #include "wx/module.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 ~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 // Outer bounds of region
131 void wxRegion::GetBox(wxCoord& x, wxCoord& y, wxCoord&w, wxCoord &h) const
132 {
133 if (m_refData)
134 {
135 rect_t rect;
136 rect = M_REGION.getBounds();
137 x = rect.left;
138 y = rect.top;
139 w = rect.right - rect.left;
140 h = rect.bottom - rect.top;
141 }
142 else
143 {
144 x = y = w = h = 0;
145 }
146 }
147
148 wxRect wxRegion::GetBox() const
149 {
150 wxCoord x, y, w, h;
151 GetBox(x, y, w, h);
152 return wxRect(x, y, w, h);
153 }
154
155 // Is region empty?
156 bool wxRegion::Empty() const
157 {
158 if (!m_refData)
159 return true;
160
161 return (bool)(M_REGION.isEmpty());
162 }
163
164 //-----------------------------------------------------------------------------
165 // Modifications
166 //-----------------------------------------------------------------------------
167
168 bool wxRegion::Offset(wxCoord x, wxCoord y)
169 {
170 AllocExclusive();
171 M_REGION.offset(x, y);
172 return true;
173 }
174
175 // Union rectangle or region with this.
176 bool wxRegion::Union(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
177 {
178 AllocExclusive();
179 M_REGION += MGLRect(x, y, x + width, y + height);
180 return true;
181 }
182
183 bool wxRegion::Union(const wxRegion& region)
184 {
185 AllocExclusive();
186 M_REGION += M_REGION_OF(region);
187 return true;
188 }
189
190 // Intersect rectangle or region with this.
191 bool wxRegion::Intersect(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
192 {
193 AllocExclusive();
194 M_REGION &= MGLRect(x, y, x + width, y + height);
195 return true;
196 }
197
198 bool wxRegion::Intersect(const wxRegion& region)
199 {
200 AllocExclusive();
201 M_REGION &= M_REGION_OF(region);
202 return true;
203 }
204
205 // Subtract rectangle or region from this:
206 // Combines the parts of 'this' that are not part of the second region.
207 bool wxRegion::Subtract(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
208 {
209 AllocExclusive();
210 M_REGION -= MGLRect(x, y, x + width, y + height);
211 return true;
212 }
213
214 bool wxRegion::Subtract(const wxRegion& region)
215 {
216 AllocExclusive();
217 M_REGION -= M_REGION_OF(region);
218 return true;
219 }
220
221 // XOR: the union of two combined regions except for any overlapping areas.
222 bool wxRegion::Xor(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
223 {
224 AllocExclusive();
225 MGLRect rect(x, y, x + width, y + height);
226 MGLRegion rg1 = M_REGION + rect,
227 rg2 = M_REGION & rect;
228 M_REGION = rg1 - rg2;
229 return true;
230 }
231
232 bool wxRegion::Xor(const wxRegion& region)
233 {
234 AllocExclusive();
235 MGLRegion rg1 = M_REGION + M_REGION_OF(region),
236 rg2 = M_REGION & M_REGION_OF(region);
237 M_REGION = rg1 - rg2;
238 return true;
239 }
240
241
242 //-----------------------------------------------------------------------------
243 // Tests
244 //-----------------------------------------------------------------------------
245
246 // Does the region contain the point (x,y)?
247 wxRegionContain wxRegion::Contains(wxCoord x, wxCoord y) const
248 {
249 if (!m_refData)
250 return wxOutRegion;
251
252 if (M_REGION.includes((int)x, (int)y))
253 return wxInRegion;
254 else
255 return wxOutRegion;
256 }
257
258 // Does the region contain the point pt?
259 wxRegionContain wxRegion::Contains(const wxPoint& pt) const
260 {
261 return Contains(pt.x, pt.y);
262 }
263
264 // Does the region contain the rectangle (x, y, w, h)?
265 wxRegionContain wxRegion::Contains(wxCoord x, wxCoord y, wxCoord w, wxCoord h) const
266 {
267 if (!m_refData)
268 return wxOutRegion;
269
270 MGLRect rect(x, y, x + w, y + h);
271 MGLRegion rg;
272
273 // 1) is the rectangle entirely covered by the region?
274 rg = MGLRegion(rect) - M_REGION;
275 if (rg.isEmpty()) return wxInRegion;
276
277 // 2) is the rectangle completely outside the region?
278 rg = M_REGION & rect; // intersection
279 if (rg.isEmpty()) return wxOutRegion;
280
281 // 3) neither case happened => it is partially covered:
282 return wxPartRegion;
283 }
284
285 // Does the region contain the rectangle rect
286 wxRegionContain wxRegion::Contains(const wxRect& rect) const
287 {
288 return Contains(rect.x, rect.y, rect.width, rect.height);
289 }
290
291
292 ///////////////////////////////////////////////////////////////////////////////
293 // wxRegionIterator //
294 ///////////////////////////////////////////////////////////////////////////////
295
296 #if wxUSE_THREADS
297 static wxMutex *gs_mutexIterator;
298
299 class wxMglRegionModule : public wxModule
300 {
301 public:
302 virtual bool OnInit()
303 {
304 gs_mutexIterator = new wxMutex();
305 return true;
306 }
307 virtual void OnExit()
308 {
309 wxDELETE(gs_mutexIterator);
310 }
311
312 DECLARE_DYNAMIC_CLASS(wxMglRegionModule)
313 };
314 IMPLEMENT_DYNAMIC_CLASS(wxMglRegionModule, wxModule)
315 #endif
316
317 /*
318 * Initialize empty iterator
319 */
320 wxRegionIterator::wxRegionIterator() : m_currentNode(NULL)
321 {
322 m_rects.DeleteContents(true);
323 }
324
325 wxRegionIterator::~wxRegionIterator()
326 {
327 }
328
329 /*
330 * Initialize iterator for region
331 */
332 wxRegionIterator::wxRegionIterator(const wxRegion& region)
333 {
334 m_rects.DeleteContents(true);
335 Reset(region);
336 }
337
338 /*
339 * Reset iterator for a new /e region.
340 */
341
342
343 static wxRegionRectList *gs_rectList;
344
345 static void MGLAPI wxMGL_region_callback(const rect_t *r)
346 {
347 gs_rectList->Append(new wxRect(r->left, r->top,
348 r->right - r->left, r->bottom - r->top));
349 }
350
351 void wxRegionIterator::Reset(const wxRegion& region)
352 {
353 m_currentNode = NULL;
354 m_rects.Clear();
355
356 if (!region.Empty())
357 {
358 #if wxUSE_THREADS
359 wxMutexLocker lock(*gs_mutexIterator);
360 #endif
361 gs_rectList = &m_rects;
362 M_REGION_OF(region).traverse(wxMGL_region_callback);
363 m_currentNode = m_rects.GetFirst();
364 }
365 }
366
367 /*
368 * Increment iterator. The rectangle returned is the one after the
369 * incrementation.
370 */
371 void wxRegionIterator::operator ++ ()
372 {
373 if (m_currentNode)
374 m_currentNode = m_currentNode->GetNext();
375 }
376
377 /*
378 * Increment iterator. The rectangle returned is the one before the
379 * incrementation.
380 */
381 void wxRegionIterator::operator ++ (int)
382 {
383 if (m_currentNode)
384 m_currentNode = m_currentNode->GetNext();
385 }
386
387 wxCoord wxRegionIterator::GetX() const
388 {
389 if (m_currentNode)
390 return m_currentNode->GetData()->x;
391 else
392 return 0;
393 }
394
395 wxCoord wxRegionIterator::GetY() const
396 {
397 if (m_currentNode)
398 return m_currentNode->GetData()->y;
399 else
400 return 0;
401 }
402
403 wxCoord wxRegionIterator::GetW() const
404 {
405 if (m_currentNode)
406 return m_currentNode->GetData()->width;
407 else
408 return 0;
409 }
410
411 wxCoord wxRegionIterator::GetH() const
412 {
413 if (m_currentNode)
414 return m_currentNode->GetData()->height;
415 else
416 return 0;
417 }