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