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