]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/gtk/region.cpp
forgot to commit project file for CW before
[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 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
35class wxGdkRegion
36{
37public:
38 wxGdkRegion() { m_region = gdk_region_new(); }
39 ~wxGdkRegion() { gdk_region_destroy(m_region); }
40
41 operator GdkRegion *() const { return m_region; }
42
43private:
44 GdkRegion *m_region;
45};
46
47#endif // __WXGTK20__
48
49// ----------------------------------------------------------------------------
50// wxRegionRefData: private class containing the information about the region
51// ----------------------------------------------------------------------------
52
53class wxRegionRefData : public wxObjectRefData
54{
55public:
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
87IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject)
88IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator,wxObject)
89
90// ----------------------------------------------------------------------------
91// wxRegion construction
92// ----------------------------------------------------------------------------
93
94#define M_REGIONDATA ((wxRegionRefData *)m_refData)
95
96void 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
113wxRegion::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
123wxRegion::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
147wxRegion::~wxRegion()
148{
149 // m_refData unrefed in ~wxObject
150}
151
152wxObjectRefData *wxRegion::CreateRefData() const
153{
154 return new wxRegionRefData;
155}
156
157wxObjectRefData *wxRegion::CloneRefData(const wxObjectRefData *data) const
158{
159 return new wxRegionRefData(*(wxRegionRefData *)data);
160}
161
162// ----------------------------------------------------------------------------
163// wxRegion comparison
164// ----------------------------------------------------------------------------
165
166bool 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
181void wxRegion::Clear()
182{
183 UnRef();
184}
185
186bool 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
220bool wxRegion::Union( const wxRect& rect )
221{
222 return Union( rect.x, rect.y, rect.width, rect.height );
223}
224
225bool 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
251bool 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
258bool wxRegion::Intersect( const wxRect& rect )
259{
260 wxRegion reg( rect );
261
262 return Intersect( reg );
263}
264
265bool 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
289bool wxRegion::Subtract( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
290{
291 wxRegion reg( x, y, width, height );
292 return Subtract( reg );
293}
294
295bool wxRegion::Subtract( const wxRect& rect )
296{
297 wxRegion reg( rect );
298 return Subtract( reg );
299}
300
301bool 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
325bool wxRegion::Xor( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
326{
327 wxRegion reg( x, y, width, height );
328 return Xor( reg );
329}
330
331bool wxRegion::Xor( const wxRect& rect )
332{
333 wxRegion reg( rect );
334 return Xor( reg );
335}
336
337bool 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
360bool 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
376void 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
396wxRect 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
403bool wxRegion::Empty() const
404{
405 if (!m_refData)
406 return TRUE;
407
408 return gdk_region_empty( M_REGIONDATA->m_region );
409}
410
411wxRegionContain 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
422wxRegionContain 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
442wxRegionContain wxRegion::Contains(const wxPoint& pt) const
443{
444 return Contains( pt.x, pt.y );
445}
446
447wxRegionContain wxRegion::Contains(const wxRect& rect) const
448{
449 return Contains( rect.x, rect.y, rect.width, rect.height );
450}
451
452GdkRegion *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
474struct _XBox {
475 short x1, x2, y1, y2;
476};
477
478struct _XRegion {
479 long size , numRects;
480 _XBox *rects, extents;
481};
482
483#endif // GTK+ 1.x
484
485class wxRIRefData: public wxObjectRefData
486{
487public:
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
499wxRIRefData::~wxRIRefData()
500{
501 delete [] m_rects;
502}
503
504void 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
556wxRegionIterator::wxRegionIterator()
557{
558 m_refData = new wxRIRefData();
559 Reset();
560}
561
562wxRegionIterator::wxRegionIterator( const wxRegion& region )
563{
564 m_refData = new wxRIRefData();
565 Reset(region);
566}
567
568void wxRegionIterator::Reset( const wxRegion& region )
569{
570 m_region = region;
571 ((wxRIRefData*)m_refData)->CreateRects(region);
572 Reset();
573}
574
575bool wxRegionIterator::HaveRects() const
576{
577 return m_current < ((wxRIRefData*)m_refData)->m_numRects;
578}
579
580wxRegionIterator& wxRegionIterator::operator ++ ()
581{
582 if (HaveRects())
583 ++m_current;
584
585 return *this;
586}
587
588wxRegionIterator wxRegionIterator::operator ++ (int)
589{
590 wxRegionIterator tmp = *this;
591 if (HaveRects())
592 ++m_current;
593
594 return tmp;
595}
596
597wxCoord 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
604wxCoord 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
611wxCoord 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
618wxCoord 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
625wxRect 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