///////////////////////////////////////////////////////////////////////////// // Name: region.cpp // Purpose: Region handling for wxWindows/MGL // Author: Vaclav Slavik // RCS-ID: $Id$ // Copyright: (c) 2001-2002 SciTech Software, Inc. (www.scitechsoft.com) // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// #ifdef __GNUG__ #pragma implementation "region.h" #endif // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ #pragma hdrstop #endif #include "wx/region.h" #include "wx/gdicmn.h" #include "wx/thread.h" #include "wx/module.h" #include #include "wx/listimpl.cpp" WX_DEFINE_LIST(wxRegionRectList) IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject) IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator, wxObject) //----------------------------------------------------------------------------- // wxRegionRefData implementation //----------------------------------------------------------------------------- class WXDLLEXPORT wxRegionRefData : public wxGDIRefData { public: wxRegionRefData() {} wxRegionRefData(const wxRegionRefData& data) { m_region = data.m_region; } ~wxRegionRefData() {} MGLRegion m_region; }; #define M_REGION (((wxRegionRefData*)m_refData)->m_region) #define M_REGION_OF(r) (((wxRegionRefData*)(r.m_refData))->m_region) //----------------------------------------------------------------------------- // wxRegion //----------------------------------------------------------------------------- wxObjectRefData *wxRegion::CreateRefData() const { return new wxRegionRefData; } wxObjectRefData *wxRegion::CloneRefData(const wxObjectRefData *data) const { return new wxRegionRefData(*(wxRegionRefData *)data); } /* * Create an empty region. */ wxRegion::wxRegion() { m_refData = NULL; } wxRegion::wxRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h) { m_refData = new wxRegionRefData; MGLRect rect(x, y, x + w, y + h); M_REGION = rect; } wxRegion::wxRegion(const wxPoint& topLeft, const wxPoint& bottomRight) { m_refData = new wxRegionRefData; MGLRect rect(topLeft.x, topLeft.y, bottomRight.x+1, bottomRight.y+1); M_REGION = rect; } wxRegion::wxRegion(const wxRect& r) { m_refData = new wxRegionRefData; MGLRect rect(r.GetLeft(), r.GetTop(), r.GetRight()+1, r.GetBottom()+1); M_REGION = rect; } wxRegion::wxRegion(const MGLRegion& region) { m_refData = new wxRegionRefData; M_REGION = region; } wxRegion::~wxRegion() { // m_refData unrefed in ~wxObject } const MGLRegion& wxRegion::GetMGLRegion() const { return M_REGION; } //----------------------------------------------------------------------------- // Modify region //----------------------------------------------------------------------------- // Clear current region void wxRegion::Clear() { UnRef(); } //----------------------------------------------------------------------------- // Information on region //----------------------------------------------------------------------------- // Outer bounds of region void wxRegion::GetBox(wxCoord& x, wxCoord& y, wxCoord&w, wxCoord &h) const { if (m_refData) { rect_t rect; rect = M_REGION.getBounds(); x = rect.left; y = rect.top; w = rect.right - rect.left; h = rect.bottom - rect.top; } else { x = y = w = h = 0; } } wxRect wxRegion::GetBox() const { wxCoord x, y, w, h; GetBox(x, y, w, h); return wxRect(x, y, w, h); } // Is region empty? bool wxRegion::Empty() const { if (!m_refData) return TRUE; return M_REGION.isEmpty(); } //----------------------------------------------------------------------------- // Modifications //----------------------------------------------------------------------------- bool wxRegion::Offset(wxCoord x, wxCoord y) { AllocExclusive(); M_REGION.offset(x, y); return TRUE; } // Union rectangle or region with this. bool wxRegion::Union(wxCoord x, wxCoord y, wxCoord width, wxCoord height) { AllocExclusive(); M_REGION += MGLRect(x, y, x + width, y + height); return TRUE; } bool wxRegion::Union(const wxRegion& region) { AllocExclusive(); M_REGION += M_REGION_OF(region); return TRUE; } // Intersect rectangle or region with this. bool wxRegion::Intersect(wxCoord x, wxCoord y, wxCoord width, wxCoord height) { AllocExclusive(); M_REGION &= MGLRect(x, y, x + width, y + height); return TRUE; } bool wxRegion::Intersect(const wxRegion& region) { AllocExclusive(); M_REGION &= M_REGION_OF(region); return TRUE; } // Subtract rectangle or region from this: // Combines the parts of 'this' that are not part of the second region. bool wxRegion::Subtract(wxCoord x, wxCoord y, wxCoord width, wxCoord height) { AllocExclusive(); M_REGION -= MGLRect(x, y, x + width, y + height); return TRUE; } bool wxRegion::Subtract(const wxRegion& region) { AllocExclusive(); M_REGION -= M_REGION_OF(region); return TRUE; } // XOR: the union of two combined regions except for any overlapping areas. bool wxRegion::Xor(wxCoord x, wxCoord y, wxCoord width, wxCoord height) { AllocExclusive(); MGLRect rect(x, y, x + width, y + height); MGLRegion rg1 = M_REGION + rect, rg2 = M_REGION & rect; M_REGION = rg1 - rg2; return TRUE; } bool wxRegion::Xor(const wxRegion& region) { AllocExclusive(); MGLRegion rg1 = M_REGION + M_REGION_OF(region), rg2 = M_REGION & M_REGION_OF(region); M_REGION = rg1 - rg2; return TRUE; } //----------------------------------------------------------------------------- // Tests //----------------------------------------------------------------------------- // Does the region contain the point (x,y)? wxRegionContain wxRegion::Contains(wxCoord x, wxCoord y) const { if (!m_refData) return wxOutRegion; if (M_REGION.includes((int)x, (int)y)) return wxInRegion; else return wxOutRegion; } // Does the region contain the point pt? wxRegionContain wxRegion::Contains(const wxPoint& pt) const { return Contains(pt.x, pt.y); } // Does the region contain the rectangle (x, y, w, h)? wxRegionContain wxRegion::Contains(wxCoord x, wxCoord y, wxCoord w, wxCoord h) const { if (!m_refData) return wxOutRegion; MGLRect rect(x, y, x + w, y + h); MGLRegion rg; // 1) is the rectangle entirely covered by the region? rg = MGLRegion(rect) - M_REGION; if (rg.isEmpty()) return wxInRegion; // 2) is the rectangle completely outside the region? rg = M_REGION & rect; // intersection if (rg.isEmpty()) return wxOutRegion; // 3) neither case happened => it is partially covered: return wxPartRegion; } // Does the region contain the rectangle rect wxRegionContain wxRegion::Contains(const wxRect& rect) const { return Contains(rect.x, rect.y, rect.width, rect.height); } /////////////////////////////////////////////////////////////////////////////// // wxRegionIterator // /////////////////////////////////////////////////////////////////////////////// #if wxUSE_THREADS static wxMutex *gs_mutexIterator; class wxMglRegionModule : public wxModule { public: virtual bool OnInit() { gs_mutexIterator = new wxMutex(); return TRUE; } virtual void OnExit() { wxDELETE(gs_mutexIterator); } DECLARE_DYNAMIC_CLASS(wxMglRegionModule) }; IMPLEMENT_DYNAMIC_CLASS(wxMglRegionModule, wxModule) #endif /* * Initialize empty iterator */ wxRegionIterator::wxRegionIterator() : m_currentNode(NULL) { m_rects.DeleteContents(TRUE); } wxRegionIterator::~wxRegionIterator() { } /* * Initialize iterator for region */ wxRegionIterator::wxRegionIterator(const wxRegion& region) { m_rects.DeleteContents(TRUE); Reset(region); } /* * Reset iterator for a new /e region. */ static wxRegionRectList *gs_rectList; static void MGLAPI wxMGL_region_callback(const rect_t *r) { gs_rectList->Append(new wxRect(r->left, r->top, r->right - r->left, r->bottom - r->top)); } void wxRegionIterator::Reset(const wxRegion& region) { m_currentNode = NULL; m_rects.Clear(); if (!region.Empty()) { #if wxUSE_THREADS wxMutexLocker(*gs_mutexIterator); #endif gs_rectList = &m_rects; M_REGION_OF(region).traverse(wxMGL_region_callback); m_currentNode = m_rects.GetFirst(); } } /* * Increment iterator. The rectangle returned is the one after the * incrementation. */ void wxRegionIterator::operator ++ () { if (m_currentNode) m_currentNode = m_currentNode->GetNext(); } /* * Increment iterator. The rectangle returned is the one before the * incrementation. */ void wxRegionIterator::operator ++ (int) { if (m_currentNode) m_currentNode = m_currentNode->GetNext(); } wxCoord wxRegionIterator::GetX() const { if (m_currentNode) return m_currentNode->GetData()->x; else return 0; } wxCoord wxRegionIterator::GetY() const { if (m_currentNode) return m_currentNode->GetData()->y; else return 0; } wxCoord wxRegionIterator::GetW() const { if (m_currentNode) return m_currentNode->GetData()->width; else return 0; } wxCoord wxRegionIterator::GetH() const { if (m_currentNode) return m_currentNode->GetData()->height; else return 0; }