Files
wxWidgets/src/msw/region.cpp
Vadim Zeitlin 8a16d7370e The Great wxRegion Refactoring:
1. added wxRegionBase class and derive all wxRegions from it
2. also added wxRegionWithCombine for the ports providing Combine() method
   (MSW, OS2 and Mac) to reduce code duplication further
3. made sure region comparison works the same way in all ports (except those
   not implementing it) and added IsEqual() method


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@41429 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2006-09-25 11:47:23 +00:00

469 lines
12 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: src/msw/region.cpp
// Purpose: wxRegion implementation using Win32 API
// Author: Vadim Zeitlin
// Modified by:
// Created: Fri Oct 24 10:46:34 MET 1997
// RCS-ID: $Id$
// Copyright: (c) 1997-2002 wxWidgets team
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#include "wx/region.h"
#ifndef WX_PRECOMP
#include "wx/gdicmn.h"
#endif
#include "wx/msw/private.h"
IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject)
IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator, wxObject)
// ----------------------------------------------------------------------------
// wxRegionRefData implementation
// ----------------------------------------------------------------------------
class WXDLLEXPORT wxRegionRefData : public wxGDIRefData
{
public:
wxRegionRefData()
{
m_region = 0;
}
wxRegionRefData(const wxRegionRefData& data) : wxGDIRefData()
{
#if defined(__WIN32__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
DWORD noBytes = ::GetRegionData(data.m_region, 0, NULL);
RGNDATA *rgnData = (RGNDATA*) new char[noBytes];
::GetRegionData(data.m_region, noBytes, rgnData);
m_region = ::ExtCreateRegion(NULL, noBytes, rgnData);
delete[] (char*) rgnData;
#else
RECT rect;
::GetRgnBox(data.m_region, &rect);
m_region = ::CreateRectRgnIndirect(&rect);
#endif
}
virtual ~wxRegionRefData()
{
::DeleteObject(m_region);
m_region = 0;
}
HRGN m_region;
private:
// Cannot use
// DECLARE_NO_COPY_CLASS(wxRegionRefData)
// because copy constructor is explicitly declared above;
// but no copy assignment operator is defined, so declare
// it private to prevent the compiler from defining it:
wxRegionRefData& operator=(const wxRegionRefData&);
};
#define M_REGION (((wxRegionRefData*)m_refData)->m_region)
#define M_REGION_OF(rgn) (((wxRegionRefData*)(rgn.m_refData))->m_region)
// ============================================================================
// wxRegion implementation
// ============================================================================
// ----------------------------------------------------------------------------
// ctors and dtor
// ----------------------------------------------------------------------------
wxRegion::wxRegion()
{
m_refData = (wxRegionRefData *)NULL;
}
wxRegion::wxRegion(WXHRGN hRegion)
{
m_refData = new wxRegionRefData;
M_REGION = (HRGN) hRegion;
}
wxRegion::wxRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
{
m_refData = new wxRegionRefData;
M_REGION = ::CreateRectRgn(x, y, x + w, y + h);
}
wxRegion::wxRegion(const wxPoint& topLeft, const wxPoint& bottomRight)
{
m_refData = new wxRegionRefData;
M_REGION = ::CreateRectRgn(topLeft.x, topLeft.y, bottomRight.x, bottomRight.y);
}
wxRegion::wxRegion(const wxRect& rect)
{
m_refData = new wxRegionRefData;
M_REGION = ::CreateRectRgn(rect.x, rect.y, rect.x + rect.width, rect.y + rect.height);
}
wxRegion::wxRegion(size_t n, const wxPoint *points, int fillStyle)
{
#if defined(__WXMICROWIN__) || defined(__WXWINCE__)
wxUnusedVar(n);
wxUnusedVar(points);
wxUnusedVar(fillStyle);
m_refData = NULL;
M_REGION = NULL;
#else
m_refData = new wxRegionRefData;
M_REGION = ::CreatePolygonRgn
(
(POINT*)points,
n,
fillStyle == wxODDEVEN_RULE ? ALTERNATE : WINDING
);
#endif
}
wxRegion::~wxRegion()
{
// m_refData unrefed in ~wxObject
}
wxObjectRefData *wxRegion::CreateRefData() const
{
return new wxRegionRefData;
}
wxObjectRefData *wxRegion::CloneRefData(const wxObjectRefData *data) const
{
return new wxRegionRefData(*(wxRegionRefData *)data);
}
// ----------------------------------------------------------------------------
// wxRegion operations
// ----------------------------------------------------------------------------
// Clear current region
void wxRegion::Clear()
{
UnRef();
}
bool wxRegion::DoOffset(wxCoord x, wxCoord y)
{
wxCHECK_MSG( M_REGION, false, _T("invalid wxRegion") );
if ( !x && !y )
{
// nothing to do
return true;
}
AllocExclusive();
if ( ::OffsetRgn(GetHrgn(), x, y) == ERROR )
{
wxLogLastError(_T("OffsetRgn"));
return false;
}
return true;
}
// combine another region with this one
bool wxRegion::DoCombine(const wxRegion& rgn, wxRegionOp op)
{
// we can't use the API functions if we don't have a valid region handle
if ( !m_refData )
{
// combining with an empty/invalid region works differently depending
// on the operation
switch ( op )
{
case wxRGN_COPY:
case wxRGN_OR:
case wxRGN_XOR:
*this = rgn;
break;
default:
wxFAIL_MSG( _T("unknown region operation") );
// fall through
case wxRGN_AND:
case wxRGN_DIFF:
// leave empty/invalid
return false;
}
}
else // we have a valid region
{
AllocExclusive();
int mode;
switch ( op )
{
case wxRGN_AND:
mode = RGN_AND;
break;
case wxRGN_OR:
mode = RGN_OR;
break;
case wxRGN_XOR:
mode = RGN_XOR;
break;
case wxRGN_DIFF:
mode = RGN_DIFF;
break;
default:
wxFAIL_MSG( _T("unknown region operation") );
// fall through
case wxRGN_COPY:
mode = RGN_COPY;
break;
}
if ( ::CombineRgn(M_REGION, M_REGION, M_REGION_OF(rgn), mode) == ERROR )
{
wxLogLastError(_T("CombineRgn"));
return false;
}
}
return true;
}
// ----------------------------------------------------------------------------
// wxRegion bounding box
// ----------------------------------------------------------------------------
// Outer bounds of region
bool wxRegion::DoGetBox(wxCoord& x, wxCoord& y, wxCoord&w, wxCoord &h) const
{
if (m_refData)
{
RECT rect;
::GetRgnBox(M_REGION, & rect);
x = rect.left;
y = rect.top;
w = rect.right - rect.left;
h = rect.bottom - rect.top;
return true;
}
else
{
x = y = w = h = 0;
return false;
}
}
// Is region empty?
bool wxRegion::IsEmpty() const
{
wxCoord x, y, w, h;
GetBox(x, y, w, h);
return (w == 0) && (h == 0);
}
bool wxRegion::DoIsEqual(const wxRegion& region) const
{
return ::EqualRgn(M_REGION, M_REGION_OF(region)) != 0;
}
// ----------------------------------------------------------------------------
// wxRegion hit testing
// ----------------------------------------------------------------------------
// Does the region contain the point (x,y)?
wxRegionContain wxRegion::DoContainsPoint(wxCoord x, wxCoord y) const
{
if (!m_refData)
return wxOutRegion;
return ::PtInRegion(M_REGION, (int) x, (int) y) ? wxInRegion : wxOutRegion;
}
// Does the region contain the rectangle (x, y, w, h)?
wxRegionContain wxRegion::DoContainsRect(const wxRect& rect) const
{
if (!m_refData)
return wxOutRegion;
RECT rc;
wxCopyRectToRECT(rect, rc);
return ::RectInRegion(M_REGION, &rc) ? wxInRegion : wxOutRegion;
}
// Get internal region handle
WXHRGN wxRegion::GetHRGN() const
{
return (WXHRGN)(m_refData ? M_REGION : 0);
}
// ============================================================================
// wxRegionIterator implementation
// ============================================================================
// ----------------------------------------------------------------------------
// wxRegionIterator ctors/dtor
// ----------------------------------------------------------------------------
void wxRegionIterator::Init()
{
m_current =
m_numRects = 0;
m_rects = NULL;
}
wxRegionIterator::~wxRegionIterator()
{
delete [] m_rects;
}
// Initialize iterator for region
wxRegionIterator::wxRegionIterator(const wxRegion& region)
{
m_rects = NULL;
Reset(region);
}
wxRegionIterator& wxRegionIterator::operator=(const wxRegionIterator& ri)
{
delete [] m_rects;
m_current = ri.m_current;
m_numRects = ri.m_numRects;
if ( m_numRects )
{
m_rects = new wxRect[m_numRects];
for ( long n = 0; n < m_numRects; n++ )
m_rects[n] = ri.m_rects[n];
}
else
{
m_rects = NULL;
}
return *this;
}
// ----------------------------------------------------------------------------
// wxRegionIterator operations
// ----------------------------------------------------------------------------
// Reset iterator for a new region.
void wxRegionIterator::Reset(const wxRegion& region)
{
m_current = 0;
m_region = region;
if (m_rects)
{
delete[] m_rects;
m_rects = NULL;
}
if (m_region.Empty())
m_numRects = 0;
else
{
DWORD noBytes = ::GetRegionData(((wxRegionRefData*)region.m_refData)->m_region, 0, NULL);
RGNDATA *rgnData = (RGNDATA*) new char[noBytes];
::GetRegionData(((wxRegionRefData*)region.m_refData)->m_region, noBytes, rgnData);
RGNDATAHEADER* header = (RGNDATAHEADER*) rgnData;
m_rects = new wxRect[header->nCount];
RECT* rect = (RECT*) ((char*)rgnData + sizeof(RGNDATAHEADER));
size_t i;
for (i = 0; i < header->nCount; i++)
{
m_rects[i] = wxRect(rect->left, rect->top,
rect->right - rect->left, rect->bottom - rect->top);
rect ++; // Advances pointer by sizeof(RECT)
}
m_numRects = header->nCount;
delete[] (char*) rgnData;
}
}
wxRegionIterator& wxRegionIterator::operator++()
{
if (m_current < m_numRects)
++m_current;
return *this;
}
wxRegionIterator wxRegionIterator::operator ++ (int)
{
wxRegionIterator tmp = *this;
if (m_current < m_numRects)
++m_current;
return tmp;
}
// ----------------------------------------------------------------------------
// wxRegionIterator accessors
// ----------------------------------------------------------------------------
wxCoord wxRegionIterator::GetX() const
{
wxCHECK_MSG( m_current < m_numRects, 0, _T("invalid wxRegionIterator") );
return m_rects[m_current].x;
}
wxCoord wxRegionIterator::GetY() const
{
wxCHECK_MSG( m_current < m_numRects, 0, _T("invalid wxRegionIterator") );
return m_rects[m_current].y;
}
wxCoord wxRegionIterator::GetW() const
{
wxCHECK_MSG( m_current < m_numRects, 0, _T("invalid wxRegionIterator") );
return m_rects[m_current].width;
}
wxCoord wxRegionIterator::GetH() const
{
wxCHECK_MSG( m_current < m_numRects, 0, _T("invalid wxRegionIterator") );
return m_rects[m_current].height;
}