1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/region.cpp
4 // Author: Robert Roebling
5 // Modified: VZ at 05.10.00: use Unshare(), comparison fixed
7 // Copyright: (c) 1998 Robert Roebling
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // ============================================================================
13 // ============================================================================
16 #pragma implementation "region.h"
19 // ----------------------------------------------------------------------------
21 // ----------------------------------------------------------------------------
23 #include "wx/region.h"
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
39 // ----------------------------------------------------------------------------
40 // wxRegionRefData: private class containing the information about the region
41 // ----------------------------------------------------------------------------
43 class wxRegionRefData
: public wxObjectRefData
47 wxRegionRefData(const wxRegionRefData
& refData
);
48 virtual ~wxRegionRefData();
56 // ----------------------------------------------------------------------------
58 // ----------------------------------------------------------------------------
60 #define M_REGIONDATA ((wxRegionRefData *)m_refData)
61 #define M_REGIONDATA_OF(rgn) ((wxRegionRefData *)(rgn.m_refData))
63 IMPLEMENT_DYNAMIC_CLASS(wxRegion
, wxGDIObject
);
64 IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator
,wxObject
);
66 // ============================================================================
68 // ============================================================================
70 // ----------------------------------------------------------------------------
72 // ----------------------------------------------------------------------------
74 wxRegionRefData::wxRegionRefData()
76 m_region
= (GdkRegion
*) NULL
;
79 wxRegionRefData::wxRegionRefData(const wxRegionRefData
& refData
)
82 m_region
= gdk_region_copy(refData
.m_region
);
84 m_region
= gdk_region_new();
85 GdkRegion
*regCopy
= gdk_regions_union(m_region
, refData
.m_region
);
86 gdk_region_destroy(m_region
);
91 wxNode
*node
= refData
.m_rects
.First();
94 wxRect
*r
= (wxRect
*)node
->Data();
95 m_rects
.Append( (wxObject
*) new wxRect(*r
) );
101 wxRegionRefData::~wxRegionRefData()
103 if (m_region
) gdk_region_destroy( m_region
);
106 wxNode
*node
= m_rects
.First();
109 wxRect
*r
= (wxRect
*)node
->Data();
116 // ----------------------------------------------------------------------------
117 // wxRegion construction
118 // ----------------------------------------------------------------------------
120 #define M_REGIONDATA ((wxRegionRefData *)m_refData)
126 wxRegion::wxRegion( wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
128 m_refData
= new wxRegionRefData();
129 GdkRegion
*reg
= gdk_region_new();
136 gdk_region_union_with_rect( reg
, &rect
);
137 M_REGIONDATA
->m_region
= reg
;
139 M_REGIONDATA
->m_region
= gdk_region_union_with_rect( reg
, &rect
);
140 gdk_region_destroy( reg
);
143 M_REGIONDATA
->m_rects
.Append( (wxObject
*) new wxRect(x
,y
,w
,h
) );
147 wxRegion::wxRegion( const wxPoint
& topLeft
, const wxPoint
& bottomRight
)
149 m_refData
= new wxRegionRefData();
150 GdkRegion
*reg
= gdk_region_new();
154 rect
.width
= bottomRight
.x
- rect
.x
;
155 rect
.height
= bottomRight
.y
- rect
.y
;
157 gdk_region_union_with_rect( reg
, &rect
);
158 M_REGIONDATA
->m_region
= reg
;
160 M_REGIONDATA
->m_region
= gdk_region_union_with_rect( reg
, &rect
);
161 gdk_region_destroy( reg
);
164 M_REGIONDATA
->m_rects
.Append( (wxObject
*) new wxRect(topLeft
,bottomRight
) );
168 wxRegion::wxRegion( const wxRect
& rect
)
170 m_refData
= new wxRegionRefData();
171 GdkRegion
*reg
= gdk_region_new();
175 g_rect
.width
= rect
.width
;
176 g_rect
.height
= rect
.height
;
178 gdk_region_union_with_rect( reg
, &g_rect
);
179 M_REGIONDATA
->m_region
= reg
;
181 M_REGIONDATA
->m_region
= gdk_region_union_with_rect( reg
, &g_rect
);
182 gdk_region_destroy( reg
);
185 M_REGIONDATA
->m_rects
.Append( (wxObject
*) new wxRect(rect
.x
,rect
.y
,rect
.width
,rect
.height
) );
189 wxRegion::wxRegion( size_t n
, const wxPoint
*points
, int fillStyle
)
191 GdkPoint
*gdkpoints
= new GdkPoint
[n
];
192 for ( size_t i
= 0 ; i
< n
; i
++ )
194 gdkpoints
[i
].x
= points
[i
].x
;
195 gdkpoints
[i
].y
= points
[i
].y
;
198 m_refData
= new wxRegionRefData();
200 GdkRegion
* reg
= gdk_region_polygon
204 fillStyle
== wxWINDING_RULE
? GDK_WINDING_RULE
208 M_REGIONDATA
->m_region
= reg
;
213 wxRegion::~wxRegion()
217 bool wxRegion::operator==( const wxRegion
& region
)
219 // VZ: compare the regions themselves, not the pointers to ref data!
220 return gdk_region_equal(M_REGIONDATA
->m_region
,
221 M_REGIONDATA_OF(region
)->m_region
);
224 bool wxRegion::operator != ( const wxRegion
& region
)
226 return !(*this == region
);
229 void wxRegion::Unshare()
233 m_refData
= new wxRegionRefData
;
234 M_REGIONDATA
->m_region
= gdk_region_new();
236 else if ( m_refData
->GetRefCount() > 1 )
238 wxRegionRefData
*refData
= new wxRegionRefData(*M_REGIONDATA
);
242 //else: we're not shared
245 // ----------------------------------------------------------------------------
246 // wxRegion operations
247 // ----------------------------------------------------------------------------
249 void wxRegion::Clear()
254 bool wxRegion::Union( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
260 rect
.height
= height
;
263 m_refData
= new wxRegionRefData();
264 GdkRegion
*reg
= gdk_region_new();
266 gdk_region_union_with_rect( reg
, &rect
);
267 M_REGIONDATA
->m_region
= reg
;
269 M_REGIONDATA
->m_region
= gdk_region_union_with_rect( reg
, &rect
);
270 gdk_region_destroy( reg
);
278 gdk_region_union_with_rect( M_REGIONDATA
->m_region
, &rect
);
280 GdkRegion
*reg
= gdk_region_union_with_rect( M_REGIONDATA
->m_region
, &rect
);
281 gdk_region_destroy( M_REGIONDATA
->m_region
);
282 M_REGIONDATA
->m_region
= reg
;
287 M_REGIONDATA
->m_rects
.Append( (wxObject
*) new wxRect(x
,y
,width
,height
) );
293 bool wxRegion::Union( const wxRect
& rect
)
295 return Union( rect
.x
, rect
.y
, rect
.width
, rect
.height
);
298 bool wxRegion::Union( const wxRegion
& region
)
306 gdk_region_union( M_REGIONDATA
->m_region
, region
.GetRegion() );
308 GdkRegion
*reg
= gdk_regions_union( M_REGIONDATA
->m_region
, region
.GetRegion() );
309 gdk_region_destroy( M_REGIONDATA
->m_region
);
310 M_REGIONDATA
->m_region
= reg
;
314 wxNode
*node
= region
.GetRectList()->First();
317 wxRect
*r
= (wxRect
*)node
->Data();
318 M_REGIONDATA
->m_rects
.Append( (wxObject
*) new wxRect(r
->x
,r
->y
,r
->width
,r
->height
) );
326 bool wxRegion::Intersect( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
328 wxRegion
reg( x
, y
, width
, height
);
330 return Intersect( reg
);
333 bool wxRegion::Intersect( const wxRect
& rect
)
335 wxRegion
reg( rect
);
336 return Intersect( reg
);
339 // this helper function just computes the region intersection without updating
340 // the list of rectangles each region maintaints: this allows us to call it
341 // from Intersect() itself without going into infinite recursion as we would
342 // if we called Intersect() itself recursively
343 bool wxRegion::IntersectRegionOnly(const wxRegion
& region
)
348 gdk_region_intersect( M_REGIONDATA
->m_region
, region
.GetRegion() );
350 GdkRegion
*reg
= gdk_regions_intersect( M_REGIONDATA
->m_region
, region
.GetRegion() );
351 gdk_region_destroy( M_REGIONDATA
->m_region
);
352 M_REGIONDATA
->m_region
= reg
;
358 bool wxRegion::Intersect( const wxRegion
& region
)
365 m_refData
= new wxRegionRefData();
366 M_REGIONDATA
->m_region
= gdk_region_new();
370 if ( !IntersectRegionOnly(region
) )
372 GetRectList()->Clear();
377 // we need to update the rect list as well
379 wxList
& list
= *GetRectList();
380 wxNode
*node
= list
.First();
383 wxRect
*r
= (wxRect
*)node
->Data();
385 wxRegion regCopy
= region
;
386 if ( regCopy
.IntersectRegionOnly(*r
) )
388 // replace the node with the intersection
389 *r
= regCopy
.GetBox();
393 // TODO remove the rect from the list
404 bool wxRegion::Subtract( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
406 wxRegion
reg( x
, y
, width
, height
);
407 return Subtract( reg
);
410 bool wxRegion::Subtract( const wxRect
& rect
)
412 wxRegion
reg( rect
);
413 return Subtract( reg
);
416 bool wxRegion::Subtract( const wxRegion
& region
)
423 m_refData
= new wxRegionRefData();
424 M_REGIONDATA
->m_region
= gdk_region_new();
430 gdk_region_subtract( M_REGIONDATA
->m_region
, region
.GetRegion() );
432 GdkRegion
*reg
= gdk_regions_subtract( M_REGIONDATA
->m_region
, region
.GetRegion() );
433 gdk_region_destroy( M_REGIONDATA
->m_region
);
434 M_REGIONDATA
->m_region
= reg
;
440 bool wxRegion::Xor( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
442 wxRegion
reg( x
, y
, width
, height
);
446 bool wxRegion::Xor( const wxRect
& rect
)
448 wxRegion
reg( rect
);
452 bool wxRegion::Xor( const wxRegion
& region
)
459 m_refData
= new wxRegionRefData();
460 M_REGIONDATA
->m_region
= gdk_region_new();
468 gdk_region_xor( M_REGIONDATA
->m_region
, region
.GetRegion() );
470 GdkRegion
*reg
= gdk_regions_xor( M_REGIONDATA
->m_region
, region
.GetRegion() );
471 gdk_region_destroy( M_REGIONDATA
->m_region
);
472 M_REGIONDATA
->m_region
= reg
;
476 wxNode
*node
= region
.GetRectList()->First();
479 wxRect
*r
= (wxRect
*)node
->Data();
480 M_REGIONDATA
->m_rects
.Append( (wxObject
*) new wxRect(r
->x
,r
->y
,r
->width
,r
->height
) );
488 // ----------------------------------------------------------------------------
490 // ----------------------------------------------------------------------------
492 void wxRegion::GetBox( wxCoord
&x
, wxCoord
&y
, wxCoord
&w
, wxCoord
&h
) const
497 gdk_region_get_clipbox( M_REGIONDATA
->m_region
, &rect
);
512 wxRect
wxRegion::GetBox() const
515 GetBox( x
, y
, w
, h
);
516 return wxRect( x
, y
, w
, h
);
519 bool wxRegion::Empty() const
524 return gdk_region_empty( M_REGIONDATA
->m_region
);
527 wxRegionContain
wxRegion::Contains( wxCoord x
, wxCoord y
) const
532 if (gdk_region_point_in( M_REGIONDATA
->m_region
, x
, y
))
538 wxRegionContain
wxRegion::Contains( wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
) const
548 GdkOverlapType res
= gdk_region_rect_in( M_REGIONDATA
->m_region
, &rect
);
551 case GDK_OVERLAP_RECTANGLE_IN
: return wxInRegion
;
552 case GDK_OVERLAP_RECTANGLE_OUT
: return wxOutRegion
;
553 case GDK_OVERLAP_RECTANGLE_PART
: return wxPartRegion
;
558 wxRegionContain
wxRegion::Contains(const wxPoint
& pt
) const
560 return Contains( pt
.x
, pt
.y
);
563 wxRegionContain
wxRegion::Contains(const wxRect
& rect
) const
565 return Contains( rect
.x
, rect
.y
, rect
.width
, rect
.height
);
568 GdkRegion
*wxRegion::GetRegion() const
571 return (GdkRegion
*) NULL
;
573 return M_REGIONDATA
->m_region
;
576 wxList
*wxRegion::GetRectList() const
580 return (wxList
*) NULL
;
582 return &(M_REGIONDATA
->m_rects
);
584 return (wxList
*) NULL
;
588 // ----------------------------------------------------------------------------
590 // ----------------------------------------------------------------------------
594 wxRegionIterator::wxRegionIterator()
599 wxRegionIterator::wxRegionIterator( const wxRegion
& region
)
604 void wxRegionIterator::Reset( const wxRegion
& region
)
610 wxRegionIterator::operator bool () const
612 return m_region
.GetRectList() && m_current
< (size_t)m_region
.GetRectList()->Number();
615 bool wxRegionIterator::HaveRects() const
617 return m_region
.GetRectList() && m_current
< (size_t)m_region
.GetRectList()->Number();
620 void wxRegionIterator::operator ++ ()
622 if (HaveRects()) ++m_current
;
625 void wxRegionIterator::operator ++ (int)
627 if (HaveRects()) ++m_current
;
630 wxCoord
wxRegionIterator::GetX() const
632 wxNode
*node
= m_region
.GetRectList()->Nth( m_current
);
634 wxRect
*r
= (wxRect
*)node
->Data();
638 wxCoord
wxRegionIterator::GetY() const
640 wxNode
*node
= m_region
.GetRectList()->Nth( m_current
);
642 wxRect
*r
= (wxRect
*)node
->Data();
646 wxCoord
wxRegionIterator::GetW() const
648 wxNode
*node
= m_region
.GetRectList()->Nth( m_current
);
650 wxRect
*r
= (wxRect
*)node
->Data();
654 wxCoord
wxRegionIterator::GetH() const
656 wxNode
*node
= m_region
.GetRectList()->Nth( m_current
);
658 wxRect
*r
= (wxRect
*)node
->Data();
664 // the following structures must match the private structures
665 // in X11 region code ( xc/lib/X11/region.h )
667 // this makes the Region type transparent
668 // and we have access to the region rectangles
671 short x1
, x2
, y1
, y2
;
675 long size
, numRects
;
676 _XBox
*rects
, extents
;
679 class wxRIRefData
: public wxObjectRefData
683 wxRIRefData() : m_rects(0), m_numRects(0){}
689 void CreateRects( const wxRegion
& r
);
692 wxRIRefData::~wxRIRefData()
697 #include <gdk/gdkprivate.h>
699 void wxRIRefData::CreateRects( const wxRegion
& region
)
705 GdkRegion
*gdkregion
= region
.GetRegion();
707 Region r
= ((GdkRegionPrivate
*)gdkregion
)->xregion
;
709 m_numRects
= r
->numRects
;
712 m_rects
= new wxRect
[m_numRects
];
713 for( size_t i
=0; i
<m_numRects
; ++i
)
715 _XBox
&xr
= r
->rects
[i
];
716 wxRect
&wr
= m_rects
[i
];
719 wr
.width
= xr
.x2
-xr
.x1
;
720 wr
.height
= xr
.y2
-xr
.y1
;
727 wxRegionIterator::wxRegionIterator()
729 m_refData
= new wxRIRefData();
733 wxRegionIterator::wxRegionIterator( const wxRegion
& region
)
735 m_refData
= new wxRIRefData();
739 void wxRegionIterator::Reset( const wxRegion
& region
)
742 ((wxRIRefData
*)m_refData
)->CreateRects(region
);
746 bool wxRegionIterator::HaveRects() const
748 return m_current
< ((wxRIRefData
*)m_refData
)->m_numRects
;
751 wxRegionIterator::operator bool () const
756 void wxRegionIterator::operator ++ ()
758 if (HaveRects()) ++m_current
;
761 void wxRegionIterator::operator ++ (int)
763 if (HaveRects()) ++m_current
;
766 wxCoord
wxRegionIterator::GetX() const
768 if( !HaveRects() ) return 0;
769 return ((wxRIRefData
*)m_refData
)->m_rects
[m_current
].x
;
772 wxCoord
wxRegionIterator::GetY() const
774 if( !HaveRects() ) return 0;
775 return ((wxRIRefData
*)m_refData
)->m_rects
[m_current
].y
;
778 wxCoord
wxRegionIterator::GetW() const
780 if( !HaveRects() ) return -1;
781 return ((wxRIRefData
*)m_refData
)->m_rects
[m_current
].width
;
784 wxCoord
wxRegionIterator::GetH() const
786 if( !HaveRects() ) return -1;
787 return ((wxRIRefData
*)m_refData
)->m_rects
[m_current
].height
;
790 wxRect
wxRegionIterator::GetRect() const
794 r
= ((wxRIRefData
*)m_refData
)->m_rects
[m_current
];