]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/region.cpp
Correct bug in the wxSpinCtrlGeneric sub-controls resizing.
[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.Ok(), false, wxT("invalid region") );
183
184 if (!m_refData)
185 {
186 m_refData = new wxRegionRefData();
187 M_REGIONDATA->m_region = gdk_region_new();
188 }
189 else
190 {
191 AllocExclusive();
192 }
193
194 gdk_region_union( M_REGIONDATA->m_region, region.GetRegion() );
195
196 return true;
197 }
198
199 bool wxRegion::DoIntersect( const wxRegion& region )
200 {
201 wxCHECK_MSG( region.Ok(), false, wxT("invalid region") );
202
203 if (!m_refData)
204 {
205 // intersecting with invalid region doesn't make sense
206 return false;
207 }
208
209 AllocExclusive();
210
211 gdk_region_intersect( M_REGIONDATA->m_region, region.GetRegion() );
212
213 return true;
214 }
215
216 bool wxRegion::DoSubtract( const wxRegion& region )
217 {
218 wxCHECK_MSG( region.Ok(), false, wxT("invalid region") );
219
220 if (!m_refData)
221 {
222 // subtracting from an invalid region doesn't make sense
223 return false;
224 }
225
226 AllocExclusive();
227
228 gdk_region_subtract( M_REGIONDATA->m_region, region.GetRegion() );
229
230 return true;
231 }
232
233 bool wxRegion::DoXor( const wxRegion& region )
234 {
235 wxCHECK_MSG( region.Ok(), false, wxT("invalid region") );
236
237 if (!m_refData)
238 {
239 return false;
240 }
241
242 AllocExclusive();
243
244 gdk_region_xor( M_REGIONDATA->m_region, region.GetRegion() );
245
246 return true;
247 }
248
249 bool wxRegion::DoOffset( wxCoord x, wxCoord y )
250 {
251 if (!m_refData)
252 return false;
253
254 AllocExclusive();
255
256 gdk_region_offset( M_REGIONDATA->m_region, x, y );
257
258 return true;
259 }
260
261 // ----------------------------------------------------------------------------
262 // wxRegion tests
263 // ----------------------------------------------------------------------------
264
265 bool wxRegion::DoGetBox( wxCoord &x, wxCoord &y, wxCoord &w, wxCoord &h ) const
266 {
267 if ( m_refData )
268 {
269 GdkRectangle rect;
270 gdk_region_get_clipbox( M_REGIONDATA->m_region, &rect );
271 x = rect.x;
272 y = rect.y;
273 w = rect.width;
274 h = rect.height;
275
276 return true;
277 }
278 else
279 {
280 x = 0;
281 y = 0;
282 w = -1;
283 h = -1;
284
285 return false;
286 }
287 }
288
289 bool wxRegion::IsEmpty() const
290 {
291 if (!m_refData)
292 return true;
293
294 return gdk_region_empty( M_REGIONDATA->m_region );
295 }
296
297 wxRegionContain wxRegion::DoContainsPoint( wxCoord x, wxCoord y ) const
298 {
299 if (!m_refData)
300 return wxOutRegion;
301
302 if (gdk_region_point_in( M_REGIONDATA->m_region, x, y ))
303 return wxInRegion;
304 else
305 return wxOutRegion;
306 }
307
308 wxRegionContain wxRegion::DoContainsRect(const wxRect& r) const
309 {
310 if (!m_refData)
311 return wxOutRegion;
312
313 GdkRectangle rect;
314 rect.x = r.x;
315 rect.y = r.y;
316 rect.width = r.width;
317 rect.height = r.height;
318 GdkOverlapType res = gdk_region_rect_in( M_REGIONDATA->m_region, &rect );
319 switch (res)
320 {
321 case GDK_OVERLAP_RECTANGLE_IN: return wxInRegion;
322 case GDK_OVERLAP_RECTANGLE_OUT: return wxOutRegion;
323 case GDK_OVERLAP_RECTANGLE_PART: return wxPartRegion;
324 }
325 return wxOutRegion;
326 }
327
328 GdkRegion *wxRegion::GetRegion() const
329 {
330 if (!m_refData)
331 return NULL;
332
333 return M_REGIONDATA->m_region;
334 }
335
336 // ----------------------------------------------------------------------------
337 // wxRegionIterator
338 // ----------------------------------------------------------------------------
339
340 wxRegionIterator::wxRegionIterator()
341 {
342 Init();
343 Reset();
344 }
345
346 wxRegionIterator::wxRegionIterator( const wxRegion& region )
347 {
348 Init();
349 Reset(region);
350 }
351
352 void wxRegionIterator::Init()
353 {
354 m_rects = NULL;
355 m_numRects = 0;
356 }
357
358 wxRegionIterator::~wxRegionIterator()
359 {
360 wxDELETEA(m_rects);
361 }
362
363 void wxRegionIterator::CreateRects( const wxRegion& region )
364 {
365 wxDELETEA(m_rects);
366 m_numRects = 0;
367
368 GdkRegion *gdkregion = region.GetRegion();
369 if (!gdkregion)
370 return;
371
372 GdkRectangle *gdkrects = NULL;
373 gint numRects = 0;
374 gdk_region_get_rectangles( gdkregion, &gdkrects, &numRects );
375
376 m_numRects = numRects;
377 if (numRects)
378 {
379 m_rects = new wxRect[m_numRects];
380 for (size_t i=0; i < m_numRects; ++i)
381 {
382 GdkRectangle &gr = gdkrects[i];
383 wxRect &wr = m_rects[i];
384 wr.x = gr.x;
385 wr.y = gr.y;
386 wr.width = gr.width;
387 wr.height = gr.height;
388 }
389 }
390 g_free( gdkrects );
391 }
392
393 void wxRegionIterator::Reset( const wxRegion& region )
394 {
395 m_region = region;
396 CreateRects(region);
397 Reset();
398 }
399
400 bool wxRegionIterator::HaveRects() const
401 {
402 return m_current < m_numRects;
403 }
404
405 wxRegionIterator& wxRegionIterator::operator ++ ()
406 {
407 if (HaveRects())
408 ++m_current;
409
410 return *this;
411 }
412
413 wxRegionIterator wxRegionIterator::operator ++ (int)
414 {
415 wxRegionIterator tmp = *this;
416
417 if (HaveRects())
418 ++m_current;
419
420 return tmp;
421 }
422
423 wxCoord wxRegionIterator::GetX() const
424 {
425 wxCHECK_MSG( HaveRects(), 0, wxT("invalid wxRegionIterator") );
426
427 return m_rects[m_current].x;
428 }
429
430 wxCoord wxRegionIterator::GetY() const
431 {
432 wxCHECK_MSG( HaveRects(), 0, wxT("invalid wxRegionIterator") );
433
434 return m_rects[m_current].y;
435 }
436
437 wxCoord wxRegionIterator::GetW() const
438 {
439 wxCHECK_MSG( HaveRects(), 0, wxT("invalid wxRegionIterator") );
440
441 return m_rects[m_current].width;
442 }
443
444 wxCoord wxRegionIterator::GetH() const
445 {
446 wxCHECK_MSG( HaveRects(), 0, wxT("invalid wxRegionIterator") );
447
448 return m_rects[m_current].height;
449 }
450
451 wxRect wxRegionIterator::GetRect() const
452 {
453 wxRect r;
454 if( HaveRects() )
455 r = m_rects[m_current];
456
457 return r;
458 }
459
460 wxRegionIterator& wxRegionIterator::operator=(const wxRegionIterator& ri)
461 {
462 wxDELETEA(m_rects);
463
464 m_current = ri.m_current;
465 m_numRects = ri.m_numRects;
466 if ( m_numRects )
467 {
468 m_rects = new wxRect[m_numRects];
469 for ( unsigned int n = 0; n < m_numRects; n++ )
470 m_rects[n] = ri.m_rects[n];
471 }
472 else
473 {
474 m_rects = NULL;
475 }
476
477 return *this;
478 }