]> git.saurik.com Git - wxWidgets.git/blob - src/gtk1/region.cpp
2c4be00d6d7d34e2d1d7d0fc2967350d6f239b6a
[wxWidgets.git] / src / gtk1 / region.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/region.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Modified: VZ at 05.10.00: use Unshare(), comparison fixed
6 // Id: $Id$
7 // Copyright: (c) 1998 Robert Roebling
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 #ifdef __GNUG__
16 #pragma implementation "region.h"
17 #endif
18
19 // ----------------------------------------------------------------------------
20 // headers
21 // ----------------------------------------------------------------------------
22
23 #include "wx/region.h"
24
25 #include <gdk/gdk.h>
26 #include <gtk/gtk.h>
27
28 // Unfortunately the new way of implementing the region iterator
29 // doesn't work with GTK+ 2.0 or above (can't access a Region in
30 // GdkPrivateRegion)
31 #ifdef __WXGTK20__
32 #define OLDCODE 1
33 #else
34 #define OLDCODE 0
35 #endif
36
37 #include "wx/log.h"
38
39 // ----------------------------------------------------------------------------
40 // wxRegionRefData: private class containing the information about the region
41 // ----------------------------------------------------------------------------
42
43 class wxRegionRefData : public wxObjectRefData
44 {
45 public:
46 wxRegionRefData();
47 wxRegionRefData(const wxRegionRefData& refData);
48 virtual ~wxRegionRefData();
49
50 GdkRegion *m_region;
51 #if OLDCODE
52 wxList m_rects;
53 #endif
54 };
55
56 // ----------------------------------------------------------------------------
57 // macros
58 // ----------------------------------------------------------------------------
59
60 #define M_REGIONDATA ((wxRegionRefData *)m_refData)
61 #define M_REGIONDATA_OF(rgn) ((wxRegionRefData *)(rgn.m_refData))
62
63 IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject);
64 IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator,wxObject);
65
66 // ============================================================================
67 // implementation
68 // ============================================================================
69
70 // ----------------------------------------------------------------------------
71 // wxRegionRefData
72 // ----------------------------------------------------------------------------
73
74 wxRegionRefData::wxRegionRefData()
75 {
76 m_region = (GdkRegion *) NULL;
77 }
78
79 wxRegionRefData::wxRegionRefData(const wxRegionRefData& refData)
80 {
81 #ifdef __WXGTK20__
82 m_region = gdk_region_copy(refData.m_region);
83 #else
84 m_region = gdk_region_new();
85 GdkRegion *regCopy = gdk_regions_union(m_region, refData.m_region);
86 gdk_region_destroy(m_region);
87 m_region = regCopy;
88 #endif
89
90 wxNode *node = refData.m_rects.First();
91 while (node)
92 {
93 wxRect *r = (wxRect*)node->Data();
94 m_rects.Append( (wxObject*) new wxRect(*r) );
95 node = node->Next();
96 }
97 }
98
99 wxRegionRefData::~wxRegionRefData()
100 {
101 if (m_region) gdk_region_destroy( m_region );
102
103 #if OLDCODE
104 wxNode *node = m_rects.First();
105 while (node)
106 {
107 wxRect *r = (wxRect*)node->Data();
108 delete r;
109 node = node->Next();
110 }
111 #endif
112 }
113
114 // ----------------------------------------------------------------------------
115 // wxRegion construction
116 // ----------------------------------------------------------------------------
117
118 #define M_REGIONDATA ((wxRegionRefData *)m_refData)
119
120 IMPLEMENT_DYNAMIC_CLASS(wxRegion,wxGDIObject);
121
122 wxRegion::wxRegion()
123 {
124 }
125
126 wxRegion::wxRegion( wxCoord x, wxCoord y, wxCoord w, wxCoord h )
127 {
128 m_refData = new wxRegionRefData();
129 GdkRegion *reg = gdk_region_new();
130 GdkRectangle rect;
131 rect.x = x;
132 rect.y = y;
133 rect.width = w;
134 rect.height = h;
135 #ifdef __WXGTK20__
136 gdk_region_union_with_rect( reg, &rect );
137 M_REGIONDATA->m_region = reg;
138 #else
139 M_REGIONDATA->m_region = gdk_region_union_with_rect( reg, &rect );
140 gdk_region_destroy( reg );
141 #endif
142 #if OLDCODE
143 M_REGIONDATA->m_rects.Append( (wxObject*) new wxRect(x,y,w,h) );
144 #endif
145 }
146
147 wxRegion::wxRegion( const wxPoint& topLeft, const wxPoint& bottomRight )
148 {
149 m_refData = new wxRegionRefData();
150 GdkRegion *reg = gdk_region_new();
151 GdkRectangle rect;
152 rect.x = topLeft.x;
153 rect.y = topLeft.y;
154 rect.width = bottomRight.x - rect.x;
155 rect.height = bottomRight.y - rect.y;
156 #ifdef __WXGTK20__
157 gdk_region_union_with_rect( reg, &rect );
158 M_REGIONDATA->m_region = reg;
159 #else
160 M_REGIONDATA->m_region = gdk_region_union_with_rect( reg, &rect );
161 gdk_region_destroy( reg );
162 #endif
163 #if OLDCODE
164 M_REGIONDATA->m_rects.Append( (wxObject*) new wxRect(topLeft,bottomRight) );
165 #endif
166 }
167
168 wxRegion::wxRegion( const wxRect& rect )
169 {
170 m_refData = new wxRegionRefData();
171 GdkRegion *reg = gdk_region_new();
172 GdkRectangle g_rect;
173 g_rect.x = rect.x;
174 g_rect.y = rect.y;
175 g_rect.width = rect.width;
176 g_rect.height = rect.height;
177 #ifdef __WXGTK20__
178 gdk_region_union_with_rect( reg, &g_rect );
179 M_REGIONDATA->m_region = reg;
180 #else
181 M_REGIONDATA->m_region = gdk_region_union_with_rect( reg, &g_rect );
182 gdk_region_destroy( reg );
183 #endif
184 #if OLDCODE
185 M_REGIONDATA->m_rects.Append( (wxObject*) new wxRect(rect.x,rect.y,rect.width,rect.height) );
186 #endif
187 }
188
189 wxRegion::~wxRegion()
190 {
191 }
192
193 bool wxRegion::operator==( const wxRegion& region )
194 {
195 // VZ: compare the regions themselves, not the pointers to ref data!
196 return gdk_region_equal(M_REGIONDATA->m_region,
197 M_REGIONDATA_OF(region)->m_region);
198 }
199
200 bool wxRegion::operator != ( const wxRegion& region )
201 {
202 return !(*this == region);
203 }
204
205 void wxRegion::Unshare()
206 {
207 if ( !m_refData )
208 {
209 m_refData = new wxRegionRefData;
210 M_REGIONDATA->m_region = gdk_region_new();
211 }
212 else if ( m_refData->GetRefCount() > 1 )
213 {
214 wxRegionRefData *refData = new wxRegionRefData(*M_REGIONDATA);
215 UnRef();
216 m_refData = refData;
217 }
218 //else: we're not shared
219 }
220
221 // ----------------------------------------------------------------------------
222 // wxRegion operations
223 // ----------------------------------------------------------------------------
224
225 void wxRegion::Clear()
226 {
227 UnRef();
228 }
229
230 bool wxRegion::Union( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
231 {
232 GdkRectangle rect;
233 rect.x = x;
234 rect.y = y;
235 rect.width = width;
236 rect.height = height;
237 if (!m_refData)
238 {
239 m_refData = new wxRegionRefData();
240 GdkRegion *reg = gdk_region_new();
241 #ifdef __WXGTK20__
242 gdk_region_union_with_rect( reg, &rect );
243 M_REGIONDATA->m_region = reg;
244 #else
245 M_REGIONDATA->m_region = gdk_region_union_with_rect( reg, &rect );
246 gdk_region_destroy( reg );
247 #endif
248 }
249 else
250 {
251 Unshare();
252
253 #ifdef __WXGTK20__
254 gdk_region_union_with_rect( M_REGIONDATA->m_region, &rect );
255 #else
256 GdkRegion *reg = gdk_region_union_with_rect( M_REGIONDATA->m_region, &rect );
257 gdk_region_destroy( M_REGIONDATA->m_region );
258 M_REGIONDATA->m_region = reg;
259 #endif
260 }
261
262 #if OLDCODE
263 M_REGIONDATA->m_rects.Append( (wxObject*) new wxRect(x,y,width,height) );
264 #endif
265
266 return TRUE;
267 }
268
269 bool wxRegion::Union( const wxRect& rect )
270 {
271 return Union( rect.x, rect.y, rect.width, rect.height );
272 }
273
274 bool wxRegion::Union( const wxRegion& region )
275 {
276 if (region.IsNull())
277 return FALSE;
278
279 Unshare();
280
281 #ifdef __WXGTK20__
282 gdk_region_union( M_REGIONDATA->m_region, region.GetRegion() );
283 #else
284 GdkRegion *reg = gdk_regions_union( M_REGIONDATA->m_region, region.GetRegion() );
285 gdk_region_destroy( M_REGIONDATA->m_region );
286 M_REGIONDATA->m_region = reg;
287 #endif
288
289 #if OLDCODE
290 wxNode *node = region.GetRectList()->First();
291 while (node)
292 {
293 wxRect *r = (wxRect*)node->Data();
294 M_REGIONDATA->m_rects.Append( (wxObject*) new wxRect(r->x,r->y,r->width,r->height) );
295 node = node->Next();
296 }
297 #endif
298
299 return TRUE;
300 }
301
302 bool wxRegion::Intersect( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
303 {
304 wxRegion reg( x, y, width, height );
305
306 return Intersect( reg );
307 }
308
309 bool wxRegion::Intersect( const wxRect& rect )
310 {
311 wxRegion reg( rect );
312 return Intersect( reg );
313 }
314
315 // this helper function just computes the region intersection without updating
316 // the list of rectangles each region maintaints: this allows us to call it
317 // from Intersect() itself without going into infinite recursion as we would
318 // if we called Intersect() itself recursively
319 bool wxRegion::IntersectRegionOnly(const wxRegion& region)
320 {
321 Unshare();
322
323 #ifdef __WXGTK20__
324 gdk_region_intersect( M_REGIONDATA->m_region, region.GetRegion() );
325 #else
326 GdkRegion *reg = gdk_regions_intersect( M_REGIONDATA->m_region, region.GetRegion() );
327 gdk_region_destroy( M_REGIONDATA->m_region );
328 M_REGIONDATA->m_region = reg;
329 #endif
330
331 return TRUE;
332 }
333
334 bool wxRegion::Intersect( const wxRegion& region )
335 {
336 if (region.IsNull())
337 return FALSE;
338
339 if (!m_refData)
340 {
341 m_refData = new wxRegionRefData();
342 M_REGIONDATA->m_region = gdk_region_new();
343 return TRUE;
344 }
345
346 if ( !IntersectRegionOnly(region) )
347 {
348 GetRectList()->Clear();
349
350 return FALSE;
351 }
352
353 // we need to update the rect list as well
354 wxList& list = *GetRectList();
355 wxNode *node = list.First();
356 while (node)
357 {
358 wxRect *r = (wxRect*)node->Data();
359
360 wxRegion regCopy = region;
361 if ( regCopy.IntersectRegionOnly(*r) )
362 {
363 // replace the node with the intersection
364 *r = regCopy.GetBox();
365 }
366 else
367 {
368 // TODO remove the rect from the list
369 r->width = 0;
370 r->height = 0;
371 }
372
373 node = node->Next();
374 }
375
376 return TRUE;
377 }
378
379 bool wxRegion::Subtract( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
380 {
381 wxRegion reg( x, y, width, height );
382 return Subtract( reg );
383 }
384
385 bool wxRegion::Subtract( const wxRect& rect )
386 {
387 wxRegion reg( rect );
388 return Subtract( reg );
389 }
390
391 bool wxRegion::Subtract( const wxRegion& region )
392 {
393 if (region.IsNull())
394 return FALSE;
395
396 if (!m_refData)
397 {
398 m_refData = new wxRegionRefData();
399 M_REGIONDATA->m_region = gdk_region_new();
400 }
401
402 Unshare();
403
404 #ifdef __WXGTK20__
405 gdk_region_subtract( M_REGIONDATA->m_region, region.GetRegion() );
406 #else
407 GdkRegion *reg = gdk_regions_subtract( M_REGIONDATA->m_region, region.GetRegion() );
408 gdk_region_destroy( M_REGIONDATA->m_region );
409 M_REGIONDATA->m_region = reg;
410 #endif
411
412 return TRUE;
413 }
414
415 bool wxRegion::Xor( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
416 {
417 wxRegion reg( x, y, width, height );
418 return Xor( reg );
419 }
420
421 bool wxRegion::Xor( const wxRect& rect )
422 {
423 wxRegion reg( rect );
424 return Xor( reg );
425 }
426
427 bool wxRegion::Xor( const wxRegion& region )
428 {
429 if (region.IsNull())
430 return FALSE;
431
432 if (!m_refData)
433 {
434 m_refData = new wxRegionRefData();
435 M_REGIONDATA->m_region = gdk_region_new();
436 }
437 else
438 {
439 Unshare();
440 }
441
442 #ifdef __WXGTK20__
443 gdk_region_xor( M_REGIONDATA->m_region, region.GetRegion() );
444 #else
445 GdkRegion *reg = gdk_regions_xor( M_REGIONDATA->m_region, region.GetRegion() );
446 gdk_region_destroy( M_REGIONDATA->m_region );
447 M_REGIONDATA->m_region = reg;
448 #endif
449
450 #if OLDCODE
451 wxNode *node = region.GetRectList()->First();
452 while (node)
453 {
454 wxRect *r = (wxRect*)node->Data();
455 M_REGIONDATA->m_rects.Append( (wxObject*) new wxRect(r->x,r->y,r->width,r->height) );
456 node = node->Next();
457 }
458 #endif
459
460 return TRUE;
461 }
462
463 // ----------------------------------------------------------------------------
464 // wxRegion tests
465 // ----------------------------------------------------------------------------
466
467 void wxRegion::GetBox( wxCoord &x, wxCoord &y, wxCoord &w, wxCoord &h ) const
468 {
469 if ( m_refData )
470 {
471 GdkRectangle rect;
472 gdk_region_get_clipbox( M_REGIONDATA->m_region, &rect );
473 x = rect.x;
474 y = rect.y;
475 w = rect.width;
476 h = rect.height;
477 }
478 else
479 {
480 x = 0;
481 y = 0;
482 w = -1;
483 h = -1;
484 }
485 }
486
487 wxRect wxRegion::GetBox() const
488 {
489 wxCoord x, y, w, h;
490 GetBox( x, y, w, h );
491 return wxRect( x, y, w, h );
492 }
493
494 bool wxRegion::Empty() const
495 {
496 if (!m_refData)
497 return TRUE;
498
499 return gdk_region_empty( M_REGIONDATA->m_region );
500 }
501
502 wxRegionContain wxRegion::Contains( wxCoord x, wxCoord y ) const
503 {
504 if (!m_refData)
505 return wxOutRegion;
506
507 if (gdk_region_point_in( M_REGIONDATA->m_region, x, y ))
508 return wxInRegion;
509 else
510 return wxOutRegion;
511 }
512
513 wxRegionContain wxRegion::Contains( wxCoord x, wxCoord y, wxCoord w, wxCoord h ) const
514 {
515 if (!m_refData)
516 return wxOutRegion;
517
518 GdkRectangle rect;
519 rect.x = x;
520 rect.y = y;
521 rect.width = w;
522 rect.height = h;
523 GdkOverlapType res = gdk_region_rect_in( M_REGIONDATA->m_region, &rect );
524 switch (res)
525 {
526 case GDK_OVERLAP_RECTANGLE_IN: return wxInRegion;
527 case GDK_OVERLAP_RECTANGLE_OUT: return wxOutRegion;
528 case GDK_OVERLAP_RECTANGLE_PART: return wxPartRegion;
529 }
530 return wxOutRegion;
531 }
532
533 wxRegionContain wxRegion::Contains(const wxPoint& pt) const
534 {
535 return Contains( pt.x, pt.y );
536 }
537
538 wxRegionContain wxRegion::Contains(const wxRect& rect) const
539 {
540 return Contains( rect.x, rect.y, rect.width, rect.height );
541 }
542
543 GdkRegion *wxRegion::GetRegion() const
544 {
545 if (!m_refData)
546 return (GdkRegion*) NULL;
547
548 return M_REGIONDATA->m_region;
549 }
550
551 wxList *wxRegion::GetRectList() const
552 {
553 #if OLDCODE
554 if (!m_refData)
555 return (wxList*) NULL;
556
557 return &(M_REGIONDATA->m_rects);
558 #else
559 return (wxList*) NULL;
560 #endif
561 }
562
563 // ----------------------------------------------------------------------------
564 // wxRegionIterator
565 // ----------------------------------------------------------------------------
566
567 #if OLDCODE
568
569 IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator,wxObject);
570
571 wxRegionIterator::wxRegionIterator()
572 {
573 Reset();
574 }
575
576 wxRegionIterator::wxRegionIterator( const wxRegion& region )
577 {
578 Reset(region);
579 }
580
581 void wxRegionIterator::Reset( const wxRegion& region )
582 {
583 m_region = region;
584 Reset();
585 }
586
587 wxRegionIterator::operator bool () const
588 {
589 return m_region.GetRectList() && m_current < (size_t)m_region.GetRectList()->Number();
590 }
591
592 bool wxRegionIterator::HaveRects() const
593 {
594 return m_region.GetRectList() && m_current < (size_t)m_region.GetRectList()->Number();
595 }
596
597 void wxRegionIterator::operator ++ ()
598 {
599 if (HaveRects()) ++m_current;
600 }
601
602 void wxRegionIterator::operator ++ (int)
603 {
604 if (HaveRects()) ++m_current;
605 }
606
607 wxCoord wxRegionIterator::GetX() const
608 {
609 wxNode *node = m_region.GetRectList()->Nth( m_current );
610 if (!node) return 0;
611 wxRect *r = (wxRect*)node->Data();
612 return r->x;
613 }
614
615 wxCoord wxRegionIterator::GetY() const
616 {
617 wxNode *node = m_region.GetRectList()->Nth( m_current );
618 if (!node) return 0;
619 wxRect *r = (wxRect*)node->Data();
620 return r->y;
621 }
622
623 wxCoord wxRegionIterator::GetW() const
624 {
625 wxNode *node = m_region.GetRectList()->Nth( m_current );
626 if (!node) return 0;
627 wxRect *r = (wxRect*)node->Data();
628 return r->width;
629 }
630
631 wxCoord wxRegionIterator::GetH() const
632 {
633 wxNode *node = m_region.GetRectList()->Nth( m_current );
634 if (!node) return 0;
635 wxRect *r = (wxRect*)node->Data();
636 return r->height;
637 }
638
639 #else
640
641 // the following structures must match the private structures
642 // in X11 region code ( xc/lib/X11/region.h )
643
644 // this makes the Region type transparent
645 // and we have access to the region rectangles
646
647 struct _XBox {
648 short x1, x2, y1, y2;
649 };
650
651 struct _XRegion {
652 long size , numRects;
653 _XBox *rects, extents;
654 };
655
656 class wxRIRefData: public wxObjectRefData
657 {
658 public:
659
660 wxRIRefData() : m_rects(0), m_numRects(0){}
661 ~wxRIRefData();
662
663 wxRect *m_rects;
664 size_t m_numRects;
665
666 void CreateRects( const wxRegion& r );
667 };
668
669 wxRIRefData::~wxRIRefData()
670 {
671 delete m_rects;
672 }
673
674 #include <gdk/gdkprivate.h>
675
676 void wxRIRefData::CreateRects( const wxRegion& region )
677 {
678 if( m_rects )
679 delete m_rects;
680 m_rects = 0;
681 m_numRects= 0;
682 GdkRegion *gdkregion= region.GetRegion();
683 if( gdkregion ){
684 Region r= ((GdkRegionPrivate *)gdkregion)->xregion;
685 if( r ){
686 m_numRects= r->numRects;
687 if( m_numRects )
688 {
689 m_rects= new wxRect[m_numRects];
690 for( size_t i=0; i<m_numRects; ++i )
691 {
692 _XBox &xr= r->rects[i];
693 wxRect&wr= m_rects[i];
694 wr.x = xr.x1;
695 wr.y = xr.y1;
696 wr.width = xr.x2-xr.x1;
697 wr.height= xr.y2-xr.y1;
698 }
699 }
700 }
701 }
702 }
703
704 IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator,wxObject);
705
706 wxRegionIterator::wxRegionIterator()
707 {
708 m_refData = new wxRIRefData();
709 Reset();
710 }
711
712 wxRegionIterator::wxRegionIterator( const wxRegion& region )
713 {
714 m_refData = new wxRIRefData();
715 Reset(region);
716 }
717
718 void wxRegionIterator::Reset( const wxRegion& region )
719 {
720 m_region = region;
721 ((wxRIRefData*)m_refData)->CreateRects(region);
722 Reset();
723 }
724
725 bool wxRegionIterator::HaveRects() const
726 {
727 return m_current < ((wxRIRefData*)m_refData)->m_numRects;
728 }
729
730 wxRegionIterator::operator bool () const
731 {
732 return HaveRects();
733 }
734
735 void wxRegionIterator::operator ++ ()
736 {
737 if (HaveRects()) ++m_current;
738 }
739
740 void wxRegionIterator::operator ++ (int)
741 {
742 if (HaveRects()) ++m_current;
743 }
744
745 wxCoord wxRegionIterator::GetX() const
746 {
747 if( !HaveRects() ) return 0;
748 return ((wxRIRefData*)m_refData)->m_rects[m_current].x;
749 }
750
751 wxCoord wxRegionIterator::GetY() const
752 {
753 if( !HaveRects() ) return 0;
754 return ((wxRIRefData*)m_refData)->m_rects[m_current].y;
755 }
756
757 wxCoord wxRegionIterator::GetW() const
758 {
759 if( !HaveRects() ) return -1;
760 return ((wxRIRefData*)m_refData)->m_rects[m_current].width;
761 }
762
763 wxCoord wxRegionIterator::GetH() const
764 {
765 if( !HaveRects() ) return -1;
766 return ((wxRIRefData*)m_refData)->m_rects[m_current].height;
767 }
768
769 wxRect wxRegionIterator::GetRect() const
770 {
771 wxRect r;
772 wxNode *node = m_region.GetRectList()->Nth( m_current );
773
774 if (node)
775 r = *((wxRect*)node->Data());
776
777 return r;
778 }
779
780 #endif
781