]> git.saurik.com Git - wxWidgets.git/blame - src/gtk1/region.cpp
forward ported patch to IsEditable()
[wxWidgets.git] / src / gtk1 / 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
5fc7ede9 8// Licence: wxWindows licence
c801d85f
KB
9/////////////////////////////////////////////////////////////////////////////
10
1e6feb95
VZ
11// ============================================================================
12// declarations
13// ============================================================================
14
c801d85f 15#ifdef __GNUG__
1e6feb95 16 #pragma implementation "region.h"
c801d85f
KB
17#endif
18
1e6feb95
VZ
19// ----------------------------------------------------------------------------
20// headers
21// ----------------------------------------------------------------------------
22
9e691f46 23#include "wx/log.h"
c801d85f 24
9e691f46 25#include "wx/region.h"
bbe0af5b 26
9e691f46 27#include "wx/gtk/private.h"
1e6feb95 28
57f2b902
VZ
29#ifndef __WXGTK20__
30
31// ----------------------------------------------------------------------------
32// wxGdkRegion: creates a new region in ctor and destroys in dtor
33// ----------------------------------------------------------------------------
34
35class wxGdkRegion
36{
37public:
38 wxGdkRegion() { m_region = gdk_region_new(); }
39 ~wxGdkRegion() { gdk_region_destroy(m_region); }
40
41 operator GdkRegion *() const { return m_region; }
42
43private:
44 GdkRegion *m_region;
45};
46
47#endif // __WXGTK20__
48
1e6feb95
VZ
49// ----------------------------------------------------------------------------
50// wxRegionRefData: private class containing the information about the region
51// ----------------------------------------------------------------------------
c801d85f 52
1e6feb95 53class wxRegionRefData : public wxObjectRefData
c801d85f 54{
864e8bd0 55public:
48850fa7
RR
56 wxRegionRefData()
57 {
58 m_region = NULL;
59 }
57f2b902 60
48850fa7 61 wxRegionRefData(const wxRegionRefData& refData)
d84afea9 62 : wxObjectRefData()
48850fa7
RR
63 {
64#ifdef __WXGTK20__
65 m_region = gdk_region_copy(refData.m_region);
66#else
57f2b902 67 m_region = gdk_regions_union(wxGdkRegion(), refData.m_region);
48850fa7
RR
68#endif
69 }
57f2b902 70
48850fa7
RR
71 ~wxRegionRefData()
72 {
73 if (m_region)
74 gdk_region_destroy( m_region );
75 }
5fc7ede9 76
c801d85f
KB
77 GdkRegion *m_region;
78};
79
1e6feb95
VZ
80// ----------------------------------------------------------------------------
81// macros
82// ----------------------------------------------------------------------------
83
84#define M_REGIONDATA ((wxRegionRefData *)m_refData)
85#define M_REGIONDATA_OF(rgn) ((wxRegionRefData *)(rgn.m_refData))
86
d84afea9
GD
87IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject)
88IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator,wxObject)
1e6feb95 89
1e6feb95
VZ
90// ----------------------------------------------------------------------------
91// wxRegion construction
92// ----------------------------------------------------------------------------
c801d85f
KB
93
94#define M_REGIONDATA ((wxRegionRefData *)m_refData)
95
9fe4c99c 96void wxRegion::InitRect(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
c801d85f 97{
bbe0af5b
RR
98 GdkRectangle rect;
99 rect.x = x;
100 rect.y = y;
101 rect.width = w;
102 rect.height = h;
57f2b902 103
48850fa7 104 m_refData = new wxRegionRefData();
57f2b902 105
b7c2d6ff 106#ifdef __WXGTK20__
9e691f46 107 M_REGIONDATA->m_region = gdk_region_rectangle( &rect );
b7c2d6ff 108#else
57f2b902 109 M_REGIONDATA->m_region = gdk_region_union_with_rect( wxGdkRegion(), &rect );
b7c2d6ff 110#endif
ff7b1510 111}
c801d85f 112
b15ed747
RR
113wxRegion::wxRegion( GdkRegion *region )
114{
115 m_refData = new wxRegionRefData();
57f2b902 116#ifdef __WXGTK20__
b15ed747 117 M_REGIONDATA->m_region = gdk_region_copy( region );
57f2b902
VZ
118#else
119 M_REGIONDATA->m_region = gdk_regions_union(wxGdkRegion(), region);
120#endif
b15ed747
RR
121}
122
5549e9f7
VZ
123wxRegion::wxRegion( size_t n, const wxPoint *points, int fillStyle )
124{
125 GdkPoint *gdkpoints = new GdkPoint[n];
126 for ( size_t i = 0 ; i < n ; i++ )
127 {
128 gdkpoints[i].x = points[i].x;
129 gdkpoints[i].y = points[i].y;
130 }
131
132 m_refData = new wxRegionRefData();
133
134 GdkRegion* reg = gdk_region_polygon
135 (
136 gdkpoints,
137 n,
138 fillStyle == wxWINDING_RULE ? GDK_WINDING_RULE
139 : GDK_EVEN_ODD_RULE
140 );
141
142 M_REGIONDATA->m_region = reg;
143
144 delete [] gdkpoints;
145}
146
1e6feb95 147wxRegion::~wxRegion()
c801d85f 148{
e0f0b197 149 // m_refData unrefed in ~wxObject
ff7b1510 150}
c801d85f 151
e0f0b197
RR
152wxObjectRefData *wxRegion::CreateRefData() const
153{
154 return new wxRegionRefData;
155}
156
157wxObjectRefData *wxRegion::CloneRefData(const wxObjectRefData *data) const
158{
159 return new wxRegionRefData(*(wxRegionRefData *)data);
160}
c89f5c02 161
9fe4c99c
VZ
162// ----------------------------------------------------------------------------
163// wxRegion comparison
164// ----------------------------------------------------------------------------
165
1e6feb95 166bool wxRegion::operator==( const wxRegion& region )
c801d85f 167{
c89f5c02
RR
168 if (m_refData == region.m_refData) return TRUE;
169
170 if (!m_refData || !region.m_refData) return FALSE;
57f2b902 171
9fe4c99c 172 // compare the regions themselves, not the pointers to ref data!
1e6feb95
VZ
173 return gdk_region_equal(M_REGIONDATA->m_region,
174 M_REGIONDATA_OF(region)->m_region);
ff7b1510 175}
c801d85f 176
1e6feb95
VZ
177// ----------------------------------------------------------------------------
178// wxRegion operations
179// ----------------------------------------------------------------------------
180
bf57d1ad 181void wxRegion::Clear()
c801d85f 182{
bbe0af5b 183 UnRef();
ff7b1510 184}
c801d85f 185
5fc7ede9 186bool wxRegion::Union( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
c801d85f 187{
57351df0
VZ
188 // workaround for a strange GTK/X11 bug: taking union with an empty
189 // rectangle results in an empty region which is definitely not what we
190 // want
191 if ( !width || !height )
192 return TRUE;
193
2b5f62a0 194 if ( !m_refData )
e1208c31 195 {
2b5f62a0 196 InitRect(x, y, width, height);
e1208c31
RR
197 }
198 else
199 {
9fe4c99c 200 AllocExclusive();
1e6feb95 201
2b5f62a0
VZ
202 GdkRectangle rect;
203 rect.x = x;
204 rect.y = y;
205 rect.width = width;
206 rect.height = height;
207
b7c2d6ff
OK
208#ifdef __WXGTK20__
209 gdk_region_union_with_rect( M_REGIONDATA->m_region, &rect );
210#else
e1208c31
RR
211 GdkRegion *reg = gdk_region_union_with_rect( M_REGIONDATA->m_region, &rect );
212 gdk_region_destroy( M_REGIONDATA->m_region );
213 M_REGIONDATA->m_region = reg;
b7c2d6ff 214#endif
e1208c31 215 }
1e6feb95 216
bbe0af5b 217 return TRUE;
ff7b1510 218}
c801d85f
KB
219
220bool wxRegion::Union( const wxRect& rect )
221{
e1208c31 222 return Union( rect.x, rect.y, rect.width, rect.height );
ff7b1510 223}
c801d85f
KB
224
225bool wxRegion::Union( const wxRegion& region )
226{
e1208c31
RR
227 if (region.IsNull())
228 return FALSE;
229
48850fa7
RR
230 if (!m_refData)
231 {
232 m_refData = new wxRegionRefData();
233 M_REGIONDATA->m_region = gdk_region_new();
234 }
235 else
236 {
237 AllocExclusive();
238 }
e1208c31 239
b7c2d6ff
OK
240#ifdef __WXGTK20__
241 gdk_region_union( M_REGIONDATA->m_region, region.GetRegion() );
242#else
bbe0af5b
RR
243 GdkRegion *reg = gdk_regions_union( M_REGIONDATA->m_region, region.GetRegion() );
244 gdk_region_destroy( M_REGIONDATA->m_region );
245 M_REGIONDATA->m_region = reg;
b7c2d6ff 246#endif
5fc7ede9 247
bbe0af5b 248 return TRUE;
ff7b1510 249}
c801d85f 250
5fc7ede9 251bool wxRegion::Intersect( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
c801d85f 252{
bbe0af5b 253 wxRegion reg( x, y, width, height );
1e6feb95
VZ
254
255 return Intersect( reg );
ff7b1510 256}
c801d85f
KB
257
258bool wxRegion::Intersect( const wxRect& rect )
259{
bbe0af5b 260 wxRegion reg( rect );
57f2b902 261
1e6feb95 262 return Intersect( reg );
ff7b1510 263}
c801d85f 264
1e6feb95 265bool wxRegion::Intersect( const wxRegion& region )
c801d85f 266{
1e6feb95
VZ
267 if (region.IsNull())
268 return FALSE;
269
e1208c31
RR
270 if (!m_refData)
271 {
2b5f62a0
VZ
272 // intersecting with invalid region doesn't make sense
273 return FALSE;
1e6feb95
VZ
274 }
275
2b5f62a0
VZ
276 AllocExclusive();
277
48850fa7
RR
278#ifdef __WXGTK20__
279 gdk_region_intersect( M_REGIONDATA->m_region, region.GetRegion() );
280#else
281 GdkRegion *reg = gdk_regions_intersect( M_REGIONDATA->m_region, region.GetRegion() );
282 gdk_region_destroy( M_REGIONDATA->m_region );
283 M_REGIONDATA->m_region = reg;
284#endif
9fe4c99c 285
bbe0af5b 286 return TRUE;
ff7b1510 287}
c801d85f 288
1e6feb95 289bool wxRegion::Subtract( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
c801d85f 290{
1e6feb95
VZ
291 wxRegion reg( x, y, width, height );
292 return Subtract( reg );
293}
e1208c31 294
1e6feb95
VZ
295bool wxRegion::Subtract( const wxRect& rect )
296{
bbe0af5b 297 wxRegion reg( rect );
1e6feb95 298 return Subtract( reg );
ff7b1510 299}
c801d85f
KB
300
301bool wxRegion::Subtract( const wxRegion& region )
302{
e1208c31
RR
303 if (region.IsNull())
304 return FALSE;
305
306 if (!m_refData)
307 {
2b5f62a0
VZ
308 // subtracting from an invalid region doesn't make sense
309 return FALSE;
48850fa7 310 }
1e6feb95 311
2b5f62a0
VZ
312 AllocExclusive();
313
b7c2d6ff
OK
314#ifdef __WXGTK20__
315 gdk_region_subtract( M_REGIONDATA->m_region, region.GetRegion() );
316#else
bbe0af5b
RR
317 GdkRegion *reg = gdk_regions_subtract( M_REGIONDATA->m_region, region.GetRegion() );
318 gdk_region_destroy( M_REGIONDATA->m_region );
319 M_REGIONDATA->m_region = reg;
b7c2d6ff 320#endif
1e6feb95 321
bbe0af5b 322 return TRUE;
ff7b1510 323}
c801d85f 324
5fc7ede9 325bool wxRegion::Xor( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
c801d85f 326{
bbe0af5b 327 wxRegion reg( x, y, width, height );
1e6feb95 328 return Xor( reg );
ff7b1510 329}
c801d85f
KB
330
331bool wxRegion::Xor( const wxRect& rect )
332{
bbe0af5b 333 wxRegion reg( rect );
1e6feb95 334 return Xor( reg );
ff7b1510 335}
c801d85f
KB
336
337bool wxRegion::Xor( const wxRegion& region )
338{
e1208c31 339 if (region.IsNull())
05a11043 340 return FALSE;
e1208c31
RR
341
342 if (!m_refData)
343 {
2b5f62a0 344 return FALSE;
1e6feb95 345 }
e1208c31 346
2b5f62a0
VZ
347 AllocExclusive();
348
b7c2d6ff
OK
349#ifdef __WXGTK20__
350 gdk_region_xor( M_REGIONDATA->m_region, region.GetRegion() );
351#else
bbe0af5b
RR
352 GdkRegion *reg = gdk_regions_xor( M_REGIONDATA->m_region, region.GetRegion() );
353 gdk_region_destroy( M_REGIONDATA->m_region );
354 M_REGIONDATA->m_region = reg;
b7c2d6ff 355#endif
5fc7ede9 356
bbe0af5b 357 return TRUE;
ff7b1510 358}
c801d85f 359
2b5f62a0
VZ
360bool wxRegion::Offset( wxCoord x, wxCoord y )
361{
362 if (!m_refData)
363 return FALSE;
364
365 AllocExclusive();
366
367 gdk_region_offset( M_REGIONDATA->m_region, x, y );
368
369 return TRUE;
370}
371
1e6feb95
VZ
372// ----------------------------------------------------------------------------
373// wxRegion tests
374// ----------------------------------------------------------------------------
375
e1208c31 376void wxRegion::GetBox( wxCoord &x, wxCoord &y, wxCoord &w, wxCoord &h ) const
c801d85f 377{
1e6feb95
VZ
378 if ( m_refData )
379 {
380 GdkRectangle rect;
381 gdk_region_get_clipbox( M_REGIONDATA->m_region, &rect );
382 x = rect.x;
383 y = rect.y;
384 w = rect.width;
385 h = rect.height;
386 }
387 else
388 {
389 x = 0;
390 y = 0;
391 w = -1;
392 h = -1;
393 }
ff7b1510 394}
c801d85f 395
bf57d1ad 396wxRect wxRegion::GetBox() const
c801d85f 397{
1e6feb95 398 wxCoord x, y, w, h;
bbe0af5b
RR
399 GetBox( x, y, w, h );
400 return wxRect( x, y, w, h );
ff7b1510 401}
c801d85f 402
bf57d1ad 403bool wxRegion::Empty() const
c801d85f 404{
e1208c31
RR
405 if (!m_refData)
406 return TRUE;
407
bbe0af5b 408 return gdk_region_empty( M_REGIONDATA->m_region );
ff7b1510 409}
c801d85f 410
5fc7ede9 411wxRegionContain wxRegion::Contains( wxCoord x, wxCoord y ) const
c801d85f 412{
e1208c31
RR
413 if (!m_refData)
414 return wxOutRegion;
415
bbe0af5b
RR
416 if (gdk_region_point_in( M_REGIONDATA->m_region, x, y ))
417 return wxInRegion;
418 else
419 return wxOutRegion;
ff7b1510 420}
c801d85f 421
5fc7ede9 422wxRegionContain wxRegion::Contains( wxCoord x, wxCoord y, wxCoord w, wxCoord h ) const
c801d85f 423{
e1208c31
RR
424 if (!m_refData)
425 return wxOutRegion;
426
bbe0af5b
RR
427 GdkRectangle rect;
428 rect.x = x;
429 rect.y = y;
430 rect.width = w;
431 rect.height = h;
432 GdkOverlapType res = gdk_region_rect_in( M_REGIONDATA->m_region, &rect );
433 switch (res)
434 {
435 case GDK_OVERLAP_RECTANGLE_IN: return wxInRegion;
436 case GDK_OVERLAP_RECTANGLE_OUT: return wxOutRegion;
437 case GDK_OVERLAP_RECTANGLE_PART: return wxPartRegion;
438 }
439 return wxOutRegion;
ff7b1510 440}
c801d85f 441
8429bec1
RR
442wxRegionContain wxRegion::Contains(const wxPoint& pt) const
443{
bbe0af5b 444 return Contains( pt.x, pt.y );
8429bec1
RR
445}
446
447wxRegionContain wxRegion::Contains(const wxRect& rect) const
448{
bbe0af5b 449 return Contains( rect.x, rect.y, rect.width, rect.height );
8429bec1
RR
450}
451
bf57d1ad 452GdkRegion *wxRegion::GetRegion() const
c801d85f 453{
e1208c31
RR
454 if (!m_refData)
455 return (GdkRegion*) NULL;
456
bbe0af5b 457 return M_REGIONDATA->m_region;
ff7b1510 458}
c801d85f 459
1e6feb95 460// ----------------------------------------------------------------------------
3d0c4d2e 461// wxRegionIterator
1e6feb95 462// ----------------------------------------------------------------------------
8429bec1 463
48850fa7 464#ifndef __WXGTK20__
3d0c4d2e
RR
465
466// the following structures must match the private structures
467// in X11 region code ( xc/lib/X11/region.h )
468
469// this makes the Region type transparent
470// and we have access to the region rectangles
471
48850fa7
RR
472#include <gdk/gdkprivate.h>
473
3d0c4d2e
RR
474struct _XBox {
475 short x1, x2, y1, y2;
476};
1e6feb95 477
3d0c4d2e
RR
478struct _XRegion {
479 long size , numRects;
480 _XBox *rects, extents;
481};
482
2b5f62a0 483#endif // GTK+ 1.x
48850fa7 484
3d0c4d2e
RR
485class wxRIRefData: public wxObjectRefData
486{
487public:
3f0fb1d4
VZ
488 wxRIRefData() { Init(); }
489 virtual ~wxRIRefData();
3d0c4d2e 490
3f0fb1d4
VZ
491 void CreateRects( const wxRegion& r );
492
493 void Init() { m_rects = NULL; m_numRects = 0; }
3d0c4d2e
RR
494
495 wxRect *m_rects;
496 size_t m_numRects;
3d0c4d2e
RR
497};
498
499wxRIRefData::~wxRIRefData()
500{
64423153 501 delete [] m_rects;
3d0c4d2e
RR
502}
503
3d0c4d2e
RR
504void wxRIRefData::CreateRects( const wxRegion& region )
505{
64423153 506 delete [] m_rects;
48850fa7 507
3f0fb1d4 508 Init();
57f2b902 509
48850fa7 510 GdkRegion *gdkregion = region.GetRegion();
3f0fb1d4
VZ
511 if (!gdkregion)
512 return;
57f2b902 513
48850fa7 514#ifdef __WXGTK20__
9e691f46 515 GdkRectangle *gdkrects = NULL;
48850fa7 516 gint numRects = 0;
9e691f46 517 gdk_region_get_rectangles( gdkregion, &gdkrects, &numRects );
57f2b902 518
48850fa7
RR
519 m_numRects = numRects;
520 if (numRects)
521 {
522 m_rects = new wxRect[m_numRects];
523 for (size_t i=0; i < m_numRects; ++i)
3d0c4d2e 524 {
48850fa7
RR
525 GdkRectangle &gr = gdkrects[i];
526 wxRect &wr = m_rects[i];
527 wr.x = gr.x;
528 wr.y = gr.y;
529 wr.width = gr.width;
530 wr.height = gr.height;
3d0c4d2e 531 }
3d0c4d2e 532 }
9e691f46
VZ
533 g_free( gdkrects );
534#else // GTK+ 1.x
48850fa7
RR
535 Region r = ((GdkRegionPrivate *)gdkregion)->xregion;
536 if (r)
537 {
538 m_numRects = r->numRects;
539 if (m_numRects)
540 {
541 m_rects = new wxRect[m_numRects];
542 for (size_t i=0; i < m_numRects; ++i)
543 {
544 _XBox &xr = r->rects[i];
545 wxRect &wr = m_rects[i];
546 wr.x = xr.x1;
547 wr.y = xr.y1;
548 wr.width = xr.x2-xr.x1;
549 wr.height = xr.y2-xr.y1;
550 }
551 }
552 }
9e691f46 553#endif // GTK+ 2.0/1.x
3d0c4d2e
RR
554}
555
3d0c4d2e
RR
556wxRegionIterator::wxRegionIterator()
557{
558 m_refData = new wxRIRefData();
559 Reset();
560}
561
562wxRegionIterator::wxRegionIterator( const wxRegion& region )
563{
564 m_refData = new wxRIRefData();
565 Reset(region);
566}
567
568void wxRegionIterator::Reset( const wxRegion& region )
569{
570 m_region = region;
571 ((wxRIRefData*)m_refData)->CreateRects(region);
572 Reset();
573}
574
575bool wxRegionIterator::HaveRects() const
576{
577 return m_current < ((wxRIRefData*)m_refData)->m_numRects;
578}
579
2b5f62a0 580wxRegionIterator& wxRegionIterator::operator ++ ()
3d0c4d2e 581{
2b5f62a0
VZ
582 if (HaveRects())
583 ++m_current;
3d0c4d2e 584
2b5f62a0 585 return *this;
3d0c4d2e
RR
586}
587
2b5f62a0 588wxRegionIterator wxRegionIterator::operator ++ (int)
3d0c4d2e 589{
2b5f62a0
VZ
590 wxRegionIterator tmp = *this;
591 if (HaveRects())
592 ++m_current;
593
594 return tmp;
3d0c4d2e
RR
595}
596
597wxCoord wxRegionIterator::GetX() const
598{
2b5f62a0
VZ
599 wxCHECK_MSG( HaveRects(), 0, _T("invalid wxRegionIterator") );
600
3d0c4d2e
RR
601 return ((wxRIRefData*)m_refData)->m_rects[m_current].x;
602}
603
604wxCoord wxRegionIterator::GetY() const
605{
2b5f62a0
VZ
606 wxCHECK_MSG( HaveRects(), 0, _T("invalid wxRegionIterator") );
607
3d0c4d2e
RR
608 return ((wxRIRefData*)m_refData)->m_rects[m_current].y;
609}
610
611wxCoord wxRegionIterator::GetW() const
612{
2b5f62a0
VZ
613 wxCHECK_MSG( HaveRects(), 0, _T("invalid wxRegionIterator") );
614
3d0c4d2e
RR
615 return ((wxRIRefData*)m_refData)->m_rects[m_current].width;
616}
617
618wxCoord wxRegionIterator::GetH() const
619{
2b5f62a0
VZ
620 wxCHECK_MSG( HaveRects(), 0, _T("invalid wxRegionIterator") );
621
3d0c4d2e
RR
622 return ((wxRIRefData*)m_refData)->m_rects[m_current].height;
623}
624
1e6feb95
VZ
625wxRect wxRegionIterator::GetRect() const
626{
627 wxRect r;
3379ed37
VZ
628 if( HaveRects() )
629 r = ((wxRIRefData*)m_refData)->m_rects[m_current];
1e6feb95
VZ
630
631 return r;
632}
633