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