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