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