]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/region.cpp
Allow 2-step creation of wxGenericProgressDialog.
[wxWidgets.git] / src / gtk / region.cpp
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
35 class wxRegionRefData : public wxGDIRefData
36 {
37 public:
38 wxRegionRefData()
39 {
40 m_region = NULL;
41 }
42
43 wxRegionRefData(const wxRegionRefData& refData)
44 : wxGDIRefData()
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
65 IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject)
66 IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator,wxObject)
67
68 // ----------------------------------------------------------------------------
69 // wxRegion construction
70 // ----------------------------------------------------------------------------
71
72 #define M_REGIONDATA ((wxRegionRefData *)m_refData)
73
74 void 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
87 wxRegion::wxRegion( GdkRegion *region )
88 {
89 m_refData = new wxRegionRefData();
90 M_REGIONDATA->m_region = gdk_region_copy( region );
91 }
92
93 wxRegion::wxRegion( size_t n, const wxPoint *points,
94 wxPolygonFillMode fillStyle )
95 {
96 GdkPoint *gdkpoints = new GdkPoint[n];
97 for ( size_t i = 0 ; i < n ; i++ )
98 {
99 gdkpoints[i].x = points[i].x;
100 gdkpoints[i].y = points[i].y;
101 }
102
103 m_refData = new wxRegionRefData();
104
105 GdkRegion* reg = gdk_region_polygon
106 (
107 gdkpoints,
108 n,
109 fillStyle == wxWINDING_RULE ? GDK_WINDING_RULE
110 : GDK_EVEN_ODD_RULE
111 );
112
113 M_REGIONDATA->m_region = reg;
114
115 delete [] gdkpoints;
116 }
117
118 wxRegion::~wxRegion()
119 {
120 // m_refData unrefed in ~wxObject
121 }
122
123 wxGDIRefData *wxRegion::CreateGDIRefData() const
124 {
125 return new wxRegionRefData;
126 }
127
128 wxGDIRefData *wxRegion::CloneGDIRefData(const wxGDIRefData *data) const
129 {
130 return new wxRegionRefData(*(wxRegionRefData *)data);
131 }
132
133 // ----------------------------------------------------------------------------
134 // wxRegion comparison
135 // ----------------------------------------------------------------------------
136
137 bool wxRegion::DoIsEqual(const wxRegion& region) const
138 {
139 return gdk_region_equal(M_REGIONDATA->m_region,
140 M_REGIONDATA_OF(region)->m_region);
141 }
142
143 // ----------------------------------------------------------------------------
144 // wxRegion operations
145 // ----------------------------------------------------------------------------
146
147 void wxRegion::Clear()
148 {
149 UnRef();
150 }
151
152 bool wxRegion::DoUnionWithRect(const wxRect& r)
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 ( r.IsEmpty() )
158 return true;
159
160 if ( !m_refData )
161 {
162 InitRect(r.x, r.y, r.width, r.height);
163 }
164 else
165 {
166 AllocExclusive();
167
168 GdkRectangle rect;
169 rect.x = r.x;
170 rect.y = r.y;
171 rect.width = r.width;
172 rect.height = r.height;
173
174 gdk_region_union_with_rect( M_REGIONDATA->m_region, &rect );
175 }
176
177 return true;
178 }
179
180 bool wxRegion::DoUnionWithRegion( const wxRegion& region )
181 {
182 wxCHECK_MSG( region.IsOk(), false, wxT("invalid region") );
183
184 if (!m_refData)
185 {
186 m_refData = new wxRegionRefData(*M_REGIONDATA_OF(region));
187 }
188 else
189 {
190 AllocExclusive();
191 gdk_region_union( M_REGIONDATA->m_region, region.GetRegion() );
192 }
193
194 return true;
195 }
196
197 bool wxRegion::DoIntersect( const wxRegion& region )
198 {
199 wxCHECK_MSG( region.IsOk(), false, wxT("invalid region") );
200
201 if (!m_refData)
202 {
203 // intersecting with invalid region doesn't make sense
204 return false;
205 }
206
207 AllocExclusive();
208
209 gdk_region_intersect( M_REGIONDATA->m_region, region.GetRegion() );
210
211 return true;
212 }
213
214 bool wxRegion::DoSubtract( const wxRegion& region )
215 {
216 wxCHECK_MSG( region.IsOk(), false, wxT("invalid region") );
217
218 if (!m_refData)
219 {
220 // subtracting from an invalid region doesn't make sense
221 return false;
222 }
223
224 AllocExclusive();
225
226 gdk_region_subtract( M_REGIONDATA->m_region, region.GetRegion() );
227
228 return true;
229 }
230
231 bool wxRegion::DoXor( const wxRegion& region )
232 {
233 wxCHECK_MSG( region.IsOk(), false, wxT("invalid region") );
234
235 if (!m_refData)
236 {
237 // XOR-ing with an invalid region is the same as XOR-ing with an empty
238 // one, i.e. it is simply a copy.
239 m_refData = new wxRegionRefData(*M_REGIONDATA_OF(region));
240 }
241 else
242 {
243 AllocExclusive();
244
245 gdk_region_xor( M_REGIONDATA->m_region, region.GetRegion() );
246 }
247
248 return true;
249 }
250
251 bool wxRegion::DoOffset( wxCoord x, wxCoord y )
252 {
253 wxCHECK_MSG( m_refData, false, wxS("invalid region") );
254
255 AllocExclusive();
256
257 gdk_region_offset( M_REGIONDATA->m_region, x, y );
258
259 return true;
260 }
261
262 // ----------------------------------------------------------------------------
263 // wxRegion tests
264 // ----------------------------------------------------------------------------
265
266 bool wxRegion::DoGetBox( wxCoord &x, wxCoord &y, wxCoord &w, wxCoord &h ) const
267 {
268 if ( m_refData )
269 {
270 GdkRectangle rect;
271 gdk_region_get_clipbox( M_REGIONDATA->m_region, &rect );
272 x = rect.x;
273 y = rect.y;
274 w = rect.width;
275 h = rect.height;
276
277 return true;
278 }
279 else
280 {
281 x = 0;
282 y = 0;
283 w = -1;
284 h = -1;
285
286 return false;
287 }
288 }
289
290 bool wxRegion::IsEmpty() const
291 {
292 if (!m_refData)
293 return true;
294
295 return gdk_region_empty( M_REGIONDATA->m_region );
296 }
297
298 wxRegionContain wxRegion::DoContainsPoint( wxCoord x, wxCoord y ) const
299 {
300 if (!m_refData)
301 return wxOutRegion;
302
303 if (gdk_region_point_in( M_REGIONDATA->m_region, x, y ))
304 return wxInRegion;
305 else
306 return wxOutRegion;
307 }
308
309 wxRegionContain wxRegion::DoContainsRect(const wxRect& r) const
310 {
311 if (!m_refData)
312 return wxOutRegion;
313
314 GdkRectangle rect;
315 rect.x = r.x;
316 rect.y = r.y;
317 rect.width = r.width;
318 rect.height = r.height;
319 GdkOverlapType res = gdk_region_rect_in( M_REGIONDATA->m_region, &rect );
320 switch (res)
321 {
322 case GDK_OVERLAP_RECTANGLE_IN: return wxInRegion;
323 case GDK_OVERLAP_RECTANGLE_OUT: return wxOutRegion;
324 case GDK_OVERLAP_RECTANGLE_PART: return wxPartRegion;
325 }
326 return wxOutRegion;
327 }
328
329 GdkRegion *wxRegion::GetRegion() const
330 {
331 if (!m_refData)
332 return NULL;
333
334 return M_REGIONDATA->m_region;
335 }
336
337 // ----------------------------------------------------------------------------
338 // wxRegionIterator
339 // ----------------------------------------------------------------------------
340
341 wxRegionIterator::wxRegionIterator()
342 {
343 Init();
344 Reset();
345 }
346
347 wxRegionIterator::wxRegionIterator( const wxRegion& region )
348 {
349 Init();
350 Reset(region);
351 }
352
353 void wxRegionIterator::Init()
354 {
355 m_rects = NULL;
356 m_numRects = 0;
357 }
358
359 wxRegionIterator::~wxRegionIterator()
360 {
361 wxDELETEA(m_rects);
362 }
363
364 void wxRegionIterator::CreateRects( const wxRegion& region )
365 {
366 wxDELETEA(m_rects);
367 m_numRects = 0;
368
369 GdkRegion *gdkregion = region.GetRegion();
370 if (!gdkregion)
371 return;
372
373 GdkRectangle* gdkrects;
374 gdk_region_get_rectangles(gdkregion, &gdkrects, &m_numRects);
375
376 if (m_numRects)
377 {
378 m_rects = new wxRect[m_numRects];
379 for (int i = 0; i < m_numRects; ++i)
380 {
381 GdkRectangle &gr = gdkrects[i];
382 wxRect &wr = m_rects[i];
383 wr.x = gr.x;
384 wr.y = gr.y;
385 wr.width = gr.width;
386 wr.height = gr.height;
387 }
388 }
389 g_free( gdkrects );
390 }
391
392 void wxRegionIterator::Reset( const wxRegion& region )
393 {
394 m_region = region;
395 CreateRects(region);
396 Reset();
397 }
398
399 bool wxRegionIterator::HaveRects() const
400 {
401 return m_current < m_numRects;
402 }
403
404 wxRegionIterator& wxRegionIterator::operator ++ ()
405 {
406 if (HaveRects())
407 ++m_current;
408
409 return *this;
410 }
411
412 wxRegionIterator wxRegionIterator::operator ++ (int)
413 {
414 wxRegionIterator tmp = *this;
415
416 if (HaveRects())
417 ++m_current;
418
419 return tmp;
420 }
421
422 wxCoord wxRegionIterator::GetX() const
423 {
424 wxCHECK_MSG( HaveRects(), 0, wxT("invalid wxRegionIterator") );
425
426 return m_rects[m_current].x;
427 }
428
429 wxCoord wxRegionIterator::GetY() const
430 {
431 wxCHECK_MSG( HaveRects(), 0, wxT("invalid wxRegionIterator") );
432
433 return m_rects[m_current].y;
434 }
435
436 wxCoord wxRegionIterator::GetW() const
437 {
438 wxCHECK_MSG( HaveRects(), 0, wxT("invalid wxRegionIterator") );
439
440 return m_rects[m_current].width;
441 }
442
443 wxCoord wxRegionIterator::GetH() const
444 {
445 wxCHECK_MSG( HaveRects(), 0, wxT("invalid wxRegionIterator") );
446
447 return m_rects[m_current].height;
448 }
449
450 wxRect wxRegionIterator::GetRect() const
451 {
452 wxRect r;
453 if( HaveRects() )
454 r = m_rects[m_current];
455
456 return r;
457 }
458
459 wxRegionIterator& wxRegionIterator::operator=(const wxRegionIterator& ri)
460 {
461 if (this != &ri)
462 {
463 wxDELETEA(m_rects);
464
465 m_current = ri.m_current;
466 m_numRects = ri.m_numRects;
467 if ( m_numRects )
468 {
469 m_rects = new wxRect[m_numRects];
470 memcpy(m_rects, ri.m_rects, m_numRects * sizeof m_rects[0]);
471 }
472 }
473 return *this;
474 }