]> git.saurik.com Git - wxWidgets.git/blob - src/gtk1/region.cpp
wxCocoa: Added preliminary Blit support
[wxWidgets.git] / src / gtk1 / 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 #ifndef __WXGTK20__
30
31 // ----------------------------------------------------------------------------
32 // wxGdkRegion: creates a new region in ctor and destroys in dtor
33 // ----------------------------------------------------------------------------
34
35 class wxGdkRegion
36 {
37 public:
38 wxGdkRegion() { m_region = gdk_region_new(); }
39 ~wxGdkRegion() { gdk_region_destroy(m_region); }
40
41 operator GdkRegion *() const { return m_region; }
42
43 private:
44 GdkRegion *m_region;
45 };
46
47 #endif // __WXGTK20__
48
49 // ----------------------------------------------------------------------------
50 // wxRegionRefData: private class containing the information about the region
51 // ----------------------------------------------------------------------------
52
53 class wxRegionRefData : public wxObjectRefData
54 {
55 public:
56 wxRegionRefData()
57 {
58 m_region = NULL;
59 }
60
61 wxRegionRefData(const wxRegionRefData& refData)
62 : wxObjectRefData()
63 {
64 #ifdef __WXGTK20__
65 m_region = gdk_region_copy(refData.m_region);
66 #else
67 m_region = gdk_regions_union(wxGdkRegion(), refData.m_region);
68 #endif
69 }
70
71 ~wxRegionRefData()
72 {
73 if (m_region)
74 gdk_region_destroy( m_region );
75 }
76
77 GdkRegion *m_region;
78 };
79
80 // ----------------------------------------------------------------------------
81 // macros
82 // ----------------------------------------------------------------------------
83
84 #define M_REGIONDATA ((wxRegionRefData *)m_refData)
85 #define M_REGIONDATA_OF(rgn) ((wxRegionRefData *)(rgn.m_refData))
86
87 IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject)
88 IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator,wxObject)
89
90 // ----------------------------------------------------------------------------
91 // wxRegion construction
92 // ----------------------------------------------------------------------------
93
94 #define M_REGIONDATA ((wxRegionRefData *)m_refData)
95
96 void wxRegion::InitRect(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
97 {
98 GdkRectangle rect;
99 rect.x = x;
100 rect.y = y;
101 rect.width = w;
102 rect.height = h;
103
104 m_refData = new wxRegionRefData();
105
106 #ifdef __WXGTK20__
107 M_REGIONDATA->m_region = gdk_region_rectangle( &rect );
108 #else
109 M_REGIONDATA->m_region = gdk_region_union_with_rect( wxGdkRegion(), &rect );
110 #endif
111 }
112
113 wxRegion::wxRegion( GdkRegion *region )
114 {
115 m_refData = new wxRegionRefData();
116 #ifdef __WXGTK20__
117 M_REGIONDATA->m_region = gdk_region_copy( region );
118 #else
119 M_REGIONDATA->m_region = gdk_regions_union(wxGdkRegion(), region);
120 #endif
121 }
122
123 wxRegion::wxRegion( size_t n, const wxPoint *points, int fillStyle )
124 {
125 GdkPoint *gdkpoints = new GdkPoint[n];
126 for ( size_t i = 0 ; i < n ; i++ )
127 {
128 gdkpoints[i].x = points[i].x;
129 gdkpoints[i].y = points[i].y;
130 }
131
132 m_refData = new wxRegionRefData();
133
134 GdkRegion* reg = gdk_region_polygon
135 (
136 gdkpoints,
137 n,
138 fillStyle == wxWINDING_RULE ? GDK_WINDING_RULE
139 : GDK_EVEN_ODD_RULE
140 );
141
142 M_REGIONDATA->m_region = reg;
143
144 delete [] gdkpoints;
145 }
146
147 wxRegion::~wxRegion()
148 {
149 // m_refData unrefed in ~wxObject
150 }
151
152 wxObjectRefData *wxRegion::CreateRefData() const
153 {
154 return new wxRegionRefData;
155 }
156
157 wxObjectRefData *wxRegion::CloneRefData(const wxObjectRefData *data) const
158 {
159 return new wxRegionRefData(*(wxRegionRefData *)data);
160 }
161
162 // ----------------------------------------------------------------------------
163 // wxRegion comparison
164 // ----------------------------------------------------------------------------
165
166 bool wxRegion::operator==( const wxRegion& region )
167 {
168 if (m_refData == region.m_refData) return TRUE;
169
170 if (!m_refData || !region.m_refData) return FALSE;
171
172 // compare the regions themselves, not the pointers to ref data!
173 return gdk_region_equal(M_REGIONDATA->m_region,
174 M_REGIONDATA_OF(region)->m_region);
175 }
176
177 // ----------------------------------------------------------------------------
178 // wxRegion operations
179 // ----------------------------------------------------------------------------
180
181 void wxRegion::Clear()
182 {
183 UnRef();
184 }
185
186 bool wxRegion::Union( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
187 {
188 // workaround for a strange GTK/X11 bug: taking union with an empty
189 // rectangle results in an empty region which is definitely not what we
190 // want
191 if ( !width || !height )
192 return TRUE;
193
194 if ( !m_refData )
195 {
196 InitRect(x, y, width, height);
197 }
198 else
199 {
200 AllocExclusive();
201
202 GdkRectangle rect;
203 rect.x = x;
204 rect.y = y;
205 rect.width = width;
206 rect.height = height;
207
208 #ifdef __WXGTK20__
209 gdk_region_union_with_rect( M_REGIONDATA->m_region, &rect );
210 #else
211 GdkRegion *reg = gdk_region_union_with_rect( M_REGIONDATA->m_region, &rect );
212 gdk_region_destroy( M_REGIONDATA->m_region );
213 M_REGIONDATA->m_region = reg;
214 #endif
215 }
216
217 return TRUE;
218 }
219
220 bool wxRegion::Union( const wxRect& rect )
221 {
222 return Union( rect.x, rect.y, rect.width, rect.height );
223 }
224
225 bool wxRegion::Union( const wxRegion& region )
226 {
227 if (region.IsNull())
228 return FALSE;
229
230 if (!m_refData)
231 {
232 m_refData = new wxRegionRefData();
233 M_REGIONDATA->m_region = gdk_region_new();
234 }
235 else
236 {
237 AllocExclusive();
238 }
239
240 #ifdef __WXGTK20__
241 gdk_region_union( M_REGIONDATA->m_region, region.GetRegion() );
242 #else
243 GdkRegion *reg = gdk_regions_union( M_REGIONDATA->m_region, region.GetRegion() );
244 gdk_region_destroy( M_REGIONDATA->m_region );
245 M_REGIONDATA->m_region = reg;
246 #endif
247
248 return TRUE;
249 }
250
251 bool wxRegion::Intersect( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
252 {
253 wxRegion reg( x, y, width, height );
254
255 return Intersect( reg );
256 }
257
258 bool wxRegion::Intersect( const wxRect& rect )
259 {
260 wxRegion reg( rect );
261
262 return Intersect( reg );
263 }
264
265 bool wxRegion::Intersect( const wxRegion& region )
266 {
267 if (region.IsNull())
268 return FALSE;
269
270 if (!m_refData)
271 {
272 // intersecting with invalid region doesn't make sense
273 return FALSE;
274 }
275
276 AllocExclusive();
277
278 #ifdef __WXGTK20__
279 gdk_region_intersect( M_REGIONDATA->m_region, region.GetRegion() );
280 #else
281 GdkRegion *reg = gdk_regions_intersect( M_REGIONDATA->m_region, region.GetRegion() );
282 gdk_region_destroy( M_REGIONDATA->m_region );
283 M_REGIONDATA->m_region = reg;
284 #endif
285
286 return TRUE;
287 }
288
289 bool wxRegion::Subtract( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
290 {
291 wxRegion reg( x, y, width, height );
292 return Subtract( reg );
293 }
294
295 bool wxRegion::Subtract( const wxRect& rect )
296 {
297 wxRegion reg( rect );
298 return Subtract( reg );
299 }
300
301 bool wxRegion::Subtract( const wxRegion& region )
302 {
303 if (region.IsNull())
304 return FALSE;
305
306 if (!m_refData)
307 {
308 // subtracting from an invalid region doesn't make sense
309 return FALSE;
310 }
311
312 AllocExclusive();
313
314 #ifdef __WXGTK20__
315 gdk_region_subtract( M_REGIONDATA->m_region, region.GetRegion() );
316 #else
317 GdkRegion *reg = gdk_regions_subtract( M_REGIONDATA->m_region, region.GetRegion() );
318 gdk_region_destroy( M_REGIONDATA->m_region );
319 M_REGIONDATA->m_region = reg;
320 #endif
321
322 return TRUE;
323 }
324
325 bool wxRegion::Xor( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
326 {
327 wxRegion reg( x, y, width, height );
328 return Xor( reg );
329 }
330
331 bool wxRegion::Xor( const wxRect& rect )
332 {
333 wxRegion reg( rect );
334 return Xor( reg );
335 }
336
337 bool wxRegion::Xor( const wxRegion& region )
338 {
339 if (region.IsNull())
340 return FALSE;
341
342 if (!m_refData)
343 {
344 return FALSE;
345 }
346
347 AllocExclusive();
348
349 #ifdef __WXGTK20__
350 gdk_region_xor( M_REGIONDATA->m_region, region.GetRegion() );
351 #else
352 GdkRegion *reg = gdk_regions_xor( M_REGIONDATA->m_region, region.GetRegion() );
353 gdk_region_destroy( M_REGIONDATA->m_region );
354 M_REGIONDATA->m_region = reg;
355 #endif
356
357 return TRUE;
358 }
359
360 bool wxRegion::Offset( wxCoord x, wxCoord y )
361 {
362 if (!m_refData)
363 return FALSE;
364
365 AllocExclusive();
366
367 gdk_region_offset( M_REGIONDATA->m_region, x, y );
368
369 return TRUE;
370 }
371
372 // ----------------------------------------------------------------------------
373 // wxRegion tests
374 // ----------------------------------------------------------------------------
375
376 void wxRegion::GetBox( wxCoord &x, wxCoord &y, wxCoord &w, wxCoord &h ) const
377 {
378 if ( m_refData )
379 {
380 GdkRectangle rect;
381 gdk_region_get_clipbox( M_REGIONDATA->m_region, &rect );
382 x = rect.x;
383 y = rect.y;
384 w = rect.width;
385 h = rect.height;
386 }
387 else
388 {
389 x = 0;
390 y = 0;
391 w = -1;
392 h = -1;
393 }
394 }
395
396 wxRect wxRegion::GetBox() const
397 {
398 wxCoord x, y, w, h;
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 // ----------------------------------------------------------------------------
461 // wxRegionIterator
462 // ----------------------------------------------------------------------------
463
464 #ifndef __WXGTK20__
465
466 // the following structures must match the private structures
467 // in X11 region code ( xc/lib/X11/region.h )
468
469 // this makes the Region type transparent
470 // and we have access to the region rectangles
471
472 #include <gdk/gdkprivate.h>
473
474 struct _XBox {
475 short x1, x2, y1, y2;
476 };
477
478 struct _XRegion {
479 long size , numRects;
480 _XBox *rects, extents;
481 };
482
483 #endif // GTK+ 1.x
484
485 class wxRIRefData: public wxObjectRefData
486 {
487 public:
488 wxRIRefData() { Init(); }
489 virtual ~wxRIRefData();
490
491 void CreateRects( const wxRegion& r );
492
493 void Init() { m_rects = NULL; m_numRects = 0; }
494
495 wxRect *m_rects;
496 size_t m_numRects;
497 };
498
499 wxRIRefData::~wxRIRefData()
500 {
501 delete [] m_rects;
502 }
503
504 void wxRIRefData::CreateRects( const wxRegion& region )
505 {
506 delete [] m_rects;
507
508 Init();
509
510 GdkRegion *gdkregion = region.GetRegion();
511 if (!gdkregion)
512 return;
513
514 #ifdef __WXGTK20__
515 GdkRectangle *gdkrects = NULL;
516 gint numRects = 0;
517 gdk_region_get_rectangles( gdkregion, &gdkrects, &numRects );
518
519 m_numRects = numRects;
520 if (numRects)
521 {
522 m_rects = new wxRect[m_numRects];
523 for (size_t i=0; i < m_numRects; ++i)
524 {
525 GdkRectangle &gr = gdkrects[i];
526 wxRect &wr = m_rects[i];
527 wr.x = gr.x;
528 wr.y = gr.y;
529 wr.width = gr.width;
530 wr.height = gr.height;
531 }
532 }
533 g_free( gdkrects );
534 #else // GTK+ 1.x
535 Region r = ((GdkRegionPrivate *)gdkregion)->xregion;
536 if (r)
537 {
538 m_numRects = r->numRects;
539 if (m_numRects)
540 {
541 m_rects = new wxRect[m_numRects];
542 for (size_t i=0; i < m_numRects; ++i)
543 {
544 _XBox &xr = r->rects[i];
545 wxRect &wr = m_rects[i];
546 wr.x = xr.x1;
547 wr.y = xr.y1;
548 wr.width = xr.x2-xr.x1;
549 wr.height = xr.y2-xr.y1;
550 }
551 }
552 }
553 #endif // GTK+ 2.0/1.x
554 }
555
556 wxRegionIterator::wxRegionIterator()
557 {
558 m_refData = new wxRIRefData();
559 Reset();
560 }
561
562 wxRegionIterator::wxRegionIterator( const wxRegion& region )
563 {
564 m_refData = new wxRIRefData();
565 Reset(region);
566 }
567
568 void wxRegionIterator::Reset( const wxRegion& region )
569 {
570 m_region = region;
571 ((wxRIRefData*)m_refData)->CreateRects(region);
572 Reset();
573 }
574
575 bool wxRegionIterator::HaveRects() const
576 {
577 return m_current < ((wxRIRefData*)m_refData)->m_numRects;
578 }
579
580 wxRegionIterator& wxRegionIterator::operator ++ ()
581 {
582 if (HaveRects())
583 ++m_current;
584
585 return *this;
586 }
587
588 wxRegionIterator wxRegionIterator::operator ++ (int)
589 {
590 wxRegionIterator tmp = *this;
591 if (HaveRects())
592 ++m_current;
593
594 return tmp;
595 }
596
597 wxCoord wxRegionIterator::GetX() const
598 {
599 wxCHECK_MSG( HaveRects(), 0, _T("invalid wxRegionIterator") );
600
601 return ((wxRIRefData*)m_refData)->m_rects[m_current].x;
602 }
603
604 wxCoord wxRegionIterator::GetY() const
605 {
606 wxCHECK_MSG( HaveRects(), 0, _T("invalid wxRegionIterator") );
607
608 return ((wxRIRefData*)m_refData)->m_rects[m_current].y;
609 }
610
611 wxCoord wxRegionIterator::GetW() const
612 {
613 wxCHECK_MSG( HaveRects(), 0, _T("invalid wxRegionIterator") );
614
615 return ((wxRIRefData*)m_refData)->m_rects[m_current].width;
616 }
617
618 wxCoord wxRegionIterator::GetH() const
619 {
620 wxCHECK_MSG( HaveRects(), 0, _T("invalid wxRegionIterator") );
621
622 return ((wxRIRefData*)m_refData)->m_rects[m_current].height;
623 }
624
625 wxRect wxRegionIterator::GetRect() const
626 {
627 wxRect r;
628 if( HaveRects() )
629 r = ((wxRIRefData*)m_refData)->m_rects[m_current];
630
631 return r;
632 }
633