]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/region.cpp
patch 1352744
[wxWidgets.git] / src / gtk / region.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: 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 #include "wx/log.h"
24 #include "wx/gtk/private.h"
25
26 #ifndef __WXGTK20__
27
28 // ----------------------------------------------------------------------------
29 // wxGdkRegion: creates a new region in ctor and destroys in dtor
30 // ----------------------------------------------------------------------------
31
32 class wxGdkRegion
33 {
34 public:
35 wxGdkRegion() { m_region = gdk_region_new(); }
36 ~wxGdkRegion() { gdk_region_destroy(m_region); }
37
38 operator GdkRegion *() const { return m_region; }
39
40 private:
41 GdkRegion *m_region;
42 };
43
44 #endif // __WXGTK20__
45
46 // ----------------------------------------------------------------------------
47 // wxRegionRefData: private class containing the information about the region
48 // ----------------------------------------------------------------------------
49
50 class wxRegionRefData : public wxObjectRefData
51 {
52 public:
53 wxRegionRefData()
54 {
55 m_region = NULL;
56 }
57
58 wxRegionRefData(const wxRegionRefData& refData)
59 : wxObjectRefData()
60 {
61 #ifdef __WXGTK20__
62 m_region = gdk_region_copy(refData.m_region);
63 #else
64 m_region = gdk_regions_union(wxGdkRegion(), refData.m_region);
65 #endif
66 }
67
68 ~wxRegionRefData()
69 {
70 if (m_region)
71 gdk_region_destroy( m_region );
72 }
73
74 GdkRegion *m_region;
75 };
76
77 // ----------------------------------------------------------------------------
78 // macros
79 // ----------------------------------------------------------------------------
80
81 #define M_REGIONDATA ((wxRegionRefData *)m_refData)
82 #define M_REGIONDATA_OF(rgn) ((wxRegionRefData *)(rgn.m_refData))
83
84 IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject)
85 IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator,wxObject)
86
87 // ----------------------------------------------------------------------------
88 // wxRegion construction
89 // ----------------------------------------------------------------------------
90
91 #define M_REGIONDATA ((wxRegionRefData *)m_refData)
92
93 void wxRegion::InitRect(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
94 {
95 GdkRectangle rect;
96 rect.x = x;
97 rect.y = y;
98 rect.width = w;
99 rect.height = h;
100
101 m_refData = new wxRegionRefData();
102
103 #ifdef __WXGTK20__
104 M_REGIONDATA->m_region = gdk_region_rectangle( &rect );
105 #else
106 M_REGIONDATA->m_region = gdk_region_union_with_rect( wxGdkRegion(), &rect );
107 #endif
108 }
109
110 wxRegion::wxRegion( GdkRegion *region )
111 {
112 m_refData = new wxRegionRefData();
113 #ifdef __WXGTK20__
114 M_REGIONDATA->m_region = gdk_region_copy( region );
115 #else
116 M_REGIONDATA->m_region = gdk_regions_union(wxGdkRegion(), region);
117 #endif
118 }
119
120 wxRegion::wxRegion( size_t n, const wxPoint *points, int fillStyle )
121 {
122 GdkPoint *gdkpoints = new GdkPoint[n];
123 for ( size_t i = 0 ; i < n ; i++ )
124 {
125 gdkpoints[i].x = points[i].x;
126 gdkpoints[i].y = points[i].y;
127 }
128
129 m_refData = new wxRegionRefData();
130
131 GdkRegion* reg = gdk_region_polygon
132 (
133 gdkpoints,
134 n,
135 fillStyle == wxWINDING_RULE ? GDK_WINDING_RULE
136 : GDK_EVEN_ODD_RULE
137 );
138
139 M_REGIONDATA->m_region = reg;
140
141 delete [] gdkpoints;
142 }
143
144 wxRegion::~wxRegion()
145 {
146 // m_refData unrefed in ~wxObject
147 }
148
149 wxObjectRefData *wxRegion::CreateRefData() const
150 {
151 return new wxRegionRefData;
152 }
153
154 wxObjectRefData *wxRegion::CloneRefData(const wxObjectRefData *data) const
155 {
156 return new wxRegionRefData(*(wxRegionRefData *)data);
157 }
158
159 // ----------------------------------------------------------------------------
160 // wxRegion comparison
161 // ----------------------------------------------------------------------------
162
163 bool wxRegion::operator==( const wxRegion& region ) const
164 {
165 if (m_refData == region.m_refData) return TRUE;
166
167 if (!m_refData || !region.m_refData) return FALSE;
168
169 // compare the regions themselves, not the pointers to ref data!
170 return gdk_region_equal(M_REGIONDATA->m_region,
171 M_REGIONDATA_OF(region)->m_region);
172 }
173
174 // ----------------------------------------------------------------------------
175 // wxRegion operations
176 // ----------------------------------------------------------------------------
177
178 void wxRegion::Clear()
179 {
180 UnRef();
181 }
182
183 bool wxRegion::Union( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
184 {
185 // workaround for a strange GTK/X11 bug: taking union with an empty
186 // rectangle results in an empty region which is definitely not what we
187 // want
188 if ( !width || !height )
189 return TRUE;
190
191 if ( !m_refData )
192 {
193 InitRect(x, y, width, height);
194 }
195 else
196 {
197 AllocExclusive();
198
199 GdkRectangle rect;
200 rect.x = x;
201 rect.y = y;
202 rect.width = width;
203 rect.height = height;
204
205 #ifdef __WXGTK20__
206 gdk_region_union_with_rect( M_REGIONDATA->m_region, &rect );
207 #else
208 GdkRegion *reg = gdk_region_union_with_rect( M_REGIONDATA->m_region, &rect );
209 gdk_region_destroy( M_REGIONDATA->m_region );
210 M_REGIONDATA->m_region = reg;
211 #endif
212 }
213
214 return TRUE;
215 }
216
217 bool wxRegion::Union( const wxRect& rect )
218 {
219 return Union( rect.x, rect.y, rect.width, rect.height );
220 }
221
222 bool wxRegion::Union( const wxRegion& region )
223 {
224 if (region.IsNull())
225 return FALSE;
226
227 if (!m_refData)
228 {
229 m_refData = new wxRegionRefData();
230 M_REGIONDATA->m_region = gdk_region_new();
231 }
232 else
233 {
234 AllocExclusive();
235 }
236
237 #ifdef __WXGTK20__
238 gdk_region_union( M_REGIONDATA->m_region, region.GetRegion() );
239 #else
240 GdkRegion *reg = gdk_regions_union( M_REGIONDATA->m_region, region.GetRegion() );
241 gdk_region_destroy( M_REGIONDATA->m_region );
242 M_REGIONDATA->m_region = reg;
243 #endif
244
245 return TRUE;
246 }
247
248 bool wxRegion::Intersect( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
249 {
250 wxRegion reg( x, y, width, height );
251
252 return Intersect( reg );
253 }
254
255 bool wxRegion::Intersect( const wxRect& rect )
256 {
257 wxRegion reg( rect );
258
259 return Intersect( reg );
260 }
261
262 bool wxRegion::Intersect( const wxRegion& region )
263 {
264 if (region.IsNull())
265 return FALSE;
266
267 if (!m_refData)
268 {
269 // intersecting with invalid region doesn't make sense
270 return FALSE;
271 }
272
273 AllocExclusive();
274
275 #ifdef __WXGTK20__
276 gdk_region_intersect( M_REGIONDATA->m_region, region.GetRegion() );
277 #else
278 GdkRegion *reg = gdk_regions_intersect( M_REGIONDATA->m_region, region.GetRegion() );
279 gdk_region_destroy( M_REGIONDATA->m_region );
280 M_REGIONDATA->m_region = reg;
281 #endif
282
283 return TRUE;
284 }
285
286 bool wxRegion::Subtract( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
287 {
288 wxRegion reg( x, y, width, height );
289 return Subtract( reg );
290 }
291
292 bool wxRegion::Subtract( const wxRect& rect )
293 {
294 wxRegion reg( rect );
295 return Subtract( reg );
296 }
297
298 bool wxRegion::Subtract( const wxRegion& region )
299 {
300 if (region.IsNull())
301 return FALSE;
302
303 if (!m_refData)
304 {
305 // subtracting from an invalid region doesn't make sense
306 return FALSE;
307 }
308
309 AllocExclusive();
310
311 #ifdef __WXGTK20__
312 gdk_region_subtract( M_REGIONDATA->m_region, region.GetRegion() );
313 #else
314 GdkRegion *reg = gdk_regions_subtract( M_REGIONDATA->m_region, region.GetRegion() );
315 gdk_region_destroy( M_REGIONDATA->m_region );
316 M_REGIONDATA->m_region = reg;
317 #endif
318
319 return TRUE;
320 }
321
322 bool wxRegion::Xor( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
323 {
324 wxRegion reg( x, y, width, height );
325 return Xor( reg );
326 }
327
328 bool wxRegion::Xor( const wxRect& rect )
329 {
330 wxRegion reg( rect );
331 return Xor( reg );
332 }
333
334 bool wxRegion::Xor( const wxRegion& region )
335 {
336 if (region.IsNull())
337 return FALSE;
338
339 if (!m_refData)
340 {
341 return FALSE;
342 }
343
344 AllocExclusive();
345
346 #ifdef __WXGTK20__
347 gdk_region_xor( M_REGIONDATA->m_region, region.GetRegion() );
348 #else
349 GdkRegion *reg = gdk_regions_xor( M_REGIONDATA->m_region, region.GetRegion() );
350 gdk_region_destroy( M_REGIONDATA->m_region );
351 M_REGIONDATA->m_region = reg;
352 #endif
353
354 return TRUE;
355 }
356
357 bool wxRegion::Offset( wxCoord x, wxCoord y )
358 {
359 if (!m_refData)
360 return FALSE;
361
362 AllocExclusive();
363
364 gdk_region_offset( M_REGIONDATA->m_region, x, y );
365
366 return TRUE;
367 }
368
369 // ----------------------------------------------------------------------------
370 // wxRegion tests
371 // ----------------------------------------------------------------------------
372
373 void wxRegion::GetBox( wxCoord &x, wxCoord &y, wxCoord &w, wxCoord &h ) const
374 {
375 if ( m_refData )
376 {
377 GdkRectangle rect;
378 gdk_region_get_clipbox( M_REGIONDATA->m_region, &rect );
379 x = rect.x;
380 y = rect.y;
381 w = rect.width;
382 h = rect.height;
383 }
384 else
385 {
386 x = 0;
387 y = 0;
388 w = -1;
389 h = -1;
390 }
391 }
392
393 wxRect wxRegion::GetBox() const
394 {
395 wxCoord x, y, w, h;
396 GetBox( x, y, w, h );
397 return wxRect( x, y, w, h );
398 }
399
400 bool wxRegion::Empty() const
401 {
402 if (!m_refData)
403 return TRUE;
404
405 return gdk_region_empty( M_REGIONDATA->m_region );
406 }
407
408 wxRegionContain wxRegion::Contains( wxCoord x, wxCoord y ) const
409 {
410 if (!m_refData)
411 return wxOutRegion;
412
413 if (gdk_region_point_in( M_REGIONDATA->m_region, x, y ))
414 return wxInRegion;
415 else
416 return wxOutRegion;
417 }
418
419 wxRegionContain wxRegion::Contains( wxCoord x, wxCoord y, wxCoord w, wxCoord h ) const
420 {
421 if (!m_refData)
422 return wxOutRegion;
423
424 GdkRectangle rect;
425 rect.x = x;
426 rect.y = y;
427 rect.width = w;
428 rect.height = h;
429 GdkOverlapType res = gdk_region_rect_in( M_REGIONDATA->m_region, &rect );
430 switch (res)
431 {
432 case GDK_OVERLAP_RECTANGLE_IN: return wxInRegion;
433 case GDK_OVERLAP_RECTANGLE_OUT: return wxOutRegion;
434 case GDK_OVERLAP_RECTANGLE_PART: return wxPartRegion;
435 }
436 return wxOutRegion;
437 }
438
439 wxRegionContain wxRegion::Contains(const wxPoint& pt) const
440 {
441 return Contains( pt.x, pt.y );
442 }
443
444 wxRegionContain wxRegion::Contains(const wxRect& rect) const
445 {
446 return Contains( rect.x, rect.y, rect.width, rect.height );
447 }
448
449 GdkRegion *wxRegion::GetRegion() const
450 {
451 if (!m_refData)
452 return (GdkRegion*) NULL;
453
454 return M_REGIONDATA->m_region;
455 }
456
457 // ----------------------------------------------------------------------------
458 // wxRegionIterator
459 // ----------------------------------------------------------------------------
460
461 #ifndef __WXGTK20__
462
463 // the following structures must match the private structures
464 // in X11 region code ( xc/lib/X11/region.h )
465
466 // this makes the Region type transparent
467 // and we have access to the region rectangles
468
469 #include <gdk/gdkprivate.h>
470
471 struct _XBox {
472 short x1, x2, y1, y2;
473 };
474
475 struct _XRegion {
476 long size , numRects;
477 _XBox *rects, extents;
478 };
479
480 #endif // GTK+ 1.x
481
482 class wxRIRefData: public wxObjectRefData
483 {
484 public:
485 wxRIRefData() { Init(); }
486 virtual ~wxRIRefData();
487
488 void CreateRects( const wxRegion& r );
489
490 void Init() { m_rects = NULL; m_numRects = 0; }
491
492 wxRect *m_rects;
493 size_t m_numRects;
494 };
495
496 wxRIRefData::~wxRIRefData()
497 {
498 delete [] m_rects;
499 }
500
501 void wxRIRefData::CreateRects( const wxRegion& region )
502 {
503 delete [] m_rects;
504
505 Init();
506
507 GdkRegion *gdkregion = region.GetRegion();
508 if (!gdkregion)
509 return;
510
511 #ifdef __WXGTK20__
512 GdkRectangle *gdkrects = NULL;
513 gint numRects = 0;
514 gdk_region_get_rectangles( gdkregion, &gdkrects, &numRects );
515
516 m_numRects = numRects;
517 if (numRects)
518 {
519 m_rects = new wxRect[m_numRects];
520 for (size_t i=0; i < m_numRects; ++i)
521 {
522 GdkRectangle &gr = gdkrects[i];
523 wxRect &wr = m_rects[i];
524 wr.x = gr.x;
525 wr.y = gr.y;
526 wr.width = gr.width;
527 wr.height = gr.height;
528 }
529 }
530 g_free( gdkrects );
531 #else // GTK+ 1.x
532 Region r = ((GdkRegionPrivate *)gdkregion)->xregion;
533 if (r)
534 {
535 m_numRects = r->numRects;
536 if (m_numRects)
537 {
538 m_rects = new wxRect[m_numRects];
539 for (size_t i=0; i < m_numRects; ++i)
540 {
541 _XBox &xr = r->rects[i];
542 wxRect &wr = m_rects[i];
543 wr.x = xr.x1;
544 wr.y = xr.y1;
545 wr.width = xr.x2-xr.x1;
546 wr.height = xr.y2-xr.y1;
547 }
548 }
549 }
550 #endif // GTK+ 2.0/1.x
551 }
552
553 wxRegionIterator::wxRegionIterator()
554 {
555 m_refData = new wxRIRefData();
556 Reset();
557 }
558
559 wxRegionIterator::wxRegionIterator( const wxRegion& region )
560 {
561 m_refData = new wxRIRefData();
562 Reset(region);
563 }
564
565 void wxRegionIterator::Reset( const wxRegion& region )
566 {
567 m_region = region;
568 ((wxRIRefData*)m_refData)->CreateRects(region);
569 Reset();
570 }
571
572 bool wxRegionIterator::HaveRects() const
573 {
574 return m_current < ((wxRIRefData*)m_refData)->m_numRects;
575 }
576
577 wxRegionIterator& wxRegionIterator::operator ++ ()
578 {
579 if (HaveRects())
580 ++m_current;
581
582 return *this;
583 }
584
585 wxRegionIterator wxRegionIterator::operator ++ (int)
586 {
587 wxRegionIterator tmp = *this;
588 if (HaveRects())
589 ++m_current;
590
591 return tmp;
592 }
593
594 wxCoord wxRegionIterator::GetX() const
595 {
596 wxCHECK_MSG( HaveRects(), 0, _T("invalid wxRegionIterator") );
597
598 return ((wxRIRefData*)m_refData)->m_rects[m_current].x;
599 }
600
601 wxCoord wxRegionIterator::GetY() const
602 {
603 wxCHECK_MSG( HaveRects(), 0, _T("invalid wxRegionIterator") );
604
605 return ((wxRIRefData*)m_refData)->m_rects[m_current].y;
606 }
607
608 wxCoord wxRegionIterator::GetW() const
609 {
610 wxCHECK_MSG( HaveRects(), 0, _T("invalid wxRegionIterator") );
611
612 return ((wxRIRefData*)m_refData)->m_rects[m_current].width;
613 }
614
615 wxCoord wxRegionIterator::GetH() const
616 {
617 wxCHECK_MSG( HaveRects(), 0, _T("invalid wxRegionIterator") );
618
619 return ((wxRIRefData*)m_refData)->m_rects[m_current].height;
620 }
621
622 wxRect wxRegionIterator::GetRect() const
623 {
624 wxRect r;
625 if( HaveRects() )
626 r = ((wxRIRefData*)m_refData)->m_rects[m_current];
627
628 return r;
629 }
630