]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/msw/region.cpp
Committing in .
[wxWidgets.git] / src / msw / region.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: msw/region.cpp
3// Purpose: Region handling for wxWindows/X11
4// Author: Markus Holzem
5// Modified by:
6// Created: Fri Oct 24 10:46:34 MET 1997
7// RCS-ID: $Id$
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
16// For compilers that support precompilation, includes "wx.h".
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
26#include "wx/window.h"
27#include "wx/msw/private.h"
28
29IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject)
30IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator, wxObject)
31
32//-----------------------------------------------------------------------------
33// wxRegionRefData implementation
34//-----------------------------------------------------------------------------
35
36class WXDLLEXPORT wxRegionRefData : public wxGDIRefData
37{
38public:
39 wxRegionRefData()
40 {
41 m_region = 0;
42 }
43
44 wxRegionRefData(const wxRegionRefData& data)
45 {
46#if defined(__WIN32__) && !defined(__WXMICROWIN__)
47 DWORD noBytes = ::GetRegionData(data.m_region, 0, NULL);
48 RGNDATA *rgnData = (RGNDATA*) new char[noBytes];
49 ::GetRegionData(data.m_region, noBytes, rgnData);
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
57 }
58
59 ~wxRegionRefData()
60 {
61 ::DeleteObject(m_region);
62 m_region = 0;
63 }
64
65 HRGN m_region;
66};
67
68#define M_REGION (((wxRegionRefData*)m_refData)->m_region)
69#define M_REGION_OF(rgn) (((wxRegionRefData*)(rgn.m_refData))->m_region)
70
71//-----------------------------------------------------------------------------
72// wxRegion
73//-----------------------------------------------------------------------------
74
75/*
76 * Create an empty region.
77 */
78wxRegion::wxRegion()
79{
80 m_refData = (wxRegionRefData *)NULL;
81}
82
83wxRegion::wxRegion(WXHRGN hRegion)
84{
85 m_refData = new wxRegionRefData;
86 M_REGION = (HRGN) hRegion;
87}
88
89wxRegion::wxRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
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;
104 M_REGION = ::CreateRectRgn(rect.x, rect.y, rect.x + rect.width, rect.y + rect.height);
105}
106
107wxRegion::wxRegion(size_t n, const wxPoint *points, int fillStyle)
108{
109#ifdef __WXMICROWIN__
110 m_refData = NULL;
111 M_REGION = NULL;
112#else
113 m_refData = new wxRegionRefData;
114 M_REGION = ::CreatePolygonRgn
115 (
116 (POINT*)points,
117 n,
118 fillStyle == wxODDEVEN_RULE ? ALTERNATE : WINDING
119 );
120#endif
121}
122
123wxRegion::~wxRegion()
124{
125 // m_refData unrefed in ~wxObject
126}
127
128wxObjectRefData *wxRegion::CreateRefData() const
129{
130 return new wxRegionRefData;
131}
132
133wxObjectRefData *wxRegion::CloneRefData(const wxObjectRefData *data) const
134{
135 return new wxRegionRefData(*(wxRegionRefData *)data);
136}
137
138//-----------------------------------------------------------------------------
139// Modify region
140//-----------------------------------------------------------------------------
141
142// Clear current region
143void wxRegion::Clear()
144{
145 UnRef();
146}
147
148bool wxRegion::Offset(wxCoord x, wxCoord y)
149{
150 wxCHECK_MSG( M_REGION, FALSE, _T("invalid wxRegion") );
151
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
170// combine another region with this one
171bool wxRegion::Combine(const wxRegion& rgn, wxRegionOp op)
172{
173 // we can't use the API functions if we don't have a valid region handle
174 if ( !m_refData )
175 {
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 }
195 }
196 else // we have a valid region
197 {
198 int mode;
199 switch ( op )
200 {
201 case wxRGN_AND:
202 mode = RGN_AND;
203 break;
204
205 case wxRGN_OR:
206 mode = RGN_OR;
207 break;
208
209 case wxRGN_XOR:
210 mode = RGN_XOR;
211 break;
212
213 case wxRGN_DIFF:
214 mode = RGN_DIFF;
215 break;
216
217 default:
218 wxFAIL_MSG( _T("unknown region operation") );
219 // fall through
220
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 }
232 }
233
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);
243}
244
245bool wxRegion::Combine(const wxRect& rect, wxRegionOp op)
246{
247 return Combine(rect.GetLeft(), rect.GetTop(),
248 rect.GetWidth(), rect.GetHeight(), op);
249}
250
251//-----------------------------------------------------------------------------
252// Information on region
253//-----------------------------------------------------------------------------
254
255// Outer bounds of region
256void wxRegion::GetBox(wxCoord& x, wxCoord& y, wxCoord&w, wxCoord &h) const
257{
258 if (m_refData)
259 {
260 RECT rect;
261 ::GetRgnBox(M_REGION, & rect);
262 x = rect.left;
263 y = rect.top;
264 w = rect.right - rect.left;
265 h = rect.bottom - rect.top;
266 }
267 else
268 {
269 x = y = w = h = 0;
270 }
271}
272
273wxRect wxRegion::GetBox() const
274{
275 wxCoord x, y, w, h;
276 GetBox(x, y, w, h);
277 return wxRect(x, y, w, h);
278}
279
280// Is region empty?
281bool wxRegion::Empty() const
282{
283 wxCoord x, y, w, h;
284 GetBox(x, y, w, h);
285
286 return (w == 0) && (h == 0);
287}
288
289//-----------------------------------------------------------------------------
290// Tests
291//-----------------------------------------------------------------------------
292
293// Does the region contain the point (x,y)?
294wxRegionContain wxRegion::Contains(wxCoord x, wxCoord y) const
295{
296 if (!m_refData)
297 return wxOutRegion;
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{
308 if (!m_refData)
309 return wxOutRegion;
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)?
318wxRegionContain wxRegion::Contains(wxCoord x, wxCoord y, wxCoord w, wxCoord h) const
319{
320 if (!m_refData)
321 return wxOutRegion;
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{
338 if (!m_refData)
339 return wxOutRegion;
340
341 wxCoord x, y, w, h;
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
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
357///////////////////////////////////////////////////////////////////////////////
358// //
359// wxRegionIterator //
360// //
361///////////////////////////////////////////////////////////////////////////////
362
363/*
364 * Initialize empty iterator
365 */
366wxRegionIterator::wxRegionIterator() : m_current(0), m_numRects(0), m_rects(NULL)
367{
368}
369
370wxRegionIterator::~wxRegionIterator()
371{
372 if (m_rects)
373 delete[] m_rects;
374}
375
376/*
377 * Initialize iterator for region
378 */
379wxRegionIterator::wxRegionIterator(const wxRegion& region)
380{
381 m_rects = NULL;
382
383 Reset(region);
384}
385
386/*
387 * Reset iterator for a new /e region.
388 */
389void wxRegionIterator::Reset(const wxRegion& region)
390{
391 m_current = 0;
392 m_region = region;
393
394 if (m_rects)
395 delete[] m_rects;
396
397 m_rects = NULL;
398
399 if (m_region.Empty())
400 m_numRects = 0;
401 else
402 {
403#if defined(__WIN32__)
404 DWORD noBytes = ::GetRegionData(((wxRegionRefData*)region.m_refData)->m_region, 0, NULL);
405 RGNDATA *rgnData = (RGNDATA*) new char[noBytes];
406 ::GetRegionData(((wxRegionRefData*)region.m_refData)->m_region, noBytes, rgnData);
407
408 RGNDATAHEADER* header = (RGNDATAHEADER*) rgnData;
409
410 m_rects = new wxRect[header->nCount];
411
412 RECT* rect = (RECT*) ((char*)rgnData + sizeof(RGNDATAHEADER));
413 size_t i;
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);
418 rect ++; // Advances pointer by sizeof(RECT)
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
438/*
439 * Increment iterator. The rectangle returned is the one after the
440 * incrementation.
441 */
442void wxRegionIterator::operator ++ ()
443{
444 if (m_current < m_numRects)
445 ++m_current;
446}
447
448/*
449 * Increment iterator. The rectangle returned is the one before the
450 * incrementation.
451 */
452void wxRegionIterator::operator ++ (int)
453{
454 if (m_current < m_numRects)
455 ++m_current;
456}
457
458wxCoord wxRegionIterator::GetX() const
459{
460 if (m_current < m_numRects)
461 return m_rects[m_current].x;
462 return 0;
463}
464
465wxCoord wxRegionIterator::GetY() const
466{
467 if (m_current < m_numRects)
468 return m_rects[m_current].y;
469 return 0;
470}
471
472wxCoord wxRegionIterator::GetW() const
473{
474 if (m_current < m_numRects)
475 return m_rects[m_current].width;
476 return 0;
477}
478
479wxCoord wxRegionIterator::GetH() const
480{
481 if (m_current < m_numRects)
482 return m_rects[m_current].height;
483 return 0;
484}
485