]> git.saurik.com Git - wxWidgets.git/blob - src/msw/region.cpp
don't include windows.h unless neccessary
[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 //-----------------------------------------------------------------------------
131 // Modify region
132 //-----------------------------------------------------------------------------
133
134 // Clear current region
135 void wxRegion::Clear()
136 {
137 UnRef();
138 }
139
140 // Combine rectangle (x, y, w, h) with this.
141 bool wxRegion::Combine(wxCoord x, wxCoord y, wxCoord width, wxCoord height, wxRegionOp op)
142 {
143 // Don't change shared data
144 if (!m_refData) {
145 m_refData = new wxRegionRefData();
146 } else if (m_refData->GetRefCount() > 1) {
147 wxRegionRefData* ref = (wxRegionRefData*)m_refData;
148 UnRef();
149 m_refData = new wxRegionRefData(*ref);
150 }
151 // If ref count is 1, that means it's 'ours' anyway so no action.
152
153 HRGN rectRegion = ::CreateRectRgn(x, y, x + width, y + height);
154
155 int mode = 0;
156 switch (op)
157 {
158 case wxRGN_AND: mode = RGN_AND; break ;
159 case wxRGN_OR: mode = RGN_OR; break ;
160 case wxRGN_XOR: mode = RGN_XOR; break ;
161 case wxRGN_DIFF: mode = RGN_DIFF; break ;
162 case wxRGN_COPY:
163 default:
164 mode = RGN_COPY; break ;
165 }
166
167 bool success = (ERROR != ::CombineRgn(M_REGION, M_REGION, rectRegion, mode));
168
169 ::DeleteObject(rectRegion);
170
171 return success;
172 }
173
174 // Union /e region with this.
175 bool wxRegion::Combine(const wxRegion& region, wxRegionOp op)
176 {
177 if (region.Empty())
178 return FALSE;
179
180 // Don't change shared data
181 if (!m_refData) {
182 m_refData = new wxRegionRefData();
183 } else if (m_refData->GetRefCount() > 1) {
184 wxRegionRefData* ref = (wxRegionRefData*)m_refData;
185 UnRef();
186 m_refData = new wxRegionRefData(*ref);
187 }
188
189 int mode = 0;
190 switch (op)
191 {
192 case wxRGN_AND: mode = RGN_AND; break ;
193 case wxRGN_OR: mode = RGN_OR; break ;
194 case wxRGN_XOR: mode = RGN_XOR; break ;
195 case wxRGN_DIFF: mode = RGN_DIFF; break ;
196 case wxRGN_COPY:
197 default:
198 mode = RGN_COPY; break ;
199 }
200
201 return (ERROR != ::CombineRgn(M_REGION, M_REGION, ((wxRegionRefData*)region.m_refData)->m_region, mode));
202 }
203
204 bool wxRegion::Combine(const wxRect& rect, wxRegionOp op)
205 {
206 return Combine(rect.GetLeft(), rect.GetTop(), rect.GetWidth(), rect.GetHeight(), op);
207 }
208
209 //-----------------------------------------------------------------------------
210 // Information on region
211 //-----------------------------------------------------------------------------
212
213 // Outer bounds of region
214 void wxRegion::GetBox(wxCoord& x, wxCoord& y, wxCoord&w, wxCoord &h) const
215 {
216 if (m_refData)
217 {
218 RECT rect;
219 ::GetRgnBox(M_REGION, & rect);
220 x = rect.left;
221 y = rect.top;
222 w = rect.right - rect.left;
223 h = rect.bottom - rect.top;
224 }
225 else
226 {
227 x = y = w = h = 0;
228 }
229 }
230
231 wxRect wxRegion::GetBox() const
232 {
233 wxCoord x, y, w, h;
234 GetBox(x, y, w, h);
235 return wxRect(x, y, w, h);
236 }
237
238 // Is region empty?
239 bool wxRegion::Empty() const
240 {
241 wxCoord x, y, w, h;
242 GetBox(x, y, w, h);
243
244 return (w == 0) && (h == 0);
245 }
246
247 //-----------------------------------------------------------------------------
248 // Tests
249 //-----------------------------------------------------------------------------
250
251 // Does the region contain the point (x,y)?
252 wxRegionContain wxRegion::Contains(wxCoord x, wxCoord y) const
253 {
254 if (!m_refData)
255 return wxOutRegion;
256
257 if (::PtInRegion(M_REGION, (int) x, (int) y))
258 return wxInRegion;
259 else
260 return wxOutRegion;
261 }
262
263 // Does the region contain the point pt?
264 wxRegionContain wxRegion::Contains(const wxPoint& pt) const
265 {
266 if (!m_refData)
267 return wxOutRegion;
268
269 if (::PtInRegion(M_REGION, (int) pt.x, (int) pt.y))
270 return wxInRegion;
271 else
272 return wxOutRegion;
273 }
274
275 // Does the region contain the rectangle (x, y, w, h)?
276 wxRegionContain wxRegion::Contains(wxCoord x, wxCoord y, wxCoord w, wxCoord h) const
277 {
278 if (!m_refData)
279 return wxOutRegion;
280
281 RECT rect;
282 rect.left = x;
283 rect.top = y;
284 rect.right = x + w;
285 rect.bottom = y + h;
286
287 if (::RectInRegion(M_REGION, & rect))
288 return wxInRegion;
289 else
290 return wxOutRegion;
291 }
292
293 // Does the region contain the rectangle rect
294 wxRegionContain wxRegion::Contains(const wxRect& rect) const
295 {
296 if (!m_refData)
297 return wxOutRegion;
298
299 wxCoord x, y, w, h;
300 x = rect.x;
301 y = rect.y;
302 w = rect.GetWidth();
303 h = rect.GetHeight();
304 return Contains(x, y, w, h);
305 }
306
307 // Get internal region handle
308 WXHRGN wxRegion::GetHRGN() const
309 {
310 if (!m_refData)
311 return (WXHRGN) 0;
312 return (WXHRGN) M_REGION;
313 }
314
315 ///////////////////////////////////////////////////////////////////////////////
316 // //
317 // wxRegionIterator //
318 // //
319 ///////////////////////////////////////////////////////////////////////////////
320
321 /*
322 * Initialize empty iterator
323 */
324 wxRegionIterator::wxRegionIterator() : m_current(0), m_numRects(0), m_rects(NULL)
325 {
326 }
327
328 wxRegionIterator::~wxRegionIterator()
329 {
330 if (m_rects)
331 delete[] m_rects;
332 }
333
334 /*
335 * Initialize iterator for region
336 */
337 wxRegionIterator::wxRegionIterator(const wxRegion& region)
338 {
339 m_rects = NULL;
340
341 Reset(region);
342 }
343
344 /*
345 * Reset iterator for a new /e region.
346 */
347 void wxRegionIterator::Reset(const wxRegion& region)
348 {
349 m_current = 0;
350 m_region = region;
351
352 if (m_rects)
353 delete[] m_rects;
354
355 m_rects = NULL;
356
357 if (m_region.Empty())
358 m_numRects = 0;
359 else
360 {
361 #if defined(__WIN32__)
362 DWORD noBytes = ::GetRegionData(((wxRegionRefData*)region.m_refData)->m_region, 0, NULL);
363 RGNDATA *rgnData = (RGNDATA*) new char[noBytes];
364 ::GetRegionData(((wxRegionRefData*)region.m_refData)->m_region, noBytes, rgnData);
365
366 RGNDATAHEADER* header = (RGNDATAHEADER*) rgnData;
367
368 m_rects = new wxRect[header->nCount];
369
370 RECT* rect = (RECT*) ((char*)rgnData + sizeof(RGNDATAHEADER)) ;
371 size_t i;
372 for (i = 0; i < header->nCount; i++)
373 {
374 m_rects[i] = wxRect(rect->left, rect->top,
375 rect->right - rect->left, rect->bottom - rect->top);
376 rect ++; // Advances pointer by sizeof(RECT)
377 }
378
379 m_numRects = header->nCount;
380
381 delete[] (char*) rgnData;
382 #else
383 RECT rect;
384 ::GetRgnBox(((wxRegionRefData*)region.m_refData)->m_region, &rect);
385 m_rects = new wxRect[1];
386 m_rects[0].x = rect.left;
387 m_rects[0].y = rect.top;
388 m_rects[0].width = rect.right - rect.left;
389 m_rects[0].height = rect.bottom - rect.top;
390
391 m_numRects = 1;
392 #endif
393 }
394 }
395
396 /*
397 * Increment iterator. The rectangle returned is the one after the
398 * incrementation.
399 */
400 void wxRegionIterator::operator ++ ()
401 {
402 if (m_current < m_numRects)
403 ++m_current;
404 }
405
406 /*
407 * Increment iterator. The rectangle returned is the one before the
408 * incrementation.
409 */
410 void wxRegionIterator::operator ++ (int)
411 {
412 if (m_current < m_numRects)
413 ++m_current;
414 }
415
416 wxCoord wxRegionIterator::GetX() const
417 {
418 if (m_current < m_numRects)
419 return m_rects[m_current].x;
420 return 0;
421 }
422
423 wxCoord wxRegionIterator::GetY() const
424 {
425 if (m_current < m_numRects)
426 return m_rects[m_current].y;
427 return 0;
428 }
429
430 wxCoord wxRegionIterator::GetW() const
431 {
432 if (m_current < m_numRects)
433 return m_rects[m_current].width ;
434 return 0;
435 }
436
437 wxCoord wxRegionIterator::GetH() const
438 {
439 if (m_current < m_numRects)
440 return m_rects[m_current].height;
441 return 0;
442 }
443