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