1///////////////////////////////////////////////////////////////////////////// 2// Name: src/gtk/region.cpp 3// Purpose: 4// Author: Robert Roebling 5// Modified: VZ at 05.10.00: use AllocExclusive(), comparison fixed 6// Id: $Id: region.cpp 42903 2006-11-01 12:56:38Z RR $ 7// Copyright: (c) 1998 Robert Roebling 8// Licence: wxWindows licence 9///////////////////////////////////////////////////////////////////////////// 10 11// ============================================================================ 12// declarations 13// ============================================================================ 14 15// ---------------------------------------------------------------------------- 16// headers 17// ---------------------------------------------------------------------------- 18 19// For compilers that support precompilation, includes "wx.h". 20#include "wx/wxprec.h" 21 22#include "wx/region.h" 23 24#ifndef WX_PRECOMP 25 #include "wx/log.h" 26#endif 27 28#include "wx/gtk/private.h" 29 30 31// ---------------------------------------------------------------------------- 32// wxRegionRefData: private class containing the information about the region 33// ---------------------------------------------------------------------------- 34 35class wxRegionRefData : public wxObjectRefData 36{ 37public: 38 wxRegionRefData() 39 { 40 m_region = NULL; 41 } 42 43 wxRegionRefData(const wxRegionRefData& refData) 44 : wxObjectRefData() 45 { 46 m_region = gdk_region_copy(refData.m_region); 47 } 48 49 virtual ~wxRegionRefData() 50 { 51 if (m_region) 52 gdk_region_destroy( m_region ); 53 } 54 55 GdkRegion *m_region; 56}; 57 58// ---------------------------------------------------------------------------- 59// macros 60// ---------------------------------------------------------------------------- 61 62#define M_REGIONDATA ((wxRegionRefData *)m_refData) 63#define M_REGIONDATA_OF(rgn) ((wxRegionRefData *)(rgn.m_refData)) 64 65IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject) 66IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator,wxObject) 67 68// ---------------------------------------------------------------------------- 69// wxRegion construction 70// ---------------------------------------------------------------------------- 71 72#define M_REGIONDATA ((wxRegionRefData *)m_refData) 73 74void wxRegion::InitRect(wxCoord x, wxCoord y, wxCoord w, wxCoord h) 75{ 76 GdkRectangle rect; 77 rect.x = x; 78 rect.y = y; 79 rect.width = w; 80 rect.height = h; 81 82 m_refData = new wxRegionRefData(); 83 84 M_REGIONDATA->m_region = gdk_region_rectangle( &rect ); 85} 86 87wxRegion::wxRegion( GdkRegion *region ) 88{ 89 m_refData = new wxRegionRefData(); 90 M_REGIONDATA->m_region = gdk_region_copy( region ); 91} 92 93wxRegion::wxRegion( size_t n, const wxPoint *points, int fillStyle ) 94{ 95 GdkPoint *gdkpoints = new GdkPoint[n]; 96 for ( size_t i = 0 ; i < n ; i++ ) 97 { 98 gdkpoints[i].x = points[i].x; 99 gdkpoints[i].y = points[i].y; 100 } 101 102 m_refData = new wxRegionRefData(); 103 104 GdkRegion* reg = gdk_region_polygon 105 ( 106 gdkpoints, 107 n, 108 fillStyle == wxWINDING_RULE ? GDK_WINDING_RULE 109 : GDK_EVEN_ODD_RULE 110 ); 111 112 M_REGIONDATA->m_region = reg; 113 114 delete [] gdkpoints; 115} 116 117wxRegion::~wxRegion() 118{ 119 // m_refData unrefed in ~wxObject 120} 121 122wxObjectRefData *wxRegion::CreateRefData() const 123{ 124 return new wxRegionRefData; 125} 126 127wxObjectRefData *wxRegion::CloneRefData(const wxObjectRefData *data) const 128{ 129 return new wxRegionRefData(*(wxRegionRefData *)data); 130} 131 132// ---------------------------------------------------------------------------- 133// wxRegion comparison 134// ---------------------------------------------------------------------------- 135 136bool wxRegion::DoIsEqual(const wxRegion& region) const 137{ 138 return gdk_region_equal(M_REGIONDATA->m_region, 139 M_REGIONDATA_OF(region)->m_region); 140} 141 142// ---------------------------------------------------------------------------- 143// wxRegion operations 144// ---------------------------------------------------------------------------- 145 146void wxRegion::Clear() 147{ 148 UnRef(); 149} 150 151bool wxRegion::DoUnionWithRect(const wxRect& r) 152{ 153 // workaround for a strange GTK/X11 bug: taking union with an empty 154 // rectangle results in an empty region which is definitely not what we 155 // want 156 if ( r.IsEmpty() ) 157 return true; 158 159 if ( !m_refData ) 160 { 161 InitRect(r.x, r.y, r.width, r.height); 162 } 163 else 164 { 165 AllocExclusive(); 166 167 GdkRectangle rect; 168 rect.x = r.x; 169 rect.y = r.y; 170 rect.width = r.width; 171 rect.height = r.height; 172 173 gdk_region_union_with_rect( M_REGIONDATA->m_region, &rect ); 174 } 175 176 return true; 177} 178 179bool wxRegion::DoUnionWithRegion( const wxRegion& region ) 180{ 181 wxCHECK_MSG( region.Ok(), false, _T("invalid region") ); 182 183 if (!m_refData) 184 { 185 m_refData = new wxRegionRefData(); 186 M_REGIONDATA->m_region = gdk_region_new(); 187 } 188 else 189 { 190 AllocExclusive(); 191 } 192 193 gdk_region_union( M_REGIONDATA->m_region, region.GetRegion() ); 194 195 return true; 196} 197 198bool wxRegion::DoIntersect( const wxRegion& region ) 199{ 200 wxCHECK_MSG( region.Ok(), false, _T("invalid region") ); 201 202 if (!m_refData) 203 { 204 // intersecting with invalid region doesn't make sense 205 return false; 206 } 207 208 AllocExclusive(); 209 210 gdk_region_intersect( M_REGIONDATA->m_region, region.GetRegion() ); 211 212 return true; 213} 214 215bool wxRegion::DoSubtract( const wxRegion& region ) 216{ 217 wxCHECK_MSG( region.Ok(), false, _T("invalid region") ); 218 219 if (!m_refData) 220 { 221 // subtracting from an invalid region doesn't make sense 222 return false; 223 } 224 225 AllocExclusive(); 226 227 gdk_region_subtract( M_REGIONDATA->m_region, region.GetRegion() ); 228 229 return true; 230} 231 232bool wxRegion::DoXor( const wxRegion& region ) 233{ 234 wxCHECK_MSG( region.Ok(), false, _T("invalid region") ); 235 236 if (!m_refData) 237 { 238 return false; 239 } 240 241 AllocExclusive(); 242 243 gdk_region_xor( M_REGIONDATA->m_region, region.GetRegion() ); 244 245 return true; 246} 247 248bool wxRegion::DoOffset( wxCoord x, wxCoord y ) 249{ 250 if (!m_refData) 251 return false; 252 253 AllocExclusive(); 254 255 gdk_region_offset( M_REGIONDATA->m_region, x, y ); 256 257 return true; 258} 259 260// ---------------------------------------------------------------------------- 261// wxRegion tests 262// ---------------------------------------------------------------------------- 263 264bool wxRegion::DoGetBox( wxCoord &x, wxCoord &y, wxCoord &w, wxCoord &h ) const 265{ 266 if ( m_refData ) 267 { 268 GdkRectangle rect; 269 gdk_region_get_clipbox( M_REGIONDATA->m_region, &rect ); 270 x = rect.x; 271 y = rect.y; 272 w = rect.width; 273 h = rect.height; 274 275 return true; 276 } 277 else 278 { 279 x = 0; 280 y = 0; 281 w = -1; 282 h = -1; 283 284 return false; 285 } 286} 287 288bool wxRegion::IsEmpty() const 289{ 290 if (!m_refData) 291 return true; 292 293 return gdk_region_empty( M_REGIONDATA->m_region ); 294} 295 296wxRegionContain wxRegion::DoContainsPoint( wxCoord x, wxCoord y ) const 297{ 298 if (!m_refData) 299 return wxOutRegion; 300 301 if (gdk_region_point_in( M_REGIONDATA->m_region, x, y )) 302 return wxInRegion; 303 else 304 return wxOutRegion; 305} 306 307wxRegionContain wxRegion::DoContainsRect(const wxRect& r) const 308{ 309 if (!m_refData) 310 return wxOutRegion; 311 312 GdkRectangle rect; 313 rect.x = r.x; 314 rect.y = r.y; 315 rect.width = r.width; 316 rect.height = r.height; 317 GdkOverlapType res = gdk_region_rect_in( M_REGIONDATA->m_region, &rect ); 318 switch (res) 319 { 320 case GDK_OVERLAP_RECTANGLE_IN: return wxInRegion; 321 case GDK_OVERLAP_RECTANGLE_OUT: return wxOutRegion; 322 case GDK_OVERLAP_RECTANGLE_PART: return wxPartRegion; 323 } 324 return wxOutRegion; 325} 326 327GdkRegion *wxRegion::GetRegion() const 328{ 329 if (!m_refData) 330 return (GdkRegion*) NULL; 331 332 return M_REGIONDATA->m_region; 333} 334 335// ---------------------------------------------------------------------------- 336// wxRegionIterator 337// ---------------------------------------------------------------------------- 338 339wxRegionIterator::wxRegionIterator() 340{ 341 Init(); 342 Reset(); 343} 344 345wxRegionIterator::wxRegionIterator( const wxRegion& region ) 346{ 347 Init(); 348 Reset(region); 349} 350 351void wxRegionIterator::Init() 352{ 353 m_rects = NULL; 354 m_numRects = 0; 355} 356 357wxRegionIterator::~wxRegionIterator() 358{ 359 wxDELETEA(m_rects); 360} 361 362void wxRegionIterator::CreateRects( const wxRegion& region ) 363{ 364 wxDELETEA(m_rects); 365 m_numRects = 0; 366 367 GdkRegion *gdkregion = region.GetRegion(); 368 if (!gdkregion) 369 return; 370 371 GdkRectangle *gdkrects = NULL; 372 gint numRects = 0; 373 gdk_region_get_rectangles( gdkregion, &gdkrects, &numRects ); 374 375 m_numRects = numRects; 376 if (numRects) 377 { 378 m_rects = new wxRect[m_numRects]; 379 for (size_t i=0; i < m_numRects; ++i) 380 { 381 GdkRectangle &gr = gdkrects[i]; 382 wxRect &wr = m_rects[i]; 383 wr.x = gr.x; 384 wr.y = gr.y; 385 wr.width = gr.width; 386 wr.height = gr.height; 387 } 388 } 389 g_free( gdkrects ); 390} 391 392void wxRegionIterator::Reset( const wxRegion& region ) 393{ 394 m_region = region; 395 CreateRects(region); 396 Reset(); 397} 398 399bool wxRegionIterator::HaveRects() const 400{ 401 return m_current < m_numRects; 402} 403 404wxRegionIterator& wxRegionIterator::operator ++ () 405{ 406 if (HaveRects()) 407 ++m_current; 408 409 return *this; 410} 411 412wxRegionIterator wxRegionIterator::operator ++ (int) 413{ 414 wxRegionIterator tmp = *this; 415 416 if (HaveRects()) 417 ++m_current; 418 419 return tmp; 420} 421 422wxCoord wxRegionIterator::GetX() const 423{ 424 wxCHECK_MSG( HaveRects(), 0, _T("invalid wxRegionIterator") ); 425 426 return m_rects[m_current].x; 427} 428 429wxCoord wxRegionIterator::GetY() const 430{ 431 wxCHECK_MSG( HaveRects(), 0, _T("invalid wxRegionIterator") ); 432 433 return m_rects[m_current].y; 434} 435 436wxCoord wxRegionIterator::GetW() const 437{ 438 wxCHECK_MSG( HaveRects(), 0, _T("invalid wxRegionIterator") ); 439 440 return m_rects[m_current].width; 441} 442 443wxCoord wxRegionIterator::GetH() const 444{ 445 wxCHECK_MSG( HaveRects(), 0, _T("invalid wxRegionIterator") ); 446 447 return m_rects[m_current].height; 448} 449 450wxRect wxRegionIterator::GetRect() const 451{ 452 wxRect r; 453 if( HaveRects() ) 454 r = m_rects[m_current]; 455 456 return r; 457} 458 459wxRegionIterator& wxRegionIterator::operator=(const wxRegionIterator& ri) 460{ 461 wxDELETEA(m_rects); 462 463 m_current = ri.m_current; 464 m_numRects = ri.m_numRects; 465 if ( m_numRects ) 466 { 467 m_rects = new wxRect[m_numRects]; 468 for ( unsigned int n = 0; n < m_numRects; n++ ) 469 m_rects[n] = ri.m_rects[n]; 470 } 471 else 472 { 473 m_rects = NULL; 474 } 475 476 return *this; 477} 478