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