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