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