]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/gtk/region.cpp
Add virtual ~wxAnyScrollHelperBase() to fix compiler warning.
[wxWidgets.git] / src / gtk / region.cpp
... / ...
CommitLineData
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// Copyright: (c) 1998 Robert Roebling
7// Licence: wxWindows licence
8/////////////////////////////////////////////////////////////////////////////
9
10// ============================================================================
11// declarations
12// ============================================================================
13
14// ----------------------------------------------------------------------------
15// headers
16// ----------------------------------------------------------------------------
17
18// For compilers that support precompilation, includes "wx.h".
19#include "wx/wxprec.h"
20
21#include "wx/region.h"
22
23#include <gdk/gdk.h>
24
25// ----------------------------------------------------------------------------
26// wxRegionRefData: private class containing the information about the region
27// ----------------------------------------------------------------------------
28
29class wxRegionRefData : public wxGDIRefData
30{
31public:
32 wxRegionRefData()
33 {
34 m_region = NULL;
35 }
36
37 wxRegionRefData(const wxRegionRefData& refData)
38 : wxGDIRefData()
39 {
40#ifdef __WXGTK3__
41 m_region = cairo_region_copy(refData.m_region);
42#else
43 m_region = gdk_region_copy(refData.m_region);
44#endif
45 }
46
47 virtual ~wxRegionRefData()
48 {
49 if (m_region)
50 {
51#ifdef __WXGTK3__
52 cairo_region_destroy(m_region);
53#else
54 gdk_region_destroy( m_region );
55#endif
56 }
57 }
58
59#ifdef __WXGTK3__
60 cairo_region_t* m_region;
61#else
62 GdkRegion *m_region;
63#endif
64};
65
66// ----------------------------------------------------------------------------
67// macros
68// ----------------------------------------------------------------------------
69
70#define M_REGIONDATA static_cast<wxRegionRefData*>(m_refData)
71#define M_REGIONDATA_OF(r) static_cast<wxRegionRefData*>(r.m_refData)
72
73IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject)
74IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator,wxObject)
75
76// ----------------------------------------------------------------------------
77// wxRegion construction
78// ----------------------------------------------------------------------------
79
80void wxRegion::InitRect(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
81{
82 GdkRectangle rect;
83 rect.x = x;
84 rect.y = y;
85 rect.width = w;
86 rect.height = h;
87
88 m_refData = new wxRegionRefData();
89
90#ifdef __WXGTK3__
91 M_REGIONDATA->m_region = cairo_region_create_rectangle(&rect);
92#else
93 M_REGIONDATA->m_region = gdk_region_rectangle( &rect );
94#endif
95}
96
97#ifndef __WXGTK3__
98wxRegion::wxRegion(const GdkRegion* region)
99{
100 m_refData = new wxRegionRefData();
101 M_REGIONDATA->m_region = gdk_region_copy(const_cast<GdkRegion*>(region));
102}
103#endif
104
105wxRegion::wxRegion( size_t n, const wxPoint *points,
106 wxPolygonFillMode fillStyle )
107{
108#ifdef __WXGTK3__
109 // Make a cairo path from the points, draw it onto an image surface, use
110 // gdk_cairo_region_create_from_surface() to get a cairo region
111
112 // need at least 3 points to make a useful polygon
113 if (n < 3)
114 return;
115 // get bounding rect
116 int min_x = points[0].x;
117 int max_x = min_x;
118 int min_y = points[0].y;
119 int max_y = min_y;
120 size_t i;
121 for (i = 1; i < n; i++)
122 {
123 const int x = points[i].x;
124 if (min_x > x)
125 min_x = x;
126 else if (max_x < x)
127 max_x = x;
128 const int y = points[i].y;
129 if (min_y > y)
130 min_y = y;
131 else if (max_y < y)
132 max_y = y;
133 }
134 const int w = max_x - min_x + 1;
135 const int h = max_y - min_y + 1;
136 // make surface just big enough to contain polygon (A1 is native format
137 // for gdk_cairo_region_create_from_surface)
138 cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_A1, w, h);
139 memset(cairo_image_surface_get_data(surface), 0, cairo_image_surface_get_stride(surface) * h);
140 cairo_surface_mark_dirty(surface);
141 cairo_surface_set_device_offset(surface, -min_x, -min_y);
142 cairo_t* cr = cairo_create(surface);
143 cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
144 if (fillStyle == wxODDEVEN_RULE)
145 cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
146 // make path
147 cairo_move_to(cr, points[0].x, points[0].y);
148 for (i = 1; i < n; i++)
149 cairo_line_to(cr, points[i].x, points[i].y);
150 cairo_close_path(cr);
151 cairo_fill(cr);
152 cairo_destroy(cr);
153 cairo_surface_flush(surface);
154 m_refData = new wxRegionRefData;
155 M_REGIONDATA->m_region = gdk_cairo_region_create_from_surface(surface);
156 cairo_surface_destroy(surface);
157#else
158 GdkPoint *gdkpoints = new GdkPoint[n];
159 for ( size_t i = 0 ; i < n ; i++ )
160 {
161 gdkpoints[i].x = points[i].x;
162 gdkpoints[i].y = points[i].y;
163 }
164
165 m_refData = new wxRegionRefData();
166
167 GdkRegion* reg = gdk_region_polygon
168 (
169 gdkpoints,
170 n,
171 fillStyle == wxWINDING_RULE ? GDK_WINDING_RULE
172 : GDK_EVEN_ODD_RULE
173 );
174
175 M_REGIONDATA->m_region = reg;
176
177 delete [] gdkpoints;
178#endif
179}
180
181wxRegion::~wxRegion()
182{
183 // m_refData unrefed in ~wxObject
184}
185
186wxGDIRefData *wxRegion::CreateGDIRefData() const
187{
188 // should never be called
189 wxFAIL;
190 return NULL;
191}
192
193wxGDIRefData *wxRegion::CloneGDIRefData(const wxGDIRefData *data) const
194{
195 return new wxRegionRefData(*static_cast<const wxRegionRefData*>(data));
196}
197
198// ----------------------------------------------------------------------------
199// wxRegion comparison
200// ----------------------------------------------------------------------------
201
202bool wxRegion::DoIsEqual(const wxRegion& region) const
203{
204#ifdef __WXGTK3__
205 return cairo_region_equal(
206 M_REGIONDATA->m_region, M_REGIONDATA_OF(region)->m_region);
207#else
208 return gdk_region_equal(M_REGIONDATA->m_region,
209 M_REGIONDATA_OF(region)->m_region) != 0;
210#endif
211}
212
213// ----------------------------------------------------------------------------
214// wxRegion operations
215// ----------------------------------------------------------------------------
216
217void wxRegion::Clear()
218{
219 UnRef();
220}
221
222bool wxRegion::DoUnionWithRect(const wxRect& r)
223{
224 // workaround for a strange GTK/X11 bug: taking union with an empty
225 // rectangle results in an empty region which is definitely not what we
226 // want
227 if ( r.IsEmpty() )
228 return true;
229
230 if ( !m_refData )
231 {
232 InitRect(r.x, r.y, r.width, r.height);
233 }
234 else
235 {
236 AllocExclusive();
237
238 GdkRectangle rect;
239 rect.x = r.x;
240 rect.y = r.y;
241 rect.width = r.width;
242 rect.height = r.height;
243
244#ifdef __WXGTK3__
245 cairo_region_union_rectangle(M_REGIONDATA->m_region, &rect);
246#else
247 gdk_region_union_with_rect( M_REGIONDATA->m_region, &rect );
248#endif
249 }
250
251 return true;
252}
253
254bool wxRegion::DoUnionWithRegion( const wxRegion& region )
255{
256 if (region.m_refData == NULL)
257 { }
258 else if (m_refData == NULL)
259 {
260 m_refData = new wxRegionRefData(*M_REGIONDATA_OF(region));
261 }
262 else
263 {
264 AllocExclusive();
265#ifdef __WXGTK3__
266 cairo_region_union(M_REGIONDATA->m_region, M_REGIONDATA_OF(region)->m_region);
267#else
268 gdk_region_union( M_REGIONDATA->m_region, region.GetRegion() );
269#endif
270 }
271
272 return true;
273}
274
275bool wxRegion::DoIntersect( const wxRegion& region )
276{
277 if (region.m_refData == NULL || m_refData == NULL)
278 return false;
279
280 AllocExclusive();
281
282#ifdef __WXGTK3__
283 cairo_region_intersect(M_REGIONDATA->m_region, M_REGIONDATA_OF(region)->m_region);
284#else
285 gdk_region_intersect( M_REGIONDATA->m_region, region.GetRegion() );
286#endif
287
288 return true;
289}
290
291bool wxRegion::DoSubtract( const wxRegion& region )
292{
293 if (region.m_refData == NULL || m_refData == NULL)
294 return false;
295
296 AllocExclusive();
297
298#ifdef __WXGTK3__
299 cairo_region_subtract(M_REGIONDATA->m_region, M_REGIONDATA_OF(region)->m_region);
300#else
301 gdk_region_subtract( M_REGIONDATA->m_region, region.GetRegion() );
302#endif
303
304 return true;
305}
306
307bool wxRegion::DoXor( const wxRegion& region )
308{
309 if (region.m_refData == NULL)
310 { }
311 else if (m_refData == NULL)
312 {
313 // XOR-ing with an invalid region is the same as XOR-ing with an empty
314 // one, i.e. it is simply a copy.
315 m_refData = new wxRegionRefData(*M_REGIONDATA_OF(region));
316 }
317 else
318 {
319 AllocExclusive();
320
321#ifdef __WXGTK3__
322 cairo_region_xor(M_REGIONDATA->m_region, M_REGIONDATA_OF(region)->m_region);
323#else
324 gdk_region_xor( M_REGIONDATA->m_region, region.GetRegion() );
325#endif
326 }
327
328 return true;
329}
330
331bool wxRegion::DoOffset( wxCoord x, wxCoord y )
332{
333 wxCHECK_MSG( m_refData, false, wxS("invalid region") );
334
335 AllocExclusive();
336
337#ifdef __WXGTK3__
338 cairo_region_translate(M_REGIONDATA->m_region, x, y);
339#else
340 gdk_region_offset( M_REGIONDATA->m_region, x, y );
341#endif
342
343 return true;
344}
345
346// ----------------------------------------------------------------------------
347// wxRegion tests
348// ----------------------------------------------------------------------------
349
350bool wxRegion::DoGetBox( wxCoord &x, wxCoord &y, wxCoord &w, wxCoord &h ) const
351{
352 if ( m_refData )
353 {
354 GdkRectangle rect;
355#ifdef __WXGTK3__
356 cairo_region_get_extents(M_REGIONDATA->m_region, &rect);
357#else
358 gdk_region_get_clipbox( M_REGIONDATA->m_region, &rect );
359#endif
360 x = rect.x;
361 y = rect.y;
362 w = rect.width;
363 h = rect.height;
364
365 return true;
366 }
367 else
368 {
369 x = 0;
370 y = 0;
371 w = -1;
372 h = -1;
373
374 return false;
375 }
376}
377
378bool wxRegion::IsEmpty() const
379{
380#ifdef __WXGTK3__
381 return m_refData == NULL || cairo_region_is_empty(M_REGIONDATA->m_region);
382#else
383 return m_refData == NULL || gdk_region_empty(M_REGIONDATA->m_region);
384#endif
385}
386
387wxRegionContain wxRegion::DoContainsPoint( wxCoord x, wxCoord y ) const
388{
389#ifdef __WXGTK3__
390 if (m_refData == NULL || !cairo_region_contains_point(M_REGIONDATA->m_region, x, y))
391#else
392 if (m_refData == NULL || !gdk_region_point_in(M_REGIONDATA->m_region, x, y))
393#endif
394 return wxOutRegion;
395
396 return wxInRegion;
397}
398
399wxRegionContain wxRegion::DoContainsRect(const wxRect& r) const
400{
401 if (!m_refData)
402 return wxOutRegion;
403
404 GdkRectangle rect;
405 rect.x = r.x;
406 rect.y = r.y;
407 rect.width = r.width;
408 rect.height = r.height;
409#ifdef __WXGTK3__
410 switch (cairo_region_contains_rectangle(M_REGIONDATA->m_region, &rect))
411 {
412 case CAIRO_REGION_OVERLAP_IN: return wxInRegion;
413 case CAIRO_REGION_OVERLAP_PART: return wxPartRegion;
414 default: break;
415 }
416#else
417 GdkOverlapType res = gdk_region_rect_in( M_REGIONDATA->m_region, &rect );
418 switch (res)
419 {
420 case GDK_OVERLAP_RECTANGLE_IN: return wxInRegion;
421 case GDK_OVERLAP_RECTANGLE_OUT: return wxOutRegion;
422 case GDK_OVERLAP_RECTANGLE_PART: return wxPartRegion;
423 }
424#endif
425 return wxOutRegion;
426}
427
428#ifdef __WXGTK3__
429cairo_region_t* wxRegion::GetRegion() const
430#else
431GdkRegion *wxRegion::GetRegion() const
432#endif
433{
434 if (!m_refData)
435 return NULL;
436
437 return M_REGIONDATA->m_region;
438}
439
440// ----------------------------------------------------------------------------
441// wxRegionIterator
442// ----------------------------------------------------------------------------
443
444wxRegionIterator::wxRegionIterator()
445{
446 Init();
447 Reset();
448}
449
450wxRegionIterator::wxRegionIterator( const wxRegion& region )
451{
452 Init();
453 Reset(region);
454}
455
456void wxRegionIterator::Init()
457{
458 m_rects = NULL;
459 m_numRects = 0;
460}
461
462wxRegionIterator::~wxRegionIterator()
463{
464 wxDELETEA(m_rects);
465}
466
467void wxRegionIterator::CreateRects( const wxRegion& region )
468{
469 wxDELETEA(m_rects);
470 m_numRects = 0;
471
472#ifdef __WXGTK3__
473 cairo_region_t* cairoRegion = region.GetRegion();
474 if (cairoRegion == NULL)
475 return;
476 m_numRects = cairo_region_num_rectangles(cairoRegion);
477
478 if (m_numRects)
479 {
480 m_rects = new wxRect[m_numRects];
481 for (int i = 0; i < m_numRects; i++)
482 {
483 GdkRectangle gr;
484 cairo_region_get_rectangle(cairoRegion, i, &gr);
485 wxRect &wr = m_rects[i];
486 wr.x = gr.x;
487 wr.y = gr.y;
488 wr.width = gr.width;
489 wr.height = gr.height;
490 }
491 }
492#else
493 GdkRegion *gdkregion = region.GetRegion();
494 if (!gdkregion)
495 return;
496
497 GdkRectangle* gdkrects;
498 gdk_region_get_rectangles(gdkregion, &gdkrects, &m_numRects);
499
500 if (m_numRects)
501 {
502 m_rects = new wxRect[m_numRects];
503 for (int i = 0; i < m_numRects; ++i)
504 {
505 GdkRectangle &gr = gdkrects[i];
506 wxRect &wr = m_rects[i];
507 wr.x = gr.x;
508 wr.y = gr.y;
509 wr.width = gr.width;
510 wr.height = gr.height;
511 }
512 }
513 g_free( gdkrects );
514#endif
515}
516
517void wxRegionIterator::Reset( const wxRegion& region )
518{
519 m_region = region;
520 CreateRects(region);
521 Reset();
522}
523
524bool wxRegionIterator::HaveRects() const
525{
526 return m_current < m_numRects;
527}
528
529wxRegionIterator& wxRegionIterator::operator ++ ()
530{
531 if (HaveRects())
532 ++m_current;
533
534 return *this;
535}
536
537wxRegionIterator wxRegionIterator::operator ++ (int)
538{
539 wxRegionIterator tmp = *this;
540
541 if (HaveRects())
542 ++m_current;
543
544 return tmp;
545}
546
547wxCoord wxRegionIterator::GetX() const
548{
549 wxCHECK_MSG( HaveRects(), 0, wxT("invalid wxRegionIterator") );
550
551 return m_rects[m_current].x;
552}
553
554wxCoord wxRegionIterator::GetY() const
555{
556 wxCHECK_MSG( HaveRects(), 0, wxT("invalid wxRegionIterator") );
557
558 return m_rects[m_current].y;
559}
560
561wxCoord wxRegionIterator::GetW() const
562{
563 wxCHECK_MSG( HaveRects(), 0, wxT("invalid wxRegionIterator") );
564
565 return m_rects[m_current].width;
566}
567
568wxCoord wxRegionIterator::GetH() const
569{
570 wxCHECK_MSG( HaveRects(), 0, wxT("invalid wxRegionIterator") );
571
572 return m_rects[m_current].height;
573}
574
575wxRect wxRegionIterator::GetRect() const
576{
577 wxRect r;
578 if( HaveRects() )
579 r = m_rects[m_current];
580
581 return r;
582}
583
584wxRegionIterator& wxRegionIterator::operator=(const wxRegionIterator& ri)
585{
586 if (this != &ri)
587 {
588 wxDELETEA(m_rects);
589
590 m_current = ri.m_current;
591 m_numRects = ri.m_numRects;
592 if ( m_numRects )
593 {
594 m_rects = new wxRect[m_numRects];
595 memcpy(m_rects, ri.m_rects, m_numRects * sizeof m_rects[0]);
596 }
597 }
598 return *this;
599}