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