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