]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/region.cpp
[ 1509599 ] 'Split pickers page in widgets sample' with more icons and rebaking.
[wxWidgets.git] / src / gtk / region.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/region.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Modified: VZ at 05.10.00: use AllocExclusive(), comparison fixed
6 // Id: $Id$
7 // Copyright: (c) 1998 Robert Roebling
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21
22 #include "wx/region.h"
23
24 #ifndef WX_PRECOMP
25 #include "wx/log.h"
26 #endif
27
28 #include "wx/gtk/private.h"
29
30
31 // ----------------------------------------------------------------------------
32 // wxRegionRefData: private class containing the information about the region
33 // ----------------------------------------------------------------------------
34
35 class wxRegionRefData : public wxObjectRefData
36 {
37 public:
38 wxRegionRefData()
39 {
40 m_region = NULL;
41 }
42
43 wxRegionRefData(const wxRegionRefData& refData)
44 : wxObjectRefData()
45 {
46 m_region = gdk_region_copy(refData.m_region);
47 }
48
49 ~wxRegionRefData()
50 {
51 if (m_region)
52 gdk_region_destroy( m_region );
53 }
54
55 GdkRegion *m_region;
56 };
57
58 // ----------------------------------------------------------------------------
59 // macros
60 // ----------------------------------------------------------------------------
61
62 #define M_REGIONDATA ((wxRegionRefData *)m_refData)
63 #define M_REGIONDATA_OF(rgn) ((wxRegionRefData *)(rgn.m_refData))
64
65 IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject)
66 IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator,wxObject)
67
68 // ----------------------------------------------------------------------------
69 // wxRegion construction
70 // ----------------------------------------------------------------------------
71
72 #define M_REGIONDATA ((wxRegionRefData *)m_refData)
73
74 void wxRegion::InitRect(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
75 {
76 GdkRectangle rect;
77 rect.x = x;
78 rect.y = y;
79 rect.width = w;
80 rect.height = h;
81
82 m_refData = new wxRegionRefData();
83
84 M_REGIONDATA->m_region = gdk_region_rectangle( &rect );
85 }
86
87 wxRegion::wxRegion( GdkRegion *region )
88 {
89 m_refData = new wxRegionRefData();
90 M_REGIONDATA->m_region = gdk_region_copy( region );
91 }
92
93 wxRegion::wxRegion( size_t n, const wxPoint *points, int fillStyle )
94 {
95 GdkPoint *gdkpoints = new GdkPoint[n];
96 for ( size_t i = 0 ; i < n ; i++ )
97 {
98 gdkpoints[i].x = points[i].x;
99 gdkpoints[i].y = points[i].y;
100 }
101
102 m_refData = new wxRegionRefData();
103
104 GdkRegion* reg = gdk_region_polygon
105 (
106 gdkpoints,
107 n,
108 fillStyle == wxWINDING_RULE ? GDK_WINDING_RULE
109 : GDK_EVEN_ODD_RULE
110 );
111
112 M_REGIONDATA->m_region = reg;
113
114 delete [] gdkpoints;
115 }
116
117 wxRegion::~wxRegion()
118 {
119 // m_refData unrefed in ~wxObject
120 }
121
122 wxObjectRefData *wxRegion::CreateRefData() const
123 {
124 return new wxRegionRefData;
125 }
126
127 wxObjectRefData *wxRegion::CloneRefData(const wxObjectRefData *data) const
128 {
129 return new wxRegionRefData(*(wxRegionRefData *)data);
130 }
131
132 // ----------------------------------------------------------------------------
133 // wxRegion comparison
134 // ----------------------------------------------------------------------------
135
136 bool wxRegion::operator==( const wxRegion& region ) const
137 {
138 if (m_refData == region.m_refData) return true;
139
140 if (!m_refData || !region.m_refData) return false;
141
142 // compare the regions themselves, not the pointers to ref data!
143 return gdk_region_equal(M_REGIONDATA->m_region,
144 M_REGIONDATA_OF(region)->m_region);
145 }
146
147 // ----------------------------------------------------------------------------
148 // wxRegion operations
149 // ----------------------------------------------------------------------------
150
151 void wxRegion::Clear()
152 {
153 UnRef();
154 }
155
156 bool wxRegion::Union( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
157 {
158 // workaround for a strange GTK/X11 bug: taking union with an empty
159 // rectangle results in an empty region which is definitely not what we
160 // want
161 if ( !width || !height )
162 return true;
163
164 if ( !m_refData )
165 {
166 InitRect(x, y, width, height);
167 }
168 else
169 {
170 AllocExclusive();
171
172 GdkRectangle rect;
173 rect.x = x;
174 rect.y = y;
175 rect.width = width;
176 rect.height = height;
177
178 gdk_region_union_with_rect( M_REGIONDATA->m_region, &rect );
179 }
180
181 return true;
182 }
183
184 bool wxRegion::Union( const wxRect& rect )
185 {
186 return Union( rect.x, rect.y, rect.width, rect.height );
187 }
188
189 bool wxRegion::Union( const wxRegion& region )
190 {
191 if (region.IsNull())
192 return false;
193
194 if (!m_refData)
195 {
196 m_refData = new wxRegionRefData();
197 M_REGIONDATA->m_region = gdk_region_new();
198 }
199 else
200 {
201 AllocExclusive();
202 }
203
204 gdk_region_union( M_REGIONDATA->m_region, region.GetRegion() );
205
206 return true;
207 }
208
209 bool wxRegion::Intersect( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
210 {
211 wxRegion reg( x, y, width, height );
212
213 return Intersect( reg );
214 }
215
216 bool wxRegion::Intersect( const wxRect& rect )
217 {
218 wxRegion reg( rect );
219
220 return Intersect( reg );
221 }
222
223 bool wxRegion::Intersect( const wxRegion& region )
224 {
225 if (region.IsNull())
226 return false;
227
228 if (!m_refData)
229 {
230 // intersecting with invalid region doesn't make sense
231 return false;
232 }
233
234 AllocExclusive();
235
236 gdk_region_intersect( M_REGIONDATA->m_region, region.GetRegion() );
237
238 return true;
239 }
240
241 bool wxRegion::Subtract( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
242 {
243 wxRegion reg( x, y, width, height );
244 return Subtract( reg );
245 }
246
247 bool wxRegion::Subtract( const wxRect& rect )
248 {
249 wxRegion reg( rect );
250 return Subtract( reg );
251 }
252
253 bool wxRegion::Subtract( const wxRegion& region )
254 {
255 if (region.IsNull())
256 return false;
257
258 if (!m_refData)
259 {
260 // subtracting from an invalid region doesn't make sense
261 return false;
262 }
263
264 AllocExclusive();
265
266 gdk_region_subtract( M_REGIONDATA->m_region, region.GetRegion() );
267
268 return true;
269 }
270
271 bool wxRegion::Xor( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
272 {
273 wxRegion reg( x, y, width, height );
274 return Xor( reg );
275 }
276
277 bool wxRegion::Xor( const wxRect& rect )
278 {
279 wxRegion reg( rect );
280 return Xor( reg );
281 }
282
283 bool wxRegion::Xor( const wxRegion& region )
284 {
285 if (region.IsNull())
286 return false;
287
288 if (!m_refData)
289 {
290 return false;
291 }
292
293 AllocExclusive();
294
295 gdk_region_xor( M_REGIONDATA->m_region, region.GetRegion() );
296
297 return true;
298 }
299
300 bool wxRegion::Offset( wxCoord x, wxCoord y )
301 {
302 if (!m_refData)
303 return false;
304
305 AllocExclusive();
306
307 gdk_region_offset( M_REGIONDATA->m_region, x, y );
308
309 return true;
310 }
311
312 // ----------------------------------------------------------------------------
313 // wxRegion tests
314 // ----------------------------------------------------------------------------
315
316 void wxRegion::GetBox( wxCoord &x, wxCoord &y, wxCoord &w, wxCoord &h ) const
317 {
318 if ( m_refData )
319 {
320 GdkRectangle rect;
321 gdk_region_get_clipbox( M_REGIONDATA->m_region, &rect );
322 x = rect.x;
323 y = rect.y;
324 w = rect.width;
325 h = rect.height;
326 }
327 else
328 {
329 x = 0;
330 y = 0;
331 w = -1;
332 h = -1;
333 }
334 }
335
336 wxRect wxRegion::GetBox() const
337 {
338 wxCoord x, y, w, h;
339 GetBox( x, y, w, h );
340 return wxRect( x, y, w, h );
341 }
342
343 bool wxRegion::Empty() const
344 {
345 if (!m_refData)
346 return true;
347
348 return gdk_region_empty( M_REGIONDATA->m_region );
349 }
350
351 wxRegionContain wxRegion::Contains( wxCoord x, wxCoord y ) const
352 {
353 if (!m_refData)
354 return wxOutRegion;
355
356 if (gdk_region_point_in( M_REGIONDATA->m_region, x, y ))
357 return wxInRegion;
358 else
359 return wxOutRegion;
360 }
361
362 wxRegionContain wxRegion::Contains( wxCoord x, wxCoord y, wxCoord w, wxCoord h ) const
363 {
364 if (!m_refData)
365 return wxOutRegion;
366
367 GdkRectangle rect;
368 rect.x = x;
369 rect.y = y;
370 rect.width = w;
371 rect.height = h;
372 GdkOverlapType res = gdk_region_rect_in( M_REGIONDATA->m_region, &rect );
373 switch (res)
374 {
375 case GDK_OVERLAP_RECTANGLE_IN: return wxInRegion;
376 case GDK_OVERLAP_RECTANGLE_OUT: return wxOutRegion;
377 case GDK_OVERLAP_RECTANGLE_PART: return wxPartRegion;
378 }
379 return wxOutRegion;
380 }
381
382 wxRegionContain wxRegion::Contains(const wxPoint& pt) const
383 {
384 return Contains( pt.x, pt.y );
385 }
386
387 wxRegionContain wxRegion::Contains(const wxRect& rect) const
388 {
389 return Contains( rect.x, rect.y, rect.width, rect.height );
390 }
391
392 GdkRegion *wxRegion::GetRegion() const
393 {
394 if (!m_refData)
395 return (GdkRegion*) NULL;
396
397 return M_REGIONDATA->m_region;
398 }
399
400 // ----------------------------------------------------------------------------
401 // wxRegionIterator
402 // ----------------------------------------------------------------------------
403
404 class wxRIRefData: public wxObjectRefData
405 {
406 public:
407 wxRIRefData() { Init(); }
408 virtual ~wxRIRefData();
409
410 void CreateRects( const wxRegion& r );
411
412 void Init() { m_rects = NULL; m_numRects = 0; }
413
414 wxRect *m_rects;
415 size_t m_numRects;
416 };
417
418 wxRIRefData::~wxRIRefData()
419 {
420 delete [] m_rects;
421 }
422
423 void wxRIRefData::CreateRects( const wxRegion& region )
424 {
425 delete [] m_rects;
426
427 Init();
428
429 GdkRegion *gdkregion = region.GetRegion();
430 if (!gdkregion)
431 return;
432
433 GdkRectangle *gdkrects = NULL;
434 gint numRects = 0;
435 gdk_region_get_rectangles( gdkregion, &gdkrects, &numRects );
436
437 m_numRects = numRects;
438 if (numRects)
439 {
440 m_rects = new wxRect[m_numRects];
441 for (size_t i=0; i < m_numRects; ++i)
442 {
443 GdkRectangle &gr = gdkrects[i];
444 wxRect &wr = m_rects[i];
445 wr.x = gr.x;
446 wr.y = gr.y;
447 wr.width = gr.width;
448 wr.height = gr.height;
449 }
450 }
451 g_free( gdkrects );
452 }
453
454 wxRegionIterator::wxRegionIterator()
455 {
456 m_refData = new wxRIRefData();
457 Reset();
458 }
459
460 wxRegionIterator::wxRegionIterator( const wxRegion& region )
461 {
462 m_refData = new wxRIRefData();
463 Reset(region);
464 }
465
466 void wxRegionIterator::Reset( const wxRegion& region )
467 {
468 m_region = region;
469 ((wxRIRefData*)m_refData)->CreateRects(region);
470 Reset();
471 }
472
473 bool wxRegionIterator::HaveRects() const
474 {
475 return m_current < ((wxRIRefData*)m_refData)->m_numRects;
476 }
477
478 wxRegionIterator& wxRegionIterator::operator ++ ()
479 {
480 if (HaveRects())
481 ++m_current;
482
483 return *this;
484 }
485
486 wxRegionIterator wxRegionIterator::operator ++ (int)
487 {
488 wxRegionIterator tmp = *this;
489 if (HaveRects())
490 ++m_current;
491
492 return tmp;
493 }
494
495 wxCoord wxRegionIterator::GetX() const
496 {
497 wxCHECK_MSG( HaveRects(), 0, _T("invalid wxRegionIterator") );
498
499 return ((wxRIRefData*)m_refData)->m_rects[m_current].x;
500 }
501
502 wxCoord wxRegionIterator::GetY() const
503 {
504 wxCHECK_MSG( HaveRects(), 0, _T("invalid wxRegionIterator") );
505
506 return ((wxRIRefData*)m_refData)->m_rects[m_current].y;
507 }
508
509 wxCoord wxRegionIterator::GetW() const
510 {
511 wxCHECK_MSG( HaveRects(), 0, _T("invalid wxRegionIterator") );
512
513 return ((wxRIRefData*)m_refData)->m_rects[m_current].width;
514 }
515
516 wxCoord wxRegionIterator::GetH() const
517 {
518 wxCHECK_MSG( HaveRects(), 0, _T("invalid wxRegionIterator") );
519
520 return ((wxRIRefData*)m_refData)->m_rects[m_current].height;
521 }
522
523 wxRect wxRegionIterator::GetRect() const
524 {
525 wxRect r;
526 if( HaveRects() )
527 r = ((wxRIRefData*)m_refData)->m_rects[m_current];
528
529 return r;
530 }