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