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