]> git.saurik.com Git - wxWidgets.git/blame - src/msw/region.cpp
don't crash in wxGetWindowXXX() if HWND is 0
[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)
69
70//-----------------------------------------------------------------------------
71// wxRegion
72//-----------------------------------------------------------------------------
73
789295bf 74/*
2bda0e17
KB
75 * Create an empty region.
76 */
789295bf 77wxRegion::wxRegion()
2bda0e17 78{
f7bd3a7d 79 m_refData = (wxRegionRefData *)NULL;
2bda0e17
KB
80}
81
81d66cf3
JS
82wxRegion::wxRegion(WXHRGN hRegion)
83{
84 m_refData = new wxRegionRefData;
85 M_REGION = (HRGN) hRegion;
86}
87
9b1801c1 88wxRegion::wxRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
2bda0e17
KB
89{
90 m_refData = new wxRegionRefData;
91 M_REGION = ::CreateRectRgn(x, y, x + w, y + h);
92}
93
94wxRegion::wxRegion(const wxPoint& topLeft, const wxPoint& bottomRight)
95{
96 m_refData = new wxRegionRefData;
97 M_REGION = ::CreateRectRgn(topLeft.x, topLeft.y, bottomRight.x, bottomRight.y);
98}
99
100wxRegion::wxRegion(const wxRect& rect)
101{
102 m_refData = new wxRegionRefData;
bc2e39e3 103 M_REGION = ::CreateRectRgn(rect.x, rect.y, rect.x + rect.width, rect.y + rect.height);
2bda0e17
KB
104}
105
5549e9f7
VZ
106wxRegion::wxRegion(size_t n, const wxPoint *points, int fillStyle)
107{
c67d6888
JS
108#ifdef __WXMICROWIN__
109 m_refData = NULL;
110 M_REGION = NULL;
111#else
5549e9f7
VZ
112 m_refData = new wxRegionRefData;
113 M_REGION = ::CreatePolygonRgn
114 (
115 (POINT*)points,
116 n,
117 fillStyle == wxODDEVEN_RULE ? ALTERNATE : WINDING
118 );
c67d6888 119#endif
5549e9f7
VZ
120}
121
789295bf 122/*
2bda0e17
KB
123 * Destroy the region.
124 */
789295bf 125wxRegion::~wxRegion()
2bda0e17
KB
126{
127 // m_refData unrefed in ~wxObject
128}
129
130//-----------------------------------------------------------------------------
789295bf 131// Modify region
2bda0e17
KB
132//-----------------------------------------------------------------------------
133
789295bf
VZ
134// Clear current region
135void wxRegion::Clear()
2bda0e17 136{
789295bf 137 UnRef();
2bda0e17
KB
138}
139
789295bf 140// Combine rectangle (x, y, w, h) with this.
9b1801c1 141bool wxRegion::Combine(wxCoord x, wxCoord y, wxCoord width, wxCoord height, wxRegionOp op)
2bda0e17 142{
789295bf
VZ
143 // Don't change shared data
144 if (!m_refData) {
145 m_refData = new wxRegionRefData();
146 } else if (m_refData->GetRefCount() > 1) {
147 wxRegionRefData* ref = (wxRegionRefData*)m_refData;
148 UnRef();
149 m_refData = new wxRegionRefData(*ref);
150 }
2bda0e17
KB
151 // If ref count is 1, that means it's 'ours' anyway so no action.
152
153 HRGN rectRegion = ::CreateRectRgn(x, y, x + width, y + height);
154
155 int mode = 0;
156 switch (op)
157 {
158 case wxRGN_AND: mode = RGN_AND; break ;
159 case wxRGN_OR: mode = RGN_OR; break ;
160 case wxRGN_XOR: mode = RGN_XOR; break ;
161 case wxRGN_DIFF: mode = RGN_DIFF; break ;
162 case wxRGN_COPY:
163 default:
164 mode = RGN_COPY; break ;
165 }
166
789295bf 167 bool success = (ERROR != ::CombineRgn(M_REGION, M_REGION, rectRegion, mode));
2bda0e17
KB
168
169 ::DeleteObject(rectRegion);
170
171 return success;
172}
173
789295bf 174// Union /e region with this.
2bda0e17
KB
175bool wxRegion::Combine(const wxRegion& region, wxRegionOp op)
176{
789295bf
VZ
177 if (region.Empty())
178 return FALSE;
179
180 // Don't change shared data
181 if (!m_refData) {
182 m_refData = new wxRegionRefData();
183 } else if (m_refData->GetRefCount() > 1) {
184 wxRegionRefData* ref = (wxRegionRefData*)m_refData;
185 UnRef();
186 m_refData = new wxRegionRefData(*ref);
187 }
2bda0e17
KB
188
189 int mode = 0;
190 switch (op)
191 {
192 case wxRGN_AND: mode = RGN_AND; break ;
193 case wxRGN_OR: mode = RGN_OR; break ;
194 case wxRGN_XOR: mode = RGN_XOR; break ;
195 case wxRGN_DIFF: mode = RGN_DIFF; break ;
196 case wxRGN_COPY:
197 default:
198 mode = RGN_COPY; break ;
199 }
200
789295bf 201 return (ERROR != ::CombineRgn(M_REGION, M_REGION, ((wxRegionRefData*)region.m_refData)->m_region, mode));
2bda0e17
KB
202}
203
204bool wxRegion::Combine(const wxRect& rect, wxRegionOp op)
205{
206 return Combine(rect.GetLeft(), rect.GetTop(), rect.GetWidth(), rect.GetHeight(), op);
207}
208
209//-----------------------------------------------------------------------------
789295bf 210// Information on region
2bda0e17
KB
211//-----------------------------------------------------------------------------
212
213// Outer bounds of region
9b1801c1 214void wxRegion::GetBox(wxCoord& x, wxCoord& y, wxCoord&w, wxCoord &h) const
2bda0e17 215{
2c40e41c
VZ
216 if (m_refData)
217 {
2bda0e17
KB
218 RECT rect;
219 ::GetRgnBox(M_REGION, & rect);
789295bf
VZ
220 x = rect.left;
221 y = rect.top;
222 w = rect.right - rect.left;
223 h = rect.bottom - rect.top;
2c40e41c
VZ
224 }
225 else
226 {
789295bf
VZ
227 x = y = w = h = 0;
228 }
2bda0e17
KB
229}
230
789295bf 231wxRect wxRegion::GetBox() const
2bda0e17 232{
9b1801c1 233 wxCoord x, y, w, h;
2bda0e17
KB
234 GetBox(x, y, w, h);
235 return wxRect(x, y, w, h);
236}
237
238// Is region empty?
789295bf 239bool wxRegion::Empty() const
2bda0e17 240{
9b1801c1 241 wxCoord x, y, w, h;
2bda0e17
KB
242 GetBox(x, y, w, h);
243
2c40e41c 244 return (w == 0) && (h == 0);
2bda0e17
KB
245}
246
247//-----------------------------------------------------------------------------
789295bf 248// Tests
2bda0e17
KB
249//-----------------------------------------------------------------------------
250
251// Does the region contain the point (x,y)?
9b1801c1 252wxRegionContain wxRegion::Contains(wxCoord x, wxCoord y) const
2bda0e17 253{
789295bf
VZ
254 if (!m_refData)
255 return wxOutRegion;
2bda0e17
KB
256
257 if (::PtInRegion(M_REGION, (int) x, (int) y))
258 return wxInRegion;
259 else
260 return wxOutRegion;
261}
262
263// Does the region contain the point pt?
264wxRegionContain wxRegion::Contains(const wxPoint& pt) const
265{
789295bf
VZ
266 if (!m_refData)
267 return wxOutRegion;
2bda0e17
KB
268
269 if (::PtInRegion(M_REGION, (int) pt.x, (int) pt.y))
270 return wxInRegion;
271 else
272 return wxOutRegion;
273}
274
275// Does the region contain the rectangle (x, y, w, h)?
9b1801c1 276wxRegionContain wxRegion::Contains(wxCoord x, wxCoord y, wxCoord w, wxCoord h) const
2bda0e17 277{
789295bf
VZ
278 if (!m_refData)
279 return wxOutRegion;
2bda0e17
KB
280
281 RECT rect;
282 rect.left = x;
283 rect.top = y;
284 rect.right = x + w;
285 rect.bottom = y + h;
286
287 if (::RectInRegion(M_REGION, & rect))
288 return wxInRegion;
289 else
290 return wxOutRegion;
291}
292
293// Does the region contain the rectangle rect
294wxRegionContain wxRegion::Contains(const wxRect& rect) const
295{
789295bf
VZ
296 if (!m_refData)
297 return wxOutRegion;
2bda0e17 298
9b1801c1 299 wxCoord x, y, w, h;
2bda0e17
KB
300 x = rect.x;
301 y = rect.y;
302 w = rect.GetWidth();
303 h = rect.GetHeight();
304 return Contains(x, y, w, h);
305}
306
a724d789
JS
307// Get internal region handle
308WXHRGN wxRegion::GetHRGN() const
309{
310 if (!m_refData)
311 return (WXHRGN) 0;
312 return (WXHRGN) M_REGION;
313}
314
2bda0e17 315///////////////////////////////////////////////////////////////////////////////
789295bf
VZ
316// //
317// wxRegionIterator //
318// //
2bda0e17
KB
319///////////////////////////////////////////////////////////////////////////////
320
789295bf 321/*
2bda0e17
KB
322 * Initialize empty iterator
323 */
789295bf 324wxRegionIterator::wxRegionIterator() : m_current(0), m_numRects(0), m_rects(NULL)
2bda0e17
KB
325{
326}
327
789295bf 328wxRegionIterator::~wxRegionIterator()
2bda0e17
KB
329{
330 if (m_rects)
331 delete[] m_rects;
332}
333
789295bf 334/*
2bda0e17
KB
335 * Initialize iterator for region
336 */
337wxRegionIterator::wxRegionIterator(const wxRegion& region)
338{
339 m_rects = NULL;
340
789295bf 341 Reset(region);
2bda0e17
KB
342}
343
789295bf 344/*
2bda0e17
KB
345 * Reset iterator for a new /e region.
346 */
347void wxRegionIterator::Reset(const wxRegion& region)
348{
789295bf
VZ
349 m_current = 0;
350 m_region = region;
2bda0e17
KB
351
352 if (m_rects)
353 delete[] m_rects;
354
355 m_rects = NULL;
356
789295bf
VZ
357 if (m_region.Empty())
358 m_numRects = 0;
359 else
2bda0e17
KB
360 {
361#if defined(__WIN32__)
362 DWORD noBytes = ::GetRegionData(((wxRegionRefData*)region.m_refData)->m_region, 0, NULL);
363 RGNDATA *rgnData = (RGNDATA*) new char[noBytes];
789295bf 364 ::GetRegionData(((wxRegionRefData*)region.m_refData)->m_region, noBytes, rgnData);
2bda0e17
KB
365
366 RGNDATAHEADER* header = (RGNDATAHEADER*) rgnData;
367
368 m_rects = new wxRect[header->nCount];
369
cba2db0c 370 RECT* rect = (RECT*) ((char*)rgnData + sizeof(RGNDATAHEADER)) ;
c86f1403 371 size_t i;
2bda0e17
KB
372 for (i = 0; i < header->nCount; i++)
373 {
374 m_rects[i] = wxRect(rect->left, rect->top,
375 rect->right - rect->left, rect->bottom - rect->top);
cba2db0c 376 rect ++; // Advances pointer by sizeof(RECT)
2bda0e17
KB
377 }
378
379 m_numRects = header->nCount;
380
381 delete[] (char*) rgnData;
382#else
383 RECT rect;
384 ::GetRgnBox(((wxRegionRefData*)region.m_refData)->m_region, &rect);
385 m_rects = new wxRect[1];
386 m_rects[0].x = rect.left;
387 m_rects[0].y = rect.top;
388 m_rects[0].width = rect.right - rect.left;
389 m_rects[0].height = rect.bottom - rect.top;
390
391 m_numRects = 1;
392#endif
393 }
394}
395
789295bf 396/*
2bda0e17
KB
397 * Increment iterator. The rectangle returned is the one after the
398 * incrementation.
399 */
789295bf 400void wxRegionIterator::operator ++ ()
2bda0e17 401{
789295bf
VZ
402 if (m_current < m_numRects)
403 ++m_current;
2bda0e17
KB
404}
405
789295bf 406/*
2bda0e17
KB
407 * Increment iterator. The rectangle returned is the one before the
408 * incrementation.
409 */
410void wxRegionIterator::operator ++ (int)
411{
789295bf
VZ
412 if (m_current < m_numRects)
413 ++m_current;
2bda0e17
KB
414}
415
9b1801c1 416wxCoord wxRegionIterator::GetX() const
2bda0e17 417{
789295bf
VZ
418 if (m_current < m_numRects)
419 return m_rects[m_current].x;
420 return 0;
2bda0e17
KB
421}
422
9b1801c1 423wxCoord wxRegionIterator::GetY() const
2bda0e17 424{
789295bf
VZ
425 if (m_current < m_numRects)
426 return m_rects[m_current].y;
427 return 0;
2bda0e17
KB
428}
429
9b1801c1 430wxCoord wxRegionIterator::GetW() const
2bda0e17 431{
789295bf
VZ
432 if (m_current < m_numRects)
433 return m_rects[m_current].width ;
434 return 0;
2bda0e17
KB
435}
436
9b1801c1 437wxCoord wxRegionIterator::GetH() const
2bda0e17 438{
789295bf
VZ
439 if (m_current < m_numRects)
440 return m_rects[m_current].height;
441 return 0;
2bda0e17
KB
442}
443