]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/gtk/region.cpp
Corrected wxScrolledWindow's OnSize behaviour.
[wxWidgets.git] / src / gtk / region.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: gtk/region.cpp
3// Purpose:
4// Author: Robert Roebling
5// Modified: VZ at 05.10.00: use Unshare(), comparison fixed
6// Id: $Id$
7// Copyright: (c) 1998 Robert Roebling
8// Licence: wxWindows licence
9/////////////////////////////////////////////////////////////////////////////
10
11// ============================================================================
12// declarations
13// ============================================================================
14
15#ifdef __GNUG__
16 #pragma implementation "region.h"
17#endif
18
19// ----------------------------------------------------------------------------
20// headers
21// ----------------------------------------------------------------------------
22
23#include "wx/region.h"
24
25#include <gdk/gdk.h>
26#include <gtk/gtk.h>
27
28// Unfortunately the new way of implementing the region iterator
29// doesn't work with GTK+ 2.0 or above (can't access a Region in
30// GdkPrivateRegion)
31#ifdef __WXGTK20__
32#define OLDCODE 1
33#else
34#define OLDCODE 0
35#endif
36
37#include "wx/log.h"
38
39// ----------------------------------------------------------------------------
40// wxRegionRefData: private class containing the information about the region
41// ----------------------------------------------------------------------------
42
43class wxRegionRefData : public wxObjectRefData
44{
45public:
46 wxRegionRefData();
47 wxRegionRefData(const wxRegionRefData& refData);
48 virtual ~wxRegionRefData();
49
50 GdkRegion *m_region;
51#if OLDCODE
52 wxList m_rects;
53#endif
54};
55
56// ----------------------------------------------------------------------------
57// macros
58// ----------------------------------------------------------------------------
59
60#define M_REGIONDATA ((wxRegionRefData *)m_refData)
61#define M_REGIONDATA_OF(rgn) ((wxRegionRefData *)(rgn.m_refData))
62
63IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject);
64IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator,wxObject);
65
66// ============================================================================
67// implementation
68// ============================================================================
69
70// ----------------------------------------------------------------------------
71// wxRegionRefData
72// ----------------------------------------------------------------------------
73
74wxRegionRefData::wxRegionRefData()
75{
76 m_region = (GdkRegion *) NULL;
77}
78
79wxRegionRefData::wxRegionRefData(const wxRegionRefData& refData)
80{
81#ifdef __WXGTK20__
82 m_region = gdk_region_copy(refData.m_region);
83#else
84 m_region = gdk_region_new();
85 GdkRegion *regCopy = gdk_regions_union(m_region, refData.m_region);
86 gdk_region_destroy(m_region);
87 m_region = regCopy;
88#endif
89
90#if OLDCODE
91 wxNode *node = refData.m_rects.First();
92 while (node)
93 {
94 wxRect *r = (wxRect*)node->Data();
95 m_rects.Append( (wxObject*) new wxRect(*r) );
96 node = node->Next();
97 }
98#endif
99}
100
101wxRegionRefData::~wxRegionRefData()
102{
103 if (m_region) gdk_region_destroy( m_region );
104
105#if OLDCODE
106 wxNode *node = m_rects.First();
107 while (node)
108 {
109 wxRect *r = (wxRect*)node->Data();
110 delete r;
111 node = node->Next();
112 }
113#endif
114}
115
116// ----------------------------------------------------------------------------
117// wxRegion construction
118// ----------------------------------------------------------------------------
119
120#define M_REGIONDATA ((wxRegionRefData *)m_refData)
121
122wxRegion::wxRegion()
123{
124}
125
126wxRegion::wxRegion( wxCoord x, wxCoord y, wxCoord w, wxCoord h )
127{
128 m_refData = new wxRegionRefData();
129 GdkRegion *reg = gdk_region_new();
130 GdkRectangle rect;
131 rect.x = x;
132 rect.y = y;
133 rect.width = w;
134 rect.height = h;
135#ifdef __WXGTK20__
136 gdk_region_union_with_rect( reg, &rect );
137 M_REGIONDATA->m_region = reg;
138#else
139 M_REGIONDATA->m_region = gdk_region_union_with_rect( reg, &rect );
140 gdk_region_destroy( reg );
141#endif
142#if OLDCODE
143 M_REGIONDATA->m_rects.Append( (wxObject*) new wxRect(x,y,w,h) );
144#endif
145}
146
147wxRegion::wxRegion( const wxPoint& topLeft, const wxPoint& bottomRight )
148{
149 m_refData = new wxRegionRefData();
150 GdkRegion *reg = gdk_region_new();
151 GdkRectangle rect;
152 rect.x = topLeft.x;
153 rect.y = topLeft.y;
154 rect.width = bottomRight.x - rect.x;
155 rect.height = bottomRight.y - rect.y;
156#ifdef __WXGTK20__
157 gdk_region_union_with_rect( reg, &rect );
158 M_REGIONDATA->m_region = reg;
159#else
160 M_REGIONDATA->m_region = gdk_region_union_with_rect( reg, &rect );
161 gdk_region_destroy( reg );
162#endif
163#if OLDCODE
164 M_REGIONDATA->m_rects.Append( (wxObject*) new wxRect(topLeft,bottomRight) );
165#endif
166}
167
168wxRegion::wxRegion( const wxRect& rect )
169{
170 m_refData = new wxRegionRefData();
171 GdkRegion *reg = gdk_region_new();
172 GdkRectangle g_rect;
173 g_rect.x = rect.x;
174 g_rect.y = rect.y;
175 g_rect.width = rect.width;
176 g_rect.height = rect.height;
177#ifdef __WXGTK20__
178 gdk_region_union_with_rect( reg, &g_rect );
179 M_REGIONDATA->m_region = reg;
180#else
181 M_REGIONDATA->m_region = gdk_region_union_with_rect( reg, &g_rect );
182 gdk_region_destroy( reg );
183#endif
184#if OLDCODE
185 M_REGIONDATA->m_rects.Append( (wxObject*) new wxRect(rect.x,rect.y,rect.width,rect.height) );
186#endif
187}
188
189wxRegion::~wxRegion()
190{
191}
192
193bool wxRegion::operator==( const wxRegion& region )
194{
195 // VZ: compare the regions themselves, not the pointers to ref data!
196 return gdk_region_equal(M_REGIONDATA->m_region,
197 M_REGIONDATA_OF(region)->m_region);
198}
199
200bool wxRegion::operator != ( const wxRegion& region )
201{
202 return !(*this == region);
203}
204
205void wxRegion::Unshare()
206{
207 if ( !m_refData )
208 {
209 m_refData = new wxRegionRefData;
210 M_REGIONDATA->m_region = gdk_region_new();
211 }
212 else if ( m_refData->GetRefCount() > 1 )
213 {
214 wxRegionRefData *refData = new wxRegionRefData(*M_REGIONDATA);
215 UnRef();
216 m_refData = refData;
217 }
218 //else: we're not shared
219}
220
221// ----------------------------------------------------------------------------
222// wxRegion operations
223// ----------------------------------------------------------------------------
224
225void wxRegion::Clear()
226{
227 UnRef();
228}
229
230bool wxRegion::Union( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
231{
232 GdkRectangle rect;
233 rect.x = x;
234 rect.y = y;
235 rect.width = width;
236 rect.height = height;
237 if (!m_refData)
238 {
239 m_refData = new wxRegionRefData();
240 GdkRegion *reg = gdk_region_new();
241#ifdef __WXGTK20__
242 gdk_region_union_with_rect( reg, &rect );
243 M_REGIONDATA->m_region = reg;
244#else
245 M_REGIONDATA->m_region = gdk_region_union_with_rect( reg, &rect );
246 gdk_region_destroy( reg );
247#endif
248 }
249 else
250 {
251 Unshare();
252
253#ifdef __WXGTK20__
254 gdk_region_union_with_rect( M_REGIONDATA->m_region, &rect );
255#else
256 GdkRegion *reg = gdk_region_union_with_rect( M_REGIONDATA->m_region, &rect );
257 gdk_region_destroy( M_REGIONDATA->m_region );
258 M_REGIONDATA->m_region = reg;
259#endif
260 }
261
262#if OLDCODE
263 M_REGIONDATA->m_rects.Append( (wxObject*) new wxRect(x,y,width,height) );
264#endif
265
266 return TRUE;
267}
268
269bool wxRegion::Union( const wxRect& rect )
270{
271 return Union( rect.x, rect.y, rect.width, rect.height );
272}
273
274bool wxRegion::Union( const wxRegion& region )
275{
276 if (region.IsNull())
277 return FALSE;
278
279 Unshare();
280
281#ifdef __WXGTK20__
282 gdk_region_union( M_REGIONDATA->m_region, region.GetRegion() );
283#else
284 GdkRegion *reg = gdk_regions_union( M_REGIONDATA->m_region, region.GetRegion() );
285 gdk_region_destroy( M_REGIONDATA->m_region );
286 M_REGIONDATA->m_region = reg;
287#endif
288
289#if OLDCODE
290 wxNode *node = region.GetRectList()->First();
291 while (node)
292 {
293 wxRect *r = (wxRect*)node->Data();
294 M_REGIONDATA->m_rects.Append( (wxObject*) new wxRect(r->x,r->y,r->width,r->height) );
295 node = node->Next();
296 }
297#endif
298
299 return TRUE;
300}
301
302bool wxRegion::Intersect( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
303{
304 wxRegion reg( x, y, width, height );
305
306 return Intersect( reg );
307}
308
309bool wxRegion::Intersect( const wxRect& rect )
310{
311 wxRegion reg( rect );
312 return Intersect( reg );
313}
314
315// this helper function just computes the region intersection without updating
316// the list of rectangles each region maintaints: this allows us to call it
317// from Intersect() itself without going into infinite recursion as we would
318// if we called Intersect() itself recursively
319bool wxRegion::IntersectRegionOnly(const wxRegion& region)
320{
321 Unshare();
322
323#ifdef __WXGTK20__
324 gdk_region_intersect( M_REGIONDATA->m_region, region.GetRegion() );
325#else
326 GdkRegion *reg = gdk_regions_intersect( M_REGIONDATA->m_region, region.GetRegion() );
327 gdk_region_destroy( M_REGIONDATA->m_region );
328 M_REGIONDATA->m_region = reg;
329#endif
330
331 return TRUE;
332}
333
334bool wxRegion::Intersect( const wxRegion& region )
335{
336 if (region.IsNull())
337 return FALSE;
338
339 if (!m_refData)
340 {
341 m_refData = new wxRegionRefData();
342 M_REGIONDATA->m_region = gdk_region_new();
343 return TRUE;
344 }
345
346 if ( !IntersectRegionOnly(region) )
347 {
348 GetRectList()->Clear();
349
350 return FALSE;
351 }
352
353 // we need to update the rect list as well
354#if OLDCODE
355 wxList& list = *GetRectList();
356 wxNode *node = list.First();
357 while (node)
358 {
359 wxRect *r = (wxRect*)node->Data();
360
361 wxRegion regCopy = region;
362 if ( regCopy.IntersectRegionOnly(*r) )
363 {
364 // replace the node with the intersection
365 *r = regCopy.GetBox();
366 }
367 else
368 {
369 // TODO remove the rect from the list
370 r->width = 0;
371 r->height = 0;
372 }
373
374 node = node->Next();
375 }
376#endif
377 return TRUE;
378}
379
380bool wxRegion::Subtract( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
381{
382 wxRegion reg( x, y, width, height );
383 return Subtract( reg );
384}
385
386bool wxRegion::Subtract( const wxRect& rect )
387{
388 wxRegion reg( rect );
389 return Subtract( reg );
390}
391
392bool wxRegion::Subtract( const wxRegion& region )
393{
394 if (region.IsNull())
395 return FALSE;
396
397 if (!m_refData)
398 {
399 m_refData = new wxRegionRefData();
400 M_REGIONDATA->m_region = gdk_region_new();
401 }
402
403 Unshare();
404
405#ifdef __WXGTK20__
406 gdk_region_subtract( M_REGIONDATA->m_region, region.GetRegion() );
407#else
408 GdkRegion *reg = gdk_regions_subtract( M_REGIONDATA->m_region, region.GetRegion() );
409 gdk_region_destroy( M_REGIONDATA->m_region );
410 M_REGIONDATA->m_region = reg;
411#endif
412
413 return TRUE;
414}
415
416bool wxRegion::Xor( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
417{
418 wxRegion reg( x, y, width, height );
419 return Xor( reg );
420}
421
422bool wxRegion::Xor( const wxRect& rect )
423{
424 wxRegion reg( rect );
425 return Xor( reg );
426}
427
428bool wxRegion::Xor( const wxRegion& region )
429{
430 if (region.IsNull())
431 return FALSE;
432
433 if (!m_refData)
434 {
435 m_refData = new wxRegionRefData();
436 M_REGIONDATA->m_region = gdk_region_new();
437 }
438 else
439 {
440 Unshare();
441 }
442
443#ifdef __WXGTK20__
444 gdk_region_xor( M_REGIONDATA->m_region, region.GetRegion() );
445#else
446 GdkRegion *reg = gdk_regions_xor( M_REGIONDATA->m_region, region.GetRegion() );
447 gdk_region_destroy( M_REGIONDATA->m_region );
448 M_REGIONDATA->m_region = reg;
449#endif
450
451#if OLDCODE
452 wxNode *node = region.GetRectList()->First();
453 while (node)
454 {
455 wxRect *r = (wxRect*)node->Data();
456 M_REGIONDATA->m_rects.Append( (wxObject*) new wxRect(r->x,r->y,r->width,r->height) );
457 node = node->Next();
458 }
459#endif
460
461 return TRUE;
462}
463
464// ----------------------------------------------------------------------------
465// wxRegion tests
466// ----------------------------------------------------------------------------
467
468void wxRegion::GetBox( wxCoord &x, wxCoord &y, wxCoord &w, wxCoord &h ) const
469{
470 if ( m_refData )
471 {
472 GdkRectangle rect;
473 gdk_region_get_clipbox( M_REGIONDATA->m_region, &rect );
474 x = rect.x;
475 y = rect.y;
476 w = rect.width;
477 h = rect.height;
478 }
479 else
480 {
481 x = 0;
482 y = 0;
483 w = -1;
484 h = -1;
485 }
486}
487
488wxRect wxRegion::GetBox() const
489{
490 wxCoord x, y, w, h;
491 GetBox( x, y, w, h );
492 return wxRect( x, y, w, h );
493}
494
495bool wxRegion::Empty() const
496{
497 if (!m_refData)
498 return TRUE;
499
500 return gdk_region_empty( M_REGIONDATA->m_region );
501}
502
503wxRegionContain wxRegion::Contains( wxCoord x, wxCoord y ) const
504{
505 if (!m_refData)
506 return wxOutRegion;
507
508 if (gdk_region_point_in( M_REGIONDATA->m_region, x, y ))
509 return wxInRegion;
510 else
511 return wxOutRegion;
512}
513
514wxRegionContain wxRegion::Contains( wxCoord x, wxCoord y, wxCoord w, wxCoord h ) const
515{
516 if (!m_refData)
517 return wxOutRegion;
518
519 GdkRectangle rect;
520 rect.x = x;
521 rect.y = y;
522 rect.width = w;
523 rect.height = h;
524 GdkOverlapType res = gdk_region_rect_in( M_REGIONDATA->m_region, &rect );
525 switch (res)
526 {
527 case GDK_OVERLAP_RECTANGLE_IN: return wxInRegion;
528 case GDK_OVERLAP_RECTANGLE_OUT: return wxOutRegion;
529 case GDK_OVERLAP_RECTANGLE_PART: return wxPartRegion;
530 }
531 return wxOutRegion;
532}
533
534wxRegionContain wxRegion::Contains(const wxPoint& pt) const
535{
536 return Contains( pt.x, pt.y );
537}
538
539wxRegionContain wxRegion::Contains(const wxRect& rect) const
540{
541 return Contains( rect.x, rect.y, rect.width, rect.height );
542}
543
544GdkRegion *wxRegion::GetRegion() const
545{
546 if (!m_refData)
547 return (GdkRegion*) NULL;
548
549 return M_REGIONDATA->m_region;
550}
551
552wxList *wxRegion::GetRectList() const
553{
554#if OLDCODE
555 if (!m_refData)
556 return (wxList*) NULL;
557
558 return &(M_REGIONDATA->m_rects);
559#else
560 return (wxList*) NULL;
561#endif
562}
563
564// ----------------------------------------------------------------------------
565// wxRegionIterator
566// ----------------------------------------------------------------------------
567
568#if OLDCODE
569
570wxRegionIterator::wxRegionIterator()
571{
572 Reset();
573}
574
575wxRegionIterator::wxRegionIterator( const wxRegion& region )
576{
577 Reset(region);
578}
579
580void wxRegionIterator::Reset( const wxRegion& region )
581{
582 m_region = region;
583 Reset();
584}
585
586wxRegionIterator::operator bool () const
587{
588 return m_region.GetRectList() && m_current < (size_t)m_region.GetRectList()->Number();
589}
590
591bool wxRegionIterator::HaveRects() const
592{
593 return m_region.GetRectList() && m_current < (size_t)m_region.GetRectList()->Number();
594}
595
596void wxRegionIterator::operator ++ ()
597{
598 if (HaveRects()) ++m_current;
599}
600
601void wxRegionIterator::operator ++ (int)
602{
603 if (HaveRects()) ++m_current;
604}
605
606wxCoord wxRegionIterator::GetX() const
607{
608 wxNode *node = m_region.GetRectList()->Nth( m_current );
609 if (!node) return 0;
610 wxRect *r = (wxRect*)node->Data();
611 return r->x;
612}
613
614wxCoord wxRegionIterator::GetY() const
615{
616 wxNode *node = m_region.GetRectList()->Nth( m_current );
617 if (!node) return 0;
618 wxRect *r = (wxRect*)node->Data();
619 return r->y;
620}
621
622wxCoord wxRegionIterator::GetW() const
623{
624 wxNode *node = m_region.GetRectList()->Nth( m_current );
625 if (!node) return 0;
626 wxRect *r = (wxRect*)node->Data();
627 return r->width;
628}
629
630wxCoord wxRegionIterator::GetH() const
631{
632 wxNode *node = m_region.GetRectList()->Nth( m_current );
633 if (!node) return 0;
634 wxRect *r = (wxRect*)node->Data();
635 return r->height;
636}
637
638#else
639
640// the following structures must match the private structures
641// in X11 region code ( xc/lib/X11/region.h )
642
643// this makes the Region type transparent
644// and we have access to the region rectangles
645
646struct _XBox {
647 short x1, x2, y1, y2;
648};
649
650struct _XRegion {
651 long size , numRects;
652 _XBox *rects, extents;
653};
654
655class wxRIRefData: public wxObjectRefData
656{
657public:
658
659 wxRIRefData() : m_rects(0), m_numRects(0){}
660 ~wxRIRefData();
661
662 wxRect *m_rects;
663 size_t m_numRects;
664
665 void CreateRects( const wxRegion& r );
666};
667
668wxRIRefData::~wxRIRefData()
669{
670 delete m_rects;
671}
672
673#include <gdk/gdkprivate.h>
674
675void wxRIRefData::CreateRects( const wxRegion& region )
676{
677 if( m_rects )
678 delete m_rects;
679 m_rects = 0;
680 m_numRects= 0;
681 GdkRegion *gdkregion= region.GetRegion();
682 if( gdkregion ){
683 Region r= ((GdkRegionPrivate *)gdkregion)->xregion;
684 if( r ){
685 m_numRects= r->numRects;
686 if( m_numRects )
687 {
688 m_rects= new wxRect[m_numRects];
689 for( size_t i=0; i<m_numRects; ++i )
690 {
691 _XBox &xr= r->rects[i];
692 wxRect&wr= m_rects[i];
693 wr.x = xr.x1;
694 wr.y = xr.y1;
695 wr.width = xr.x2-xr.x1;
696 wr.height= xr.y2-xr.y1;
697 }
698 }
699 }
700 }
701}
702
703wxRegionIterator::wxRegionIterator()
704{
705 m_refData = new wxRIRefData();
706 Reset();
707}
708
709wxRegionIterator::wxRegionIterator( const wxRegion& region )
710{
711 m_refData = new wxRIRefData();
712 Reset(region);
713}
714
715void wxRegionIterator::Reset( const wxRegion& region )
716{
717 m_region = region;
718 ((wxRIRefData*)m_refData)->CreateRects(region);
719 Reset();
720}
721
722bool wxRegionIterator::HaveRects() const
723{
724 return m_current < ((wxRIRefData*)m_refData)->m_numRects;
725}
726
727wxRegionIterator::operator bool () const
728{
729 return HaveRects();
730}
731
732void wxRegionIterator::operator ++ ()
733{
734 if (HaveRects()) ++m_current;
735}
736
737void wxRegionIterator::operator ++ (int)
738{
739 if (HaveRects()) ++m_current;
740}
741
742wxCoord wxRegionIterator::GetX() const
743{
744 if( !HaveRects() ) return 0;
745 return ((wxRIRefData*)m_refData)->m_rects[m_current].x;
746}
747
748wxCoord wxRegionIterator::GetY() const
749{
750 if( !HaveRects() ) return 0;
751 return ((wxRIRefData*)m_refData)->m_rects[m_current].y;
752}
753
754wxCoord wxRegionIterator::GetW() const
755{
756 if( !HaveRects() ) return -1;
757 return ((wxRIRefData*)m_refData)->m_rects[m_current].width;
758}
759
760wxCoord wxRegionIterator::GetH() const
761{
762 if( !HaveRects() ) return -1;
763 return ((wxRIRefData*)m_refData)->m_rects[m_current].height;
764}
765
766wxRect wxRegionIterator::GetRect() const
767{
768 wxRect r;
769 if( HaveRects() )
770 r = ((wxRIRefData*)m_refData)->m_rects[m_current];
771
772 return r;
773}
774
775#endif
776