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