]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/region.cpp
Put some life into GTK 2.0 drawing.
[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/log.h"
24
25 #include "wx/region.h"
26
27 #include "wx/gtk/private.h"
28
29 // ----------------------------------------------------------------------------
30 // wxRegionRefData: private class containing the information about the region
31 // ----------------------------------------------------------------------------
32
33 class wxRegionRefData : public wxObjectRefData
34 {
35 public:
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 }
58
59 GdkRegion *m_region;
60 };
61
62 // ----------------------------------------------------------------------------
63 // macros
64 // ----------------------------------------------------------------------------
65
66 #define M_REGIONDATA ((wxRegionRefData *)m_refData)
67 #define M_REGIONDATA_OF(rgn) ((wxRegionRefData *)(rgn.m_refData))
68
69 IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject);
70 IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator,wxObject);
71
72 // ----------------------------------------------------------------------------
73 // wxRegion construction
74 // ----------------------------------------------------------------------------
75
76 #define M_REGIONDATA ((wxRegionRefData *)m_refData)
77
78 void wxRegion::InitRect(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
79 {
80 GdkRectangle rect;
81 rect.x = x;
82 rect.y = y;
83 rect.width = w;
84 rect.height = h;
85
86 m_refData = new wxRegionRefData();
87
88 #ifdef __WXGTK20__
89 M_REGIONDATA->m_region = gdk_region_rectangle( &rect );
90 #else
91 GdkRegion *reg = gdk_region_new();
92 M_REGIONDATA->m_region = gdk_region_union_with_rect( reg, &rect );
93 gdk_region_destroy( reg );
94 #endif
95 }
96
97 wxRegion::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
121 wxRegion::~wxRegion()
122 {
123 // m_refData unrefed in ~wxObject
124 }
125
126 wxObjectRefData *wxRegion::CreateRefData() const
127 {
128 return new wxRegionRefData;
129 }
130
131 wxObjectRefData *wxRegion::CloneRefData(const wxObjectRefData *data) const
132 {
133 return new wxRegionRefData(*(wxRegionRefData *)data);
134 }
135
136 // ----------------------------------------------------------------------------
137 // wxRegion comparison
138 // ----------------------------------------------------------------------------
139
140 bool wxRegion::operator==( const wxRegion& region )
141 {
142 if (m_refData == region.m_refData) return TRUE;
143
144 if (!m_refData || !region.m_refData) return FALSE;
145
146 // compare the regions themselves, not the pointers to ref data!
147 return gdk_region_equal(M_REGIONDATA->m_region,
148 M_REGIONDATA_OF(region)->m_region);
149 }
150
151 // ----------------------------------------------------------------------------
152 // wxRegion operations
153 // ----------------------------------------------------------------------------
154
155 void wxRegion::Clear()
156 {
157 UnRef();
158 }
159
160 bool wxRegion::Union( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
161 {
162 GdkRectangle rect;
163 rect.x = x;
164 rect.y = y;
165 rect.width = width;
166 rect.height = height;
167
168 if (!m_refData)
169 {
170 m_refData = new wxRegionRefData();
171 #ifdef __WXGTK20__
172 M_REGIONDATA->m_region = gdk_region_rectangle( &rect );
173 #else
174 GdkRegion *reg = gdk_region_new();
175 M_REGIONDATA->m_region = gdk_region_union_with_rect( reg, &rect );
176 gdk_region_destroy( reg );
177 #endif
178 }
179 else
180 {
181 AllocExclusive();
182
183 #ifdef __WXGTK20__
184 gdk_region_union_with_rect( M_REGIONDATA->m_region, &rect );
185 #else
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;
189 #endif
190 }
191
192 return TRUE;
193 }
194
195 bool wxRegion::Union( const wxRect& rect )
196 {
197 return Union( rect.x, rect.y, rect.width, rect.height );
198 }
199
200 bool wxRegion::Union( const wxRegion& region )
201 {
202 if (region.IsNull())
203 return FALSE;
204
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 }
214
215 #ifdef __WXGTK20__
216 gdk_region_union( M_REGIONDATA->m_region, region.GetRegion() );
217 #else
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;
221 #endif
222
223 return TRUE;
224 }
225
226 bool wxRegion::Intersect( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
227 {
228 wxRegion reg( x, y, width, height );
229
230 return Intersect( reg );
231 }
232
233 bool wxRegion::Intersect( const wxRect& rect )
234 {
235 wxRegion reg( rect );
236
237 return Intersect( reg );
238 }
239
240 bool wxRegion::Intersect( const wxRegion& region )
241 {
242 if (region.IsNull())
243 return FALSE;
244
245 if (!m_refData)
246 {
247 m_refData = new wxRegionRefData();
248 M_REGIONDATA->m_region = gdk_region_new();
249
250 // leave here
251 return TRUE;
252 }
253 else
254 {
255 AllocExclusive();
256 }
257
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
265
266 return TRUE;
267 }
268
269 bool wxRegion::Subtract( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
270 {
271 wxRegion reg( x, y, width, height );
272 return Subtract( reg );
273 }
274
275 bool wxRegion::Subtract( const wxRect& rect )
276 {
277 wxRegion reg( rect );
278 return Subtract( reg );
279 }
280
281 bool wxRegion::Subtract( const wxRegion& region )
282 {
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 }
291 else
292 {
293 AllocExclusive();
294 }
295
296 #ifdef __WXGTK20__
297 gdk_region_subtract( M_REGIONDATA->m_region, region.GetRegion() );
298 #else
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;
302 #endif
303
304 return TRUE;
305 }
306
307 bool wxRegion::Xor( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
308 {
309 wxRegion reg( x, y, width, height );
310 return Xor( reg );
311 }
312
313 bool wxRegion::Xor( const wxRect& rect )
314 {
315 wxRegion reg( rect );
316 return Xor( reg );
317 }
318
319 bool wxRegion::Xor( const wxRegion& region )
320 {
321 if (region.IsNull())
322 return FALSE;
323
324 if (!m_refData)
325 {
326 m_refData = new wxRegionRefData();
327 M_REGIONDATA->m_region = gdk_region_new();
328 }
329 else
330 {
331 AllocExclusive();
332 }
333
334 #ifdef __WXGTK20__
335 gdk_region_xor( M_REGIONDATA->m_region, region.GetRegion() );
336 #else
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;
340 #endif
341
342 return TRUE;
343 }
344
345 // ----------------------------------------------------------------------------
346 // wxRegion tests
347 // ----------------------------------------------------------------------------
348
349 void wxRegion::GetBox( wxCoord &x, wxCoord &y, wxCoord &w, wxCoord &h ) const
350 {
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 }
367 }
368
369 wxRect wxRegion::GetBox() const
370 {
371 wxCoord x, y, w, h;
372 GetBox( x, y, w, h );
373 return wxRect( x, y, w, h );
374 }
375
376 bool wxRegion::Offset( wxCoord x, wxCoord y )
377 {
378 if (!m_refData)
379 return FALSE;
380
381 AllocExclusive();
382
383 gdk_region_offset( M_REGIONDATA->m_region, x, y );
384
385 return TRUE;
386 }
387
388 bool wxRegion::Empty() const
389 {
390 if (!m_refData)
391 return TRUE;
392
393 return gdk_region_empty( M_REGIONDATA->m_region );
394 }
395
396 wxRegionContain wxRegion::Contains( wxCoord x, wxCoord y ) const
397 {
398 if (!m_refData)
399 return wxOutRegion;
400
401 if (gdk_region_point_in( M_REGIONDATA->m_region, x, y ))
402 return wxInRegion;
403 else
404 return wxOutRegion;
405 }
406
407 wxRegionContain wxRegion::Contains( wxCoord x, wxCoord y, wxCoord w, wxCoord h ) const
408 {
409 if (!m_refData)
410 return wxOutRegion;
411
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;
425 }
426
427 wxRegionContain wxRegion::Contains(const wxPoint& pt) const
428 {
429 return Contains( pt.x, pt.y );
430 }
431
432 wxRegionContain wxRegion::Contains(const wxRect& rect) const
433 {
434 return Contains( rect.x, rect.y, rect.width, rect.height );
435 }
436
437 GdkRegion *wxRegion::GetRegion() const
438 {
439 if (!m_refData)
440 return (GdkRegion*) NULL;
441
442 return M_REGIONDATA->m_region;
443 }
444
445 // ----------------------------------------------------------------------------
446 // wxRegionIterator
447 // ----------------------------------------------------------------------------
448
449 #ifndef __WXGTK20__
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
457 #include <gdk/gdkprivate.h>
458
459 struct _XBox {
460 short x1, x2, y1, y2;
461 };
462
463 struct _XRegion {
464 long size , numRects;
465 _XBox *rects, extents;
466 };
467
468 #endif
469
470 class wxRIRefData: public wxObjectRefData
471 {
472 public:
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
483 wxRIRefData::~wxRIRefData()
484 {
485 delete m_rects;
486 }
487
488 void wxRIRefData::CreateRects( const wxRegion& region )
489 {
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__
500 GdkRectangle *gdkrects = NULL;
501 gint numRects = 0;
502 gdk_region_get_rectangles( gdkregion, &gdkrects, &numRects );
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)
509 {
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;
516 }
517 }
518 g_free( gdkrects );
519 #else // GTK+ 1.x
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 }
538 #endif // GTK+ 2.0/1.x
539 }
540
541 wxRegionIterator::wxRegionIterator()
542 {
543 m_refData = new wxRIRefData();
544 Reset();
545 }
546
547 wxRegionIterator::wxRegionIterator( const wxRegion& region )
548 {
549 m_refData = new wxRIRefData();
550 Reset(region);
551 }
552
553 void wxRegionIterator::Reset( const wxRegion& region )
554 {
555 m_region = region;
556 ((wxRIRefData*)m_refData)->CreateRects(region);
557 Reset();
558 }
559
560 bool wxRegionIterator::HaveRects() const
561 {
562 return m_current < ((wxRIRefData*)m_refData)->m_numRects;
563 }
564
565 wxRegionIterator::operator bool () const
566 {
567 return HaveRects();
568 }
569
570 void wxRegionIterator::operator ++ ()
571 {
572 if (HaveRects()) ++m_current;
573 }
574
575 void wxRegionIterator::operator ++ (int)
576 {
577 if (HaveRects()) ++m_current;
578 }
579
580 wxCoord wxRegionIterator::GetX() const
581 {
582 if( !HaveRects() ) return 0;
583 return ((wxRIRefData*)m_refData)->m_rects[m_current].x;
584 }
585
586 wxCoord wxRegionIterator::GetY() const
587 {
588 if( !HaveRects() ) return 0;
589 return ((wxRIRefData*)m_refData)->m_rects[m_current].y;
590 }
591
592 wxCoord wxRegionIterator::GetW() const
593 {
594 if( !HaveRects() ) return -1;
595 return ((wxRIRefData*)m_refData)->m_rects[m_current].width;
596 }
597
598 wxCoord wxRegionIterator::GetH() const
599 {
600 if( !HaveRects() ) return -1;
601 return ((wxRIRefData*)m_refData)->m_rects[m_current].height;
602 }
603
604 wxRect wxRegionIterator::GetRect() const
605 {
606 wxRect r;
607 if( HaveRects() )
608 r = ((wxRIRefData*)m_refData)->m_rects[m_current];
609
610 return r;
611 }
612