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