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