]> git.saurik.com Git - wxWidgets.git/blob - src/osx/carbon/region.cpp
ffd0f106d9f6bcfe9918ff9762fa8151cc2f1dc2
[wxWidgets.git] / src / osx / carbon / region.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // File: src/osx/carbon/region.cpp
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
13 #if wxOSX_USE_COCOA_OR_CARBON
14
15 #include "wx/region.h"
16
17 #ifndef WX_PRECOMP
18 #include "wx/gdicmn.h"
19 #endif
20
21 #include "wx/osx/private.h"
22
23 IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject)
24 IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator, wxObject)
25
26 //-----------------------------------------------------------------------------
27 // wxRegionRefData implementation
28 //-----------------------------------------------------------------------------
29
30 class WXDLLEXPORT wxRegionRefData : public wxGDIRefData
31 {
32 public:
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 */
73 wxRegion::wxRegion()
74 {
75 m_refData = new wxRegionRefData();
76 }
77
78 wxRegion::wxRegion(WXHRGN hRegion )
79 {
80 wxCFRef< HIShapeRef > shape( (HIShapeRef) hRegion );
81 m_refData = new wxRegionRefData(shape);
82 }
83
84 wxRegion::wxRegion(long x, long y, long w, long h)
85 {
86 m_refData = new wxRegionRefData(x , y , w , h );
87 }
88
89 wxRegion::wxRegion(const wxPoint& topLeft, const wxPoint& bottomRight)
90 {
91 m_refData = new wxRegionRefData(topLeft.x , topLeft.y ,
92 topLeft.x - bottomRight.x ,
93 topLeft.y - bottomRight.y);
94 }
95
96 wxRegion::wxRegion(const wxRect& rect)
97 {
98 m_refData = new wxRegionRefData(rect.x , rect.y , rect.width , rect.height);
99 }
100
101 wxRegion::wxRegion(size_t n, const wxPoint *points, wxPolygonFillMode WXUNUSED(fillStyle))
102 {
103 wxUnusedVar(n);
104 wxUnusedVar(points);
105
106 #if 0
107 // no non-QD APIs available
108 // TODO : remove ?
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 ) ;
144
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
160 wxRegion::~wxRegion()
161 {
162 // m_refData unrefed in ~wxObject
163 }
164
165 wxGDIRefData *wxRegion::CreateGDIRefData() const
166 {
167 return new wxRegionRefData;
168 }
169
170 wxGDIRefData *wxRegion::CloneGDIRefData(const wxGDIRefData *data) const
171 {
172 return new wxRegionRefData(*static_cast<const wxRegionRefData *>(data));
173 }
174
175 //-----------------------------------------------------------------------------
176 //# Modify region
177 //-----------------------------------------------------------------------------
178
179 //! Clear current region
180 void wxRegion::Clear()
181 {
182 UnRef();
183 }
184
185 // Move the region
186 bool wxRegion::DoOffset(wxCoord x, wxCoord y)
187 {
188 wxCHECK_MSG( M_REGION, false, wxT("invalid wxRegion") );
189
190 if ( !x && !y )
191 // nothing to do
192 return true;
193
194 AllocExclusive();
195
196 verify_noerr( HIShapeOffset( M_REGION , x , y ) ) ;
197
198 return true ;
199 }
200
201
202 //! Union /e region with this.
203 bool wxRegion::DoCombine(const wxRegion& region, wxRegionOp op)
204 {
205 wxCHECK_MSG( region.IsOk(), false, wxT("invalid wxRegion") );
206
207 AllocExclusive();
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
245 bool wxRegion::DoIsEqual(const wxRegion& WXUNUSED(region)) const
246 {
247 wxFAIL_MSG( wxT("not implemented") );
248
249 return false;
250 }
251
252 // Outer bounds of region
253 bool wxRegion::DoGetBox(wxCoord& x, wxCoord& y, wxCoord& w, wxCoord& h) const
254 {
255 if (m_refData)
256 {
257 CGRect box ;
258 HIShapeGetBounds( M_REGION , &box ) ;
259 x = static_cast<int>(box.origin.x);
260 y = static_cast<int>(box.origin.y);
261 w = static_cast<int>(box.size.width);
262 h = static_cast<int>(box.size.height);
263
264 return true;
265 }
266 else
267 {
268 x = y = w = h = 0;
269
270 return false;
271 }
272 }
273
274 // Is region empty?
275 bool wxRegion::IsEmpty() const
276 {
277 if ( m_refData )
278 return HIShapeIsEmpty( M_REGION ) ;
279 else
280 return true ;
281 }
282
283 WXHRGN wxRegion::GetWXHRGN() const
284 {
285 return M_REGION ;
286 }
287
288 //-----------------------------------------------------------------------------
289 //# Tests
290 //-----------------------------------------------------------------------------
291
292 // Does the region contain the point?
293 wxRegionContain wxRegion::DoContainsPoint(wxCoord x, wxCoord y) const
294 {
295 if (!m_refData)
296 return wxOutRegion;
297
298 CGPoint p = { x, y } ;
299 if (HIShapeContainsPoint( M_REGION , &p ) )
300 return wxInRegion;
301
302 return wxOutRegion;
303 }
304
305 // Does the region contain the rectangle (x, y, w, h)?
306 wxRegionContain wxRegion::DoContainsRect(const wxRect& r) const
307 {
308 if (!m_refData)
309 return wxOutRegion;
310
311 CGRect rect = CGRectMake(r.x,r.y,r.width,r.height);
312 wxCFRef<HIShapeRef> rectshape(HIShapeCreateWithRect(&rect));
313 wxCFRef<HIShapeRef> intersect(HIShapeCreateIntersection(rectshape,M_REGION));
314 CGRect bounds;
315 HIShapeGetBounds(intersect, &bounds);
316
317 if ( HIShapeIsRectangular(intersect) && CGRectEqualToRect(rect,bounds) )
318 return wxInRegion;
319 else if ( HIShapeIsEmpty( intersect ) )
320 return wxOutRegion;
321 else
322 return wxPartRegion;
323 }
324
325 ///////////////////////////////////////////////////////////////////////////////
326 // //
327 // wxRegionIterator //
328 // //
329 ///////////////////////////////////////////////////////////////////////////////
330
331 /*!
332 * Initialize empty iterator
333 */
334 wxRegionIterator::wxRegionIterator()
335 : m_current(0), m_numRects(0), m_rects(NULL)
336 {
337 }
338
339 wxRegionIterator::~wxRegionIterator()
340 {
341 wxDELETEA(m_rects);
342 }
343
344 wxRegionIterator::wxRegionIterator(const wxRegionIterator& iterator)
345 : wxObject()
346 , m_current(iterator.m_current)
347 , m_numRects(0)
348 , m_rects(NULL)
349 {
350 SetRects(iterator.m_numRects, iterator.m_rects);
351 }
352
353 wxRegionIterator& wxRegionIterator::operator=(const wxRegionIterator& iterator)
354 {
355 m_current = iterator.m_current;
356 SetRects(iterator.m_numRects, iterator.m_rects);
357
358 return *this;
359 }
360
361 /*!
362 * Set iterator rects for region
363 */
364 void wxRegionIterator::SetRects(long numRects, wxRect *rects)
365 {
366 wxDELETEA(m_rects);
367
368 if (rects && (numRects > 0))
369 {
370 int i;
371
372 m_rects = new wxRect[numRects];
373 for (i = 0; i < numRects; i++)
374 m_rects[i] = rects[i];
375 }
376
377 m_numRects = numRects;
378 }
379
380 /*!
381 * Initialize iterator for region
382 */
383 wxRegionIterator::wxRegionIterator(const wxRegion& region)
384 {
385 m_rects = NULL;
386
387 Reset(region);
388 }
389
390 /*!
391 * Reset iterator for a new /e region.
392 */
393
394 class RegionToRectsCallbackData
395 {
396 public :
397 wxRect* m_rects ;
398 long m_current ;
399 };
400
401 #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
402
403 OSStatus wxMacRegionToRectsCounterCallback(
404 UInt16 message, RgnHandle WXUNUSED(region), const Rect *WXUNUSED(rect), void *data )
405 {
406 long *m_numRects = (long*) data ;
407 if ( message == kQDRegionToRectsMsgInit )
408 {
409 (*m_numRects) = 0 ;
410 }
411 else if (message == kQDRegionToRectsMsgParse)
412 {
413 (*m_numRects) += 1 ;
414 }
415
416 return noErr;
417 }
418
419 OSStatus wxMacRegionToRectsSetterCallback(
420 UInt16 message, RgnHandle WXUNUSED(region), const Rect *rect, void *data )
421 {
422 if (message == kQDRegionToRectsMsgParse)
423 {
424 RegionToRectsCallbackData *cb = (RegionToRectsCallbackData*) data ;
425 cb->m_rects[cb->m_current++] = wxRect( rect->left , rect->top , rect->right - rect->left , rect->bottom - rect->top ) ;
426 }
427
428 return noErr;
429 }
430
431 #endif
432
433 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
434
435 OSStatus wxOSXRegionToRectsCounterCallback(
436 int message, HIShapeRef WXUNUSED(region), const CGRect *WXUNUSED(rect), void *data )
437 {
438 long *m_numRects = (long*) data ;
439 if ( message == kHIShapeEnumerateInit )
440 {
441 (*m_numRects) = 0 ;
442 }
443 else if (message == kHIShapeEnumerateRect)
444 {
445 (*m_numRects) += 1 ;
446 }
447
448 return noErr;
449 }
450
451 OSStatus wxOSXRegionToRectsSetterCallback(
452 int message, HIShapeRef WXUNUSED(region), const CGRect *rect, void *data )
453 {
454 if (message == kHIShapeEnumerateRect)
455 {
456 RegionToRectsCallbackData *cb = (RegionToRectsCallbackData*) data ;
457 cb->m_rects[cb->m_current++] = wxRect( rect->origin.x , rect->origin.y , rect->size.width , rect->size.height ) ;
458 }
459
460 return noErr;
461 }
462
463 #endif
464
465 void wxRegionIterator::Reset(const wxRegion& region)
466 {
467 m_current = 0;
468 m_region = region;
469
470 wxDELETEA(m_rects);
471
472 if (m_region.IsEmpty())
473 {
474 m_numRects = 0;
475 }
476 else
477 {
478 #if 0
479 // fallback code in case we ever need it again
480 // copying this to a path and dissecting the path would be an option
481 m_numRects = 1;
482 m_rects = new wxRect[m_numRects];
483 m_rects[0] = m_region.GetBox();
484 #endif
485
486 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
487 if ( HIShapeEnumerate != NULL )
488 {
489 OSStatus err = HIShapeEnumerate (OTHER_M_REGION(region), kHIShapeParseFromTopLeft, wxOSXRegionToRectsCounterCallback,
490 (void*)&m_numRects);
491 if (err == noErr)
492 {
493 m_rects = new wxRect[m_numRects];
494 RegionToRectsCallbackData data ;
495 data.m_rects = m_rects ;
496 data.m_current = 0 ;
497 HIShapeEnumerate( OTHER_M_REGION(region), kHIShapeParseFromTopLeft, wxOSXRegionToRectsSetterCallback,
498 (void*)&data );
499 }
500 else
501 {
502 m_numRects = 0;
503 }
504 }
505 else
506 #endif
507 {
508 #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
509 OSStatus err = noErr;
510 RgnHandle rgn = NewRgn();
511 HIShapeGetAsQDRgn(OTHER_M_REGION(region), rgn);
512
513 err = QDRegionToRects (rgn, kQDParseRegionFromTopLeft, wxMacRegionToRectsCounterCallback
514 , (void*)&m_numRects);
515 if (err == noErr)
516 {
517 m_rects = new wxRect[m_numRects];
518 RegionToRectsCallbackData data ;
519 data.m_rects = m_rects ;
520 data.m_current = 0 ;
521 QDRegionToRects( rgn , kQDParseRegionFromTopLeft, wxMacRegionToRectsSetterCallback,
522 (void*)&data );
523 }
524 else
525 {
526 m_numRects = 0;
527 }
528 DisposeRgn( rgn );
529 #endif
530 }
531 }
532 }
533
534 /*!
535 * Increment iterator. The rectangle returned is the one after the
536 * incrementation.
537 */
538 wxRegionIterator& wxRegionIterator::operator ++ ()
539 {
540 if (m_current < m_numRects)
541 ++m_current;
542
543 return *this;
544 }
545
546 /*!
547 * Increment iterator. The rectangle returned is the one before the
548 * incrementation.
549 */
550 wxRegionIterator wxRegionIterator::operator ++ (int)
551 {
552 wxRegionIterator previous(*this);
553
554 if (m_current < m_numRects)
555 ++m_current;
556
557 return previous;
558 }
559
560 long wxRegionIterator::GetX() const
561 {
562 if (m_current < m_numRects)
563 return m_rects[m_current].x;
564
565 return 0;
566 }
567
568 long wxRegionIterator::GetY() const
569 {
570 if (m_current < m_numRects)
571 return m_rects[m_current].y;
572
573 return 0;
574 }
575
576 long wxRegionIterator::GetW() const
577 {
578 if (m_current < m_numRects)
579 return m_rects[m_current].width ;
580
581 return 0;
582 }
583
584 long wxRegionIterator::GetH() const
585 {
586 if (m_current < m_numRects)
587 return m_rects[m_current].height;
588
589 return 0;
590 }
591
592 #endif