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