]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/region.cpp
[ 1487463 ] XRC handler for wxOwnerDrawnComboBox.
[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
48850fa7
RR
49 ~wxRegionRefData()
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
fbfb8bcc 136bool wxRegion::operator==( const wxRegion& region ) const
c801d85f 137{
b3a44e05 138 if (m_refData == region.m_refData) return true;
c89f5c02 139
b3a44e05 140 if (!m_refData || !region.m_refData) return false;
57f2b902 141
9fe4c99c 142 // compare the regions themselves, not the pointers to ref data!
1e6feb95
VZ
143 return gdk_region_equal(M_REGIONDATA->m_region,
144 M_REGIONDATA_OF(region)->m_region);
ff7b1510 145}
c801d85f 146
1e6feb95
VZ
147// ----------------------------------------------------------------------------
148// wxRegion operations
149// ----------------------------------------------------------------------------
150
bf57d1ad 151void wxRegion::Clear()
c801d85f 152{
bbe0af5b 153 UnRef();
ff7b1510 154}
c801d85f 155
5fc7ede9 156bool wxRegion::Union( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
c801d85f 157{
57351df0
VZ
158 // workaround for a strange GTK/X11 bug: taking union with an empty
159 // rectangle results in an empty region which is definitely not what we
160 // want
161 if ( !width || !height )
b3a44e05 162 return true;
57351df0 163
2b5f62a0 164 if ( !m_refData )
e1208c31 165 {
2b5f62a0 166 InitRect(x, y, width, height);
e1208c31
RR
167 }
168 else
169 {
9fe4c99c 170 AllocExclusive();
1e6feb95 171
2b5f62a0
VZ
172 GdkRectangle rect;
173 rect.x = x;
174 rect.y = y;
175 rect.width = width;
176 rect.height = height;
177
b7c2d6ff 178 gdk_region_union_with_rect( M_REGIONDATA->m_region, &rect );
e1208c31 179 }
1e6feb95 180
b3a44e05 181 return true;
ff7b1510 182}
c801d85f
KB
183
184bool wxRegion::Union( const wxRect& rect )
185{
e1208c31 186 return Union( rect.x, rect.y, rect.width, rect.height );
ff7b1510 187}
c801d85f
KB
188
189bool wxRegion::Union( const wxRegion& region )
190{
e1208c31 191 if (region.IsNull())
b3a44e05 192 return false;
e1208c31 193
48850fa7
RR
194 if (!m_refData)
195 {
196 m_refData = new wxRegionRefData();
197 M_REGIONDATA->m_region = gdk_region_new();
198 }
199 else
200 {
201 AllocExclusive();
202 }
e1208c31 203
b7c2d6ff 204 gdk_region_union( M_REGIONDATA->m_region, region.GetRegion() );
5fc7ede9 205
b3a44e05 206 return true;
ff7b1510 207}
c801d85f 208
5fc7ede9 209bool wxRegion::Intersect( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
c801d85f 210{
bbe0af5b 211 wxRegion reg( x, y, width, height );
1e6feb95
VZ
212
213 return Intersect( reg );
ff7b1510 214}
c801d85f
KB
215
216bool wxRegion::Intersect( const wxRect& rect )
217{
bbe0af5b 218 wxRegion reg( rect );
57f2b902 219
1e6feb95 220 return Intersect( reg );
ff7b1510 221}
c801d85f 222
1e6feb95 223bool wxRegion::Intersect( const wxRegion& region )
c801d85f 224{
1e6feb95 225 if (region.IsNull())
b3a44e05 226 return false;
1e6feb95 227
e1208c31
RR
228 if (!m_refData)
229 {
2b5f62a0 230 // intersecting with invalid region doesn't make sense
b3a44e05 231 return false;
1e6feb95
VZ
232 }
233
2b5f62a0
VZ
234 AllocExclusive();
235
48850fa7 236 gdk_region_intersect( M_REGIONDATA->m_region, region.GetRegion() );
9fe4c99c 237
b3a44e05 238 return true;
ff7b1510 239}
c801d85f 240
1e6feb95 241bool wxRegion::Subtract( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
c801d85f 242{
1e6feb95
VZ
243 wxRegion reg( x, y, width, height );
244 return Subtract( reg );
245}
e1208c31 246
1e6feb95
VZ
247bool wxRegion::Subtract( const wxRect& rect )
248{
bbe0af5b 249 wxRegion reg( rect );
1e6feb95 250 return Subtract( reg );
ff7b1510 251}
c801d85f
KB
252
253bool wxRegion::Subtract( const wxRegion& region )
254{
e1208c31 255 if (region.IsNull())
b3a44e05 256 return false;
e1208c31
RR
257
258 if (!m_refData)
259 {
2b5f62a0 260 // subtracting from an invalid region doesn't make sense
b3a44e05 261 return false;
48850fa7 262 }
1e6feb95 263
2b5f62a0
VZ
264 AllocExclusive();
265
b7c2d6ff 266 gdk_region_subtract( M_REGIONDATA->m_region, region.GetRegion() );
1e6feb95 267
b3a44e05 268 return true;
ff7b1510 269}
c801d85f 270
5fc7ede9 271bool wxRegion::Xor( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
c801d85f 272{
bbe0af5b 273 wxRegion reg( x, y, width, height );
1e6feb95 274 return Xor( reg );
ff7b1510 275}
c801d85f
KB
276
277bool wxRegion::Xor( const wxRect& rect )
278{
bbe0af5b 279 wxRegion reg( rect );
1e6feb95 280 return Xor( reg );
ff7b1510 281}
c801d85f
KB
282
283bool wxRegion::Xor( const wxRegion& region )
284{
e1208c31 285 if (region.IsNull())
b3a44e05 286 return false;
e1208c31
RR
287
288 if (!m_refData)
289 {
b3a44e05 290 return false;
1e6feb95 291 }
e1208c31 292
2b5f62a0
VZ
293 AllocExclusive();
294
b7c2d6ff 295 gdk_region_xor( M_REGIONDATA->m_region, region.GetRegion() );
5fc7ede9 296
b3a44e05 297 return true;
ff7b1510 298}
c801d85f 299
2b5f62a0
VZ
300bool wxRegion::Offset( wxCoord x, wxCoord y )
301{
302 if (!m_refData)
b3a44e05 303 return false;
2b5f62a0
VZ
304
305 AllocExclusive();
306
307 gdk_region_offset( M_REGIONDATA->m_region, x, y );
308
b3a44e05 309 return true;
2b5f62a0
VZ
310}
311
1e6feb95
VZ
312// ----------------------------------------------------------------------------
313// wxRegion tests
314// ----------------------------------------------------------------------------
315
e1208c31 316void wxRegion::GetBox( wxCoord &x, wxCoord &y, wxCoord &w, wxCoord &h ) const
c801d85f 317{
1e6feb95
VZ
318 if ( m_refData )
319 {
320 GdkRectangle rect;
321 gdk_region_get_clipbox( M_REGIONDATA->m_region, &rect );
322 x = rect.x;
323 y = rect.y;
324 w = rect.width;
325 h = rect.height;
326 }
327 else
328 {
329 x = 0;
330 y = 0;
331 w = -1;
332 h = -1;
333 }
ff7b1510 334}
c801d85f 335
bf57d1ad 336wxRect wxRegion::GetBox() const
c801d85f 337{
1e6feb95 338 wxCoord x, y, w, h;
bbe0af5b
RR
339 GetBox( x, y, w, h );
340 return wxRect( x, y, w, h );
ff7b1510 341}
c801d85f 342
bf57d1ad 343bool wxRegion::Empty() const
c801d85f 344{
e1208c31 345 if (!m_refData)
b3a44e05 346 return true;
e1208c31 347
bbe0af5b 348 return gdk_region_empty( M_REGIONDATA->m_region );
ff7b1510 349}
c801d85f 350
5fc7ede9 351wxRegionContain wxRegion::Contains( wxCoord x, wxCoord y ) const
c801d85f 352{
e1208c31
RR
353 if (!m_refData)
354 return wxOutRegion;
355
bbe0af5b
RR
356 if (gdk_region_point_in( M_REGIONDATA->m_region, x, y ))
357 return wxInRegion;
358 else
359 return wxOutRegion;
ff7b1510 360}
c801d85f 361
5fc7ede9 362wxRegionContain wxRegion::Contains( wxCoord x, wxCoord y, wxCoord w, wxCoord h ) const
c801d85f 363{
e1208c31
RR
364 if (!m_refData)
365 return wxOutRegion;
366
bbe0af5b
RR
367 GdkRectangle rect;
368 rect.x = x;
369 rect.y = y;
370 rect.width = w;
371 rect.height = h;
372 GdkOverlapType res = gdk_region_rect_in( M_REGIONDATA->m_region, &rect );
373 switch (res)
374 {
375 case GDK_OVERLAP_RECTANGLE_IN: return wxInRegion;
376 case GDK_OVERLAP_RECTANGLE_OUT: return wxOutRegion;
377 case GDK_OVERLAP_RECTANGLE_PART: return wxPartRegion;
378 }
379 return wxOutRegion;
ff7b1510 380}
c801d85f 381
8429bec1
RR
382wxRegionContain wxRegion::Contains(const wxPoint& pt) const
383{
bbe0af5b 384 return Contains( pt.x, pt.y );
8429bec1
RR
385}
386
387wxRegionContain wxRegion::Contains(const wxRect& rect) const
388{
bbe0af5b 389 return Contains( rect.x, rect.y, rect.width, rect.height );
8429bec1
RR
390}
391
bf57d1ad 392GdkRegion *wxRegion::GetRegion() const
c801d85f 393{
e1208c31
RR
394 if (!m_refData)
395 return (GdkRegion*) NULL;
396
bbe0af5b 397 return M_REGIONDATA->m_region;
ff7b1510 398}
c801d85f 399
1e6feb95 400// ----------------------------------------------------------------------------
3d0c4d2e 401// wxRegionIterator
1e6feb95 402// ----------------------------------------------------------------------------
8429bec1 403
3d0c4d2e
RR
404class wxRIRefData: public wxObjectRefData
405{
406public:
3f0fb1d4
VZ
407 wxRIRefData() { Init(); }
408 virtual ~wxRIRefData();
3d0c4d2e 409
3f0fb1d4
VZ
410 void CreateRects( const wxRegion& r );
411
412 void Init() { m_rects = NULL; m_numRects = 0; }
3d0c4d2e
RR
413
414 wxRect *m_rects;
415 size_t m_numRects;
3d0c4d2e
RR
416};
417
418wxRIRefData::~wxRIRefData()
419{
64423153 420 delete [] m_rects;
3d0c4d2e
RR
421}
422
3d0c4d2e
RR
423void wxRIRefData::CreateRects( const wxRegion& region )
424{
64423153 425 delete [] m_rects;
48850fa7 426
3f0fb1d4 427 Init();
57f2b902 428
48850fa7 429 GdkRegion *gdkregion = region.GetRegion();
3f0fb1d4
VZ
430 if (!gdkregion)
431 return;
57f2b902 432
9e691f46 433 GdkRectangle *gdkrects = NULL;
48850fa7 434 gint numRects = 0;
9e691f46 435 gdk_region_get_rectangles( gdkregion, &gdkrects, &numRects );
57f2b902 436
48850fa7
RR
437 m_numRects = numRects;
438 if (numRects)
439 {
440 m_rects = new wxRect[m_numRects];
441 for (size_t i=0; i < m_numRects; ++i)
3d0c4d2e 442 {
48850fa7
RR
443 GdkRectangle &gr = gdkrects[i];
444 wxRect &wr = m_rects[i];
445 wr.x = gr.x;
446 wr.y = gr.y;
447 wr.width = gr.width;
448 wr.height = gr.height;
3d0c4d2e 449 }
3d0c4d2e 450 }
9e691f46 451 g_free( gdkrects );
3d0c4d2e
RR
452}
453
3d0c4d2e
RR
454wxRegionIterator::wxRegionIterator()
455{
456 m_refData = new wxRIRefData();
457 Reset();
458}
459
460wxRegionIterator::wxRegionIterator( const wxRegion& region )
461{
462 m_refData = new wxRIRefData();
463 Reset(region);
464}
465
466void wxRegionIterator::Reset( const wxRegion& region )
467{
468 m_region = region;
469 ((wxRIRefData*)m_refData)->CreateRects(region);
470 Reset();
471}
472
473bool wxRegionIterator::HaveRects() const
474{
475 return m_current < ((wxRIRefData*)m_refData)->m_numRects;
476}
477
2b5f62a0 478wxRegionIterator& wxRegionIterator::operator ++ ()
3d0c4d2e 479{
2b5f62a0
VZ
480 if (HaveRects())
481 ++m_current;
3d0c4d2e 482
2b5f62a0 483 return *this;
3d0c4d2e
RR
484}
485
2b5f62a0 486wxRegionIterator wxRegionIterator::operator ++ (int)
3d0c4d2e 487{
2b5f62a0
VZ
488 wxRegionIterator tmp = *this;
489 if (HaveRects())
490 ++m_current;
491
492 return tmp;
3d0c4d2e
RR
493}
494
495wxCoord wxRegionIterator::GetX() const
496{
2b5f62a0
VZ
497 wxCHECK_MSG( HaveRects(), 0, _T("invalid wxRegionIterator") );
498
3d0c4d2e
RR
499 return ((wxRIRefData*)m_refData)->m_rects[m_current].x;
500}
501
502wxCoord wxRegionIterator::GetY() const
503{
2b5f62a0
VZ
504 wxCHECK_MSG( HaveRects(), 0, _T("invalid wxRegionIterator") );
505
3d0c4d2e
RR
506 return ((wxRIRefData*)m_refData)->m_rects[m_current].y;
507}
508
509wxCoord wxRegionIterator::GetW() const
510{
2b5f62a0
VZ
511 wxCHECK_MSG( HaveRects(), 0, _T("invalid wxRegionIterator") );
512
3d0c4d2e
RR
513 return ((wxRIRefData*)m_refData)->m_rects[m_current].width;
514}
515
516wxCoord wxRegionIterator::GetH() const
517{
2b5f62a0
VZ
518 wxCHECK_MSG( HaveRects(), 0, _T("invalid wxRegionIterator") );
519
3d0c4d2e
RR
520 return ((wxRIRefData*)m_refData)->m_rects[m_current].height;
521}
522
1e6feb95
VZ
523wxRect wxRegionIterator::GetRect() const
524{
525 wxRect r;
3379ed37
VZ
526 if( HaveRects() )
527 r = ((wxRIRefData*)m_refData)->m_rects[m_current];
1e6feb95
VZ
528
529 return r;
530}