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