1. some minor but nasty bugs fixed (see post to the list)
[wxWidgets.git] / src / msw / region.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: msw/region.cpp
3 // Purpose: Region handling for wxWindows/X11
4 // Author: Markus Holzem
5 // Modified by:
6 // Created: Fri Oct 24 10:46:34 MET 1997
7 // RCS-ID: $Id$
8 // Copyright: (c) 1997 Julian Smart and Markus Holzem
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "region.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #include "wx/msw/region.h"
24 #include "wx/gdicmn.h"
25
26 #include "wx/msw/private.h"
27
28 #if !USE_SHARED_LIBRARY
29 IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject)
30 IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator, wxObject)
31 #endif
32
33 //-----------------------------------------------------------------------------
34 // wxRegionRefData implementation
35 //-----------------------------------------------------------------------------
36
37 class WXDLLEXPORT wxRegionRefData : public wxGDIRefData
38 {
39 public:
40 wxRegionRefData()
41 {
42 m_region = 0;
43 }
44
45 wxRegionRefData(const wxRegionRefData& data)
46 {
47 #if defined(__WIN32__)
48 DWORD noBytes = ::GetRegionData(data.m_region, 0, NULL);
49 RGNDATA *rgnData = (RGNDATA*) new char[noBytes];
50 ::GetRegionData(data.m_region, noBytes, rgnData);
51 m_region = ::ExtCreateRegion(NULL, noBytes, rgnData);
52 delete[] (char*) rgnData;
53 #else
54 RECT rect;
55 ::GetRgnBox(data.m_region, &rect);
56 m_region = ::CreateRectRgnIndirect(&rect);
57 #endif
58 }
59
60 ~wxRegionRefData()
61 {
62 ::DeleteObject(m_region);
63 m_region = 0;
64 }
65
66 HRGN m_region;
67 };
68
69 #define M_REGION (((wxRegionRefData*)m_refData)->m_region)
70
71 //-----------------------------------------------------------------------------
72 // wxRegion
73 //-----------------------------------------------------------------------------
74
75 /*
76 * Create an empty region.
77 */
78 wxRegion::wxRegion()
79 {
80 m_refData = new wxRegionRefData;
81 M_REGION = ::CreateRectRgn(0, 0, 0, 0);
82 }
83
84 wxRegion::wxRegion(WXHRGN hRegion)
85 {
86 m_refData = new wxRegionRefData;
87 M_REGION = (HRGN) hRegion;
88 }
89
90 wxRegion::wxRegion(long x, long y, long w, long h)
91 {
92 m_refData = new wxRegionRefData;
93 M_REGION = ::CreateRectRgn(x, y, x + w, y + h);
94 }
95
96 wxRegion::wxRegion(const wxPoint& topLeft, const wxPoint& bottomRight)
97 {
98 m_refData = new wxRegionRefData;
99 M_REGION = ::CreateRectRgn(topLeft.x, topLeft.y, bottomRight.x, bottomRight.y);
100 }
101
102 wxRegion::wxRegion(const wxRect& rect)
103 {
104 m_refData = new wxRegionRefData;
105 M_REGION = ::CreateRectRgn(rect.GetLeft(), rect.GetTop(), rect.GetRight(), rect.GetBottom());
106 }
107
108 /*
109 * Destroy the region.
110 */
111 wxRegion::~wxRegion()
112 {
113 // m_refData unrefed in ~wxObject
114 }
115
116 //-----------------------------------------------------------------------------
117 // Modify region
118 //-----------------------------------------------------------------------------
119
120 // Clear current region
121 void wxRegion::Clear()
122 {
123 UnRef();
124 }
125
126 // Combine rectangle (x, y, w, h) with this.
127 bool wxRegion::Combine(long x, long y, long width, long height, wxRegionOp op)
128 {
129 // Don't change shared data
130 if (!m_refData) {
131 m_refData = new wxRegionRefData();
132 } else if (m_refData->GetRefCount() > 1) {
133 wxRegionRefData* ref = (wxRegionRefData*)m_refData;
134 UnRef();
135 m_refData = new wxRegionRefData(*ref);
136 }
137 // If ref count is 1, that means it's 'ours' anyway so no action.
138
139 HRGN rectRegion = ::CreateRectRgn(x, y, x + width, y + height);
140
141 int mode = 0;
142 switch (op)
143 {
144 case wxRGN_AND: mode = RGN_AND; break ;
145 case wxRGN_OR: mode = RGN_OR; break ;
146 case wxRGN_XOR: mode = RGN_XOR; break ;
147 case wxRGN_DIFF: mode = RGN_DIFF; break ;
148 case wxRGN_COPY:
149 default:
150 mode = RGN_COPY; break ;
151 }
152
153 bool success = (ERROR != ::CombineRgn(M_REGION, M_REGION, rectRegion, mode));
154
155 ::DeleteObject(rectRegion);
156
157 return success;
158 }
159
160 // Union /e region with this.
161 bool wxRegion::Combine(const wxRegion& region, wxRegionOp op)
162 {
163 if (region.Empty())
164 return FALSE;
165
166 // Don't change shared data
167 if (!m_refData) {
168 m_refData = new wxRegionRefData();
169 } else if (m_refData->GetRefCount() > 1) {
170 wxRegionRefData* ref = (wxRegionRefData*)m_refData;
171 UnRef();
172 m_refData = new wxRegionRefData(*ref);
173 }
174
175 int mode = 0;
176 switch (op)
177 {
178 case wxRGN_AND: mode = RGN_AND; break ;
179 case wxRGN_OR: mode = RGN_OR; break ;
180 case wxRGN_XOR: mode = RGN_XOR; break ;
181 case wxRGN_DIFF: mode = RGN_DIFF; break ;
182 case wxRGN_COPY:
183 default:
184 mode = RGN_COPY; break ;
185 }
186
187 return (ERROR != ::CombineRgn(M_REGION, M_REGION, ((wxRegionRefData*)region.m_refData)->m_region, mode));
188 }
189
190 bool wxRegion::Combine(const wxRect& rect, wxRegionOp op)
191 {
192 return Combine(rect.GetLeft(), rect.GetTop(), rect.GetWidth(), rect.GetHeight(), op);
193 }
194
195 //-----------------------------------------------------------------------------
196 // Information on region
197 //-----------------------------------------------------------------------------
198
199 // Outer bounds of region
200 void wxRegion::GetBox(long& x, long& y, long&w, long &h) const
201 {
202 if (m_refData) {
203 RECT rect;
204 ::GetRgnBox(M_REGION, & rect);
205 x = rect.left;
206 y = rect.top;
207 w = rect.right - rect.left;
208 h = rect.bottom - rect.top;
209 } else {
210 x = y = w = h = 0;
211 }
212 }
213
214 wxRect wxRegion::GetBox() const
215 {
216 long x, y, w, h;
217 GetBox(x, y, w, h);
218 return wxRect(x, y, w, h);
219 }
220
221 // Is region empty?
222 bool wxRegion::Empty() const
223 {
224 if (M_REGION == 0)
225 return TRUE;
226 long x, y, w, h;
227 GetBox(x, y, w, h);
228
229 return ((w == 0) && (h == 0));
230 }
231
232 //-----------------------------------------------------------------------------
233 // Tests
234 //-----------------------------------------------------------------------------
235
236 // Does the region contain the point (x,y)?
237 wxRegionContain wxRegion::Contains(long x, long y) const
238 {
239 if (!m_refData)
240 return wxOutRegion;
241
242 if (::PtInRegion(M_REGION, (int) x, (int) y))
243 return wxInRegion;
244 else
245 return wxOutRegion;
246 }
247
248 // Does the region contain the point pt?
249 wxRegionContain wxRegion::Contains(const wxPoint& pt) const
250 {
251 if (!m_refData)
252 return wxOutRegion;
253
254 if (::PtInRegion(M_REGION, (int) pt.x, (int) pt.y))
255 return wxInRegion;
256 else
257 return wxOutRegion;
258 }
259
260 // Does the region contain the rectangle (x, y, w, h)?
261 wxRegionContain wxRegion::Contains(long x, long y, long w, long h) const
262 {
263 if (!m_refData)
264 return wxOutRegion;
265
266 RECT rect;
267 rect.left = x;
268 rect.top = y;
269 rect.right = x + w;
270 rect.bottom = y + h;
271
272 if (::RectInRegion(M_REGION, & rect))
273 return wxInRegion;
274 else
275 return wxOutRegion;
276 }
277
278 // Does the region contain the rectangle rect
279 wxRegionContain wxRegion::Contains(const wxRect& rect) const
280 {
281 if (!m_refData)
282 return wxOutRegion;
283
284 long x, y, w, h;
285 x = rect.x;
286 y = rect.y;
287 w = rect.GetWidth();
288 h = rect.GetHeight();
289 return Contains(x, y, w, h);
290 }
291
292 // Get internal region handle
293 WXHRGN wxRegion::GetHRGN() const
294 {
295 if (!m_refData)
296 return (WXHRGN) 0;
297 return (WXHRGN) M_REGION;
298 }
299
300 ///////////////////////////////////////////////////////////////////////////////
301 // //
302 // wxRegionIterator //
303 // //
304 ///////////////////////////////////////////////////////////////////////////////
305
306 /*
307 * Initialize empty iterator
308 */
309 wxRegionIterator::wxRegionIterator() : m_current(0), m_numRects(0), m_rects(NULL)
310 {
311 }
312
313 wxRegionIterator::~wxRegionIterator()
314 {
315 if (m_rects)
316 delete[] m_rects;
317 }
318
319 /*
320 * Initialize iterator for region
321 */
322 wxRegionIterator::wxRegionIterator(const wxRegion& region)
323 {
324 m_rects = NULL;
325
326 Reset(region);
327 }
328
329 /*
330 * Reset iterator for a new /e region.
331 */
332 void wxRegionIterator::Reset(const wxRegion& region)
333 {
334 m_current = 0;
335 m_region = region;
336
337 if (m_rects)
338 delete[] m_rects;
339
340 m_rects = NULL;
341
342 if (m_region.Empty())
343 m_numRects = 0;
344 else
345 {
346 #if defined(__WIN32__)
347 DWORD noBytes = ::GetRegionData(((wxRegionRefData*)region.m_refData)->m_region, 0, NULL);
348 RGNDATA *rgnData = (RGNDATA*) new char[noBytes];
349 ::GetRegionData(((wxRegionRefData*)region.m_refData)->m_region, noBytes, rgnData);
350
351 RGNDATAHEADER* header = (RGNDATAHEADER*) rgnData;
352
353 m_rects = new wxRect[header->nCount];
354
355 RECT* rect = (RECT*) ((char*)rgnData + sizeof(RGNDATAHEADER)) ;
356 size_t i;
357 for (i = 0; i < header->nCount; i++)
358 {
359 m_rects[i] = wxRect(rect->left, rect->top,
360 rect->right - rect->left, rect->bottom - rect->top);
361 rect ++; // Advances pointer by sizeof(RECT)
362 }
363
364 m_numRects = header->nCount;
365
366 delete[] (char*) rgnData;
367 #else
368 RECT rect;
369 ::GetRgnBox(((wxRegionRefData*)region.m_refData)->m_region, &rect);
370 m_rects = new wxRect[1];
371 m_rects[0].x = rect.left;
372 m_rects[0].y = rect.top;
373 m_rects[0].width = rect.right - rect.left;
374 m_rects[0].height = rect.bottom - rect.top;
375
376 m_numRects = 1;
377 #endif
378 }
379 }
380
381 /*
382 * Increment iterator. The rectangle returned is the one after the
383 * incrementation.
384 */
385 void wxRegionIterator::operator ++ ()
386 {
387 if (m_current < m_numRects)
388 ++m_current;
389 }
390
391 /*
392 * Increment iterator. The rectangle returned is the one before the
393 * incrementation.
394 */
395 void wxRegionIterator::operator ++ (int)
396 {
397 if (m_current < m_numRects)
398 ++m_current;
399 }
400
401 long wxRegionIterator::GetX() const
402 {
403 if (m_current < m_numRects)
404 return m_rects[m_current].x;
405 return 0;
406 }
407
408 long wxRegionIterator::GetY() const
409 {
410 if (m_current < m_numRects)
411 return m_rects[m_current].y;
412 return 0;
413 }
414
415 long wxRegionIterator::GetW() const
416 {
417 if (m_current < m_numRects)
418 return m_rects[m_current].width ;
419 return 0;
420 }
421
422 long wxRegionIterator::GetH() const
423 {
424 if (m_current < m_numRects)
425 return m_rects[m_current].height;
426 return 0;
427 }
428