]> git.saurik.com Git - wxWidgets.git/blame - src/msw/region.cpp
Avoid core dumps when SetImageList is used.
[wxWidgets.git] / src / msw / region.cpp
CommitLineData
2bda0e17 1/////////////////////////////////////////////////////////////////////////////
789295bf 2// Name: msw/region.cpp
2b5f62a0 3// Purpose: wxRegion implementation using Win32 API
6c9a19aa 4// Author: Vadim Zeitlin
a3b46648 5// Modified by:
2bda0e17 6// Created: Fri Oct 24 10:46:34 MET 1997
789295bf 7// RCS-ID: $Id$
2b5f62a0 8// Copyright: (c) 1997-2002 wxWindows team
2bda0e17
KB
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
2b5f62a0
VZ
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
14f355c2 20#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
2b5f62a0 21 #pragma implementation "region.h"
2bda0e17
KB
22#endif
23
a3b46648 24// For compilers that support precompilation, includes "wx.h".
2bda0e17
KB
25#include "wx/wxprec.h"
26
27#ifdef __BORLANDC__
28#pragma hdrstop
29#endif
30
2b5f62a0 31#include "wx/region.h"
2bda0e17
KB
32#include "wx/gdicmn.h"
33
789295bf 34#include "wx/msw/private.h"
2bda0e17 35
2c40e41c
VZ
36IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject)
37IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator, wxObject)
2bda0e17 38
2b5f62a0 39// ----------------------------------------------------------------------------
2bda0e17 40// wxRegionRefData implementation
2b5f62a0 41// ----------------------------------------------------------------------------
2bda0e17 42
789295bf
VZ
43class WXDLLEXPORT wxRegionRefData : public wxGDIRefData
44{
2bda0e17 45public:
789295bf
VZ
46 wxRegionRefData()
47 {
b823f5a1 48 m_region = 0;
789295bf 49 }
2bda0e17 50
789295bf
VZ
51 wxRegionRefData(const wxRegionRefData& data)
52 {
4676948b 53#if defined(__WIN32__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
2bda0e17
KB
54 DWORD noBytes = ::GetRegionData(data.m_region, 0, NULL);
55 RGNDATA *rgnData = (RGNDATA*) new char[noBytes];
789295bf 56 ::GetRegionData(data.m_region, noBytes, rgnData);
2bda0e17
KB
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
789295bf 64 }
2bda0e17 65
2b5f62a0 66 virtual ~wxRegionRefData()
789295bf
VZ
67 {
68 ::DeleteObject(m_region);
2bda0e17 69 m_region = 0;
789295bf 70 }
2bda0e17 71
789295bf 72 HRGN m_region;
22f3361e
VZ
73
74private:
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&);
2bda0e17
KB
81};
82
83#define M_REGION (((wxRegionRefData*)m_refData)->m_region)
3317223b 84#define M_REGION_OF(rgn) (((wxRegionRefData*)(rgn.m_refData))->m_region)
2bda0e17 85
2b5f62a0
VZ
86// ============================================================================
87// wxRegion implementation
88// ============================================================================
89
90// ----------------------------------------------------------------------------
91// ctors and dtor
92// ----------------------------------------------------------------------------
2bda0e17 93
789295bf 94wxRegion::wxRegion()
2bda0e17 95{
f7bd3a7d 96 m_refData = (wxRegionRefData *)NULL;
2bda0e17
KB
97}
98
81d66cf3
JS
99wxRegion::wxRegion(WXHRGN hRegion)
100{
101 m_refData = new wxRegionRefData;
102 M_REGION = (HRGN) hRegion;
103}
104
9b1801c1 105wxRegion::wxRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
2bda0e17
KB
106{
107 m_refData = new wxRegionRefData;
108 M_REGION = ::CreateRectRgn(x, y, x + w, y + h);
109}
110
111wxRegion::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
117wxRegion::wxRegion(const wxRect& rect)
118{
119 m_refData = new wxRegionRefData;
bc2e39e3 120 M_REGION = ::CreateRectRgn(rect.x, rect.y, rect.x + rect.width, rect.y + rect.height);
2bda0e17
KB
121}
122
5549e9f7
VZ
123wxRegion::wxRegion(size_t n, const wxPoint *points, int fillStyle)
124{
4676948b 125#if defined(__WXMICROWIN__) || defined(__WXWINCE__)
c67d6888
JS
126 m_refData = NULL;
127 M_REGION = NULL;
128#else
5549e9f7
VZ
129 m_refData = new wxRegionRefData;
130 M_REGION = ::CreatePolygonRgn
131 (
132 (POINT*)points,
133 n,
134 fillStyle == wxODDEVEN_RULE ? ALTERNATE : WINDING
135 );
c67d6888 136#endif
5549e9f7
VZ
137}
138
789295bf 139wxRegion::~wxRegion()
2bda0e17
KB
140{
141 // m_refData unrefed in ~wxObject
142}
143
02576308 144wxObjectRefData *wxRegion::CreateRefData() const
0fb067bb
VZ
145{
146 return new wxRegionRefData;
147}
148
b8027888 149wxObjectRefData *wxRegion::CloneRefData(const wxObjectRefData *data) const
0fb067bb
VZ
150{
151 return new wxRegionRefData(*(wxRegionRefData *)data);
152}
153
2b5f62a0
VZ
154// ----------------------------------------------------------------------------
155// wxRegion operations
156// ----------------------------------------------------------------------------
2bda0e17 157
789295bf
VZ
158// Clear current region
159void wxRegion::Clear()
2bda0e17 160{
789295bf 161 UnRef();
2bda0e17
KB
162}
163
0fb067bb
VZ
164bool wxRegion::Offset(wxCoord x, wxCoord y)
165{
3317223b
VZ
166 wxCHECK_MSG( M_REGION, FALSE, _T("invalid wxRegion") );
167
0fb067bb
VZ
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
3317223b
VZ
186// combine another region with this one
187bool wxRegion::Combine(const wxRegion& rgn, wxRegionOp op)
2bda0e17 188{
3317223b
VZ
189 // we can't use the API functions if we don't have a valid region handle
190 if ( !m_refData )
2bda0e17 191 {
3317223b
VZ
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 }
2bda0e17 211 }
3317223b 212 else // we have a valid region
0fb067bb 213 {
2b5f62a0
VZ
214 AllocExclusive();
215
3317223b
VZ
216 int mode;
217 switch ( op )
218 {
219 case wxRGN_AND:
220 mode = RGN_AND;
221 break;
2bda0e17 222
3317223b
VZ
223 case wxRGN_OR:
224 mode = RGN_OR;
225 break;
2bda0e17 226
3317223b
VZ
227 case wxRGN_XOR:
228 mode = RGN_XOR;
229 break;
2bda0e17 230
3317223b
VZ
231 case wxRGN_DIFF:
232 mode = RGN_DIFF;
233 break;
789295bf 234
3317223b
VZ
235 default:
236 wxFAIL_MSG( _T("unknown region operation") );
237 // fall through
2bda0e17 238
3317223b
VZ
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 }
2bda0e17
KB
250 }
251
3317223b
VZ
252 return TRUE;
253}
254
255// Combine rectangle (x, y, w, h) with this.
256bool wxRegion::Combine(wxCoord x, wxCoord y,
257 wxCoord width, wxCoord height,
258 wxRegionOp op)
259{
260 return Combine(wxRegion(x, y, width, height), op);
2bda0e17
KB
261}
262
263bool wxRegion::Combine(const wxRect& rect, wxRegionOp op)
264{
3317223b
VZ
265 return Combine(rect.GetLeft(), rect.GetTop(),
266 rect.GetWidth(), rect.GetHeight(), op);
2bda0e17
KB
267}
268
2b5f62a0
VZ
269// ----------------------------------------------------------------------------
270// wxRegion bounding box
271// ----------------------------------------------------------------------------
2bda0e17
KB
272
273// Outer bounds of region
9b1801c1 274void wxRegion::GetBox(wxCoord& x, wxCoord& y, wxCoord&w, wxCoord &h) const
2bda0e17 275{
2c40e41c
VZ
276 if (m_refData)
277 {
2bda0e17
KB
278 RECT rect;
279 ::GetRgnBox(M_REGION, & rect);
789295bf
VZ
280 x = rect.left;
281 y = rect.top;
282 w = rect.right - rect.left;
283 h = rect.bottom - rect.top;
2c40e41c
VZ
284 }
285 else
286 {
789295bf
VZ
287 x = y = w = h = 0;
288 }
2bda0e17
KB
289}
290
789295bf 291wxRect wxRegion::GetBox() const
2bda0e17 292{
9b1801c1 293 wxCoord x, y, w, h;
2bda0e17
KB
294 GetBox(x, y, w, h);
295 return wxRect(x, y, w, h);
296}
297
298// Is region empty?
789295bf 299bool wxRegion::Empty() const
2bda0e17 300{
9b1801c1 301 wxCoord x, y, w, h;
2bda0e17
KB
302 GetBox(x, y, w, h);
303
2c40e41c 304 return (w == 0) && (h == 0);
2bda0e17
KB
305}
306
2b5f62a0
VZ
307// ----------------------------------------------------------------------------
308// wxRegion hit testing
309// ----------------------------------------------------------------------------
2bda0e17
KB
310
311// Does the region contain the point (x,y)?
9b1801c1 312wxRegionContain wxRegion::Contains(wxCoord x, wxCoord y) const
2bda0e17 313{
789295bf
VZ
314 if (!m_refData)
315 return wxOutRegion;
2bda0e17 316
2b5f62a0 317 return ::PtInRegion(M_REGION, (int) x, (int) y) ? wxInRegion : wxOutRegion;
2bda0e17
KB
318}
319
320// Does the region contain the point pt?
321wxRegionContain wxRegion::Contains(const wxPoint& pt) const
322{
2b5f62a0 323 return Contains(pt.x, pt.y);
2bda0e17
KB
324}
325
326// Does the region contain the rectangle (x, y, w, h)?
2b5f62a0
VZ
327wxRegionContain wxRegion::Contains(wxCoord x, wxCoord y,
328 wxCoord w, wxCoord h) const
2bda0e17 329{
789295bf
VZ
330 if (!m_refData)
331 return wxOutRegion;
2bda0e17
KB
332
333 RECT rect;
334 rect.left = x;
335 rect.top = y;
336 rect.right = x + w;
337 rect.bottom = y + h;
338
2b5f62a0 339 return ::RectInRegion(M_REGION, &rect) ? wxInRegion : wxOutRegion;
2bda0e17
KB
340}
341
342// Does the region contain the rectangle rect
343wxRegionContain wxRegion::Contains(const wxRect& rect) const
344{
2b5f62a0 345 return Contains(rect.x, rect.y, rect.width, rect.height);
2bda0e17
KB
346}
347
a724d789
JS
348// Get internal region handle
349WXHRGN wxRegion::GetHRGN() const
350{
2b5f62a0 351 return (WXHRGN)(m_refData ? M_REGION : 0);
a724d789
JS
352}
353
2b5f62a0
VZ
354// ============================================================================
355// wxRegionIterator implementation
356// ============================================================================
357
358// ----------------------------------------------------------------------------
359// wxRegionIterator ctors/dtor
360// ----------------------------------------------------------------------------
2bda0e17 361
2b5f62a0 362void wxRegionIterator::Init()
2bda0e17 363{
2b5f62a0
VZ
364 m_current =
365 m_numRects = 0;
366
367 m_rects = NULL;
2bda0e17
KB
368}
369
789295bf 370wxRegionIterator::~wxRegionIterator()
2bda0e17 371{
2b5f62a0 372 delete [] m_rects;
2bda0e17
KB
373}
374
2b5f62a0 375// Initialize iterator for region
2bda0e17
KB
376wxRegionIterator::wxRegionIterator(const wxRegion& region)
377{
378 m_rects = NULL;
379
789295bf 380 Reset(region);
2bda0e17
KB
381}
382
2b5f62a0
VZ
383wxRegionIterator& 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.
2bda0e17
KB
408void wxRegionIterator::Reset(const wxRegion& region)
409{
789295bf
VZ
410 m_current = 0;
411 m_region = region;
2bda0e17
KB
412
413 if (m_rects)
2b5f62a0 414 {
2bda0e17
KB
415 delete[] m_rects;
416
2b5f62a0
VZ
417 m_rects = NULL;
418 }
2bda0e17 419
789295bf
VZ
420 if (m_region.Empty())
421 m_numRects = 0;
422 else
2bda0e17 423 {
2bda0e17
KB
424 DWORD noBytes = ::GetRegionData(((wxRegionRefData*)region.m_refData)->m_region, 0, NULL);
425 RGNDATA *rgnData = (RGNDATA*) new char[noBytes];
789295bf 426 ::GetRegionData(((wxRegionRefData*)region.m_refData)->m_region, noBytes, rgnData);
2bda0e17
KB
427
428 RGNDATAHEADER* header = (RGNDATAHEADER*) rgnData;
429
430 m_rects = new wxRect[header->nCount];
431
3317223b 432 RECT* rect = (RECT*) ((char*)rgnData + sizeof(RGNDATAHEADER));
c86f1403 433 size_t i;
2bda0e17
KB
434 for (i = 0; i < header->nCount; i++)
435 {
436 m_rects[i] = wxRect(rect->left, rect->top,
437 rect->right - rect->left, rect->bottom - rect->top);
cba2db0c 438 rect ++; // Advances pointer by sizeof(RECT)
2bda0e17
KB
439 }
440
441 m_numRects = header->nCount;
442
443 delete[] (char*) rgnData;
2bda0e17
KB
444 }
445}
446
2b5f62a0 447wxRegionIterator& wxRegionIterator::operator++()
2bda0e17 448{
789295bf
VZ
449 if (m_current < m_numRects)
450 ++m_current;
2b5f62a0
VZ
451
452 return *this;
2bda0e17
KB
453}
454
2b5f62a0 455wxRegionIterator wxRegionIterator::operator ++ (int)
2bda0e17 456{
2b5f62a0 457 wxRegionIterator tmp = *this;
789295bf
VZ
458 if (m_current < m_numRects)
459 ++m_current;
2b5f62a0
VZ
460
461 return tmp;
2bda0e17
KB
462}
463
2b5f62a0
VZ
464// ----------------------------------------------------------------------------
465// wxRegionIterator accessors
466// ----------------------------------------------------------------------------
467
9b1801c1 468wxCoord wxRegionIterator::GetX() const
2bda0e17 469{
2b5f62a0
VZ
470 wxCHECK_MSG( m_current < m_numRects, 0, _T("invalid wxRegionIterator") );
471
472 return m_rects[m_current].x;
2bda0e17
KB
473}
474
9b1801c1 475wxCoord wxRegionIterator::GetY() const
2bda0e17 476{
2b5f62a0
VZ
477 wxCHECK_MSG( m_current < m_numRects, 0, _T("invalid wxRegionIterator") );
478
479 return m_rects[m_current].y;
2bda0e17
KB
480}
481
9b1801c1 482wxCoord wxRegionIterator::GetW() const
2bda0e17 483{
2b5f62a0
VZ
484 wxCHECK_MSG( m_current < m_numRects, 0, _T("invalid wxRegionIterator") );
485
486 return m_rects[m_current].width;
2bda0e17
KB
487}
488
9b1801c1 489wxCoord wxRegionIterator::GetH() const
2bda0e17 490{
2b5f62a0
VZ
491 wxCHECK_MSG( m_current < m_numRects, 0, _T("invalid wxRegionIterator") );
492
493 return m_rects[m_current].height;
2bda0e17
KB
494}
495