]> git.saurik.com Git - wxWidgets.git/blame - src/mac/carbon/region.cpp
copying as much values from the dc as possible
[wxWidgets.git] / src / mac / carbon / region.cpp
CommitLineData
e9576ca5 1/////////////////////////////////////////////////////////////////////////////
b3a44e05 2// File: src/mac/carbon/region.cpp
e9576ca5 3// Purpose: Region class
6aa89a22 4// Author: Stefan Csomor
e9576ca5 5// Created: Fri Oct 24 10:46:34 MET 1997
6aa89a22
JS
6// RCS-ID: $Id$
7// Copyright: (c) 1997 Stefan Csomor
65571936 8// Licence: wxWindows licence
e9576ca5
SC
9/////////////////////////////////////////////////////////////////////////////
10
3d1a4878
SC
11#include "wx/wxprec.h"
12
e9576ca5 13#include "wx/region.h"
b3a44e05 14
dd05139a
WS
15#ifndef WX_PRECOMP
16 #include "wx/gdicmn.h"
17#endif
18
2f1ae414 19#include "wx/mac/uma.h"
e9576ca5 20
fd04970a
SC
21IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject)
22IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator, wxObject)
e9576ca5
SC
23
24//-----------------------------------------------------------------------------
25// wxRegionRefData implementation
26//-----------------------------------------------------------------------------
27
5fa7a49c
DS
28class WXDLLEXPORT wxRegionRefData : public wxGDIRefData
29{
e9576ca5 30public:
e7600a2c 31 wxRegionRefData()
5fa7a49c 32 { m_macRgn = NewRgn(); }
e9576ca5 33
e7600a2c
GD
34 wxRegionRefData(const wxRegionRefData& data)
35 : wxGDIRefData()
36 {
5fa7a49c
DS
37 m_macRgn = NewRgn();
38 CopyRgn( data.m_macRgn , m_macRgn );
e7600a2c 39 }
e9576ca5 40
d3c7fc99 41 virtual ~wxRegionRefData()
5fa7a49c
DS
42 { DisposeRgn( m_macRgn ); }
43
44 RgnHandle m_macRgn;
e9576ca5
SC
45};
46
519cb848
SC
47#define M_REGION (((wxRegionRefData*)m_refData)->m_macRgn)
48#define OTHER_M_REGION(a) (((wxRegionRefData*)(a.m_refData))->m_macRgn)
e9576ca5
SC
49
50//-----------------------------------------------------------------------------
51// wxRegion
52//-----------------------------------------------------------------------------
53
54/*!
55 * Create an empty region.
56 */
57wxRegion::wxRegion()
58{
59 m_refData = new wxRegionRefData;
519cb848
SC
60}
61
62wxRegion::wxRegion(WXHRGN hRegion )
63{
64 m_refData = new wxRegionRefData;
76a5e5d2 65 CopyRgn( (RgnHandle) hRegion , (RgnHandle) M_REGION ) ;
e9576ca5
SC
66}
67
68wxRegion::wxRegion(long x, long y, long w, long h)
69{
70 m_refData = new wxRegionRefData;
5fa7a49c 71 SetRectRgn( (RgnHandle) M_REGION , x , y , x + w , y + h ) ;
e9576ca5
SC
72}
73
74wxRegion::wxRegion(const wxPoint& topLeft, const wxPoint& bottomRight)
75{
76 m_refData = new wxRegionRefData;
76a5e5d2 77 SetRectRgn( (RgnHandle) M_REGION , topLeft.x , topLeft.y , bottomRight.x , bottomRight.y ) ;
e9576ca5
SC
78}
79
80wxRegion::wxRegion(const wxRect& rect)
81{
82 m_refData = new wxRegionRefData;
5fa7a49c 83 SetRectRgn( (RgnHandle) M_REGION , rect.x , rect.y , rect.x + rect.width , rect.y + rect.height ) ;
e9576ca5
SC
84}
85
564cb9de
SC
86wxRegion::wxRegion(size_t n, const wxPoint *points, int WXUNUSED(fillStyle))
87{
88 m_refData = new wxRegionRefData;
89
5e8c9935
SC
90 // OS X somehow does not collect the region invisibly as before, so sometimes things
91 // get drawn on screen instead of just being combined into a region, therefore we allocate a temp gworld now
5fa7a49c
DS
92
93 GWorldPtr gWorld = NULL;
94 GWorldPtr oldWorld;
95 GDHandle oldGDHandle;
96 OSStatus err;
97 Rect destRect = { 0, 0, 1, 1 };
98
5e8c9935 99 ::GetGWorld( &oldWorld, &oldGDHandle );
5fa7a49c 100 err = ::NewGWorld( &gWorld, 32, &destRect, NULL, NULL, 0 );
5e8c9935 101 if ( err == noErr )
564cb9de 102 {
5e8c9935 103 ::SetGWorld( gWorld, GetGDevice() );
5fa7a49c 104
5e8c9935
SC
105 OpenRgn();
106
107 wxCoord x1, x2 , y1 , y2 ;
108 x2 = x1 = points[0].x ;
109 y2 = y1 = points[0].y ;
5fa7a49c
DS
110
111 ::MoveTo( x1, y1 );
5e8c9935
SC
112 for (size_t i = 1; i < n; i++)
113 {
114 x2 = points[i].x ;
115 y2 = points[i].y ;
5fa7a49c 116 ::LineTo( x2, y2 );
5e8c9935 117 }
5fa7a49c 118
5e8c9935
SC
119 // close the polyline if necessary
120 if ( x1 != x2 || y1 != y2 )
5fa7a49c
DS
121 ::LineTo( x1, y1 ) ;
122
5e8c9935 123 CloseRgn( M_REGION ) ;
5fa7a49c 124
5e8c9935 125 ::SetGWorld( oldWorld, oldGDHandle );
564cb9de 126 }
564cb9de
SC
127}
128
e9576ca5
SC
129wxRegion::~wxRegion()
130{
131 // m_refData unrefed in ~wxObject
132}
133
134//-----------------------------------------------------------------------------
135//# Modify region
136//-----------------------------------------------------------------------------
137
138//! Clear current region
139void wxRegion::Clear()
140{
141 UnRef();
142}
143
c871c71b 144// Move the region
8a16d737 145bool wxRegion::DoOffset(wxCoord x, wxCoord y)
c871c71b
SC
146{
147 wxCHECK_MSG( M_REGION, false, _T("invalid wxRegion") );
148
149 if ( !x && !y )
c871c71b
SC
150 // nothing to do
151 return true;
c871c71b
SC
152
153 OffsetRgn( M_REGION , x , y ) ;
5fa7a49c 154
c871c71b
SC
155 return true ;
156}
157
158
e9576ca5 159//! Union /e region with this.
8a16d737 160bool wxRegion::DoCombine(const wxRegion& region, wxRegionOp op)
e9576ca5 161{
8a16d737 162 wxCHECK_MSG( region.Ok(), false, _T("invalid wxRegion") );
e40298d5
JS
163
164 // Don't change shared data
5fa7a49c
DS
165 if (!m_refData)
166 {
e40298d5 167 m_refData = new wxRegionRefData();
5fa7a49c
DS
168 }
169 else if (m_refData->GetRefCount() > 1)
e40298d5
JS
170 {
171 wxRegionRefData* ref = (wxRegionRefData*)m_refData;
172 UnRef();
173 m_refData = new wxRegionRefData(*ref);
174 }
e9576ca5 175
e9576ca5
SC
176 switch (op)
177 {
178 case wxRGN_AND:
519cb848 179 SectRgn( M_REGION , OTHER_M_REGION(region) , M_REGION ) ;
e9576ca5 180 break ;
5fa7a49c 181
e9576ca5 182 case wxRGN_OR:
519cb848 183 UnionRgn( M_REGION , OTHER_M_REGION(region) , M_REGION ) ;
e9576ca5 184 break ;
5fa7a49c 185
e9576ca5 186 case wxRGN_XOR:
519cb848 187 XorRgn( M_REGION , OTHER_M_REGION(region) , M_REGION ) ;
e9576ca5 188 break ;
5fa7a49c 189
e9576ca5 190 case wxRGN_DIFF:
519cb848 191 DiffRgn( M_REGION , OTHER_M_REGION(region) , M_REGION ) ;
e9576ca5 192 break ;
5fa7a49c 193
e9576ca5
SC
194 case wxRGN_COPY:
195 default:
5fa7a49c 196 CopyRgn( OTHER_M_REGION(region) , M_REGION ) ;
e9576ca5
SC
197 break ;
198 }
199
5fa7a49c 200 return true;
e9576ca5
SC
201}
202
e9576ca5
SC
203//-----------------------------------------------------------------------------
204//# Information on region
205//-----------------------------------------------------------------------------
206
8a16d737
VZ
207bool wxRegion::DoIsEqual(const wxRegion& region) const
208{
209 wxFAIL_MSG( _T("not implemented") );
210
211 return false;
212}
213
e9576ca5 214// Outer bounds of region
8a16d737 215bool wxRegion::DoGetBox(wxCoord& x, wxCoord& y, wxCoord& w, wxCoord& h) const
e9576ca5 216{
5fa7a49c 217 if (m_refData)
e40298d5
JS
218 {
219 Rect box ;
220 GetRegionBounds( M_REGION , &box ) ;
519cb848
SC
221 x = box.left ;
222 y = box.top ;
223 w = box.right - box.left ;
224 h = box.bottom - box.top ;
8a16d737
VZ
225
226 return true;
5fa7a49c
DS
227 }
228 else
e40298d5
JS
229 {
230 x = y = w = h = 0;
5fa7a49c 231
8a16d737
VZ
232 return false;
233 }
e9576ca5
SC
234}
235
236// Is region empty?
8a16d737 237bool wxRegion::IsEmpty() const
e9576ca5 238{
54a6974c
SC
239 if ( m_refData )
240 return EmptyRgn( M_REGION ) ;
241 else
242 return true ;
519cb848
SC
243}
244
245const WXHRGN wxRegion::GetWXHRGN() const
246{
e40298d5 247 return M_REGION ;
e9576ca5
SC
248}
249
250//-----------------------------------------------------------------------------
251//# Tests
252//-----------------------------------------------------------------------------
253
5fa7a49c 254// Does the region contain the point?
8a16d737 255wxRegionContain wxRegion::DoContainsPoint(wxCoord x, wxCoord y) const
e9576ca5 256{
e40298d5
JS
257 if (!m_refData)
258 return wxOutRegion;
e9576ca5 259
8a16d737 260 Point p = { y , x } ;
519cb848 261 if (PtInRgn( p , M_REGION ) )
e9576ca5 262 return wxInRegion;
5fa7a49c 263
519cb848 264 return wxOutRegion;
e9576ca5
SC
265}
266
267// Does the region contain the rectangle (x, y, w, h)?
8a16d737 268wxRegionContain wxRegion::DoContainsRect(const wxRect& r) const
e9576ca5 269{
e40298d5
JS
270 if (!m_refData)
271 return wxOutRegion;
e9576ca5 272
22143f71 273 Rect rect = { r.y , r.x , r.y + r.height , r.x + r.width } ;
519cb848 274 if (RectInRgn( &rect , M_REGION ) )
e9576ca5
SC
275 return wxInRegion;
276 else
277 return wxOutRegion;
278}
279
e9576ca5 280///////////////////////////////////////////////////////////////////////////////
e7600a2c
GD
281// //
282// wxRegionIterator //
283// //
e9576ca5
SC
284///////////////////////////////////////////////////////////////////////////////
285
286/*!
287 * Initialize empty iterator
288 */
e7600a2c
GD
289wxRegionIterator::wxRegionIterator()
290 : m_current(0), m_numRects(0), m_rects(NULL)
e9576ca5
SC
291{
292}
293
294wxRegionIterator::~wxRegionIterator()
295{
5fa7a49c
DS
296 if (m_rects)
297 {
298 delete [] m_rects;
6dcbb6d0
GD
299 m_rects = NULL;
300 }
e9576ca5
SC
301}
302
e7600a2c
GD
303wxRegionIterator::wxRegionIterator(const wxRegionIterator& iterator)
304 : wxObject()
305 , m_current(iterator.m_current)
6dcbb6d0 306 , m_numRects(0)
2012e3ea 307 , m_rects(NULL)
e7600a2c 308{
6dcbb6d0 309 SetRects(iterator.m_numRects, iterator.m_rects);
e7600a2c
GD
310}
311
312wxRegionIterator& wxRegionIterator::operator=(const wxRegionIterator& iterator)
313{
314 m_current = iterator.m_current;
6dcbb6d0 315 SetRects(iterator.m_numRects, iterator.m_rects);
5fa7a49c 316
e7600a2c
GD
317 return *this;
318}
319
6dcbb6d0
GD
320/*!
321 * Set iterator rects for region
322 */
323void wxRegionIterator::SetRects(long numRects, wxRect *rects)
324{
5fa7a49c
DS
325 if (m_rects)
326 {
327 delete [] m_rects;
6dcbb6d0
GD
328 m_rects = NULL;
329 }
5fa7a49c
DS
330
331 if (rects && (numRects > 0))
6dcbb6d0
GD
332 {
333 int i;
5fa7a49c 334
6dcbb6d0
GD
335 m_rects = new wxRect[numRects];
336 for (i = 0; i < numRects; i++)
337 m_rects[i] = rects[i];
338 }
5fa7a49c 339
6dcbb6d0
GD
340 m_numRects = numRects;
341}
342
e9576ca5
SC
343/*!
344 * Initialize iterator for region
345 */
346wxRegionIterator::wxRegionIterator(const wxRegion& region)
347{
348 m_rects = NULL;
349
e7600a2c 350 Reset(region);
e9576ca5
SC
351}
352
353/*!
354 * Reset iterator for a new /e region.
355 */
5fa7a49c
DS
356
357OSStatus wxMacRegionToRectsCounterCallback(
358 UInt16 message, RgnHandle region, const Rect *rect, void *data )
20b69855
SC
359{
360 long *m_numRects = (long*) data ;
361 if ( message == kQDRegionToRectsMsgInit )
362 {
363 (*m_numRects) = 0 ;
364 }
365 else if (message == kQDRegionToRectsMsgParse)
366 {
367 (*m_numRects) += 1 ;
368 }
5fa7a49c 369
20b69855
SC
370 return noErr;
371}
5fa7a49c
DS
372
373class RegionToRectsCallbackData
20b69855
SC
374{
375public :
376 wxRect* m_rects ;
377 long m_current ;
5fa7a49c 378};
20b69855 379
5fa7a49c
DS
380OSStatus wxMacRegionToRectsSetterCallback(
381 UInt16 message, RgnHandle region, const Rect *rect, void *data )
20b69855
SC
382{
383 if (message == kQDRegionToRectsMsgParse)
384 {
385 RegionToRectsCallbackData *cb = (RegionToRectsCallbackData*) data ;
2b822a7e 386 cb->m_rects[cb->m_current++] = wxRect( rect->left , rect->top , rect->right - rect->left , rect->bottom - rect->top ) ;
20b69855 387 }
5fa7a49c 388
20b69855
SC
389 return noErr;
390}
391
e9576ca5
SC
392void wxRegionIterator::Reset(const wxRegion& region)
393{
6dcbb6d0
GD
394 m_current = 0;
395 m_region = region;
e9576ca5 396
5fa7a49c
DS
397 if (m_rects)
398 {
399 delete [] m_rects;
6dcbb6d0
GD
400 m_rects = NULL;
401 }
e9576ca5 402
8a16d737 403 if (m_region.IsEmpty())
5fa7a49c 404 {
6dcbb6d0 405 m_numRects = 0;
5fa7a49c 406 }
6dcbb6d0 407 else
e9576ca5 408 {
5fa7a49c 409 RegionToRectsUPP proc = NewRegionToRectsUPP( wxMacRegionToRectsCounterCallback );
20b69855
SC
410
411 OSStatus err = noErr;
5fa7a49c
DS
412 err = QDRegionToRects (OTHER_M_REGION( region ) , kQDParseRegionFromTopLeft, proc, (void*)&m_numRects);
413 if (err == noErr)
20b69855
SC
414 {
415 DisposeRegionToRectsUPP (proc);
416 proc = NewRegionToRectsUPP (wxMacRegionToRectsSetterCallback);
417 m_rects = new wxRect[m_numRects];
418 RegionToRectsCallbackData data ;
419 data.m_rects = m_rects ;
420 data.m_current = 0 ;
5fa7a49c 421 QDRegionToRects( OTHER_M_REGION( region ) , kQDParseRegionFromTopLeft, proc, (void*)&data );
20b69855 422 }
5fa7a49c 423 else
20b69855 424 {
5fa7a49c 425 m_numRects = 0;
20b69855 426 }
5fa7a49c
DS
427
428 DisposeRegionToRectsUPP( proc );
e9576ca5
SC
429 }
430}
431
432/*!
433 * Increment iterator. The rectangle returned is the one after the
434 * incrementation.
435 */
e7600a2c 436wxRegionIterator& wxRegionIterator::operator ++ ()
e9576ca5 437{
e7600a2c
GD
438 if (m_current < m_numRects)
439 ++m_current;
b3a44e05 440
e7600a2c 441 return *this;
e9576ca5
SC
442}
443
444/*!
445 * Increment iterator. The rectangle returned is the one before the
446 * incrementation.
447 */
e7600a2c 448wxRegionIterator wxRegionIterator::operator ++ (int)
e9576ca5 449{
e7600a2c
GD
450 wxRegionIterator previous(*this);
451
452 if (m_current < m_numRects)
453 ++m_current;
454
455 return previous;
e9576ca5
SC
456}
457
458long wxRegionIterator::GetX() const
459{
e40298d5
JS
460 if (m_current < m_numRects)
461 return m_rects[m_current].x;
5fa7a49c 462
e40298d5 463 return 0;
e9576ca5
SC
464}
465
466long wxRegionIterator::GetY() const
467{
e40298d5
JS
468 if (m_current < m_numRects)
469 return m_rects[m_current].y;
5fa7a49c 470
e40298d5 471 return 0;
e9576ca5
SC
472}
473
474long wxRegionIterator::GetW() const
475{
e40298d5
JS
476 if (m_current < m_numRects)
477 return m_rects[m_current].width ;
5fa7a49c 478
e40298d5 479 return 0;
e9576ca5
SC
480}
481
482long wxRegionIterator::GetH() const
483{
e40298d5
JS
484 if (m_current < m_numRects)
485 return m_rects[m_current].height;
5fa7a49c 486
e40298d5 487 return 0;
e9576ca5 488}