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