1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/region.cpp
4 // Author: Robert Roebling
5 // Modified: VZ at 05.10.00: use AllocExclusive(), 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()
104 gdk_region_destroy( m_region
);
107 wxNode
*node
= m_rects
.First();
110 wxRect
*r
= (wxRect
*)node
->Data();
117 // ----------------------------------------------------------------------------
118 // wxRegion construction
119 // ----------------------------------------------------------------------------
121 #define M_REGIONDATA ((wxRegionRefData *)m_refData)
127 void wxRegion::InitRect(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
129 m_refData
= new wxRegionRefData();
130 GdkRegion
*reg
= gdk_region_new();
137 gdk_region_union_with_rect( reg
, &rect
);
138 M_REGIONDATA
->m_region
= reg
;
140 M_REGIONDATA
->m_region
= gdk_region_union_with_rect( reg
, &rect
);
141 gdk_region_destroy( reg
);
145 M_REGIONDATA
->m_rects
.Append( (wxObject
*) new wxRect(x
, y
, w
, h
) );
149 wxRegion::wxRegion( size_t n
, const wxPoint
*points
, int fillStyle
)
151 GdkPoint
*gdkpoints
= new GdkPoint
[n
];
152 for ( size_t i
= 0 ; i
< n
; i
++ )
154 gdkpoints
[i
].x
= points
[i
].x
;
155 gdkpoints
[i
].y
= points
[i
].y
;
158 m_refData
= new wxRegionRefData();
160 GdkRegion
* reg
= gdk_region_polygon
164 fillStyle
== wxWINDING_RULE
? GDK_WINDING_RULE
168 M_REGIONDATA
->m_region
= reg
;
173 wxRegion::~wxRegion()
177 // ----------------------------------------------------------------------------
178 // wxRegion comparison
179 // ----------------------------------------------------------------------------
181 bool wxRegion::operator==( const wxRegion
& region
)
183 // compare the regions themselves, not the pointers to ref data!
184 return gdk_region_equal(M_REGIONDATA
->m_region
,
185 M_REGIONDATA_OF(region
)->m_region
);
188 bool wxRegion::operator != ( const wxRegion
& region
)
190 return !(*this == region
);
193 // ----------------------------------------------------------------------------
194 // wxRegion operations
195 // ----------------------------------------------------------------------------
197 void wxRegion::Clear()
202 bool wxRegion::Union( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
208 rect
.height
= height
;
211 m_refData
= new wxRegionRefData();
212 GdkRegion
*reg
= gdk_region_new();
214 gdk_region_union_with_rect( reg
, &rect
);
215 M_REGIONDATA
->m_region
= reg
;
217 M_REGIONDATA
->m_region
= gdk_region_union_with_rect( reg
, &rect
);
218 gdk_region_destroy( reg
);
226 gdk_region_union_with_rect( M_REGIONDATA
->m_region
, &rect
);
228 GdkRegion
*reg
= gdk_region_union_with_rect( M_REGIONDATA
->m_region
, &rect
);
229 gdk_region_destroy( M_REGIONDATA
->m_region
);
230 M_REGIONDATA
->m_region
= reg
;
235 M_REGIONDATA
->m_rects
.Append( (wxObject
*) new wxRect(x
,y
,width
,height
) );
241 bool wxRegion::Union( const wxRect
& rect
)
243 return Union( rect
.x
, rect
.y
, rect
.width
, rect
.height
);
246 bool wxRegion::Union( const wxRegion
& region
)
254 gdk_region_union( M_REGIONDATA
->m_region
, region
.GetRegion() );
256 GdkRegion
*reg
= gdk_regions_union( M_REGIONDATA
->m_region
, region
.GetRegion() );
257 gdk_region_destroy( M_REGIONDATA
->m_region
);
258 M_REGIONDATA
->m_region
= reg
;
262 wxNode
*node
= region
.GetRectList()->First();
265 wxRect
*r
= (wxRect
*)node
->Data();
266 M_REGIONDATA
->m_rects
.Append( (wxObject
*) new wxRect(r
->x
,r
->y
,r
->width
,r
->height
) );
274 bool wxRegion::Intersect( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
276 wxRegion
reg( x
, y
, width
, height
);
278 return Intersect( reg
);
281 bool wxRegion::Intersect( const wxRect
& rect
)
283 wxRegion
reg( rect
);
284 return Intersect( reg
);
287 // this helper function just computes the region intersection without updating
288 // the list of rectangles each region maintaints: this allows us to call it
289 // from Intersect() itself without going into infinite recursion as we would
290 // if we called Intersect() itself recursively
291 bool wxRegion::IntersectRegionOnly(const wxRegion
& region
)
296 gdk_region_intersect( M_REGIONDATA
->m_region
, region
.GetRegion() );
298 GdkRegion
*reg
= gdk_regions_intersect( M_REGIONDATA
->m_region
, region
.GetRegion() );
299 gdk_region_destroy( M_REGIONDATA
->m_region
);
300 M_REGIONDATA
->m_region
= reg
;
306 bool wxRegion::Intersect( const wxRegion
& region
)
313 m_refData
= new wxRegionRefData();
314 M_REGIONDATA
->m_region
= gdk_region_new();
318 if ( !IntersectRegionOnly(region
) )
320 GetRectList()->Clear();
325 // we need to update the rect list as well
327 wxList
& list
= *GetRectList();
328 wxNode
*node
= list
.First();
331 wxRect
*r
= (wxRect
*)node
->Data();
333 wxRegion regCopy
= region
;
334 if ( regCopy
.IntersectRegionOnly(*r
) )
336 // replace the node with the intersection
337 *r
= regCopy
.GetBox();
341 // TODO remove the rect from the list
353 bool wxRegion::Subtract( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
355 wxRegion
reg( x
, y
, width
, height
);
356 return Subtract( reg
);
359 bool wxRegion::Subtract( const wxRect
& rect
)
361 wxRegion
reg( rect
);
362 return Subtract( reg
);
365 bool wxRegion::Subtract( const wxRegion
& region
)
372 m_refData
= new wxRegionRefData();
373 M_REGIONDATA
->m_region
= gdk_region_new();
379 gdk_region_subtract( M_REGIONDATA
->m_region
, region
.GetRegion() );
381 GdkRegion
*reg
= gdk_regions_subtract( M_REGIONDATA
->m_region
, region
.GetRegion() );
382 gdk_region_destroy( M_REGIONDATA
->m_region
);
383 M_REGIONDATA
->m_region
= reg
;
389 bool wxRegion::Xor( wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
391 wxRegion
reg( x
, y
, width
, height
);
395 bool wxRegion::Xor( const wxRect
& rect
)
397 wxRegion
reg( rect
);
401 bool wxRegion::Xor( const wxRegion
& region
)
408 m_refData
= new wxRegionRefData();
409 M_REGIONDATA
->m_region
= gdk_region_new();
417 gdk_region_xor( M_REGIONDATA
->m_region
, region
.GetRegion() );
419 GdkRegion
*reg
= gdk_regions_xor( M_REGIONDATA
->m_region
, region
.GetRegion() );
420 gdk_region_destroy( M_REGIONDATA
->m_region
);
421 M_REGIONDATA
->m_region
= reg
;
425 wxNode
*node
= region
.GetRectList()->First();
428 wxRect
*r
= (wxRect
*)node
->Data();
429 M_REGIONDATA
->m_rects
.Append( (wxObject
*) new wxRect(r
->x
,r
->y
,r
->width
,r
->height
) );
437 // ----------------------------------------------------------------------------
439 // ----------------------------------------------------------------------------
441 void wxRegion::GetBox( wxCoord
&x
, wxCoord
&y
, wxCoord
&w
, wxCoord
&h
) const
446 gdk_region_get_clipbox( M_REGIONDATA
->m_region
, &rect
);
461 wxRect
wxRegion::GetBox() const
464 GetBox( x
, y
, w
, h
);
465 return wxRect( x
, y
, w
, h
);
468 bool wxRegion::Offset( wxCoord x
, wxCoord y
)
475 gdk_region_offset( M_REGIONDATA
->m_region
, x
, y
);
480 bool wxRegion::Empty() const
485 return gdk_region_empty( M_REGIONDATA
->m_region
);
488 wxRegionContain
wxRegion::Contains( wxCoord x
, wxCoord y
) const
493 if (gdk_region_point_in( M_REGIONDATA
->m_region
, x
, y
))
499 wxRegionContain
wxRegion::Contains( wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
) const
509 GdkOverlapType res
= gdk_region_rect_in( M_REGIONDATA
->m_region
, &rect
);
512 case GDK_OVERLAP_RECTANGLE_IN
: return wxInRegion
;
513 case GDK_OVERLAP_RECTANGLE_OUT
: return wxOutRegion
;
514 case GDK_OVERLAP_RECTANGLE_PART
: return wxPartRegion
;
519 wxRegionContain
wxRegion::Contains(const wxPoint
& pt
) const
521 return Contains( pt
.x
, pt
.y
);
524 wxRegionContain
wxRegion::Contains(const wxRect
& rect
) const
526 return Contains( rect
.x
, rect
.y
, rect
.width
, rect
.height
);
529 GdkRegion
*wxRegion::GetRegion() const
532 return (GdkRegion
*) NULL
;
534 return M_REGIONDATA
->m_region
;
537 wxList
*wxRegion::GetRectList() const
541 return (wxList
*) NULL
;
543 return &(M_REGIONDATA
->m_rects
);
545 return (wxList
*) NULL
;
549 // ----------------------------------------------------------------------------
551 // ----------------------------------------------------------------------------
555 wxRegionIterator::wxRegionIterator()
560 wxRegionIterator::wxRegionIterator( const wxRegion
& region
)
565 void wxRegionIterator::Reset( const wxRegion
& region
)
571 wxRegionIterator::operator bool () const
573 return m_region
.GetRectList() && m_current
< (size_t)m_region
.GetRectList()->Number();
576 bool wxRegionIterator::HaveRects() const
578 return m_region
.GetRectList() && m_current
< (size_t)m_region
.GetRectList()->Number();
581 void wxRegionIterator::operator ++ ()
583 if (HaveRects()) ++m_current
;
586 void wxRegionIterator::operator ++ (int)
588 if (HaveRects()) ++m_current
;
591 wxCoord
wxRegionIterator::GetX() const
593 wxNode
*node
= m_region
.GetRectList()->Nth( m_current
);
595 wxRect
*r
= (wxRect
*)node
->Data();
599 wxCoord
wxRegionIterator::GetY() const
601 wxNode
*node
= m_region
.GetRectList()->Nth( m_current
);
603 wxRect
*r
= (wxRect
*)node
->Data();
607 wxCoord
wxRegionIterator::GetW() const
609 wxNode
*node
= m_region
.GetRectList()->Nth( m_current
);
611 wxRect
*r
= (wxRect
*)node
->Data();
615 wxCoord
wxRegionIterator::GetH() const
617 wxNode
*node
= m_region
.GetRectList()->Nth( m_current
);
619 wxRect
*r
= (wxRect
*)node
->Data();
625 // the following structures must match the private structures
626 // in X11 region code ( xc/lib/X11/region.h )
628 // this makes the Region type transparent
629 // and we have access to the region rectangles
632 short x1
, x2
, y1
, y2
;
636 long size
, numRects
;
637 _XBox
*rects
, extents
;
640 class wxRIRefData
: public wxObjectRefData
644 wxRIRefData() : m_rects(0), m_numRects(0){}
650 void CreateRects( const wxRegion
& r
);
653 wxRIRefData::~wxRIRefData()
658 #include <gdk/gdkprivate.h>
660 void wxRIRefData::CreateRects( const wxRegion
& region
)
666 GdkRegion
*gdkregion
= region
.GetRegion();
668 Region r
= ((GdkRegionPrivate
*)gdkregion
)->xregion
;
670 m_numRects
= r
->numRects
;
673 m_rects
= new wxRect
[m_numRects
];
674 for( size_t i
=0; i
<m_numRects
; ++i
)
676 _XBox
&xr
= r
->rects
[i
];
677 wxRect
&wr
= m_rects
[i
];
680 wr
.width
= xr
.x2
-xr
.x1
;
681 wr
.height
= xr
.y2
-xr
.y1
;
688 wxRegionIterator::wxRegionIterator()
690 m_refData
= new wxRIRefData();
694 wxRegionIterator::wxRegionIterator( const wxRegion
& region
)
696 m_refData
= new wxRIRefData();
700 void wxRegionIterator::Reset( const wxRegion
& region
)
703 ((wxRIRefData
*)m_refData
)->CreateRects(region
);
707 bool wxRegionIterator::HaveRects() const
709 return m_current
< ((wxRIRefData
*)m_refData
)->m_numRects
;
712 wxRegionIterator::operator bool () const
717 void wxRegionIterator::operator ++ ()
719 if (HaveRects()) ++m_current
;
722 void wxRegionIterator::operator ++ (int)
724 if (HaveRects()) ++m_current
;
727 wxCoord
wxRegionIterator::GetX() const
729 if( !HaveRects() ) return 0;
730 return ((wxRIRefData
*)m_refData
)->m_rects
[m_current
].x
;
733 wxCoord
wxRegionIterator::GetY() const
735 if( !HaveRects() ) return 0;
736 return ((wxRIRefData
*)m_refData
)->m_rects
[m_current
].y
;
739 wxCoord
wxRegionIterator::GetW() const
741 if( !HaveRects() ) return -1;
742 return ((wxRIRefData
*)m_refData
)->m_rects
[m_current
].width
;
745 wxCoord
wxRegionIterator::GetH() const
747 if( !HaveRects() ) return -1;
748 return ((wxRIRefData
*)m_refData
)->m_rects
[m_current
].height
;
751 wxRect
wxRegionIterator::GetRect() const
755 r
= ((wxRIRefData
*)m_refData
)->m_rects
[m_current
];
760 #endif // OLDCODE/!OLDCODE