]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/region.cpp
making virtual lists faster by not sorting items
[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 #ifndef WX_PRECOMP
16 #include "wx/gdicmn.h"
17 #endif
18
19 #include "wx/mac/uma.h"
20
21 IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject)
22 IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator, wxObject)
23
24 //-----------------------------------------------------------------------------
25 // wxRegionRefData implementation
26 //-----------------------------------------------------------------------------
27
28 class WXDLLEXPORT wxRegionRefData : public wxGDIRefData
29 {
30 public:
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 virtual ~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 */
57 wxRegion::wxRegion()
58 {
59 m_refData = new wxRegionRefData;
60 }
61
62 wxRegion::wxRegion(WXHRGN hRegion )
63 {
64 m_refData = new wxRegionRefData;
65 CopyRgn( (RgnHandle) hRegion , (RgnHandle) M_REGION ) ;
66 }
67
68 wxRegion::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
74 wxRegion::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
80 wxRegion::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
86 wxRegion::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
129 wxRegion::~wxRegion()
130 {
131 // m_refData unrefed in ~wxObject
132 }
133
134 //-----------------------------------------------------------------------------
135 //# Modify region
136 //-----------------------------------------------------------------------------
137
138 //! Clear current region
139 void wxRegion::Clear()
140 {
141 UnRef();
142 }
143
144 // Move the region
145 bool wxRegion::DoOffset(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 //! Union /e region with this.
160 bool wxRegion::DoCombine(const wxRegion& region, wxRegionOp op)
161 {
162 wxCHECK_MSG( region.Ok(), false, _T("invalid wxRegion") );
163
164 // Don't change shared data
165 if (!m_refData)
166 {
167 m_refData = new wxRegionRefData();
168 }
169 else if (m_refData->GetRefCount() > 1)
170 {
171 wxRegionRefData* ref = (wxRegionRefData*)m_refData;
172 UnRef();
173 m_refData = new wxRegionRefData(*ref);
174 }
175
176 switch (op)
177 {
178 case wxRGN_AND:
179 SectRgn( M_REGION , OTHER_M_REGION(region) , M_REGION ) ;
180 break ;
181
182 case wxRGN_OR:
183 UnionRgn( M_REGION , OTHER_M_REGION(region) , M_REGION ) ;
184 break ;
185
186 case wxRGN_XOR:
187 XorRgn( M_REGION , OTHER_M_REGION(region) , M_REGION ) ;
188 break ;
189
190 case wxRGN_DIFF:
191 DiffRgn( M_REGION , OTHER_M_REGION(region) , M_REGION ) ;
192 break ;
193
194 case wxRGN_COPY:
195 default:
196 CopyRgn( OTHER_M_REGION(region) , M_REGION ) ;
197 break ;
198 }
199
200 return true;
201 }
202
203 //-----------------------------------------------------------------------------
204 //# Information on region
205 //-----------------------------------------------------------------------------
206
207 bool wxRegion::DoIsEqual(const wxRegion& region) const
208 {
209 wxFAIL_MSG( _T("not implemented") );
210
211 return false;
212 }
213
214 // Outer bounds of region
215 bool wxRegion::DoGetBox(wxCoord& x, wxCoord& y, wxCoord& w, wxCoord& h) const
216 {
217 if (m_refData)
218 {
219 Rect box ;
220 GetRegionBounds( M_REGION , &box ) ;
221 x = box.left ;
222 y = box.top ;
223 w = box.right - box.left ;
224 h = box.bottom - box.top ;
225
226 return true;
227 }
228 else
229 {
230 x = y = w = h = 0;
231
232 return false;
233 }
234 }
235
236 // Is region empty?
237 bool wxRegion::IsEmpty() const
238 {
239 if ( m_refData )
240 return EmptyRgn( M_REGION ) ;
241 else
242 return true ;
243 }
244
245 const WXHRGN wxRegion::GetWXHRGN() const
246 {
247 return M_REGION ;
248 }
249
250 //-----------------------------------------------------------------------------
251 //# Tests
252 //-----------------------------------------------------------------------------
253
254 // Does the region contain the point?
255 wxRegionContain wxRegion::DoContainsPoint(wxCoord x, wxCoord y) const
256 {
257 if (!m_refData)
258 return wxOutRegion;
259
260 Point p = { y , x } ;
261 if (PtInRgn( p , M_REGION ) )
262 return wxInRegion;
263
264 return wxOutRegion;
265 }
266
267 // Does the region contain the rectangle (x, y, w, h)?
268 wxRegionContain wxRegion::DoContainsRect(const wxRect& r) const
269 {
270 if (!m_refData)
271 return wxOutRegion;
272
273 Rect rect = { r.y , r.x , r.y + r.height , r.x + r.width } ;
274 if (RectInRgn( &rect , M_REGION ) )
275 return wxInRegion;
276 else
277 return wxOutRegion;
278 }
279
280 ///////////////////////////////////////////////////////////////////////////////
281 // //
282 // wxRegionIterator //
283 // //
284 ///////////////////////////////////////////////////////////////////////////////
285
286 /*!
287 * Initialize empty iterator
288 */
289 wxRegionIterator::wxRegionIterator()
290 : m_current(0), m_numRects(0), m_rects(NULL)
291 {
292 }
293
294 wxRegionIterator::~wxRegionIterator()
295 {
296 if (m_rects)
297 {
298 delete [] m_rects;
299 m_rects = NULL;
300 }
301 }
302
303 wxRegionIterator::wxRegionIterator(const wxRegionIterator& iterator)
304 : wxObject()
305 , m_current(iterator.m_current)
306 , m_numRects(0)
307 , m_rects(NULL)
308 {
309 SetRects(iterator.m_numRects, iterator.m_rects);
310 }
311
312 wxRegionIterator& wxRegionIterator::operator=(const wxRegionIterator& iterator)
313 {
314 m_current = iterator.m_current;
315 SetRects(iterator.m_numRects, iterator.m_rects);
316
317 return *this;
318 }
319
320 /*!
321 * Set iterator rects for region
322 */
323 void wxRegionIterator::SetRects(long numRects, wxRect *rects)
324 {
325 if (m_rects)
326 {
327 delete [] m_rects;
328 m_rects = NULL;
329 }
330
331 if (rects && (numRects > 0))
332 {
333 int i;
334
335 m_rects = new wxRect[numRects];
336 for (i = 0; i < numRects; i++)
337 m_rects[i] = rects[i];
338 }
339
340 m_numRects = numRects;
341 }
342
343 /*!
344 * Initialize iterator for region
345 */
346 wxRegionIterator::wxRegionIterator(const wxRegion& region)
347 {
348 m_rects = NULL;
349
350 Reset(region);
351 }
352
353 /*!
354 * Reset iterator for a new /e region.
355 */
356
357 OSStatus wxMacRegionToRectsCounterCallback(
358 UInt16 message, RgnHandle region, const Rect *rect, void *data )
359 {
360 long *m_numRects = (long*) data ;
361 if ( message == kQDRegionToRectsMsgInit )
362 {
363 (*m_numRects) = 0 ;
364 }
365 else if (message == kQDRegionToRectsMsgParse)
366 {
367 (*m_numRects) += 1 ;
368 }
369
370 return noErr;
371 }
372
373 class RegionToRectsCallbackData
374 {
375 public :
376 wxRect* m_rects ;
377 long m_current ;
378 };
379
380 OSStatus wxMacRegionToRectsSetterCallback(
381 UInt16 message, RgnHandle region, const Rect *rect, void *data )
382 {
383 if (message == kQDRegionToRectsMsgParse)
384 {
385 RegionToRectsCallbackData *cb = (RegionToRectsCallbackData*) data ;
386 cb->m_rects[cb->m_current++] = wxRect( rect->left , rect->top , rect->right - rect->left , rect->bottom - rect->top ) ;
387 }
388
389 return noErr;
390 }
391
392 void wxRegionIterator::Reset(const wxRegion& region)
393 {
394 m_current = 0;
395 m_region = region;
396
397 if (m_rects)
398 {
399 delete [] m_rects;
400 m_rects = NULL;
401 }
402
403 if (m_region.IsEmpty())
404 {
405 m_numRects = 0;
406 }
407 else
408 {
409 RegionToRectsUPP proc = NewRegionToRectsUPP( wxMacRegionToRectsCounterCallback );
410
411 OSStatus err = noErr;
412 err = QDRegionToRects (OTHER_M_REGION( region ) , kQDParseRegionFromTopLeft, proc, (void*)&m_numRects);
413 if (err == noErr)
414 {
415 DisposeRegionToRectsUPP (proc);
416 proc = NewRegionToRectsUPP (wxMacRegionToRectsSetterCallback);
417 m_rects = new wxRect[m_numRects];
418 RegionToRectsCallbackData data ;
419 data.m_rects = m_rects ;
420 data.m_current = 0 ;
421 QDRegionToRects( OTHER_M_REGION( region ) , kQDParseRegionFromTopLeft, proc, (void*)&data );
422 }
423 else
424 {
425 m_numRects = 0;
426 }
427
428 DisposeRegionToRectsUPP( proc );
429 }
430 }
431
432 /*!
433 * Increment iterator. The rectangle returned is the one after the
434 * incrementation.
435 */
436 wxRegionIterator& wxRegionIterator::operator ++ ()
437 {
438 if (m_current < m_numRects)
439 ++m_current;
440
441 return *this;
442 }
443
444 /*!
445 * Increment iterator. The rectangle returned is the one before the
446 * incrementation.
447 */
448 wxRegionIterator wxRegionIterator::operator ++ (int)
449 {
450 wxRegionIterator previous(*this);
451
452 if (m_current < m_numRects)
453 ++m_current;
454
455 return previous;
456 }
457
458 long wxRegionIterator::GetX() const
459 {
460 if (m_current < m_numRects)
461 return m_rects[m_current].x;
462
463 return 0;
464 }
465
466 long wxRegionIterator::GetY() const
467 {
468 if (m_current < m_numRects)
469 return m_rects[m_current].y;
470
471 return 0;
472 }
473
474 long wxRegionIterator::GetW() const
475 {
476 if (m_current < m_numRects)
477 return m_rects[m_current].width ;
478
479 return 0;
480 }
481
482 long wxRegionIterator::GetH() const
483 {
484 if (m_current < m_numRects)
485 return m_rects[m_current].height;
486
487 return 0;
488 }