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