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