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