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