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