]> git.saurik.com Git - wxWidgets.git/blame - src/osx/carbon/region.cpp
missing commit for RAW_CONTROL changes
[wxWidgets.git] / src / osx / carbon / region.cpp
CommitLineData
489468fe 1/////////////////////////////////////////////////////////////////////////////
233f5738 2// File: src/osx/carbon/region.cpp
489468fe
SC
3// Purpose: Region class
4// Author: Stefan Csomor
5// Created: Fri Oct 24 10:46:34 MET 1997
6// RCS-ID: $Id$
7// Copyright: (c) 1997 Stefan Csomor
8// Licence: wxWindows licence
9/////////////////////////////////////////////////////////////////////////////
10
11#include "wx/wxprec.h"
12
afd5d91c
SC
13#if wxOSX_USE_COCOA_OR_CARBON
14
489468fe
SC
15#include "wx/region.h"
16
17#ifndef WX_PRECOMP
18 #include "wx/gdicmn.h"
19#endif
20
5398a2e0 21#include "wx/osx/private.h"
489468fe
SC
22
23IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject)
24IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator, wxObject)
25
26//-----------------------------------------------------------------------------
27// wxRegionRefData implementation
28//-----------------------------------------------------------------------------
29
30class WXDLLEXPORT wxRegionRefData : public wxGDIRefData
31{
32public:
33 wxRegionRefData()
34 {
35 m_macRgn.reset( HIShapeCreateMutable() );
36 }
37
38 wxRegionRefData(wxCFRef<HIShapeRef> &region)
39 {
40 m_macRgn.reset( HIShapeCreateMutableCopy(region) );
41 }
42
43 wxRegionRefData(long x, long y, long w, long h)
44 {
45 CGRect r = CGRectMake(x,y,w,h);
46 wxCFRef<HIShapeRef> rect(HIShapeCreateWithRect(&r));
47 m_macRgn.reset( HIShapeCreateMutableCopy(rect) );
48 }
49
50 wxRegionRefData(const wxRegionRefData& data)
51 : wxGDIRefData()
52 {
53 m_macRgn.reset( HIShapeCreateMutableCopy(data.m_macRgn) );
54 }
55
56 virtual ~wxRegionRefData()
57 {
58 }
59
60 wxCFRef<HIMutableShapeRef> m_macRgn;
61};
62
63#define M_REGION (((wxRegionRefData*)m_refData)->m_macRgn)
64#define OTHER_M_REGION(a) (((wxRegionRefData*)(a.m_refData))->m_macRgn)
65
66//-----------------------------------------------------------------------------
67// wxRegion
68//-----------------------------------------------------------------------------
69
70/*!
71 * Create an empty region.
72 */
73wxRegion::wxRegion()
74{
75 m_refData = new wxRegionRefData();
76}
77
78wxRegion::wxRegion(WXHRGN hRegion )
79{
80 wxCFRef< HIShapeRef > shape( (HIShapeRef) hRegion );
81 m_refData = new wxRegionRefData(shape);
82}
83
84wxRegion::wxRegion(long x, long y, long w, long h)
85{
86 m_refData = new wxRegionRefData(x , y , w , h );
87}
88
89wxRegion::wxRegion(const wxPoint& topLeft, const wxPoint& bottomRight)
90{
91 m_refData = new wxRegionRefData(topLeft.x , topLeft.y ,
f51afd8f
SC
92 bottomRight.x - topLeft.x,
93 bottomRight.y - topLeft.y);
489468fe
SC
94}
95
96wxRegion::wxRegion(const wxRect& rect)
97{
98 m_refData = new wxRegionRefData(rect.x , rect.y , rect.width , rect.height);
99}
100
1ed06824 101wxRegion::wxRegion(size_t n, const wxPoint *points, wxPolygonFillMode WXUNUSED(fillStyle))
489468fe
SC
102{
103 wxUnusedVar(n);
104 wxUnusedVar(points);
105
03647350 106#if 0
5398a2e0
SC
107 // no non-QD APIs available
108 // TODO : remove ?
489468fe
SC
109 // OS X somehow does not collect the region invisibly as before, so sometimes things
110 // get drawn on screen instead of just being combined into a region, therefore we allocate a temp gworld now
111
112 GWorldPtr gWorld = NULL;
113 GWorldPtr oldWorld;
114 GDHandle oldGDHandle;
115 OSStatus err;
116 Rect destRect = { 0, 0, 1, 1 };
117
118 ::GetGWorld( &oldWorld, &oldGDHandle );
119 err = ::NewGWorld( &gWorld, 32, &destRect, NULL, NULL, 0 );
120 if ( err == noErr )
121 {
122 ::SetGWorld( gWorld, GetGDevice() );
123
124 OpenRgn();
125
126 wxCoord x1, x2 , y1 , y2 ;
127 x2 = x1 = points[0].x ;
128 y2 = y1 = points[0].y ;
129
130 ::MoveTo( x1, y1 );
131 for (size_t i = 1; i < n; i++)
132 {
133 x2 = points[i].x ;
134 y2 = points[i].y ;
135 ::LineTo( x2, y2 );
136 }
137
138 // close the polyline if necessary
139 if ( x1 != x2 || y1 != y2 )
140 ::LineTo( x1, y1 ) ;
141
142 RgnHandle tempRgn = NewRgn();
143 CloseRgn( tempRgn ) ;
03647350 144
489468fe
SC
145 ::SetGWorld( oldWorld, oldGDHandle );
146 wxCFRef<HIShapeRef> tempShape( HIShapeCreateWithQDRgn(tempRgn ) );
147 m_refData = new wxRegionRefData(tempShape);
148 DisposeRgn( tempRgn );
149 }
150 else
151 {
152 m_refData = new wxRegionRefData;
153 }
154#else
155 wxFAIL_MSG( "not implemented" );
156 m_refData = NULL;
157#endif
158}
159
160wxRegion::~wxRegion()
161{
162 // m_refData unrefed in ~wxObject
163}
164
165wxGDIRefData *wxRegion::CreateGDIRefData() const
166{
167 return new wxRegionRefData;
168}
169
170wxGDIRefData *wxRegion::CloneGDIRefData(const wxGDIRefData *data) const
171{
5c33522f 172 return new wxRegionRefData(*static_cast<const wxRegionRefData *>(data));
489468fe
SC
173}
174
175//-----------------------------------------------------------------------------
176//# Modify region
177//-----------------------------------------------------------------------------
178
179//! Clear current region
180void wxRegion::Clear()
181{
182 UnRef();
183}
184
185// Move the region
186bool wxRegion::DoOffset(wxCoord x, wxCoord y)
187{
9a83f860 188 wxCHECK_MSG( M_REGION, false, wxT("invalid wxRegion") );
489468fe
SC
189
190 if ( !x && !y )
191 // nothing to do
192 return true;
193
0aab87fd
VZ
194 AllocExclusive();
195
489468fe
SC
196 verify_noerr( HIShapeOffset( M_REGION , x , y ) ) ;
197
198 return true ;
199}
200
201
202//! Union /e region with this.
203bool wxRegion::DoCombine(const wxRegion& region, wxRegionOp op)
204{
a1b806b9 205 wxCHECK_MSG( region.IsOk(), false, wxT("invalid wxRegion") );
489468fe 206
22aa243d 207 AllocExclusive();
489468fe
SC
208
209 switch (op)
210 {
211 case wxRGN_AND:
212 verify_noerr( HIShapeIntersect( M_REGION , OTHER_M_REGION(region) , M_REGION ) );
213 break ;
214
215 case wxRGN_OR:
216 verify_noerr( HIShapeUnion( M_REGION , OTHER_M_REGION(region) , M_REGION ) );
217 break ;
218
219 case wxRGN_XOR:
220 {
221 // XOR is defined as the difference between union and intersection
222 wxCFRef< HIShapeRef > unionshape( HIShapeCreateUnion( M_REGION , OTHER_M_REGION(region) ) );
223 wxCFRef< HIShapeRef > intersectionshape( HIShapeCreateIntersection( M_REGION , OTHER_M_REGION(region) ) );
224 verify_noerr( HIShapeDifference( unionshape, intersectionshape, M_REGION ) );
225 }
226 break ;
227
228 case wxRGN_DIFF:
229 verify_noerr( HIShapeDifference( M_REGION , OTHER_M_REGION(region) , M_REGION ) ) ;
230 break ;
231
232 case wxRGN_COPY:
233 default:
234 M_REGION.reset( HIShapeCreateMutableCopy( OTHER_M_REGION(region) ) );
235 break ;
236 }
237
238 return true;
239}
240
241//-----------------------------------------------------------------------------
242//# Information on region
243//-----------------------------------------------------------------------------
244
1715d4fe 245bool wxRegion::DoIsEqual(const wxRegion& region) const
489468fe 246{
1715d4fe
VZ
247 // There doesn't seem to be any native function for checking the equality
248 // of HIShapes so we compute their differences to determine if they are
249 // equal.
913bcbfc 250 wxRegion r(*this);
1715d4fe 251 r.Subtract(region);
489468fe 252
1715d4fe
VZ
253 if ( !r.IsEmpty() )
254 return false;
255
256 wxRegion r2(region);
257 r2.Subtract(*this);
258
259 return r2.IsEmpty();
489468fe
SC
260}
261
262// Outer bounds of region
263bool wxRegion::DoGetBox(wxCoord& x, wxCoord& y, wxCoord& w, wxCoord& h) const
264{
265 if (m_refData)
266 {
267 CGRect box ;
268 HIShapeGetBounds( M_REGION , &box ) ;
5c33522f
VZ
269 x = static_cast<int>(box.origin.x);
270 y = static_cast<int>(box.origin.y);
271 w = static_cast<int>(box.size.width);
272 h = static_cast<int>(box.size.height);
489468fe
SC
273
274 return true;
275 }
276 else
277 {
278 x = y = w = h = 0;
279
280 return false;
281 }
282}
283
284// Is region empty?
285bool wxRegion::IsEmpty() const
286{
287 if ( m_refData )
288 return HIShapeIsEmpty( M_REGION ) ;
289 else
290 return true ;
291}
292
7279a306 293WXHRGN wxRegion::GetWXHRGN() const
489468fe
SC
294{
295 return M_REGION ;
296}
297
298//-----------------------------------------------------------------------------
299//# Tests
300//-----------------------------------------------------------------------------
301
302// Does the region contain the point?
303wxRegionContain wxRegion::DoContainsPoint(wxCoord x, wxCoord y) const
304{
305 if (!m_refData)
306 return wxOutRegion;
307
e331a94e 308 CGPoint p = { x, y } ;
489468fe
SC
309 if (HIShapeContainsPoint( M_REGION , &p ) )
310 return wxInRegion;
311
312 return wxOutRegion;
313}
314
315// Does the region contain the rectangle (x, y, w, h)?
316wxRegionContain wxRegion::DoContainsRect(const wxRect& r) const
317{
318 if (!m_refData)
319 return wxOutRegion;
320
321 CGRect rect = CGRectMake(r.x,r.y,r.width,r.height);
322 wxCFRef<HIShapeRef> rectshape(HIShapeCreateWithRect(&rect));
323 wxCFRef<HIShapeRef> intersect(HIShapeCreateIntersection(rectshape,M_REGION));
324 CGRect bounds;
325 HIShapeGetBounds(intersect, &bounds);
326
327 if ( HIShapeIsRectangular(intersect) && CGRectEqualToRect(rect,bounds) )
328 return wxInRegion;
329 else if ( HIShapeIsEmpty( intersect ) )
330 return wxOutRegion;
331 else
332 return wxPartRegion;
333}
334
335///////////////////////////////////////////////////////////////////////////////
336// //
337// wxRegionIterator //
338// //
339///////////////////////////////////////////////////////////////////////////////
340
341/*!
342 * Initialize empty iterator
343 */
344wxRegionIterator::wxRegionIterator()
345 : m_current(0), m_numRects(0), m_rects(NULL)
346{
347}
348
349wxRegionIterator::~wxRegionIterator()
350{
5276b0a5 351 wxDELETEA(m_rects);
489468fe
SC
352}
353
354wxRegionIterator::wxRegionIterator(const wxRegionIterator& iterator)
355 : wxObject()
356 , m_current(iterator.m_current)
357 , m_numRects(0)
358 , m_rects(NULL)
359{
360 SetRects(iterator.m_numRects, iterator.m_rects);
361}
362
363wxRegionIterator& wxRegionIterator::operator=(const wxRegionIterator& iterator)
364{
365 m_current = iterator.m_current;
366 SetRects(iterator.m_numRects, iterator.m_rects);
367
368 return *this;
369}
370
371/*!
372 * Set iterator rects for region
373 */
374void wxRegionIterator::SetRects(long numRects, wxRect *rects)
375{
5276b0a5 376 wxDELETEA(m_rects);
489468fe
SC
377
378 if (rects && (numRects > 0))
379 {
380 int i;
381
382 m_rects = new wxRect[numRects];
383 for (i = 0; i < numRects; i++)
384 m_rects[i] = rects[i];
385 }
386
387 m_numRects = numRects;
388}
389
390/*!
391 * Initialize iterator for region
392 */
393wxRegionIterator::wxRegionIterator(const wxRegion& region)
394{
395 m_rects = NULL;
396
397 Reset(region);
398}
399
400/*!
401 * Reset iterator for a new /e region.
402 */
403
5398a2e0
SC
404class RegionToRectsCallbackData
405{
406public :
407 wxRect* m_rects ;
408 long m_current ;
409};
410
411#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
412
489468fe
SC
413OSStatus wxMacRegionToRectsCounterCallback(
414 UInt16 message, RgnHandle WXUNUSED(region), const Rect *WXUNUSED(rect), void *data )
415{
416 long *m_numRects = (long*) data ;
417 if ( message == kQDRegionToRectsMsgInit )
418 {
419 (*m_numRects) = 0 ;
420 }
421 else if (message == kQDRegionToRectsMsgParse)
422 {
423 (*m_numRects) += 1 ;
424 }
425
426 return noErr;
427}
428
489468fe
SC
429OSStatus wxMacRegionToRectsSetterCallback(
430 UInt16 message, RgnHandle WXUNUSED(region), const Rect *rect, void *data )
431{
432 if (message == kQDRegionToRectsMsgParse)
433 {
434 RegionToRectsCallbackData *cb = (RegionToRectsCallbackData*) data ;
435 cb->m_rects[cb->m_current++] = wxRect( rect->left , rect->top , rect->right - rect->left , rect->bottom - rect->top ) ;
436 }
437
438 return noErr;
439}
5398a2e0
SC
440
441#endif
442
443#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
444
445OSStatus wxOSXRegionToRectsCounterCallback(
446 int message, HIShapeRef WXUNUSED(region), const CGRect *WXUNUSED(rect), void *data )
447{
448 long *m_numRects = (long*) data ;
449 if ( message == kHIShapeEnumerateInit )
450 {
451 (*m_numRects) = 0 ;
452 }
453 else if (message == kHIShapeEnumerateRect)
454 {
455 (*m_numRects) += 1 ;
456 }
457
458 return noErr;
459}
460
461OSStatus wxOSXRegionToRectsSetterCallback(
462 int message, HIShapeRef WXUNUSED(region), const CGRect *rect, void *data )
463{
464 if (message == kHIShapeEnumerateRect)
465 {
466 RegionToRectsCallbackData *cb = (RegionToRectsCallbackData*) data ;
467 cb->m_rects[cb->m_current++] = wxRect( rect->origin.x , rect->origin.y , rect->size.width , rect->size.height ) ;
468 }
469
470 return noErr;
471}
472
489468fe
SC
473#endif
474
475void wxRegionIterator::Reset(const wxRegion& region)
476{
477 m_current = 0;
478 m_region = region;
479
5276b0a5 480 wxDELETEA(m_rects);
489468fe
SC
481
482 if (m_region.IsEmpty())
483 {
484 m_numRects = 0;
485 }
486 else
487 {
5398a2e0
SC
488#if 0
489 // fallback code in case we ever need it again
489468fe
SC
490 // copying this to a path and dissecting the path would be an option
491 m_numRects = 1;
492 m_rects = new wxRect[m_numRects];
493 m_rects[0] = m_region.GetBox();
5398a2e0 494#endif
489468fe 495
5398a2e0
SC
496#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
497 if ( HIShapeEnumerate != NULL )
489468fe 498 {
03647350 499 OSStatus err = HIShapeEnumerate (OTHER_M_REGION(region), kHIShapeParseFromTopLeft, wxOSXRegionToRectsCounterCallback,
5398a2e0
SC
500 (void*)&m_numRects);
501 if (err == noErr)
502 {
503 m_rects = new wxRect[m_numRects];
504 RegionToRectsCallbackData data ;
505 data.m_rects = m_rects ;
506 data.m_current = 0 ;
03647350 507 HIShapeEnumerate( OTHER_M_REGION(region), kHIShapeParseFromTopLeft, wxOSXRegionToRectsSetterCallback,
5398a2e0
SC
508 (void*)&data );
509 }
510 else
511 {
512 m_numRects = 0;
513 }
489468fe
SC
514 }
515 else
5398a2e0 516#endif
489468fe 517 {
5398a2e0
SC
518#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
519 OSStatus err = noErr;
520 RgnHandle rgn = NewRgn();
521 HIShapeGetAsQDRgn(OTHER_M_REGION(region), rgn);
522
523 err = QDRegionToRects (rgn, kQDParseRegionFromTopLeft, wxMacRegionToRectsCounterCallback
524 , (void*)&m_numRects);
525 if (err == noErr)
526 {
527 m_rects = new wxRect[m_numRects];
528 RegionToRectsCallbackData data ;
529 data.m_rects = m_rects ;
530 data.m_current = 0 ;
03647350 531 QDRegionToRects( rgn , kQDParseRegionFromTopLeft, wxMacRegionToRectsSetterCallback,
5398a2e0
SC
532 (void*)&data );
533 }
534 else
535 {
536 m_numRects = 0;
537 }
538 DisposeRgn( rgn );
489468fe 539#endif
5398a2e0 540 }
489468fe
SC
541 }
542}
543
544/*!
545 * Increment iterator. The rectangle returned is the one after the
546 * incrementation.
547 */
548wxRegionIterator& wxRegionIterator::operator ++ ()
549{
550 if (m_current < m_numRects)
551 ++m_current;
552
553 return *this;
554}
555
556/*!
557 * Increment iterator. The rectangle returned is the one before the
558 * incrementation.
559 */
560wxRegionIterator wxRegionIterator::operator ++ (int)
561{
562 wxRegionIterator previous(*this);
563
564 if (m_current < m_numRects)
565 ++m_current;
566
567 return previous;
568}
569
570long wxRegionIterator::GetX() const
571{
572 if (m_current < m_numRects)
573 return m_rects[m_current].x;
574
575 return 0;
576}
577
578long wxRegionIterator::GetY() const
579{
580 if (m_current < m_numRects)
581 return m_rects[m_current].y;
582
583 return 0;
584}
585
586long wxRegionIterator::GetW() const
587{
588 if (m_current < m_numRects)
589 return m_rects[m_current].width ;
590
591 return 0;
592}
593
594long wxRegionIterator::GetH() const
595{
596 if (m_current < m_numRects)
597 return m_rects[m_current].height;
598
599 return 0;
600}
afd5d91c
SC
601
602#endif