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