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