]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/region.cpp
Add wx.ListBox.HitTest
[wxWidgets.git] / src / gtk / region.cpp
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
31 class wxRegionRefData : public wxObjectRefData
32 {
33 public:
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
61 IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject)
62 IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator,wxObject)
63
64 // ----------------------------------------------------------------------------
65 // wxRegion construction
66 // ----------------------------------------------------------------------------
67
68 #define M_REGIONDATA ((wxRegionRefData *)m_refData)
69
70 void 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
83 wxRegion::wxRegion( GdkRegion *region )
84 {
85 m_refData = new wxRegionRefData();
86 M_REGIONDATA->m_region = gdk_region_copy( region );
87 }
88
89 wxRegion::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
113 wxRegion::~wxRegion()
114 {
115 // m_refData unrefed in ~wxObject
116 }
117
118 wxObjectRefData *wxRegion::CreateRefData() const
119 {
120 return new wxRegionRefData;
121 }
122
123 wxObjectRefData *wxRegion::CloneRefData(const wxObjectRefData *data) const
124 {
125 return new wxRegionRefData(*(wxRegionRefData *)data);
126 }
127
128 // ----------------------------------------------------------------------------
129 // wxRegion comparison
130 // ----------------------------------------------------------------------------
131
132 bool 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
147 void wxRegion::Clear()
148 {
149 UnRef();
150 }
151
152 bool 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
180 bool wxRegion::Union( const wxRect& rect )
181 {
182 return Union( rect.x, rect.y, rect.width, rect.height );
183 }
184
185 bool 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
205 bool 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
212 bool wxRegion::Intersect( const wxRect& rect )
213 {
214 wxRegion reg( rect );
215
216 return Intersect( reg );
217 }
218
219 bool 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
237 bool wxRegion::Subtract( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
238 {
239 wxRegion reg( x, y, width, height );
240 return Subtract( reg );
241 }
242
243 bool wxRegion::Subtract( const wxRect& rect )
244 {
245 wxRegion reg( rect );
246 return Subtract( reg );
247 }
248
249 bool 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
267 bool wxRegion::Xor( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
268 {
269 wxRegion reg( x, y, width, height );
270 return Xor( reg );
271 }
272
273 bool wxRegion::Xor( const wxRect& rect )
274 {
275 wxRegion reg( rect );
276 return Xor( reg );
277 }
278
279 bool 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
296 bool 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
312 void 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
332 wxRect 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
339 bool wxRegion::Empty() const
340 {
341 if (!m_refData)
342 return TRUE;
343
344 return gdk_region_empty( M_REGIONDATA->m_region );
345 }
346
347 wxRegionContain 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
358 wxRegionContain 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
378 wxRegionContain wxRegion::Contains(const wxPoint& pt) const
379 {
380 return Contains( pt.x, pt.y );
381 }
382
383 wxRegionContain wxRegion::Contains(const wxRect& rect) const
384 {
385 return Contains( rect.x, rect.y, rect.width, rect.height );
386 }
387
388 GdkRegion *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
400 class wxRIRefData: public wxObjectRefData
401 {
402 public:
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
414 wxRIRefData::~wxRIRefData()
415 {
416 delete [] m_rects;
417 }
418
419 void 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
450 wxRegionIterator::wxRegionIterator()
451 {
452 m_refData = new wxRIRefData();
453 Reset();
454 }
455
456 wxRegionIterator::wxRegionIterator( const wxRegion& region )
457 {
458 m_refData = new wxRIRefData();
459 Reset(region);
460 }
461
462 void wxRegionIterator::Reset( const wxRegion& region )
463 {
464 m_region = region;
465 ((wxRIRefData*)m_refData)->CreateRects(region);
466 Reset();
467 }
468
469 bool wxRegionIterator::HaveRects() const
470 {
471 return m_current < ((wxRIRefData*)m_refData)->m_numRects;
472 }
473
474 wxRegionIterator& wxRegionIterator::operator ++ ()
475 {
476 if (HaveRects())
477 ++m_current;
478
479 return *this;
480 }
481
482 wxRegionIterator wxRegionIterator::operator ++ (int)
483 {
484 wxRegionIterator tmp = *this;
485 if (HaveRects())
486 ++m_current;
487
488 return tmp;
489 }
490
491 wxCoord 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
498 wxCoord 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
505 wxCoord 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
512 wxCoord 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
519 wxRect 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