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