1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Region class
4 // Author: Julian Smart
5 // Created: Fri Oct 24 10:46:34 MET 1997
7 // Copyright: (c) 1997 Julian Smart
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
12 #pragma implementation "region.h"
15 #include "wx/region.h"
16 #include "wx/gdicmn.h"
19 #pragma message disable nosimpint
23 #pragma message enable nosimpint
25 // #include "wx/motif/private.h"
27 IMPLEMENT_DYNAMIC_CLASS(wxRegion
, wxGDIObject
)
28 IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator
, wxObject
)
30 // ----------------------------------------------------------------------------
32 // ----------------------------------------------------------------------------
34 #include "wx/listimpl.cpp"
36 WX_DEFINE_LIST(wxRectList
);
38 //-----------------------------------------------------------------------------
39 // wxRegionRefData implementation
40 //-----------------------------------------------------------------------------
42 class WXDLLEXPORT wxRegionRefData
: public wxGDIRefData
{
46 m_region
= XCreateRegion();
48 m_rects
= (wxRect
*) NULL
;
52 wxRegionRefData(const wxRegionRefData
& data
)
54 m_region
= XCreateRegion();
55 m_rects
= (wxRect
*) NULL
;
57 XUnionRegion(m_region
, data
.m_region
, m_region
);
59 SetRects(data
.m_rectCount
, data
.m_rects
);
64 XDestroyRegion(m_region
);
68 wxRect
* GetRects() { return m_rects
; };
69 void SetRects(const wxRectList
& rectList
);
70 void SetRects(int count
, const wxRect
* rects
);
71 bool UsingRects() const { return m_usingRects
; }
72 int GetRectCount() const { return m_rectCount
; }
79 bool m_usingRects
; // TRUE if we're using the above.
82 void wxRegionRefData::SetRects(const wxRectList
& rectList
)
85 m_usingRects
= (rectList
.GetCount() > 0);
88 m_rectCount
= rectList
.GetCount();
89 m_rects
= new wxRect
[m_rectCount
];
92 wxRectList::Node
* node
= rectList
.GetFirst();
95 wxRect
* rect
= node
->GetData();
97 node
= node
->GetNext();
102 void wxRegionRefData::SetRects(int count
, const wxRect
* rects
)
105 m_usingRects
= (count
> 0);
109 m_rects
= new wxRect
[m_rectCount
];
111 for (i
= 0; i
< m_rectCount
; i
++)
112 m_rects
[i
] = rects
[i
];
116 void wxRegionRefData::DeleteRects()
121 m_rects
= (wxRect
*) NULL
;
124 m_usingRects
= FALSE
;
127 #define M_REGION (((wxRegionRefData*)m_refData)->m_region)
129 //-----------------------------------------------------------------------------
131 //-----------------------------------------------------------------------------
134 * Create an empty region.
140 wxRegion::wxRegion(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
142 m_refData
= new wxRegionRefData
;
149 XUnionRectWithRegion(&rect
, M_REGION
, M_REGION
);
152 wxRegion::wxRegion(const wxPoint
& topLeft
, const wxPoint
& bottomRight
)
154 m_refData
= new wxRegionRefData
;
159 rect
.width
= bottomRight
.x
- topLeft
.x
;
160 rect
.height
= bottomRight
.y
- topLeft
.y
;
161 XUnionRectWithRegion(&rect
, M_REGION
, M_REGION
);
164 wxRegion::wxRegion(const wxRect
& rect
)
166 m_refData
= new wxRegionRefData
;
171 rect1
.width
= rect
.width
;
172 rect1
.height
= rect
.height
;
173 XUnionRectWithRegion(&rect1
, M_REGION
, M_REGION
);
177 * Destroy the region.
179 wxRegion::~wxRegion()
181 // m_refData unrefed in ~wxObject
184 // Get the internal region handle
185 WXRegion
wxRegion::GetXRegion() const
187 wxASSERT( m_refData
!=NULL
);
189 return (WXRegion
) ((wxRegionRefData
*)m_refData
)->m_region
;
192 //-----------------------------------------------------------------------------
194 //-----------------------------------------------------------------------------
196 //! Clear current region
197 void wxRegion::Clear()
202 //! Combine rectangle (x, y, w, h) with this.
204 wxRegion::Combine(wxCoord x
, wxCoord y
,
205 wxCoord width
, wxCoord height
,
208 // work around for XUnionRectWithRegion() bug: taking a union with an empty
209 // rect results in an empty region (at least XFree 3.3.6 and 4.0 have this
211 if ( op
== wxRGN_OR
&& (!width
|| !height
) )
214 // Don't change shared data
216 m_refData
= new wxRegionRefData();
217 } else if (m_refData
->GetRefCount() > 1) {
218 wxRegionRefData
* ref
= (wxRegionRefData
*)m_refData
;
220 m_refData
= new wxRegionRefData(*ref
);
222 // If ref count is 1, that means it's 'ours' anyway so no action.
224 Region rectRegion
= XCreateRegion();
230 rect
.height
= height
;
231 XUnionRectWithRegion(&rect
, rectRegion
, rectRegion
);
236 XIntersectRegion(M_REGION
, rectRegion
, M_REGION
);
239 XUnionRegion(M_REGION
, rectRegion
, M_REGION
);
247 case wxRGN_COPY
: // Don't have to do this one
256 //! Union /e region with this.
257 bool wxRegion::Combine(const wxRegion
& region
, wxRegionOp op
)
262 // Don't change shared data
264 m_refData
= new wxRegionRefData();
265 } else if (m_refData
->GetRefCount() > 1) {
266 wxRegionRefData
* ref
= (wxRegionRefData
*)m_refData
;
268 m_refData
= new wxRegionRefData(*ref
);
274 XIntersectRegion(M_REGION
, ((wxRegionRefData
*)region
.m_refData
)->m_region
,
278 XUnionRegion(M_REGION
, ((wxRegionRefData
*)region
.m_refData
)->m_region
,
287 case wxRGN_COPY
: // Don't have to do this one
296 bool wxRegion::Combine(const wxRect
& rect
, wxRegionOp op
)
298 return Combine(rect
.GetLeft(), rect
.GetTop(), rect
.GetWidth(), rect
.GetHeight(), op
);
301 //-----------------------------------------------------------------------------
302 //# Information on region
303 //-----------------------------------------------------------------------------
305 // Outer bounds of region
306 void wxRegion::GetBox(wxCoord
& x
, wxCoord
& y
, wxCoord
&w
, wxCoord
&h
) const
310 XClipBox(M_REGION
, &rect
);
320 wxRect
wxRegion::GetBox() const
324 return wxRect(x
, y
, w
, h
);
328 bool wxRegion::Empty() const
330 return m_refData
? XEmptyRegion(M_REGION
) : TRUE
;
333 //-----------------------------------------------------------------------------
335 //-----------------------------------------------------------------------------
337 // Does the region contain the point (x,y)?
338 wxRegionContain
wxRegion::Contains(wxCoord
WXUNUSED(x
), wxCoord
WXUNUSED(y
)) const
343 // TODO. Return wxInRegion if within region.
349 // Does the region contain the point pt?
350 wxRegionContain
wxRegion::Contains(const wxPoint
& pt
) const
355 return XPointInRegion(M_REGION
, pt
.x
, pt
.y
) ? wxInRegion
: wxOutRegion
;
358 // Does the region contain the rectangle (x, y, w, h)?
359 wxRegionContain
wxRegion::Contains(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
) const
364 switch (XRectInRegion(M_REGION
, x
, y
, w
, h
)) {
365 case RectangleIn
: return wxInRegion
;
366 case RectanglePart
: return wxPartRegion
;
371 // Does the region contain the rectangle rect
372 wxRegionContain
wxRegion::Contains(const wxRect
& rect
) const
381 h
= rect
.GetHeight();
382 return Contains(x
, y
, w
, h
);
385 bool wxRegion::UsingRects() const
387 return ((wxRegionRefData
*)m_refData
)->UsingRects();
391 wxRectList& wxRegion::GetRectList()
393 return ((wxRegionRefData*)m_refData)->GetRectList();
397 wxRect
* wxRegion::GetRects()
399 return ((wxRegionRefData
*)m_refData
)->GetRects();
402 int wxRegion::GetRectCount() const
404 return ((wxRegionRefData
*)m_refData
)->GetRectCount();
407 void wxRegion::SetRects(const wxRectList
& rectList
)
409 ((wxRegionRefData
*)m_refData
)->SetRects(rectList
);
412 void wxRegion::SetRects(int count
, const wxRect
* rects
)
414 ((wxRegionRefData
*)m_refData
)->SetRects(count
, rects
);
417 ///////////////////////////////////////////////////////////////////////////////
419 // wxRegionIterator //
421 ///////////////////////////////////////////////////////////////////////////////
424 * Initialize empty iterator
426 wxRegionIterator::wxRegionIterator() : m_current(0), m_numRects(0), m_rects(NULL
)
430 wxRegionIterator::~wxRegionIterator()
437 * Initialize iterator for region
439 wxRegionIterator::wxRegionIterator(const wxRegion
& region
)
447 * Reset iterator for a new /e region.
449 void wxRegionIterator::Reset(const wxRegion
& region
)
459 if (m_region
.Empty())
463 // Create m_rects and fill with rectangles for this region.
464 // Since we can't find the rectangles in a region, we cheat
465 // by retrieving the rectangles explicitly set in wxPaintDC::wxPaintDC
467 if (m_region
.UsingRects())
469 wxRect
* rects
= m_region
.GetRects();
470 int count
= m_region
.GetRectCount();
472 m_rects
= new wxRect
[m_numRects
];
474 for (size_t i
= 0; i
< m_numRects
; i
++)
475 m_rects
[i
] = rects
[i
];
479 wxRectList::Node* node = rectList.GetFirst();
481 wxRect* rect = node->GetData();
483 node = node->GetNext();
490 // For now, fudge by getting the whole bounding box.
491 m_rects
= new wxRect
[1];
493 m_rects
[0] = m_region
.GetBox();
499 * Increment iterator. The rectangle returned is the one after the
502 void wxRegionIterator::operator ++ ()
504 if (m_current
< m_numRects
)
509 * Increment iterator. The rectangle returned is the one before the
512 void wxRegionIterator::operator ++ (int)
514 if (m_current
< m_numRects
)
518 wxCoord
wxRegionIterator::GetX() const
520 if (m_current
< m_numRects
)
521 return m_rects
[m_current
].x
;
525 wxCoord
wxRegionIterator::GetY() const
527 if (m_current
< m_numRects
)
528 return m_rects
[m_current
].y
;
532 wxCoord
wxRegionIterator::GetW() const
534 if (m_current
< m_numRects
)
535 return m_rects
[m_current
].width
;
539 wxCoord
wxRegionIterator::GetH() const
541 if (m_current
< m_numRects
)
542 return m_rects
[m_current
].height
;