implemented wxRegion::Offset() for MSW and documented it
[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/window.h"
27 #include "wx/msw/private.h"
28
29 IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject)
30 IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator, wxObject)
31
32 //-----------------------------------------------------------------------------
33 // wxRegionRefData implementation
34 //-----------------------------------------------------------------------------
35
36 class WXDLLEXPORT wxRegionRefData : public wxGDIRefData
37 {
38 public:
39 wxRegionRefData()
40 {
41 m_region = 0;
42 }
43
44 wxRegionRefData(const wxRegionRefData& data)
45 {
46 #if defined(__WIN32__) && !defined(__WXMICROWIN__)
47 DWORD noBytes = ::GetRegionData(data.m_region, 0, NULL);
48 RGNDATA *rgnData = (RGNDATA*) new char[noBytes];
49 ::GetRegionData(data.m_region, noBytes, rgnData);
50 m_region = ::ExtCreateRegion(NULL, noBytes, rgnData);
51 delete[] (char*) rgnData;
52 #else
53 RECT rect;
54 ::GetRgnBox(data.m_region, &rect);
55 m_region = ::CreateRectRgnIndirect(&rect);
56 #endif
57 }
58
59 ~wxRegionRefData()
60 {
61 ::DeleteObject(m_region);
62 m_region = 0;
63 }
64
65 HRGN m_region;
66 };
67
68 #define M_REGION (((wxRegionRefData*)m_refData)->m_region)
69
70 //-----------------------------------------------------------------------------
71 // wxRegion
72 //-----------------------------------------------------------------------------
73
74 /*
75 * Create an empty region.
76 */
77 wxRegion::wxRegion()
78 {
79 m_refData = (wxRegionRefData *)NULL;
80 }
81
82 wxRegion::wxRegion(WXHRGN hRegion)
83 {
84 m_refData = new wxRegionRefData;
85 M_REGION = (HRGN) hRegion;
86 }
87
88 wxRegion::wxRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
89 {
90 m_refData = new wxRegionRefData;
91 M_REGION = ::CreateRectRgn(x, y, x + w, y + h);
92 }
93
94 wxRegion::wxRegion(const wxPoint& topLeft, const wxPoint& bottomRight)
95 {
96 m_refData = new wxRegionRefData;
97 M_REGION = ::CreateRectRgn(topLeft.x, topLeft.y, bottomRight.x, bottomRight.y);
98 }
99
100 wxRegion::wxRegion(const wxRect& rect)
101 {
102 m_refData = new wxRegionRefData;
103 M_REGION = ::CreateRectRgn(rect.x, rect.y, rect.x + rect.width, rect.y + rect.height);
104 }
105
106 wxRegion::wxRegion(size_t n, const wxPoint *points, int fillStyle)
107 {
108 #ifdef __WXMICROWIN__
109 m_refData = NULL;
110 M_REGION = NULL;
111 #else
112 m_refData = new wxRegionRefData;
113 M_REGION = ::CreatePolygonRgn
114 (
115 (POINT*)points,
116 n,
117 fillStyle == wxODDEVEN_RULE ? ALTERNATE : WINDING
118 );
119 #endif
120 }
121
122 /*
123 * Destroy the region.
124 */
125 wxRegion::~wxRegion()
126 {
127 // m_refData unrefed in ~wxObject
128 }
129
130 wxObjectRefData *wxRegion::CreateData() const
131 {
132 return new wxRegionRefData;
133 }
134
135 wxObjectRefData *wxRegion::CloneData(wxObjectRefData *data) const
136 {
137 return new wxRegionRefData(*(wxRegionRefData *)data);
138 }
139
140 //-----------------------------------------------------------------------------
141 // Modify region
142 //-----------------------------------------------------------------------------
143
144 // Clear current region
145 void wxRegion::Clear()
146 {
147 UnRef();
148 }
149
150 bool wxRegion::Offset(wxCoord x, wxCoord y)
151 {
152 if ( !x && !y )
153 {
154 // nothing to do
155 return TRUE;
156 }
157
158 AllocExclusive();
159
160 if ( ::OffsetRgn(GetHrgn(), x, y) == ERROR )
161 {
162 wxLogLastError(_T("OffsetRgn"));
163
164 return FALSE;
165 }
166
167 return TRUE;
168 }
169
170 // Combine rectangle (x, y, w, h) with this.
171 bool wxRegion::Combine(wxCoord x, wxCoord y, wxCoord width, wxCoord height, wxRegionOp op)
172 {
173 AllocExclusive();
174
175 HRGN rectRegion = ::CreateRectRgn(x, y, x + width, y + height);
176
177 int mode = 0;
178 switch (op)
179 {
180 case wxRGN_AND: mode = RGN_AND; break ;
181 case wxRGN_OR: mode = RGN_OR; break ;
182 case wxRGN_XOR: mode = RGN_XOR; break ;
183 case wxRGN_DIFF: mode = RGN_DIFF; break ;
184 case wxRGN_COPY:
185 default:
186 mode = RGN_COPY; break ;
187 }
188
189 bool success = ::CombineRgn(M_REGION, M_REGION, rectRegion, mode) != ERROR;
190 if ( !success )
191 {
192 wxLogLastError(_T("CombineRgn"));
193 }
194
195 ::DeleteObject(rectRegion);
196
197 return success;
198 }
199
200 // Union /e region with this.
201 bool wxRegion::Combine(const wxRegion& region, wxRegionOp op)
202 {
203 if (region.Empty())
204 return FALSE;
205
206 AllocExclusive();
207
208 int mode = 0;
209 switch (op)
210 {
211 case wxRGN_AND: mode = RGN_AND; break ;
212 case wxRGN_OR: mode = RGN_OR; break ;
213 case wxRGN_XOR: mode = RGN_XOR; break ;
214 case wxRGN_DIFF: mode = RGN_DIFF; break ;
215 case wxRGN_COPY:
216 default:
217 mode = RGN_COPY; break ;
218 }
219
220 return (ERROR != ::CombineRgn(M_REGION, M_REGION, ((wxRegionRefData*)region.m_refData)->m_region, mode));
221 }
222
223 bool wxRegion::Combine(const wxRect& rect, wxRegionOp op)
224 {
225 return Combine(rect.GetLeft(), rect.GetTop(), rect.GetWidth(), rect.GetHeight(), op);
226 }
227
228 //-----------------------------------------------------------------------------
229 // Information on region
230 //-----------------------------------------------------------------------------
231
232 // Outer bounds of region
233 void wxRegion::GetBox(wxCoord& x, wxCoord& y, wxCoord&w, wxCoord &h) const
234 {
235 if (m_refData)
236 {
237 RECT rect;
238 ::GetRgnBox(M_REGION, & rect);
239 x = rect.left;
240 y = rect.top;
241 w = rect.right - rect.left;
242 h = rect.bottom - rect.top;
243 }
244 else
245 {
246 x = y = w = h = 0;
247 }
248 }
249
250 wxRect wxRegion::GetBox() const
251 {
252 wxCoord x, y, w, h;
253 GetBox(x, y, w, h);
254 return wxRect(x, y, w, h);
255 }
256
257 // Is region empty?
258 bool wxRegion::Empty() const
259 {
260 wxCoord x, y, w, h;
261 GetBox(x, y, w, h);
262
263 return (w == 0) && (h == 0);
264 }
265
266 //-----------------------------------------------------------------------------
267 // Tests
268 //-----------------------------------------------------------------------------
269
270 // Does the region contain the point (x,y)?
271 wxRegionContain wxRegion::Contains(wxCoord x, wxCoord y) const
272 {
273 if (!m_refData)
274 return wxOutRegion;
275
276 if (::PtInRegion(M_REGION, (int) x, (int) y))
277 return wxInRegion;
278 else
279 return wxOutRegion;
280 }
281
282 // Does the region contain the point pt?
283 wxRegionContain wxRegion::Contains(const wxPoint& pt) const
284 {
285 if (!m_refData)
286 return wxOutRegion;
287
288 if (::PtInRegion(M_REGION, (int) pt.x, (int) pt.y))
289 return wxInRegion;
290 else
291 return wxOutRegion;
292 }
293
294 // Does the region contain the rectangle (x, y, w, h)?
295 wxRegionContain wxRegion::Contains(wxCoord x, wxCoord y, wxCoord w, wxCoord h) const
296 {
297 if (!m_refData)
298 return wxOutRegion;
299
300 RECT rect;
301 rect.left = x;
302 rect.top = y;
303 rect.right = x + w;
304 rect.bottom = y + h;
305
306 if (::RectInRegion(M_REGION, & rect))
307 return wxInRegion;
308 else
309 return wxOutRegion;
310 }
311
312 // Does the region contain the rectangle rect
313 wxRegionContain wxRegion::Contains(const wxRect& rect) const
314 {
315 if (!m_refData)
316 return wxOutRegion;
317
318 wxCoord x, y, w, h;
319 x = rect.x;
320 y = rect.y;
321 w = rect.GetWidth();
322 h = rect.GetHeight();
323 return Contains(x, y, w, h);
324 }
325
326 // Get internal region handle
327 WXHRGN wxRegion::GetHRGN() const
328 {
329 if (!m_refData)
330 return (WXHRGN) 0;
331 return (WXHRGN) M_REGION;
332 }
333
334 ///////////////////////////////////////////////////////////////////////////////
335 // //
336 // wxRegionIterator //
337 // //
338 ///////////////////////////////////////////////////////////////////////////////
339
340 /*
341 * Initialize empty iterator
342 */
343 wxRegionIterator::wxRegionIterator() : m_current(0), m_numRects(0), m_rects(NULL)
344 {
345 }
346
347 wxRegionIterator::~wxRegionIterator()
348 {
349 if (m_rects)
350 delete[] m_rects;
351 }
352
353 /*
354 * Initialize iterator for region
355 */
356 wxRegionIterator::wxRegionIterator(const wxRegion& region)
357 {
358 m_rects = NULL;
359
360 Reset(region);
361 }
362
363 /*
364 * Reset iterator for a new /e region.
365 */
366 void wxRegionIterator::Reset(const wxRegion& region)
367 {
368 m_current = 0;
369 m_region = region;
370
371 if (m_rects)
372 delete[] m_rects;
373
374 m_rects = NULL;
375
376 if (m_region.Empty())
377 m_numRects = 0;
378 else
379 {
380 #if defined(__WIN32__)
381 DWORD noBytes = ::GetRegionData(((wxRegionRefData*)region.m_refData)->m_region, 0, NULL);
382 RGNDATA *rgnData = (RGNDATA*) new char[noBytes];
383 ::GetRegionData(((wxRegionRefData*)region.m_refData)->m_region, noBytes, rgnData);
384
385 RGNDATAHEADER* header = (RGNDATAHEADER*) rgnData;
386
387 m_rects = new wxRect[header->nCount];
388
389 RECT* rect = (RECT*) ((char*)rgnData + sizeof(RGNDATAHEADER)) ;
390 size_t i;
391 for (i = 0; i < header->nCount; i++)
392 {
393 m_rects[i] = wxRect(rect->left, rect->top,
394 rect->right - rect->left, rect->bottom - rect->top);
395 rect ++; // Advances pointer by sizeof(RECT)
396 }
397
398 m_numRects = header->nCount;
399
400 delete[] (char*) rgnData;
401 #else
402 RECT rect;
403 ::GetRgnBox(((wxRegionRefData*)region.m_refData)->m_region, &rect);
404 m_rects = new wxRect[1];
405 m_rects[0].x = rect.left;
406 m_rects[0].y = rect.top;
407 m_rects[0].width = rect.right - rect.left;
408 m_rects[0].height = rect.bottom - rect.top;
409
410 m_numRects = 1;
411 #endif
412 }
413 }
414
415 /*
416 * Increment iterator. The rectangle returned is the one after the
417 * incrementation.
418 */
419 void wxRegionIterator::operator ++ ()
420 {
421 if (m_current < m_numRects)
422 ++m_current;
423 }
424
425 /*
426 * Increment iterator. The rectangle returned is the one before the
427 * incrementation.
428 */
429 void wxRegionIterator::operator ++ (int)
430 {
431 if (m_current < m_numRects)
432 ++m_current;
433 }
434
435 wxCoord wxRegionIterator::GetX() const
436 {
437 if (m_current < m_numRects)
438 return m_rects[m_current].x;
439 return 0;
440 }
441
442 wxCoord wxRegionIterator::GetY() const
443 {
444 if (m_current < m_numRects)
445 return m_rects[m_current].y;
446 return 0;
447 }
448
449 wxCoord wxRegionIterator::GetW() const
450 {
451 if (m_current < m_numRects)
452 return m_rects[m_current].width ;
453 return 0;
454 }
455
456 wxCoord wxRegionIterator::GetH() const
457 {
458 if (m_current < m_numRects)
459 return m_rects[m_current].height;
460 return 0;
461 }
462