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