]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/region.cpp
rebaked after timer/socket changes
[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
1e6feb95 35class wxRegionRefData : public wxObjectRefData
c801d85f 36{
864e8bd0 37public:
48850fa7
RR
38 wxRegionRefData()
39 {
40 m_region = NULL;
41 }
57f2b902 42
48850fa7 43 wxRegionRefData(const wxRegionRefData& refData)
d84afea9 44 : wxObjectRefData()
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
5549e9f7
VZ
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
1e6feb95 117wxRegion::~wxRegion()
c801d85f 118{
e0f0b197 119 // m_refData unrefed in ~wxObject
ff7b1510 120}
c801d85f 121
e0f0b197
RR
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}
c89f5c02 131
9fe4c99c
VZ
132// ----------------------------------------------------------------------------
133// wxRegion comparison
134// ----------------------------------------------------------------------------
135
8a16d737 136bool wxRegion::DoIsEqual(const wxRegion& region) const
c801d85f 137{
1e6feb95
VZ
138 return gdk_region_equal(M_REGIONDATA->m_region,
139 M_REGIONDATA_OF(region)->m_region);
ff7b1510 140}
c801d85f 141
1e6feb95
VZ
142// ----------------------------------------------------------------------------
143// wxRegion operations
144// ----------------------------------------------------------------------------
145
bf57d1ad 146void wxRegion::Clear()
c801d85f 147{
bbe0af5b 148 UnRef();
ff7b1510 149}
c801d85f 150
8a16d737 151bool wxRegion::DoUnionWithRect(const wxRect& r)
c801d85f 152{
57351df0
VZ
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
8a16d737 156 if ( r.IsEmpty() )
b3a44e05 157 return true;
57351df0 158
2b5f62a0 159 if ( !m_refData )
e1208c31 160 {
8a16d737 161 InitRect(r.x, r.y, r.width, r.height);
e1208c31
RR
162 }
163 else
164 {
9fe4c99c 165 AllocExclusive();
1e6feb95 166
2b5f62a0 167 GdkRectangle rect;
8a16d737
VZ
168 rect.x = r.x;
169 rect.y = r.y;
170 rect.width = r.width;
171 rect.height = r.height;
2b5f62a0 172
b7c2d6ff 173 gdk_region_union_with_rect( M_REGIONDATA->m_region, &rect );
e1208c31 174 }
1e6feb95 175
b3a44e05 176 return true;
ff7b1510 177}
c801d85f 178
8a16d737 179bool wxRegion::DoUnionWithRegion( const wxRegion& region )
c801d85f 180{
8a16d737 181 wxCHECK_MSG( region.Ok(), false, _T("invalid region") );
e1208c31 182
48850fa7
RR
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 }
e1208c31 192
b7c2d6ff 193 gdk_region_union( M_REGIONDATA->m_region, region.GetRegion() );
5fc7ede9 194
b3a44e05 195 return true;
ff7b1510 196}
c801d85f 197
8a16d737 198bool wxRegion::DoIntersect( const wxRegion& region )
c801d85f 199{
8a16d737 200 wxCHECK_MSG( region.Ok(), false, _T("invalid region") );
1e6feb95 201
e1208c31
RR
202 if (!m_refData)
203 {
2b5f62a0 204 // intersecting with invalid region doesn't make sense
b3a44e05 205 return false;
1e6feb95
VZ
206 }
207
2b5f62a0
VZ
208 AllocExclusive();
209
48850fa7 210 gdk_region_intersect( M_REGIONDATA->m_region, region.GetRegion() );
9fe4c99c 211
b3a44e05 212 return true;
ff7b1510 213}
c801d85f 214
8a16d737 215bool wxRegion::DoSubtract( const wxRegion& region )
c801d85f 216{
8a16d737 217 wxCHECK_MSG( region.Ok(), false, _T("invalid region") );
e1208c31
RR
218
219 if (!m_refData)
220 {
2b5f62a0 221 // subtracting from an invalid region doesn't make sense
b3a44e05 222 return false;
48850fa7 223 }
1e6feb95 224
2b5f62a0
VZ
225 AllocExclusive();
226
b7c2d6ff 227 gdk_region_subtract( M_REGIONDATA->m_region, region.GetRegion() );
1e6feb95 228
b3a44e05 229 return true;
ff7b1510 230}
c801d85f 231
8a16d737 232bool wxRegion::DoXor( const wxRegion& region )
c801d85f 233{
8a16d737 234 wxCHECK_MSG( region.Ok(), false, _T("invalid region") );
e1208c31
RR
235
236 if (!m_refData)
237 {
b3a44e05 238 return false;
1e6feb95 239 }
e1208c31 240
2b5f62a0
VZ
241 AllocExclusive();
242
b7c2d6ff 243 gdk_region_xor( M_REGIONDATA->m_region, region.GetRegion() );
5fc7ede9 244
b3a44e05 245 return true;
ff7b1510 246}
c801d85f 247
8a16d737 248bool wxRegion::DoOffset( wxCoord x, wxCoord y )
2b5f62a0
VZ
249{
250 if (!m_refData)
b3a44e05 251 return false;
2b5f62a0
VZ
252
253 AllocExclusive();
254
255 gdk_region_offset( M_REGIONDATA->m_region, x, y );
256
b3a44e05 257 return true;
2b5f62a0
VZ
258}
259
1e6feb95
VZ
260// ----------------------------------------------------------------------------
261// wxRegion tests
262// ----------------------------------------------------------------------------
263
8a16d737 264bool wxRegion::DoGetBox( wxCoord &x, wxCoord &y, wxCoord &w, wxCoord &h ) const
c801d85f 265{
1e6feb95
VZ
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;
8a16d737
VZ
274
275 return true;
1e6feb95
VZ
276 }
277 else
278 {
279 x = 0;
280 y = 0;
281 w = -1;
282 h = -1;
c801d85f 283
8a16d737
VZ
284 return false;
285 }
ff7b1510 286}
c801d85f 287
8a16d737 288bool wxRegion::IsEmpty() const
c801d85f 289{
e1208c31 290 if (!m_refData)
b3a44e05 291 return true;
e1208c31 292
bbe0af5b 293 return gdk_region_empty( M_REGIONDATA->m_region );
ff7b1510 294}
c801d85f 295
8a16d737 296wxRegionContain wxRegion::DoContainsPoint( wxCoord x, wxCoord y ) const
c801d85f 297{
e1208c31
RR
298 if (!m_refData)
299 return wxOutRegion;
300
bbe0af5b
RR
301 if (gdk_region_point_in( M_REGIONDATA->m_region, x, y ))
302 return wxInRegion;
303 else
304 return wxOutRegion;
ff7b1510 305}
c801d85f 306
8a16d737 307wxRegionContain wxRegion::DoContainsRect(const wxRect& r) const
c801d85f 308{
e1208c31
RR
309 if (!m_refData)
310 return wxOutRegion;
311
bbe0af5b 312 GdkRectangle rect;
8a16d737
VZ
313 rect.x = r.x;
314 rect.y = r.y;
315 rect.width = r.width;
316 rect.height = r.height;
bbe0af5b
RR
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;
ff7b1510 325}
c801d85f 326
bf57d1ad 327GdkRegion *wxRegion::GetRegion() const
c801d85f 328{
e1208c31
RR
329 if (!m_refData)
330 return (GdkRegion*) NULL;
331
bbe0af5b 332 return M_REGIONDATA->m_region;
ff7b1510 333}
c801d85f 334
1e6feb95 335// ----------------------------------------------------------------------------
3d0c4d2e 336// wxRegionIterator
1e6feb95 337// ----------------------------------------------------------------------------
8429bec1 338
55ccdb93 339wxRegionIterator::wxRegionIterator()
3d0c4d2e 340{
55ccdb93
VZ
341 Init();
342 Reset();
343}
3d0c4d2e 344
55ccdb93
VZ
345wxRegionIterator::wxRegionIterator( const wxRegion& region )
346{
347 Init();
348 Reset(region);
349}
3d0c4d2e 350
55ccdb93 351void wxRegionIterator::Init()
3d0c4d2e 352{
55ccdb93
VZ
353 m_rects = NULL;
354 m_numRects = 0;
3d0c4d2e
RR
355}
356
55ccdb93 357wxRegionIterator::~wxRegionIterator()
3d0c4d2e 358{
55ccdb93
VZ
359 wxDELETEA(m_rects);
360}
48850fa7 361
55ccdb93
VZ
362void wxRegionIterator::CreateRects( const wxRegion& region )
363{
364 wxDELETEA(m_rects);
365 m_numRects = 0;
57f2b902 366
48850fa7 367 GdkRegion *gdkregion = region.GetRegion();
3f0fb1d4
VZ
368 if (!gdkregion)
369 return;
57f2b902 370
9e691f46 371 GdkRectangle *gdkrects = NULL;
48850fa7 372 gint numRects = 0;
9e691f46 373 gdk_region_get_rectangles( gdkregion, &gdkrects, &numRects );
57f2b902 374
48850fa7
RR
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)
3d0c4d2e 380 {
48850fa7
RR
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;
3d0c4d2e 387 }
3d0c4d2e 388 }
9e691f46 389 g_free( gdkrects );
3d0c4d2e
RR
390}
391
3d0c4d2e
RR
392void wxRegionIterator::Reset( const wxRegion& region )
393{
394 m_region = region;
55ccdb93 395 CreateRects(region);
3d0c4d2e
RR
396 Reset();
397}
398
399bool wxRegionIterator::HaveRects() const
400{
55ccdb93 401 return m_current < m_numRects;
3d0c4d2e
RR
402}
403
2b5f62a0 404wxRegionIterator& wxRegionIterator::operator ++ ()
3d0c4d2e 405{
2b5f62a0
VZ
406 if (HaveRects())
407 ++m_current;
3d0c4d2e 408
2b5f62a0 409 return *this;
3d0c4d2e
RR
410}
411
2b5f62a0 412wxRegionIterator wxRegionIterator::operator ++ (int)
3d0c4d2e 413{
2b5f62a0 414 wxRegionIterator tmp = *this;
55ccdb93 415
2b5f62a0
VZ
416 if (HaveRects())
417 ++m_current;
418
419 return tmp;
3d0c4d2e
RR
420}
421
422wxCoord wxRegionIterator::GetX() const
423{
2b5f62a0
VZ
424 wxCHECK_MSG( HaveRects(), 0, _T("invalid wxRegionIterator") );
425
55ccdb93 426 return m_rects[m_current].x;
3d0c4d2e
RR
427}
428
429wxCoord wxRegionIterator::GetY() const
430{
2b5f62a0
VZ
431 wxCHECK_MSG( HaveRects(), 0, _T("invalid wxRegionIterator") );
432
55ccdb93 433 return m_rects[m_current].y;
3d0c4d2e
RR
434}
435
436wxCoord wxRegionIterator::GetW() const
437{
2b5f62a0
VZ
438 wxCHECK_MSG( HaveRects(), 0, _T("invalid wxRegionIterator") );
439
55ccdb93 440 return m_rects[m_current].width;
3d0c4d2e
RR
441}
442
443wxCoord wxRegionIterator::GetH() const
444{
2b5f62a0
VZ
445 wxCHECK_MSG( HaveRects(), 0, _T("invalid wxRegionIterator") );
446
55ccdb93 447 return m_rects[m_current].height;
3d0c4d2e
RR
448}
449
1e6feb95
VZ
450wxRect wxRegionIterator::GetRect() const
451{
452 wxRect r;
3379ed37 453 if( HaveRects() )
55ccdb93 454 r = m_rects[m_current];
1e6feb95
VZ
455
456 return r;
457}
ac7d3dd1
RR
458
459wxRegionIterator& wxRegionIterator::operator=(const wxRegionIterator& ri)
460{
461 wxDELETEA(m_rects);
f4322df6 462
ac7d3dd1
RR
463 m_current = ri.m_current;
464 m_numRects = ri.m_numRects;
465 if ( m_numRects )
466 {
467 m_rects = new wxRect[m_numRects];
de3cfa6e 468 for ( unsigned int n = 0; n < m_numRects; n++ )
ac7d3dd1
RR
469 m_rects[n] = ri.m_rects[n];
470 }
471 else
472 {
473 m_rects = NULL;
474 }
475
476 return *this;
477}