Fix Ok/IsOk() mess in wxGDIObject-derived classes; also added
[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, 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
117 wxRegion::~wxRegion()
118 {
119 // m_refData unrefed in ~wxObject
120 }
121
122 wxGDIRefData *wxRegion::CreateGDIRefData() const
123 {
124 return new wxRegionRefData;
125 }
126
127 wxGDIRefData *wxRegion::CloneGDIRefData(const wxGDIRefData *data) const
128 {
129 return new wxRegionRefData(*(wxRegionRefData *)data);
130 }
131
132 // ----------------------------------------------------------------------------
133 // wxRegion comparison
134 // ----------------------------------------------------------------------------
135
136 bool wxRegion::DoIsEqual(const wxRegion& region) const
137 {
138 return gdk_region_equal(M_REGIONDATA->m_region,
139 M_REGIONDATA_OF(region)->m_region);
140 }
141
142 // ----------------------------------------------------------------------------
143 // wxRegion operations
144 // ----------------------------------------------------------------------------
145
146 void wxRegion::Clear()
147 {
148 UnRef();
149 }
150
151 bool wxRegion::DoUnionWithRect(const wxRect& r)
152 {
153 // workaround for a strange GTK/X11 bug: taking union with an empty
154 // rectangle results in an empty region which is definitely not what we
155 // want
156 if ( r.IsEmpty() )
157 return true;
158
159 if ( !m_refData )
160 {
161 InitRect(r.x, r.y, r.width, r.height);
162 }
163 else
164 {
165 AllocExclusive();
166
167 GdkRectangle rect;
168 rect.x = r.x;
169 rect.y = r.y;
170 rect.width = r.width;
171 rect.height = r.height;
172
173 gdk_region_union_with_rect( M_REGIONDATA->m_region, &rect );
174 }
175
176 return true;
177 }
178
179 bool wxRegion::DoUnionWithRegion( const wxRegion& region )
180 {
181 wxCHECK_MSG( region.Ok(), false, _T("invalid region") );
182
183 if (!m_refData)
184 {
185 m_refData = new wxRegionRefData();
186 M_REGIONDATA->m_region = gdk_region_new();
187 }
188 else
189 {
190 AllocExclusive();
191 }
192
193 gdk_region_union( M_REGIONDATA->m_region, region.GetRegion() );
194
195 return true;
196 }
197
198 bool wxRegion::DoIntersect( const wxRegion& region )
199 {
200 wxCHECK_MSG( region.Ok(), false, _T("invalid region") );
201
202 if (!m_refData)
203 {
204 // intersecting with invalid region doesn't make sense
205 return false;
206 }
207
208 AllocExclusive();
209
210 gdk_region_intersect( M_REGIONDATA->m_region, region.GetRegion() );
211
212 return true;
213 }
214
215 bool wxRegion::DoSubtract( const wxRegion& region )
216 {
217 wxCHECK_MSG( region.Ok(), false, _T("invalid region") );
218
219 if (!m_refData)
220 {
221 // subtracting from an invalid region doesn't make sense
222 return false;
223 }
224
225 AllocExclusive();
226
227 gdk_region_subtract( M_REGIONDATA->m_region, region.GetRegion() );
228
229 return true;
230 }
231
232 bool wxRegion::DoXor( const wxRegion& region )
233 {
234 wxCHECK_MSG( region.Ok(), false, _T("invalid region") );
235
236 if (!m_refData)
237 {
238 return false;
239 }
240
241 AllocExclusive();
242
243 gdk_region_xor( M_REGIONDATA->m_region, region.GetRegion() );
244
245 return true;
246 }
247
248 bool wxRegion::DoOffset( wxCoord x, wxCoord y )
249 {
250 if (!m_refData)
251 return false;
252
253 AllocExclusive();
254
255 gdk_region_offset( M_REGIONDATA->m_region, x, y );
256
257 return true;
258 }
259
260 // ----------------------------------------------------------------------------
261 // wxRegion tests
262 // ----------------------------------------------------------------------------
263
264 bool wxRegion::DoGetBox( wxCoord &x, wxCoord &y, wxCoord &w, wxCoord &h ) const
265 {
266 if ( m_refData )
267 {
268 GdkRectangle rect;
269 gdk_region_get_clipbox( M_REGIONDATA->m_region, &rect );
270 x = rect.x;
271 y = rect.y;
272 w = rect.width;
273 h = rect.height;
274
275 return true;
276 }
277 else
278 {
279 x = 0;
280 y = 0;
281 w = -1;
282 h = -1;
283
284 return false;
285 }
286 }
287
288 bool wxRegion::IsEmpty() const
289 {
290 if (!m_refData)
291 return true;
292
293 return gdk_region_empty( M_REGIONDATA->m_region );
294 }
295
296 wxRegionContain wxRegion::DoContainsPoint( wxCoord x, wxCoord y ) const
297 {
298 if (!m_refData)
299 return wxOutRegion;
300
301 if (gdk_region_point_in( M_REGIONDATA->m_region, x, y ))
302 return wxInRegion;
303 else
304 return wxOutRegion;
305 }
306
307 wxRegionContain wxRegion::DoContainsRect(const wxRect& r) const
308 {
309 if (!m_refData)
310 return wxOutRegion;
311
312 GdkRectangle rect;
313 rect.x = r.x;
314 rect.y = r.y;
315 rect.width = r.width;
316 rect.height = r.height;
317 GdkOverlapType res = gdk_region_rect_in( M_REGIONDATA->m_region, &rect );
318 switch (res)
319 {
320 case GDK_OVERLAP_RECTANGLE_IN: return wxInRegion;
321 case GDK_OVERLAP_RECTANGLE_OUT: return wxOutRegion;
322 case GDK_OVERLAP_RECTANGLE_PART: return wxPartRegion;
323 }
324 return wxOutRegion;
325 }
326
327 GdkRegion *wxRegion::GetRegion() const
328 {
329 if (!m_refData)
330 return (GdkRegion*) NULL;
331
332 return M_REGIONDATA->m_region;
333 }
334
335 // ----------------------------------------------------------------------------
336 // wxRegionIterator
337 // ----------------------------------------------------------------------------
338
339 wxRegionIterator::wxRegionIterator()
340 {
341 Init();
342 Reset();
343 }
344
345 wxRegionIterator::wxRegionIterator( const wxRegion& region )
346 {
347 Init();
348 Reset(region);
349 }
350
351 void wxRegionIterator::Init()
352 {
353 m_rects = NULL;
354 m_numRects = 0;
355 }
356
357 wxRegionIterator::~wxRegionIterator()
358 {
359 wxDELETEA(m_rects);
360 }
361
362 void wxRegionIterator::CreateRects( const wxRegion& region )
363 {
364 wxDELETEA(m_rects);
365 m_numRects = 0;
366
367 GdkRegion *gdkregion = region.GetRegion();
368 if (!gdkregion)
369 return;
370
371 GdkRectangle *gdkrects = NULL;
372 gint numRects = 0;
373 gdk_region_get_rectangles( gdkregion, &gdkrects, &numRects );
374
375 m_numRects = numRects;
376 if (numRects)
377 {
378 m_rects = new wxRect[m_numRects];
379 for (size_t 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, _T("invalid wxRegionIterator") );
425
426 return m_rects[m_current].x;
427 }
428
429 wxCoord wxRegionIterator::GetY() const
430 {
431 wxCHECK_MSG( HaveRects(), 0, _T("invalid wxRegionIterator") );
432
433 return m_rects[m_current].y;
434 }
435
436 wxCoord wxRegionIterator::GetW() const
437 {
438 wxCHECK_MSG( HaveRects(), 0, _T("invalid wxRegionIterator") );
439
440 return m_rects[m_current].width;
441 }
442
443 wxCoord wxRegionIterator::GetH() const
444 {
445 wxCHECK_MSG( HaveRects(), 0, _T("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 wxDELETEA(m_rects);
462
463 m_current = ri.m_current;
464 m_numRects = ri.m_numRects;
465 if ( m_numRects )
466 {
467 m_rects = new wxRect[m_numRects];
468 for ( unsigned int n = 0; n < m_numRects; n++ )
469 m_rects[n] = ri.m_rects[n];
470 }
471 else
472 {
473 m_rects = NULL;
474 }
475
476 return *this;
477 }