]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/gtk/region.cpp
fix for wxBitmapType definition problem
[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 wxList& list = *GetRectList();
355 wxNode *node = list.First();
356 while (node)
357 {
358 wxRect *r = (wxRect*)node->Data();
359
360 wxRegion regCopy = region;
361 if ( regCopy.IntersectRegionOnly(*r) )
362 {
363 // replace the node with the intersection
364 *r = regCopy.GetBox();
365 }
366 else
367 {
368 // TODO remove the rect from the list
369 r->width = 0;
370 r->height = 0;
371 }
372
373 node = node->Next();
374 }
375
376 return TRUE;
377}
378
379bool wxRegion::Subtract( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
380{
381 wxRegion reg( x, y, width, height );
382 return Subtract( reg );
383}
384
385bool wxRegion::Subtract( const wxRect& rect )
386{
387 wxRegion reg( rect );
388 return Subtract( reg );
389}
390
391bool wxRegion::Subtract( const wxRegion& region )
392{
393 if (region.IsNull())
394 return FALSE;
395
396 if (!m_refData)
397 {
398 m_refData = new wxRegionRefData();
399 M_REGIONDATA->m_region = gdk_region_new();
400 }
401
402 Unshare();
403
404#ifdef __WXGTK20__
405 gdk_region_subtract( M_REGIONDATA->m_region, region.GetRegion() );
406#else
407 GdkRegion *reg = gdk_regions_subtract( M_REGIONDATA->m_region, region.GetRegion() );
408 gdk_region_destroy( M_REGIONDATA->m_region );
409 M_REGIONDATA->m_region = reg;
410#endif
411
412 return TRUE;
413}
414
415bool wxRegion::Xor( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
416{
417 wxRegion reg( x, y, width, height );
418 return Xor( reg );
419}
420
421bool wxRegion::Xor( const wxRect& rect )
422{
423 wxRegion reg( rect );
424 return Xor( reg );
425}
426
427bool wxRegion::Xor( const wxRegion& region )
428{
429 if (region.IsNull())
430 return FALSE;
431
432 if (!m_refData)
433 {
434 m_refData = new wxRegionRefData();
435 M_REGIONDATA->m_region = gdk_region_new();
436 }
437 else
438 {
439 Unshare();
440 }
441
442#ifdef __WXGTK20__
443 gdk_region_xor( M_REGIONDATA->m_region, region.GetRegion() );
444#else
445 GdkRegion *reg = gdk_regions_xor( M_REGIONDATA->m_region, region.GetRegion() );
446 gdk_region_destroy( M_REGIONDATA->m_region );
447 M_REGIONDATA->m_region = reg;
448#endif
449
450#if OLDCODE
451 wxNode *node = region.GetRectList()->First();
452 while (node)
453 {
454 wxRect *r = (wxRect*)node->Data();
455 M_REGIONDATA->m_rects.Append( (wxObject*) new wxRect(r->x,r->y,r->width,r->height) );
456 node = node->Next();
457 }
458#endif
459
460 return TRUE;
461}
462
463// ----------------------------------------------------------------------------
464// wxRegion tests
465// ----------------------------------------------------------------------------
466
467void wxRegion::GetBox( wxCoord &x, wxCoord &y, wxCoord &w, wxCoord &h ) const
468{
469 if ( m_refData )
470 {
471 GdkRectangle rect;
472 gdk_region_get_clipbox( M_REGIONDATA->m_region, &rect );
473 x = rect.x;
474 y = rect.y;
475 w = rect.width;
476 h = rect.height;
477 }
478 else
479 {
480 x = 0;
481 y = 0;
482 w = -1;
483 h = -1;
484 }
485}
486
487wxRect wxRegion::GetBox() const
488{
489 wxCoord x, y, w, h;
490 GetBox( x, y, w, h );
491 return wxRect( x, y, w, h );
492}
493
494bool wxRegion::Empty() const
495{
496 if (!m_refData)
497 return TRUE;
498
499 return gdk_region_empty( M_REGIONDATA->m_region );
500}
501
502wxRegionContain wxRegion::Contains( wxCoord x, wxCoord y ) const
503{
504 if (!m_refData)
505 return wxOutRegion;
506
507 if (gdk_region_point_in( M_REGIONDATA->m_region, x, y ))
508 return wxInRegion;
509 else
510 return wxOutRegion;
511}
512
513wxRegionContain wxRegion::Contains( wxCoord x, wxCoord y, wxCoord w, wxCoord h ) const
514{
515 if (!m_refData)
516 return wxOutRegion;
517
518 GdkRectangle rect;
519 rect.x = x;
520 rect.y = y;
521 rect.width = w;
522 rect.height = h;
523 GdkOverlapType res = gdk_region_rect_in( M_REGIONDATA->m_region, &rect );
524 switch (res)
525 {
526 case GDK_OVERLAP_RECTANGLE_IN: return wxInRegion;
527 case GDK_OVERLAP_RECTANGLE_OUT: return wxOutRegion;
528 case GDK_OVERLAP_RECTANGLE_PART: return wxPartRegion;
529 }
530 return wxOutRegion;
531}
532
533wxRegionContain wxRegion::Contains(const wxPoint& pt) const
534{
535 return Contains( pt.x, pt.y );
536}
537
538wxRegionContain wxRegion::Contains(const wxRect& rect) const
539{
540 return Contains( rect.x, rect.y, rect.width, rect.height );
541}
542
543GdkRegion *wxRegion::GetRegion() const
544{
545 if (!m_refData)
546 return (GdkRegion*) NULL;
547
548 return M_REGIONDATA->m_region;
549}
550
551wxList *wxRegion::GetRectList() const
552{
553#if OLDCODE
554 if (!m_refData)
555 return (wxList*) NULL;
556
557 return &(M_REGIONDATA->m_rects);
558#else
559 return (wxList*) NULL;
560#endif
561}
562
563// ----------------------------------------------------------------------------
564// wxRegionIterator
565// ----------------------------------------------------------------------------
566
567#if OLDCODE
568
569wxRegionIterator::wxRegionIterator()
570{
571 Reset();
572}
573
574wxRegionIterator::wxRegionIterator( const wxRegion& region )
575{
576 Reset(region);
577}
578
579void wxRegionIterator::Reset( const wxRegion& region )
580{
581 m_region = region;
582 Reset();
583}
584
585wxRegionIterator::operator bool () const
586{
587 return m_region.GetRectList() && m_current < (size_t)m_region.GetRectList()->Number();
588}
589
590bool wxRegionIterator::HaveRects() const
591{
592 return m_region.GetRectList() && m_current < (size_t)m_region.GetRectList()->Number();
593}
594
595void wxRegionIterator::operator ++ ()
596{
597 if (HaveRects()) ++m_current;
598}
599
600void wxRegionIterator::operator ++ (int)
601{
602 if (HaveRects()) ++m_current;
603}
604
605wxCoord wxRegionIterator::GetX() const
606{
607 wxNode *node = m_region.GetRectList()->Nth( m_current );
608 if (!node) return 0;
609 wxRect *r = (wxRect*)node->Data();
610 return r->x;
611}
612
613wxCoord wxRegionIterator::GetY() const
614{
615 wxNode *node = m_region.GetRectList()->Nth( m_current );
616 if (!node) return 0;
617 wxRect *r = (wxRect*)node->Data();
618 return r->y;
619}
620
621wxCoord wxRegionIterator::GetW() const
622{
623 wxNode *node = m_region.GetRectList()->Nth( m_current );
624 if (!node) return 0;
625 wxRect *r = (wxRect*)node->Data();
626 return r->width;
627}
628
629wxCoord wxRegionIterator::GetH() const
630{
631 wxNode *node = m_region.GetRectList()->Nth( m_current );
632 if (!node) return 0;
633 wxRect *r = (wxRect*)node->Data();
634 return r->height;
635}
636
637#else
638
639// the following structures must match the private structures
640// in X11 region code ( xc/lib/X11/region.h )
641
642// this makes the Region type transparent
643// and we have access to the region rectangles
644
645struct _XBox {
646 short x1, x2, y1, y2;
647};
648
649struct _XRegion {
650 long size , numRects;
651 _XBox *rects, extents;
652};
653
654class wxRIRefData: public wxObjectRefData
655{
656public:
657
658 wxRIRefData() : m_rects(0), m_numRects(0){}
659 ~wxRIRefData();
660
661 wxRect *m_rects;
662 size_t m_numRects;
663
664 void CreateRects( const wxRegion& r );
665};
666
667wxRIRefData::~wxRIRefData()
668{
669 delete m_rects;
670}
671
672#include <gdk/gdkprivate.h>
673
674void wxRIRefData::CreateRects( const wxRegion& region )
675{
676 if( m_rects )
677 delete m_rects;
678 m_rects = 0;
679 m_numRects= 0;
680 GdkRegion *gdkregion= region.GetRegion();
681 if( gdkregion ){
682 Region r= ((GdkRegionPrivate *)gdkregion)->xregion;
683 if( r ){
684 m_numRects= r->numRects;
685 if( m_numRects )
686 {
687 m_rects= new wxRect[m_numRects];
688 for( size_t i=0; i<m_numRects; ++i )
689 {
690 _XBox &xr= r->rects[i];
691 wxRect&wr= m_rects[i];
692 wr.x = xr.x1;
693 wr.y = xr.y1;
694 wr.width = xr.x2-xr.x1;
695 wr.height= xr.y2-xr.y1;
696 }
697 }
698 }
699 }
700}
701
702wxRegionIterator::wxRegionIterator()
703{
704 m_refData = new wxRIRefData();
705 Reset();
706}
707
708wxRegionIterator::wxRegionIterator( const wxRegion& region )
709{
710 m_refData = new wxRIRefData();
711 Reset(region);
712}
713
714void wxRegionIterator::Reset( const wxRegion& region )
715{
716 m_region = region;
717 ((wxRIRefData*)m_refData)->CreateRects(region);
718 Reset();
719}
720
721bool wxRegionIterator::HaveRects() const
722{
723 return m_current < ((wxRIRefData*)m_refData)->m_numRects;
724}
725
726wxRegionIterator::operator bool () const
727{
728 return HaveRects();
729}
730
731void wxRegionIterator::operator ++ ()
732{
733 if (HaveRects()) ++m_current;
734}
735
736void wxRegionIterator::operator ++ (int)
737{
738 if (HaveRects()) ++m_current;
739}
740
741wxCoord wxRegionIterator::GetX() const
742{
743 if( !HaveRects() ) return 0;
744 return ((wxRIRefData*)m_refData)->m_rects[m_current].x;
745}
746
747wxCoord wxRegionIterator::GetY() const
748{
749 if( !HaveRects() ) return 0;
750 return ((wxRIRefData*)m_refData)->m_rects[m_current].y;
751}
752
753wxCoord wxRegionIterator::GetW() const
754{
755 if( !HaveRects() ) return -1;
756 return ((wxRIRefData*)m_refData)->m_rects[m_current].width;
757}
758
759wxCoord wxRegionIterator::GetH() const
760{
761 if( !HaveRects() ) return -1;
762 return ((wxRIRefData*)m_refData)->m_rects[m_current].height;
763}
764
765wxRect wxRegionIterator::GetRect() const
766{
767 wxRect r;
768 wxNode *node = m_region.GetRectList()->Nth( m_current );
769
770 if (node)
771 r = *((wxRect*)node->Data());
772
773 return r;
774}
775
776#endif
777