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
355 wxList
& list
= *GetRectList();
356 wxNode
*node
= list
.First();
359 wxRect
*r
= (wxRect
*)node
->Data();
361 wxRegion regCopy
= region
;
362 if ( regCopy
.IntersectRegionOnly(*r
) )
364 // replace the node with the intersection
365 *r
= regCopy
.GetBox();
369 // TODO remove the rect from the list
380 bool wxRegion::Subtract( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
382 wxRegion
reg( x
, y
, width
, height
);
383 return Subtract( reg
);
386 bool wxRegion::Subtract( const wxRect
& rect
)
388 wxRegion
reg( rect
);
389 return Subtract( reg
);
392 bool wxRegion::Subtract( const wxRegion
& region
)
399 m_refData
= new wxRegionRefData();
400 M_REGIONDATA
->m_region
= gdk_region_new();
406 gdk_region_subtract( M_REGIONDATA
->m_region
, region
.GetRegion() );
408 GdkRegion
*reg
= gdk_regions_subtract( M_REGIONDATA
->m_region
, region
.GetRegion() );
409 gdk_region_destroy( M_REGIONDATA
->m_region
);
410 M_REGIONDATA
->m_region
= reg
;
416 bool wxRegion::Xor( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
418 wxRegion
reg( x
, y
, width
, height
);
422 bool wxRegion::Xor( const wxRect
& rect
)
424 wxRegion
reg( rect
);
428 bool wxRegion::Xor( const wxRegion
& region
)
435 m_refData
= new wxRegionRefData();
436 M_REGIONDATA
->m_region
= gdk_region_new();
444 gdk_region_xor( M_REGIONDATA
->m_region
, region
.GetRegion() );
446 GdkRegion
*reg
= gdk_regions_xor( M_REGIONDATA
->m_region
, region
.GetRegion() );
447 gdk_region_destroy( M_REGIONDATA
->m_region
);
448 M_REGIONDATA
->m_region
= reg
;
452 wxNode
*node
= region
.GetRectList()->First();
455 wxRect
*r
= (wxRect
*)node
->Data();
456 M_REGIONDATA
->m_rects
.Append( (wxObject
*) new wxRect(r
->x
,r
->y
,r
->width
,r
->height
) );
464 // ----------------------------------------------------------------------------
466 // ----------------------------------------------------------------------------
468 void wxRegion::GetBox( wxCoord
&x
, wxCoord
&y
, wxCoord
&w
, wxCoord
&h
) const
473 gdk_region_get_clipbox( M_REGIONDATA
->m_region
, &rect
);
488 wxRect
wxRegion::GetBox() const
491 GetBox( x
, y
, w
, h
);
492 return wxRect( x
, y
, w
, h
);
495 bool wxRegion::Empty() const
500 return gdk_region_empty( M_REGIONDATA
->m_region
);
503 wxRegionContain
wxRegion::Contains( wxCoord x
, wxCoord y
) const
508 if (gdk_region_point_in( M_REGIONDATA
->m_region
, x
, y
))
514 wxRegionContain
wxRegion::Contains( wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
) const
524 GdkOverlapType res
= gdk_region_rect_in( M_REGIONDATA
->m_region
, &rect
);
527 case GDK_OVERLAP_RECTANGLE_IN
: return wxInRegion
;
528 case GDK_OVERLAP_RECTANGLE_OUT
: return wxOutRegion
;
529 case GDK_OVERLAP_RECTANGLE_PART
: return wxPartRegion
;
534 wxRegionContain
wxRegion::Contains(const wxPoint
& pt
) const
536 return Contains( pt
.x
, pt
.y
);
539 wxRegionContain
wxRegion::Contains(const wxRect
& rect
) const
541 return Contains( rect
.x
, rect
.y
, rect
.width
, rect
.height
);
544 GdkRegion
*wxRegion::GetRegion() const
547 return (GdkRegion
*) NULL
;
549 return M_REGIONDATA
->m_region
;
552 wxList
*wxRegion::GetRectList() const
556 return (wxList
*) NULL
;
558 return &(M_REGIONDATA
->m_rects
);
560 return (wxList
*) NULL
;
564 // ----------------------------------------------------------------------------
566 // ----------------------------------------------------------------------------
570 wxRegionIterator::wxRegionIterator()
575 wxRegionIterator::wxRegionIterator( const wxRegion
& region
)
580 void wxRegionIterator::Reset( const wxRegion
& region
)
586 wxRegionIterator::operator bool () const
588 return m_region
.GetRectList() && m_current
< (size_t)m_region
.GetRectList()->Number();
591 bool wxRegionIterator::HaveRects() const
593 return m_region
.GetRectList() && m_current
< (size_t)m_region
.GetRectList()->Number();
596 void wxRegionIterator::operator ++ ()
598 if (HaveRects()) ++m_current
;
601 void wxRegionIterator::operator ++ (int)
603 if (HaveRects()) ++m_current
;
606 wxCoord
wxRegionIterator::GetX() const
608 wxNode
*node
= m_region
.GetRectList()->Nth( m_current
);
610 wxRect
*r
= (wxRect
*)node
->Data();
614 wxCoord
wxRegionIterator::GetY() const
616 wxNode
*node
= m_region
.GetRectList()->Nth( m_current
);
618 wxRect
*r
= (wxRect
*)node
->Data();
622 wxCoord
wxRegionIterator::GetW() const
624 wxNode
*node
= m_region
.GetRectList()->Nth( m_current
);
626 wxRect
*r
= (wxRect
*)node
->Data();
630 wxCoord
wxRegionIterator::GetH() const
632 wxNode
*node
= m_region
.GetRectList()->Nth( m_current
);
634 wxRect
*r
= (wxRect
*)node
->Data();
640 // the following structures must match the private structures
641 // in X11 region code ( xc/lib/X11/region.h )
643 // this makes the Region type transparent
644 // and we have access to the region rectangles
647 short x1
, x2
, y1
, y2
;
651 long size
, numRects
;
652 _XBox
*rects
, extents
;
655 class wxRIRefData
: public wxObjectRefData
659 wxRIRefData() : m_rects(0), m_numRects(0){}
665 void CreateRects( const wxRegion
& r
);
668 wxRIRefData::~wxRIRefData()
673 #include <gdk/gdkprivate.h>
675 void wxRIRefData::CreateRects( const wxRegion
& region
)
681 GdkRegion
*gdkregion
= region
.GetRegion();
683 Region r
= ((GdkRegionPrivate
*)gdkregion
)->xregion
;
685 m_numRects
= r
->numRects
;
688 m_rects
= new wxRect
[m_numRects
];
689 for( size_t i
=0; i
<m_numRects
; ++i
)
691 _XBox
&xr
= r
->rects
[i
];
692 wxRect
&wr
= m_rects
[i
];
695 wr
.width
= xr
.x2
-xr
.x1
;
696 wr
.height
= xr
.y2
-xr
.y1
;
703 wxRegionIterator::wxRegionIterator()
705 m_refData
= new wxRIRefData();
709 wxRegionIterator::wxRegionIterator( const wxRegion
& region
)
711 m_refData
= new wxRIRefData();
715 void wxRegionIterator::Reset( const wxRegion
& region
)
718 ((wxRIRefData
*)m_refData
)->CreateRects(region
);
722 bool wxRegionIterator::HaveRects() const
724 return m_current
< ((wxRIRefData
*)m_refData
)->m_numRects
;
727 wxRegionIterator::operator bool () const
732 void wxRegionIterator::operator ++ ()
734 if (HaveRects()) ++m_current
;
737 void wxRegionIterator::operator ++ (int)
739 if (HaveRects()) ++m_current
;
742 wxCoord
wxRegionIterator::GetX() const
744 if( !HaveRects() ) return 0;
745 return ((wxRIRefData
*)m_refData
)->m_rects
[m_current
].x
;
748 wxCoord
wxRegionIterator::GetY() const
750 if( !HaveRects() ) return 0;
751 return ((wxRIRefData
*)m_refData
)->m_rects
[m_current
].y
;
754 wxCoord
wxRegionIterator::GetW() const
756 if( !HaveRects() ) return -1;
757 return ((wxRIRefData
*)m_refData
)->m_rects
[m_current
].width
;
760 wxCoord
wxRegionIterator::GetH() const
762 if( !HaveRects() ) return -1;
763 return ((wxRIRefData
*)m_refData
)->m_rects
[m_current
].height
;
766 wxRect
wxRegionIterator::GetRect() const
770 r
= ((wxRIRefData
*)m_refData
)->m_rects
[m_current
];