]> git.saurik.com Git - wxWidgets.git/blame - src/msw/region.cpp
Clean-up, speed-up and bug-fix for wxListCtrl drawing,
[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
789295bf
VZ
29 IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject)
30 IMPLEMENT_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 {
2bda0e17
KB
46#if defined(__WIN32__)
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)
69
70//-----------------------------------------------------------------------------
71// wxRegion
72//-----------------------------------------------------------------------------
73
789295bf 74/*
2bda0e17
KB
75 * Create an empty region.
76 */
789295bf 77wxRegion::wxRegion()
2bda0e17
KB
78{
79 m_refData = new wxRegionRefData;
80 M_REGION = ::CreateRectRgn(0, 0, 0, 0);
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
789295bf 107/*
2bda0e17
KB
108 * Destroy the region.
109 */
789295bf 110wxRegion::~wxRegion()
2bda0e17
KB
111{
112 // m_refData unrefed in ~wxObject
113}
114
115//-----------------------------------------------------------------------------
789295bf 116// Modify region
2bda0e17
KB
117//-----------------------------------------------------------------------------
118
789295bf
VZ
119// Clear current region
120void wxRegion::Clear()
2bda0e17 121{
789295bf 122 UnRef();
2bda0e17
KB
123}
124
789295bf 125// Combine rectangle (x, y, w, h) with this.
9b1801c1 126bool wxRegion::Combine(wxCoord x, wxCoord y, wxCoord width, wxCoord height, wxRegionOp op)
2bda0e17 127{
789295bf
VZ
128 // Don't change shared data
129 if (!m_refData) {
130 m_refData = new wxRegionRefData();
131 } else if (m_refData->GetRefCount() > 1) {
132 wxRegionRefData* ref = (wxRegionRefData*)m_refData;
133 UnRef();
134 m_refData = new wxRegionRefData(*ref);
135 }
2bda0e17
KB
136 // If ref count is 1, that means it's 'ours' anyway so no action.
137
138 HRGN rectRegion = ::CreateRectRgn(x, y, x + width, y + height);
139
140 int mode = 0;
141 switch (op)
142 {
143 case wxRGN_AND: mode = RGN_AND; break ;
144 case wxRGN_OR: mode = RGN_OR; break ;
145 case wxRGN_XOR: mode = RGN_XOR; break ;
146 case wxRGN_DIFF: mode = RGN_DIFF; break ;
147 case wxRGN_COPY:
148 default:
149 mode = RGN_COPY; break ;
150 }
151
789295bf 152 bool success = (ERROR != ::CombineRgn(M_REGION, M_REGION, rectRegion, mode));
2bda0e17
KB
153
154 ::DeleteObject(rectRegion);
155
156 return success;
157}
158
789295bf 159// Union /e region with this.
2bda0e17
KB
160bool wxRegion::Combine(const wxRegion& region, wxRegionOp op)
161{
789295bf
VZ
162 if (region.Empty())
163 return FALSE;
164
165 // Don't change shared data
166 if (!m_refData) {
167 m_refData = new wxRegionRefData();
168 } else if (m_refData->GetRefCount() > 1) {
169 wxRegionRefData* ref = (wxRegionRefData*)m_refData;
170 UnRef();
171 m_refData = new wxRegionRefData(*ref);
172 }
2bda0e17
KB
173
174 int mode = 0;
175 switch (op)
176 {
177 case wxRGN_AND: mode = RGN_AND; break ;
178 case wxRGN_OR: mode = RGN_OR; break ;
179 case wxRGN_XOR: mode = RGN_XOR; break ;
180 case wxRGN_DIFF: mode = RGN_DIFF; break ;
181 case wxRGN_COPY:
182 default:
183 mode = RGN_COPY; break ;
184 }
185
789295bf 186 return (ERROR != ::CombineRgn(M_REGION, M_REGION, ((wxRegionRefData*)region.m_refData)->m_region, mode));
2bda0e17
KB
187}
188
189bool wxRegion::Combine(const wxRect& rect, wxRegionOp op)
190{
191 return Combine(rect.GetLeft(), rect.GetTop(), rect.GetWidth(), rect.GetHeight(), op);
192}
193
194//-----------------------------------------------------------------------------
789295bf 195// Information on region
2bda0e17
KB
196//-----------------------------------------------------------------------------
197
198// Outer bounds of region
9b1801c1 199void wxRegion::GetBox(wxCoord& x, wxCoord& y, wxCoord&w, wxCoord &h) const
2bda0e17 200{
789295bf 201 if (m_refData) {
2bda0e17
KB
202 RECT rect;
203 ::GetRgnBox(M_REGION, & rect);
789295bf
VZ
204 x = rect.left;
205 y = rect.top;
206 w = rect.right - rect.left;
207 h = rect.bottom - rect.top;
208 } else {
209 x = y = w = h = 0;
210 }
2bda0e17
KB
211}
212
789295bf 213wxRect wxRegion::GetBox() const
2bda0e17 214{
9b1801c1 215 wxCoord x, y, w, h;
2bda0e17
KB
216 GetBox(x, y, w, h);
217 return wxRect(x, y, w, h);
218}
219
220// Is region empty?
789295bf 221bool wxRegion::Empty() const
2bda0e17
KB
222{
223 if (M_REGION == 0)
224 return TRUE;
9b1801c1 225 wxCoord x, y, w, h;
2bda0e17
KB
226 GetBox(x, y, w, h);
227
228 return ((w == 0) && (h == 0));
229}
230
231//-----------------------------------------------------------------------------
789295bf 232// Tests
2bda0e17
KB
233//-----------------------------------------------------------------------------
234
235// Does the region contain the point (x,y)?
9b1801c1 236wxRegionContain wxRegion::Contains(wxCoord x, wxCoord y) const
2bda0e17 237{
789295bf
VZ
238 if (!m_refData)
239 return wxOutRegion;
2bda0e17
KB
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?
248wxRegionContain wxRegion::Contains(const wxPoint& pt) const
249{
789295bf
VZ
250 if (!m_refData)
251 return wxOutRegion;
2bda0e17
KB
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)?
9b1801c1 260wxRegionContain wxRegion::Contains(wxCoord x, wxCoord y, wxCoord w, wxCoord h) const
2bda0e17 261{
789295bf
VZ
262 if (!m_refData)
263 return wxOutRegion;
2bda0e17
KB
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
278wxRegionContain wxRegion::Contains(const wxRect& rect) const
279{
789295bf
VZ
280 if (!m_refData)
281 return wxOutRegion;
2bda0e17 282
9b1801c1 283 wxCoord x, y, w, h;
2bda0e17
KB
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
a724d789
JS
291// Get internal region handle
292WXHRGN wxRegion::GetHRGN() const
293{
294 if (!m_refData)
295 return (WXHRGN) 0;
296 return (WXHRGN) M_REGION;
297}
298
2bda0e17 299///////////////////////////////////////////////////////////////////////////////
789295bf
VZ
300// //
301// wxRegionIterator //
302// //
2bda0e17
KB
303///////////////////////////////////////////////////////////////////////////////
304
789295bf 305/*
2bda0e17
KB
306 * Initialize empty iterator
307 */
789295bf 308wxRegionIterator::wxRegionIterator() : m_current(0), m_numRects(0), m_rects(NULL)
2bda0e17
KB
309{
310}
311
789295bf 312wxRegionIterator::~wxRegionIterator()
2bda0e17
KB
313{
314 if (m_rects)
315 delete[] m_rects;
316}
317
789295bf 318/*
2bda0e17
KB
319 * Initialize iterator for region
320 */
321wxRegionIterator::wxRegionIterator(const wxRegion& region)
322{
323 m_rects = NULL;
324
789295bf 325 Reset(region);
2bda0e17
KB
326}
327
789295bf 328/*
2bda0e17
KB
329 * Reset iterator for a new /e region.
330 */
331void wxRegionIterator::Reset(const wxRegion& region)
332{
789295bf
VZ
333 m_current = 0;
334 m_region = region;
2bda0e17
KB
335
336 if (m_rects)
337 delete[] m_rects;
338
339 m_rects = NULL;
340
789295bf
VZ
341 if (m_region.Empty())
342 m_numRects = 0;
343 else
2bda0e17
KB
344 {
345#if defined(__WIN32__)
346 DWORD noBytes = ::GetRegionData(((wxRegionRefData*)region.m_refData)->m_region, 0, NULL);
347 RGNDATA *rgnData = (RGNDATA*) new char[noBytes];
789295bf 348 ::GetRegionData(((wxRegionRefData*)region.m_refData)->m_region, noBytes, rgnData);
2bda0e17
KB
349
350 RGNDATAHEADER* header = (RGNDATAHEADER*) rgnData;
351
352 m_rects = new wxRect[header->nCount];
353
cba2db0c 354 RECT* rect = (RECT*) ((char*)rgnData + sizeof(RGNDATAHEADER)) ;
c86f1403 355 size_t i;
2bda0e17
KB
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);
cba2db0c 360 rect ++; // Advances pointer by sizeof(RECT)
2bda0e17
KB
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
789295bf 380/*
2bda0e17
KB
381 * Increment iterator. The rectangle returned is the one after the
382 * incrementation.
383 */
789295bf 384void wxRegionIterator::operator ++ ()
2bda0e17 385{
789295bf
VZ
386 if (m_current < m_numRects)
387 ++m_current;
2bda0e17
KB
388}
389
789295bf 390/*
2bda0e17
KB
391 * Increment iterator. The rectangle returned is the one before the
392 * incrementation.
393 */
394void wxRegionIterator::operator ++ (int)
395{
789295bf
VZ
396 if (m_current < m_numRects)
397 ++m_current;
2bda0e17
KB
398}
399
9b1801c1 400wxCoord wxRegionIterator::GetX() const
2bda0e17 401{
789295bf
VZ
402 if (m_current < m_numRects)
403 return m_rects[m_current].x;
404 return 0;
2bda0e17
KB
405}
406
9b1801c1 407wxCoord wxRegionIterator::GetY() const
2bda0e17 408{
789295bf
VZ
409 if (m_current < m_numRects)
410 return m_rects[m_current].y;
411 return 0;
2bda0e17
KB
412}
413
9b1801c1 414wxCoord wxRegionIterator::GetW() const
2bda0e17 415{
789295bf
VZ
416 if (m_current < m_numRects)
417 return m_rects[m_current].width ;
418 return 0;
2bda0e17
KB
419}
420
9b1801c1 421wxCoord wxRegionIterator::GetH() const
2bda0e17 422{
789295bf
VZ
423 if (m_current < m_numRects)
424 return m_rects[m_current].height;
425 return 0;
2bda0e17
KB
426}
427