1///////////////////////////////////////////////////////////////////////////// 2// Name: src/msw/region.cpp 3// Purpose: wxRegion implementation using Win32 API 4// Author: Vadim Zeitlin 5// Modified by: 6// Created: Fri Oct 24 10:46:34 MET 1997 7// RCS-ID: $Id: region.cpp 41429 2006-09-25 11:47:23Z VZ $ 8// Copyright: (c) 1997-2002 wxWidgets team 9// Licence: wxWindows licence 10///////////////////////////////////////////////////////////////////////////// 11 12// ============================================================================ 13// declarations 14// ============================================================================ 15 16// ---------------------------------------------------------------------------- 17// headers 18// ---------------------------------------------------------------------------- 19 20// For compilers that support precompilation, includes "wx.h". 21#include "wx/wxprec.h" 22 23#ifdef __BORLANDC__ 24 #pragma hdrstop 25#endif 26 27#include "wx/region.h" 28 29#ifndef WX_PRECOMP 30 #include "wx/gdicmn.h" 31#endif 32 33#include "wx/msw/private.h" 34 35IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject) 36IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator, wxObject) 37 38// ---------------------------------------------------------------------------- 39// wxRegionRefData implementation 40// ---------------------------------------------------------------------------- 41 42class WXDLLEXPORT wxRegionRefData : public wxGDIRefData 43{ 44public: 45 wxRegionRefData() 46 { 47 m_region = 0; 48 } 49 50 wxRegionRefData(const wxRegionRefData& data) : wxGDIRefData() 51 { 52#if defined(__WIN32__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__) 53 DWORD noBytes = ::GetRegionData(data.m_region, 0, NULL); 54 RGNDATA *rgnData = (RGNDATA*) new char[noBytes]; 55 ::GetRegionData(data.m_region, noBytes, rgnData); 56 m_region = ::ExtCreateRegion(NULL, noBytes, rgnData); 57 delete[] (char*) rgnData; 58#else 59 RECT rect; 60 ::GetRgnBox(data.m_region, &rect); 61 m_region = ::CreateRectRgnIndirect(&rect); 62#endif 63 } 64 65 virtual ~wxRegionRefData() 66 { 67 ::DeleteObject(m_region); 68 m_region = 0; 69 } 70 71 HRGN m_region; 72 73private: 74// Cannot use 75// DECLARE_NO_COPY_CLASS(wxRegionRefData) 76// because copy constructor is explicitly declared above; 77// but no copy assignment operator is defined, so declare 78// it private to prevent the compiler from defining it: 79 wxRegionRefData& operator=(const wxRegionRefData&); 80}; 81 82#define M_REGION (((wxRegionRefData*)m_refData)->m_region) 83#define M_REGION_OF(rgn) (((wxRegionRefData*)(rgn.m_refData))->m_region) 84 85// ============================================================================ 86// wxRegion implementation 87// ============================================================================ 88 89// ---------------------------------------------------------------------------- 90// ctors and dtor 91// ---------------------------------------------------------------------------- 92 93wxRegion::wxRegion() 94{ 95 m_refData = (wxRegionRefData *)NULL; 96} 97 98wxRegion::wxRegion(WXHRGN hRegion) 99{ 100 m_refData = new wxRegionRefData; 101 M_REGION = (HRGN) hRegion; 102} 103 104wxRegion::wxRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h) 105{ 106 m_refData = new wxRegionRefData; 107 M_REGION = ::CreateRectRgn(x, y, x + w, y + h); 108} 109 110wxRegion::wxRegion(const wxPoint& topLeft, const wxPoint& bottomRight) 111{ 112 m_refData = new wxRegionRefData; 113 M_REGION = ::CreateRectRgn(topLeft.x, topLeft.y, bottomRight.x, bottomRight.y); 114} 115 116wxRegion::wxRegion(const wxRect& rect) 117{ 118 m_refData = new wxRegionRefData; 119 M_REGION = ::CreateRectRgn(rect.x, rect.y, rect.x + rect.width, rect.y + rect.height); 120} 121 122wxRegion::wxRegion(size_t n, const wxPoint *points, int fillStyle) 123{ 124#if defined(__WXMICROWIN__) || defined(__WXWINCE__) 125 wxUnusedVar(n); 126 wxUnusedVar(points); 127 wxUnusedVar(fillStyle); 128 m_refData = NULL; 129 M_REGION = NULL; 130#else 131 m_refData = new wxRegionRefData; 132 M_REGION = ::CreatePolygonRgn 133 ( 134 (POINT*)points, 135 n, 136 fillStyle == wxODDEVEN_RULE ? ALTERNATE : WINDING 137 ); 138#endif 139} 140 141wxRegion::~wxRegion() 142{ 143 // m_refData unrefed in ~wxObject 144} 145 146wxObjectRefData *wxRegion::CreateRefData() const 147{ 148 return new wxRegionRefData; 149} 150 151wxObjectRefData *wxRegion::CloneRefData(const wxObjectRefData *data) const 152{ 153 return new wxRegionRefData(*(wxRegionRefData *)data); 154} 155 156// ---------------------------------------------------------------------------- 157// wxRegion operations 158// ---------------------------------------------------------------------------- 159 160// Clear current region 161void wxRegion::Clear() 162{ 163 UnRef(); 164} 165 166bool wxRegion::DoOffset(wxCoord x, wxCoord y) 167{ 168 wxCHECK_MSG( M_REGION, false, _T("invalid wxRegion") ); 169 170 if ( !x && !y ) 171 { 172 // nothing to do 173 return true; 174 } 175 176 AllocExclusive(); 177 178 if ( ::OffsetRgn(GetHrgn(), x, y) == ERROR ) 179 { 180 wxLogLastError(_T("OffsetRgn")); 181 182 return false; 183 } 184 185 return true; 186} 187 188// combine another region with this one 189bool wxRegion::DoCombine(const wxRegion& rgn, wxRegionOp op) 190{ 191 // we can't use the API functions if we don't have a valid region handle 192 if ( !m_refData ) 193 { 194 // combining with an empty/invalid region works differently depending 195 // on the operation 196 switch ( op ) 197 { 198 case wxRGN_COPY: 199 case wxRGN_OR: 200 case wxRGN_XOR: 201 *this = rgn; 202 break; 203 204 default: 205 wxFAIL_MSG( _T("unknown region operation") ); 206 // fall through 207 208 case wxRGN_AND: 209 case wxRGN_DIFF: 210 // leave empty/invalid 211 return false; 212 } 213 } 214 else // we have a valid region 215 { 216 AllocExclusive(); 217 218 int mode; 219 switch ( op ) 220 { 221 case wxRGN_AND: 222 mode = RGN_AND; 223 break; 224 225 case wxRGN_OR: 226 mode = RGN_OR; 227 break; 228 229 case wxRGN_XOR: 230 mode = RGN_XOR; 231 break; 232 233 case wxRGN_DIFF: 234 mode = RGN_DIFF; 235 break; 236 237 default: 238 wxFAIL_MSG( _T("unknown region operation") ); 239 // fall through 240 241 case wxRGN_COPY: 242 mode = RGN_COPY; 243 break; 244 } 245 246 if ( ::CombineRgn(M_REGION, M_REGION, M_REGION_OF(rgn), mode) == ERROR ) 247 { 248 wxLogLastError(_T("CombineRgn")); 249 250 return false; 251 } 252 } 253 254 return true; 255} 256 257// ---------------------------------------------------------------------------- 258// wxRegion bounding box 259// ---------------------------------------------------------------------------- 260 261// Outer bounds of region 262bool wxRegion::DoGetBox(wxCoord& x, wxCoord& y, wxCoord&w, wxCoord &h) const 263{ 264 if (m_refData) 265 { 266 RECT rect; 267 ::GetRgnBox(M_REGION, & rect); 268 x = rect.left; 269 y = rect.top; 270 w = rect.right - rect.left; 271 h = rect.bottom - rect.top; 272 273 return true; 274 } 275 else 276 { 277 x = y = w = h = 0; 278 279 return false; 280 } 281} 282 283// Is region empty? 284bool wxRegion::IsEmpty() const 285{ 286 wxCoord x, y, w, h; 287 GetBox(x, y, w, h); 288 289 return (w == 0) && (h == 0); 290} 291 292bool wxRegion::DoIsEqual(const wxRegion& region) const 293{ 294 return ::EqualRgn(M_REGION, M_REGION_OF(region)) != 0; 295} 296 297// ---------------------------------------------------------------------------- 298// wxRegion hit testing 299// ---------------------------------------------------------------------------- 300 301// Does the region contain the point (x,y)? 302wxRegionContain wxRegion::DoContainsPoint(wxCoord x, wxCoord y) const 303{ 304 if (!m_refData) 305 return wxOutRegion; 306 307 return ::PtInRegion(M_REGION, (int) x, (int) y) ? wxInRegion : wxOutRegion; 308} 309 310// Does the region contain the rectangle (x, y, w, h)? 311wxRegionContain wxRegion::DoContainsRect(const wxRect& rect) const 312{ 313 if (!m_refData) 314 return wxOutRegion; 315 316 RECT rc; 317 wxCopyRectToRECT(rect, rc); 318 319 return ::RectInRegion(M_REGION, &rc) ? wxInRegion : wxOutRegion; 320} 321 322// Get internal region handle 323WXHRGN wxRegion::GetHRGN() const 324{ 325 return (WXHRGN)(m_refData ? M_REGION : 0); 326} 327 328// ============================================================================ 329// wxRegionIterator implementation 330// ============================================================================ 331 332// ---------------------------------------------------------------------------- 333// wxRegionIterator ctors/dtor 334// ---------------------------------------------------------------------------- 335 336void wxRegionIterator::Init() 337{ 338 m_current = 339 m_numRects = 0; 340 341 m_rects = NULL; 342} 343 344wxRegionIterator::~wxRegionIterator() 345{ 346 delete [] m_rects; 347} 348 349// Initialize iterator for region 350wxRegionIterator::wxRegionIterator(const wxRegion& region) 351{ 352 m_rects = NULL; 353 354 Reset(region); 355} 356 357wxRegionIterator& wxRegionIterator::operator=(const wxRegionIterator& ri) 358{ 359 delete [] m_rects; 360 361 m_current = ri.m_current; 362 m_numRects = ri.m_numRects; 363 if ( m_numRects ) 364 { 365 m_rects = new wxRect[m_numRects]; 366 for ( long n = 0; n < m_numRects; n++ ) 367 m_rects[n] = ri.m_rects[n]; 368 } 369 else 370 { 371 m_rects = NULL; 372 } 373 374 return *this; 375} 376 377// ---------------------------------------------------------------------------- 378// wxRegionIterator operations 379// ---------------------------------------------------------------------------- 380 381// Reset iterator for a new region. 382void wxRegionIterator::Reset(const wxRegion& region) 383{ 384 m_current = 0; 385 m_region = region; 386 387 if (m_rects) 388 { 389 delete[] m_rects; 390 391 m_rects = NULL; 392 } 393 394 if (m_region.Empty()) 395 m_numRects = 0; 396 else 397 { 398 DWORD noBytes = ::GetRegionData(((wxRegionRefData*)region.m_refData)->m_region, 0, NULL); 399 RGNDATA *rgnData = (RGNDATA*) new char[noBytes]; 400 ::GetRegionData(((wxRegionRefData*)region.m_refData)->m_region, noBytes, rgnData); 401 402 RGNDATAHEADER* header = (RGNDATAHEADER*) rgnData; 403 404 m_rects = new wxRect[header->nCount]; 405 406 RECT* rect = (RECT*) ((char*)rgnData + sizeof(RGNDATAHEADER)); 407 size_t i; 408 for (i = 0; i < header->nCount; i++) 409 { 410 m_rects[i] = wxRect(rect->left, rect->top, 411 rect->right - rect->left, rect->bottom - rect->top); 412 rect ++; // Advances pointer by sizeof(RECT) 413 } 414 415 m_numRects = header->nCount; 416 417 delete[] (char*) rgnData; 418 } 419} 420 421wxRegionIterator& wxRegionIterator::operator++() 422{ 423 if (m_current < m_numRects) 424 ++m_current; 425 426 return *this; 427} 428 429wxRegionIterator wxRegionIterator::operator ++ (int) 430{ 431 wxRegionIterator tmp = *this; 432 if (m_current < m_numRects) 433 ++m_current; 434 435 return tmp; 436} 437 438// ---------------------------------------------------------------------------- 439// wxRegionIterator accessors 440// ---------------------------------------------------------------------------- 441 442wxCoord wxRegionIterator::GetX() const 443{ 444 wxCHECK_MSG( m_current < m_numRects, 0, _T("invalid wxRegionIterator") ); 445 446 return m_rects[m_current].x; 447} 448 449wxCoord wxRegionIterator::GetY() const 450{ 451 wxCHECK_MSG( m_current < m_numRects, 0, _T("invalid wxRegionIterator") ); 452 453 return m_rects[m_current].y; 454} 455 456wxCoord wxRegionIterator::GetW() const 457{ 458 wxCHECK_MSG( m_current < m_numRects, 0, _T("invalid wxRegionIterator") ); 459 460 return m_rects[m_current].width; 461} 462 463wxCoord wxRegionIterator::GetH() const 464{ 465 wxCHECK_MSG( m_current < m_numRects, 0, _T("invalid wxRegionIterator") ); 466 467 return m_rects[m_current].height; 468} 469