]> git.saurik.com Git - wxWidgets.git/blob - src/msw/region.cpp
* Fix logical error in m_overflow attribute merging
[wxWidgets.git] / src / msw / region.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: msw/region.cpp
3 // Purpose: wxRegion implementation using Win32 API
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: Fri Oct 24 10:46:34 MET 1997
7 // RCS-ID: $Id$
8 // Copyright: (c) 1997-2002 wxWindows team
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "region.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #include "wx/region.h"
32 #include "wx/gdicmn.h"
33
34 #include "wx/msw/private.h"
35
36 IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject)
37 IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator, wxObject)
38
39 // ----------------------------------------------------------------------------
40 // wxRegionRefData implementation
41 // ----------------------------------------------------------------------------
42
43 class WXDLLEXPORT wxRegionRefData : public wxGDIRefData
44 {
45 public:
46 wxRegionRefData()
47 {
48 m_region = 0;
49 }
50
51 wxRegionRefData(const wxRegionRefData& data)
52 {
53 #if defined(__WIN32__) && !defined(__WXMICROWIN__)
54 DWORD noBytes = ::GetRegionData(data.m_region, 0, NULL);
55 RGNDATA *rgnData = (RGNDATA*) new char[noBytes];
56 ::GetRegionData(data.m_region, noBytes, rgnData);
57 m_region = ::ExtCreateRegion(NULL, noBytes, rgnData);
58 delete[] (char*) rgnData;
59 #else
60 RECT rect;
61 ::GetRgnBox(data.m_region, &rect);
62 m_region = ::CreateRectRgnIndirect(&rect);
63 #endif
64 }
65
66 virtual ~wxRegionRefData()
67 {
68 ::DeleteObject(m_region);
69 m_region = 0;
70 }
71
72 HRGN m_region;
73
74 private:
75 // Cannot use
76 // DECLARE_NO_COPY_CLASS(wxRegionRefData)
77 // because copy constructor is explicitly declared above;
78 // but no copy assignment operator is defined, so declare
79 // it private to prevent the compiler from defining it:
80 wxRegionRefData& operator=(const wxRegionRefData&);
81 };
82
83 #define M_REGION (((wxRegionRefData*)m_refData)->m_region)
84 #define M_REGION_OF(rgn) (((wxRegionRefData*)(rgn.m_refData))->m_region)
85
86 // ============================================================================
87 // wxRegion implementation
88 // ============================================================================
89
90 // ----------------------------------------------------------------------------
91 // ctors and dtor
92 // ----------------------------------------------------------------------------
93
94 wxRegion::wxRegion()
95 {
96 m_refData = (wxRegionRefData *)NULL;
97 }
98
99 wxRegion::wxRegion(WXHRGN hRegion)
100 {
101 m_refData = new wxRegionRefData;
102 M_REGION = (HRGN) hRegion;
103 }
104
105 wxRegion::wxRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
106 {
107 m_refData = new wxRegionRefData;
108 M_REGION = ::CreateRectRgn(x, y, x + w, y + h);
109 }
110
111 wxRegion::wxRegion(const wxPoint& topLeft, const wxPoint& bottomRight)
112 {
113 m_refData = new wxRegionRefData;
114 M_REGION = ::CreateRectRgn(topLeft.x, topLeft.y, bottomRight.x, bottomRight.y);
115 }
116
117 wxRegion::wxRegion(const wxRect& rect)
118 {
119 m_refData = new wxRegionRefData;
120 M_REGION = ::CreateRectRgn(rect.x, rect.y, rect.x + rect.width, rect.y + rect.height);
121 }
122
123 wxRegion::wxRegion(size_t n, const wxPoint *points, int fillStyle)
124 {
125 #ifdef __WXMICROWIN__
126 m_refData = NULL;
127 M_REGION = NULL;
128 #else
129 m_refData = new wxRegionRefData;
130 M_REGION = ::CreatePolygonRgn
131 (
132 (POINT*)points,
133 n,
134 fillStyle == wxODDEVEN_RULE ? ALTERNATE : WINDING
135 );
136 #endif
137 }
138
139 wxRegion::~wxRegion()
140 {
141 // m_refData unrefed in ~wxObject
142 }
143
144 wxObjectRefData *wxRegion::CreateRefData() const
145 {
146 return new wxRegionRefData;
147 }
148
149 wxObjectRefData *wxRegion::CloneRefData(const wxObjectRefData *data) const
150 {
151 return new wxRegionRefData(*(wxRegionRefData *)data);
152 }
153
154 // ----------------------------------------------------------------------------
155 // wxRegion operations
156 // ----------------------------------------------------------------------------
157
158 // Clear current region
159 void wxRegion::Clear()
160 {
161 UnRef();
162 }
163
164 bool wxRegion::Offset(wxCoord x, wxCoord y)
165 {
166 wxCHECK_MSG( M_REGION, FALSE, _T("invalid wxRegion") );
167
168 if ( !x && !y )
169 {
170 // nothing to do
171 return TRUE;
172 }
173
174 AllocExclusive();
175
176 if ( ::OffsetRgn(GetHrgn(), x, y) == ERROR )
177 {
178 wxLogLastError(_T("OffsetRgn"));
179
180 return FALSE;
181 }
182
183 return TRUE;
184 }
185
186 // combine another region with this one
187 bool wxRegion::Combine(const wxRegion& rgn, wxRegionOp op)
188 {
189 // we can't use the API functions if we don't have a valid region handle
190 if ( !m_refData )
191 {
192 // combining with an empty/invalid region works differently depending
193 // on the operation
194 switch ( op )
195 {
196 case wxRGN_COPY:
197 case wxRGN_OR:
198 case wxRGN_XOR:
199 *this = rgn;
200 break;
201
202 default:
203 wxFAIL_MSG( _T("unknown region operation") );
204 // fall through
205
206 case wxRGN_AND:
207 case wxRGN_DIFF:
208 // leave empty/invalid
209 return FALSE;
210 }
211 }
212 else // we have a valid region
213 {
214 AllocExclusive();
215
216 int mode;
217 switch ( op )
218 {
219 case wxRGN_AND:
220 mode = RGN_AND;
221 break;
222
223 case wxRGN_OR:
224 mode = RGN_OR;
225 break;
226
227 case wxRGN_XOR:
228 mode = RGN_XOR;
229 break;
230
231 case wxRGN_DIFF:
232 mode = RGN_DIFF;
233 break;
234
235 default:
236 wxFAIL_MSG( _T("unknown region operation") );
237 // fall through
238
239 case wxRGN_COPY:
240 mode = RGN_COPY;
241 break;
242 }
243
244 if ( ::CombineRgn(M_REGION, M_REGION, M_REGION_OF(rgn), mode) == ERROR )
245 {
246 wxLogLastError(_T("CombineRgn"));
247
248 return FALSE;
249 }
250 }
251
252 return TRUE;
253 }
254
255 // Combine rectangle (x, y, w, h) with this.
256 bool wxRegion::Combine(wxCoord x, wxCoord y,
257 wxCoord width, wxCoord height,
258 wxRegionOp op)
259 {
260 return Combine(wxRegion(x, y, width, height), op);
261 }
262
263 bool wxRegion::Combine(const wxRect& rect, wxRegionOp op)
264 {
265 return Combine(rect.GetLeft(), rect.GetTop(),
266 rect.GetWidth(), rect.GetHeight(), op);
267 }
268
269 // ----------------------------------------------------------------------------
270 // wxRegion bounding box
271 // ----------------------------------------------------------------------------
272
273 // Outer bounds of region
274 void wxRegion::GetBox(wxCoord& x, wxCoord& y, wxCoord&w, wxCoord &h) const
275 {
276 if (m_refData)
277 {
278 RECT rect;
279 ::GetRgnBox(M_REGION, & rect);
280 x = rect.left;
281 y = rect.top;
282 w = rect.right - rect.left;
283 h = rect.bottom - rect.top;
284 }
285 else
286 {
287 x = y = w = h = 0;
288 }
289 }
290
291 wxRect wxRegion::GetBox() const
292 {
293 wxCoord x, y, w, h;
294 GetBox(x, y, w, h);
295 return wxRect(x, y, w, h);
296 }
297
298 // Is region empty?
299 bool wxRegion::Empty() const
300 {
301 wxCoord x, y, w, h;
302 GetBox(x, y, w, h);
303
304 return (w == 0) && (h == 0);
305 }
306
307 // ----------------------------------------------------------------------------
308 // wxRegion hit testing
309 // ----------------------------------------------------------------------------
310
311 // Does the region contain the point (x,y)?
312 wxRegionContain wxRegion::Contains(wxCoord x, wxCoord y) const
313 {
314 if (!m_refData)
315 return wxOutRegion;
316
317 return ::PtInRegion(M_REGION, (int) x, (int) y) ? wxInRegion : wxOutRegion;
318 }
319
320 // Does the region contain the point pt?
321 wxRegionContain wxRegion::Contains(const wxPoint& pt) const
322 {
323 return Contains(pt.x, pt.y);
324 }
325
326 // Does the region contain the rectangle (x, y, w, h)?
327 wxRegionContain wxRegion::Contains(wxCoord x, wxCoord y,
328 wxCoord w, wxCoord h) const
329 {
330 if (!m_refData)
331 return wxOutRegion;
332
333 RECT rect;
334 rect.left = x;
335 rect.top = y;
336 rect.right = x + w;
337 rect.bottom = y + h;
338
339 return ::RectInRegion(M_REGION, &rect) ? wxInRegion : wxOutRegion;
340 }
341
342 // Does the region contain the rectangle rect
343 wxRegionContain wxRegion::Contains(const wxRect& rect) const
344 {
345 return Contains(rect.x, rect.y, rect.width, rect.height);
346 }
347
348 // Get internal region handle
349 WXHRGN wxRegion::GetHRGN() const
350 {
351 return (WXHRGN)(m_refData ? M_REGION : 0);
352 }
353
354 // ============================================================================
355 // wxRegionIterator implementation
356 // ============================================================================
357
358 // ----------------------------------------------------------------------------
359 // wxRegionIterator ctors/dtor
360 // ----------------------------------------------------------------------------
361
362 void wxRegionIterator::Init()
363 {
364 m_current =
365 m_numRects = 0;
366
367 m_rects = NULL;
368 }
369
370 wxRegionIterator::~wxRegionIterator()
371 {
372 delete [] m_rects;
373 }
374
375 // Initialize iterator for region
376 wxRegionIterator::wxRegionIterator(const wxRegion& region)
377 {
378 m_rects = NULL;
379
380 Reset(region);
381 }
382
383 wxRegionIterator& wxRegionIterator::operator=(const wxRegionIterator& ri)
384 {
385 delete [] m_rects;
386
387 m_current = ri.m_current;
388 m_numRects = ri.m_numRects;
389 if ( m_numRects )
390 {
391 m_rects = new wxRect[m_numRects];
392 for ( long n = 0; n < m_numRects; n++ )
393 m_rects[n] = ri.m_rects[n];
394 }
395 else
396 {
397 m_rects = NULL;
398 }
399
400 return *this;
401 }
402
403 // ----------------------------------------------------------------------------
404 // wxRegionIterator operations
405 // ----------------------------------------------------------------------------
406
407 // Reset iterator for a new region.
408 void wxRegionIterator::Reset(const wxRegion& region)
409 {
410 m_current = 0;
411 m_region = region;
412
413 if (m_rects)
414 {
415 delete[] m_rects;
416
417 m_rects = NULL;
418 }
419
420 if (m_region.Empty())
421 m_numRects = 0;
422 else
423 {
424 #if defined(__WIN32__)
425 DWORD noBytes = ::GetRegionData(((wxRegionRefData*)region.m_refData)->m_region, 0, NULL);
426 RGNDATA *rgnData = (RGNDATA*) new char[noBytes];
427 ::GetRegionData(((wxRegionRefData*)region.m_refData)->m_region, noBytes, rgnData);
428
429 RGNDATAHEADER* header = (RGNDATAHEADER*) rgnData;
430
431 m_rects = new wxRect[header->nCount];
432
433 RECT* rect = (RECT*) ((char*)rgnData + sizeof(RGNDATAHEADER));
434 size_t i;
435 for (i = 0; i < header->nCount; i++)
436 {
437 m_rects[i] = wxRect(rect->left, rect->top,
438 rect->right - rect->left, rect->bottom - rect->top);
439 rect ++; // Advances pointer by sizeof(RECT)
440 }
441
442 m_numRects = header->nCount;
443
444 delete[] (char*) rgnData;
445 #else // Win16
446 RECT rect;
447 ::GetRgnBox(((wxRegionRefData*)region.m_refData)->m_region, &rect);
448 m_rects = new wxRect[1];
449 m_rects[0].x = rect.left;
450 m_rects[0].y = rect.top;
451 m_rects[0].width = rect.right - rect.left;
452 m_rects[0].height = rect.bottom - rect.top;
453
454 m_numRects = 1;
455 #endif // Win32/16
456 }
457 }
458
459 wxRegionIterator& wxRegionIterator::operator++()
460 {
461 if (m_current < m_numRects)
462 ++m_current;
463
464 return *this;
465 }
466
467 wxRegionIterator wxRegionIterator::operator ++ (int)
468 {
469 wxRegionIterator tmp = *this;
470 if (m_current < m_numRects)
471 ++m_current;
472
473 return tmp;
474 }
475
476 // ----------------------------------------------------------------------------
477 // wxRegionIterator accessors
478 // ----------------------------------------------------------------------------
479
480 wxCoord wxRegionIterator::GetX() const
481 {
482 wxCHECK_MSG( m_current < m_numRects, 0, _T("invalid wxRegionIterator") );
483
484 return m_rects[m_current].x;
485 }
486
487 wxCoord wxRegionIterator::GetY() const
488 {
489 wxCHECK_MSG( m_current < m_numRects, 0, _T("invalid wxRegionIterator") );
490
491 return m_rects[m_current].y;
492 }
493
494 wxCoord wxRegionIterator::GetW() const
495 {
496 wxCHECK_MSG( m_current < m_numRects, 0, _T("invalid wxRegionIterator") );
497
498 return m_rects[m_current].width;
499 }
500
501 wxCoord wxRegionIterator::GetH() const
502 {
503 wxCHECK_MSG( m_current < m_numRects, 0, _T("invalid wxRegionIterator") );
504
505 return m_rects[m_current].height;
506 }
507