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