]> git.saurik.com Git - wxWidgets.git/blob - src/msw/region.cpp
A fix for attribrute sorting, but it's still broken if there are
[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 /*
107 * Destroy the region.
108 */
109 wxRegion::~wxRegion()
110 {
111 // m_refData unrefed in ~wxObject
112 }
113
114 //-----------------------------------------------------------------------------
115 // Modify region
116 //-----------------------------------------------------------------------------
117
118 // Clear current region
119 void wxRegion::Clear()
120 {
121 UnRef();
122 }
123
124 // Combine rectangle (x, y, w, h) with this.
125 bool wxRegion::Combine(wxCoord x, wxCoord y, wxCoord width, wxCoord height, wxRegionOp op)
126 {
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 }
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
151 bool success = (ERROR != ::CombineRgn(M_REGION, M_REGION, rectRegion, mode));
152
153 ::DeleteObject(rectRegion);
154
155 return success;
156 }
157
158 // Union /e region with this.
159 bool wxRegion::Combine(const wxRegion& region, wxRegionOp op)
160 {
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 }
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
185 return (ERROR != ::CombineRgn(M_REGION, M_REGION, ((wxRegionRefData*)region.m_refData)->m_region, mode));
186 }
187
188 bool wxRegion::Combine(const wxRect& rect, wxRegionOp op)
189 {
190 return Combine(rect.GetLeft(), rect.GetTop(), rect.GetWidth(), rect.GetHeight(), op);
191 }
192
193 //-----------------------------------------------------------------------------
194 // Information on region
195 //-----------------------------------------------------------------------------
196
197 // Outer bounds of region
198 void wxRegion::GetBox(wxCoord& x, wxCoord& y, wxCoord&w, wxCoord &h) const
199 {
200 if (m_refData)
201 {
202 RECT rect;
203 ::GetRgnBox(M_REGION, & rect);
204 x = rect.left;
205 y = rect.top;
206 w = rect.right - rect.left;
207 h = rect.bottom - rect.top;
208 }
209 else
210 {
211 x = y = w = h = 0;
212 }
213 }
214
215 wxRect wxRegion::GetBox() const
216 {
217 wxCoord x, y, w, h;
218 GetBox(x, y, w, h);
219 return wxRect(x, y, w, h);
220 }
221
222 // Is region empty?
223 bool wxRegion::Empty() const
224 {
225 wxCoord x, y, w, h;
226 GetBox(x, y, w, h);
227
228 return (w == 0) && (h == 0);
229 }
230
231 //-----------------------------------------------------------------------------
232 // Tests
233 //-----------------------------------------------------------------------------
234
235 // Does the region contain the point (x,y)?
236 wxRegionContain wxRegion::Contains(wxCoord x, wxCoord y) const
237 {
238 if (!m_refData)
239 return wxOutRegion;
240
241 if (::PtInRegion(M_REGION, (int) x, (int) y))
242 return wxInRegion;
243 else
244 return wxOutRegion;
245 }
246
247 // Does the region contain the point pt?
248 wxRegionContain wxRegion::Contains(const wxPoint& pt) const
249 {
250 if (!m_refData)
251 return wxOutRegion;
252
253 if (::PtInRegion(M_REGION, (int) pt.x, (int) pt.y))
254 return wxInRegion;
255 else
256 return wxOutRegion;
257 }
258
259 // Does the region contain the rectangle (x, y, w, h)?
260 wxRegionContain wxRegion::Contains(wxCoord x, wxCoord y, wxCoord w, wxCoord h) const
261 {
262 if (!m_refData)
263 return wxOutRegion;
264
265 RECT rect;
266 rect.left = x;
267 rect.top = y;
268 rect.right = x + w;
269 rect.bottom = y + h;
270
271 if (::RectInRegion(M_REGION, & rect))
272 return wxInRegion;
273 else
274 return wxOutRegion;
275 }
276
277 // Does the region contain the rectangle rect
278 wxRegionContain wxRegion::Contains(const wxRect& rect) const
279 {
280 if (!m_refData)
281 return wxOutRegion;
282
283 wxCoord x, y, w, h;
284 x = rect.x;
285 y = rect.y;
286 w = rect.GetWidth();
287 h = rect.GetHeight();
288 return Contains(x, y, w, h);
289 }
290
291 // Get internal region handle
292 WXHRGN wxRegion::GetHRGN() const
293 {
294 if (!m_refData)
295 return (WXHRGN) 0;
296 return (WXHRGN) M_REGION;
297 }
298
299 ///////////////////////////////////////////////////////////////////////////////
300 // //
301 // wxRegionIterator //
302 // //
303 ///////////////////////////////////////////////////////////////////////////////
304
305 /*
306 * Initialize empty iterator
307 */
308 wxRegionIterator::wxRegionIterator() : m_current(0), m_numRects(0), m_rects(NULL)
309 {
310 }
311
312 wxRegionIterator::~wxRegionIterator()
313 {
314 if (m_rects)
315 delete[] m_rects;
316 }
317
318 /*
319 * Initialize iterator for region
320 */
321 wxRegionIterator::wxRegionIterator(const wxRegion& region)
322 {
323 m_rects = NULL;
324
325 Reset(region);
326 }
327
328 /*
329 * Reset iterator for a new /e region.
330 */
331 void wxRegionIterator::Reset(const wxRegion& region)
332 {
333 m_current = 0;
334 m_region = region;
335
336 if (m_rects)
337 delete[] m_rects;
338
339 m_rects = NULL;
340
341 if (m_region.Empty())
342 m_numRects = 0;
343 else
344 {
345 #if defined(__WIN32__)
346 DWORD noBytes = ::GetRegionData(((wxRegionRefData*)region.m_refData)->m_region, 0, NULL);
347 RGNDATA *rgnData = (RGNDATA*) new char[noBytes];
348 ::GetRegionData(((wxRegionRefData*)region.m_refData)->m_region, noBytes, rgnData);
349
350 RGNDATAHEADER* header = (RGNDATAHEADER*) rgnData;
351
352 m_rects = new wxRect[header->nCount];
353
354 RECT* rect = (RECT*) ((char*)rgnData + sizeof(RGNDATAHEADER)) ;
355 size_t i;
356 for (i = 0; i < header->nCount; i++)
357 {
358 m_rects[i] = wxRect(rect->left, rect->top,
359 rect->right - rect->left, rect->bottom - rect->top);
360 rect ++; // Advances pointer by sizeof(RECT)
361 }
362
363 m_numRects = header->nCount;
364
365 delete[] (char*) rgnData;
366 #else
367 RECT rect;
368 ::GetRgnBox(((wxRegionRefData*)region.m_refData)->m_region, &rect);
369 m_rects = new wxRect[1];
370 m_rects[0].x = rect.left;
371 m_rects[0].y = rect.top;
372 m_rects[0].width = rect.right - rect.left;
373 m_rects[0].height = rect.bottom - rect.top;
374
375 m_numRects = 1;
376 #endif
377 }
378 }
379
380 /*
381 * Increment iterator. The rectangle returned is the one after the
382 * incrementation.
383 */
384 void wxRegionIterator::operator ++ ()
385 {
386 if (m_current < m_numRects)
387 ++m_current;
388 }
389
390 /*
391 * Increment iterator. The rectangle returned is the one before the
392 * incrementation.
393 */
394 void wxRegionIterator::operator ++ (int)
395 {
396 if (m_current < m_numRects)
397 ++m_current;
398 }
399
400 wxCoord wxRegionIterator::GetX() const
401 {
402 if (m_current < m_numRects)
403 return m_rects[m_current].x;
404 return 0;
405 }
406
407 wxCoord wxRegionIterator::GetY() const
408 {
409 if (m_current < m_numRects)
410 return m_rects[m_current].y;
411 return 0;
412 }
413
414 wxCoord wxRegionIterator::GetW() const
415 {
416 if (m_current < m_numRects)
417 return m_rects[m_current].width ;
418 return 0;
419 }
420
421 wxCoord wxRegionIterator::GetH() const
422 {
423 if (m_current < m_numRects)
424 return m_rects[m_current].height;
425 return 0;
426 }
427