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()
193 bool wxRegion::operator==( const wxRegion
& region
)
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
);
200 bool wxRegion::operator != ( const wxRegion
& region
)
202 return !(*this == region
);
205 void wxRegion::Unshare()
209 m_refData
= new wxRegionRefData
;
210 M_REGIONDATA
->m_region
= gdk_region_new();
212 else if ( m_refData
->GetRefCount() > 1 )
214 wxRegionRefData
*refData
= new wxRegionRefData(*M_REGIONDATA
);
218 //else: we're not shared
221 // ----------------------------------------------------------------------------
222 // wxRegion operations
223 // ----------------------------------------------------------------------------
225 void wxRegion::Clear()
230 bool wxRegion::Union( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
236 rect
.height
= height
;
239 m_refData
= new wxRegionRefData();
240 GdkRegion
*reg
= gdk_region_new();
242 gdk_region_union_with_rect( reg
, &rect
);
243 M_REGIONDATA
->m_region
= reg
;
245 M_REGIONDATA
->m_region
= gdk_region_union_with_rect( reg
, &rect
);
246 gdk_region_destroy( reg
);
254 gdk_region_union_with_rect( M_REGIONDATA
->m_region
, &rect
);
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
;
263 M_REGIONDATA
->m_rects
.Append( (wxObject
*) new wxRect(x
,y
,width
,height
) );
269 bool wxRegion::Union( const wxRect
& rect
)
271 return Union( rect
.x
, rect
.y
, rect
.width
, rect
.height
);
274 bool wxRegion::Union( const wxRegion
& region
)
282 gdk_region_union( M_REGIONDATA
->m_region
, region
.GetRegion() );
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
;
290 wxNode
*node
= region
.GetRectList()->First();
293 wxRect
*r
= (wxRect
*)node
->Data();
294 M_REGIONDATA
->m_rects
.Append( (wxObject
*) new wxRect(r
->x
,r
->y
,r
->width
,r
->height
) );
302 bool wxRegion::Intersect( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
304 wxRegion
reg( x
, y
, width
, height
);
306 return Intersect( reg
);
309 bool wxRegion::Intersect( const wxRect
& rect
)
311 wxRegion
reg( rect
);
312 return Intersect( reg
);
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
)
324 gdk_region_intersect( M_REGIONDATA
->m_region
, region
.GetRegion() );
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
;
334 bool wxRegion::Intersect( const wxRegion
& region
)
341 m_refData
= new wxRegionRefData();
342 M_REGIONDATA
->m_region
= gdk_region_new();
346 if ( !IntersectRegionOnly(region
) )
348 GetRectList()->Clear();
353 // we need to update the rect list as well
354 wxList
& list
= *GetRectList();
355 wxNode
*node
= list
.First();
358 wxRect
*r
= (wxRect
*)node
->Data();
360 wxRegion regCopy
= region
;
361 if ( regCopy
.IntersectRegionOnly(*r
) )
363 // replace the node with the intersection
364 *r
= regCopy
.GetBox();
368 // TODO remove the rect from the list
379 bool wxRegion::Subtract( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
381 wxRegion
reg( x
, y
, width
, height
);
382 return Subtract( reg
);
385 bool wxRegion::Subtract( const wxRect
& rect
)
387 wxRegion
reg( rect
);
388 return Subtract( reg
);
391 bool wxRegion::Subtract( const wxRegion
& region
)
398 m_refData
= new wxRegionRefData();
399 M_REGIONDATA
->m_region
= gdk_region_new();
405 gdk_region_subtract( M_REGIONDATA
->m_region
, region
.GetRegion() );
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
;
415 bool wxRegion::Xor( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
417 wxRegion
reg( x
, y
, width
, height
);
421 bool wxRegion::Xor( const wxRect
& rect
)
423 wxRegion
reg( rect
);
427 bool wxRegion::Xor( const wxRegion
& region
)
434 m_refData
= new wxRegionRefData();
435 M_REGIONDATA
->m_region
= gdk_region_new();
443 gdk_region_xor( M_REGIONDATA
->m_region
, region
.GetRegion() );
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
;
451 wxNode
*node
= region
.GetRectList()->First();
454 wxRect
*r
= (wxRect
*)node
->Data();
455 M_REGIONDATA
->m_rects
.Append( (wxObject
*) new wxRect(r
->x
,r
->y
,r
->width
,r
->height
) );
463 // ----------------------------------------------------------------------------
465 // ----------------------------------------------------------------------------
467 void wxRegion::GetBox( wxCoord
&x
, wxCoord
&y
, wxCoord
&w
, wxCoord
&h
) const
472 gdk_region_get_clipbox( M_REGIONDATA
->m_region
, &rect
);
487 wxRect
wxRegion::GetBox() const
490 GetBox( x
, y
, w
, h
);
491 return wxRect( x
, y
, w
, h
);
494 bool wxRegion::Empty() const
499 return gdk_region_empty( M_REGIONDATA
->m_region
);
502 wxRegionContain
wxRegion::Contains( wxCoord x
, wxCoord y
) const
507 if (gdk_region_point_in( M_REGIONDATA
->m_region
, x
, y
))
513 wxRegionContain
wxRegion::Contains( wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
) const
523 GdkOverlapType res
= gdk_region_rect_in( M_REGIONDATA
->m_region
, &rect
);
526 case GDK_OVERLAP_RECTANGLE_IN
: return wxInRegion
;
527 case GDK_OVERLAP_RECTANGLE_OUT
: return wxOutRegion
;
528 case GDK_OVERLAP_RECTANGLE_PART
: return wxPartRegion
;
533 wxRegionContain
wxRegion::Contains(const wxPoint
& pt
) const
535 return Contains( pt
.x
, pt
.y
);
538 wxRegionContain
wxRegion::Contains(const wxRect
& rect
) const
540 return Contains( rect
.x
, rect
.y
, rect
.width
, rect
.height
);
543 GdkRegion
*wxRegion::GetRegion() const
546 return (GdkRegion
*) NULL
;
548 return M_REGIONDATA
->m_region
;
551 wxList
*wxRegion::GetRectList() const
555 return (wxList
*) NULL
;
557 return &(M_REGIONDATA
->m_rects
);
559 return (wxList
*) NULL
;
563 // ----------------------------------------------------------------------------
565 // ----------------------------------------------------------------------------
569 wxRegionIterator::wxRegionIterator()
574 wxRegionIterator::wxRegionIterator( const wxRegion
& region
)
579 void wxRegionIterator::Reset( const wxRegion
& region
)
585 wxRegionIterator::operator bool () const
587 return m_region
.GetRectList() && m_current
< (size_t)m_region
.GetRectList()->Number();
590 bool wxRegionIterator::HaveRects() const
592 return m_region
.GetRectList() && m_current
< (size_t)m_region
.GetRectList()->Number();
595 void wxRegionIterator::operator ++ ()
597 if (HaveRects()) ++m_current
;
600 void wxRegionIterator::operator ++ (int)
602 if (HaveRects()) ++m_current
;
605 wxCoord
wxRegionIterator::GetX() const
607 wxNode
*node
= m_region
.GetRectList()->Nth( m_current
);
609 wxRect
*r
= (wxRect
*)node
->Data();
613 wxCoord
wxRegionIterator::GetY() const
615 wxNode
*node
= m_region
.GetRectList()->Nth( m_current
);
617 wxRect
*r
= (wxRect
*)node
->Data();
621 wxCoord
wxRegionIterator::GetW() const
623 wxNode
*node
= m_region
.GetRectList()->Nth( m_current
);
625 wxRect
*r
= (wxRect
*)node
->Data();
629 wxCoord
wxRegionIterator::GetH() const
631 wxNode
*node
= m_region
.GetRectList()->Nth( m_current
);
633 wxRect
*r
= (wxRect
*)node
->Data();
639 // the following structures must match the private structures
640 // in X11 region code ( xc/lib/X11/region.h )
642 // this makes the Region type transparent
643 // and we have access to the region rectangles
646 short x1
, x2
, y1
, y2
;
650 long size
, numRects
;
651 _XBox
*rects
, extents
;
654 class wxRIRefData
: public wxObjectRefData
658 wxRIRefData() : m_rects(0), m_numRects(0){}
664 void CreateRects( const wxRegion
& r
);
667 wxRIRefData::~wxRIRefData()
672 #include <gdk/gdkprivate.h>
674 void wxRIRefData::CreateRects( const wxRegion
& region
)
680 GdkRegion
*gdkregion
= region
.GetRegion();
682 Region r
= ((GdkRegionPrivate
*)gdkregion
)->xregion
;
684 m_numRects
= r
->numRects
;
687 m_rects
= new wxRect
[m_numRects
];
688 for( size_t i
=0; i
<m_numRects
; ++i
)
690 _XBox
&xr
= r
->rects
[i
];
691 wxRect
&wr
= m_rects
[i
];
694 wr
.width
= xr
.x2
-xr
.x1
;
695 wr
.height
= xr
.y2
-xr
.y1
;
702 wxRegionIterator::wxRegionIterator()
704 m_refData
= new wxRIRefData();
708 wxRegionIterator::wxRegionIterator( const wxRegion
& region
)
710 m_refData
= new wxRIRefData();
714 void wxRegionIterator::Reset( const wxRegion
& region
)
717 ((wxRIRefData
*)m_refData
)->CreateRects(region
);
721 bool wxRegionIterator::HaveRects() const
723 return m_current
< ((wxRIRefData
*)m_refData
)->m_numRects
;
726 wxRegionIterator::operator bool () const
731 void wxRegionIterator::operator ++ ()
733 if (HaveRects()) ++m_current
;
736 void wxRegionIterator::operator ++ (int)
738 if (HaveRects()) ++m_current
;
741 wxCoord
wxRegionIterator::GetX() const
743 if( !HaveRects() ) return 0;
744 return ((wxRIRefData
*)m_refData
)->m_rects
[m_current
].x
;
747 wxCoord
wxRegionIterator::GetY() const
749 if( !HaveRects() ) return 0;
750 return ((wxRIRefData
*)m_refData
)->m_rects
[m_current
].y
;
753 wxCoord
wxRegionIterator::GetW() const
755 if( !HaveRects() ) return -1;
756 return ((wxRIRefData
*)m_refData
)->m_rects
[m_current
].width
;
759 wxCoord
wxRegionIterator::GetH() const
761 if( !HaveRects() ) return -1;
762 return ((wxRIRefData
*)m_refData
)->m_rects
[m_current
].height
;
765 wxRect
wxRegionIterator::GetRect() const
768 wxNode
*node
= m_region
.GetRectList()->Nth( m_current
);
771 r
= *((wxRect
*)node
->Data());