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