]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/region.cpp
Go back to using a fixed value of 3 for lines/columns per action for mouse wheel...
[wxWidgets.git] / src / gtk / region.cpp
CommitLineData
c801d85f 1/////////////////////////////////////////////////////////////////////////////
e4db172a 2// Name: src/gtk/region.cpp
c801d85f
KB
3// Purpose:
4// Author: Robert Roebling
9fe4c99c 5// Modified: VZ at 05.10.00: use AllocExclusive(), comparison fixed
f96aa4d9 6// Copyright: (c) 1998 Robert Roebling
65571936 7// Licence: wxWindows licence
c801d85f
KB
8/////////////////////////////////////////////////////////////////////////////
9
1e6feb95
VZ
10// ============================================================================
11// declarations
12// ============================================================================
13
1e6feb95
VZ
14// ----------------------------------------------------------------------------
15// headers
16// ----------------------------------------------------------------------------
17
14f355c2
VS
18// For compilers that support precompilation, includes "wx.h".
19#include "wx/wxprec.h"
20
b3a44e05
WS
21#include "wx/region.h"
22
9dc44eff 23#include <gdk/gdk.h>
57f2b902 24
1e6feb95
VZ
25// ----------------------------------------------------------------------------
26// wxRegionRefData: private class containing the information about the region
27// ----------------------------------------------------------------------------
c801d85f 28
8f884a0d 29class wxRegionRefData : public wxGDIRefData
c801d85f 30{
864e8bd0 31public:
48850fa7
RR
32 wxRegionRefData()
33 {
34 m_region = NULL;
35 }
57f2b902 36
48850fa7 37 wxRegionRefData(const wxRegionRefData& refData)
8f884a0d 38 : wxGDIRefData()
48850fa7 39 {
9dc44eff
PC
40#ifdef __WXGTK3__
41 m_region = cairo_region_copy(refData.m_region);
42#else
48850fa7 43 m_region = gdk_region_copy(refData.m_region);
9dc44eff 44#endif
48850fa7 45 }
57f2b902 46
d3c7fc99 47 virtual ~wxRegionRefData()
48850fa7
RR
48 {
49 if (m_region)
9dc44eff
PC
50 {
51#ifdef __WXGTK3__
52 cairo_region_destroy(m_region);
53#else
48850fa7 54 gdk_region_destroy( m_region );
9dc44eff
PC
55#endif
56 }
48850fa7 57 }
5fc7ede9 58
9dc44eff
PC
59#ifdef __WXGTK3__
60 cairo_region_t* m_region;
61#else
c801d85f 62 GdkRegion *m_region;
9dc44eff 63#endif
c801d85f
KB
64};
65
1e6feb95
VZ
66// ----------------------------------------------------------------------------
67// macros
68// ----------------------------------------------------------------------------
69
9dc44eff
PC
70#define M_REGIONDATA static_cast<wxRegionRefData*>(m_refData)
71#define M_REGIONDATA_OF(r) static_cast<wxRegionRefData*>(r.m_refData)
1e6feb95 72
d84afea9
GD
73IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject)
74IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator,wxObject)
1e6feb95 75
1e6feb95
VZ
76// ----------------------------------------------------------------------------
77// wxRegion construction
78// ----------------------------------------------------------------------------
c801d85f 79
9fe4c99c 80void wxRegion::InitRect(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
c801d85f 81{
bbe0af5b
RR
82 GdkRectangle rect;
83 rect.x = x;
84 rect.y = y;
85 rect.width = w;
86 rect.height = h;
57f2b902 87
48850fa7 88 m_refData = new wxRegionRefData();
57f2b902 89
9dc44eff
PC
90#ifdef __WXGTK3__
91 M_REGIONDATA->m_region = cairo_region_create_rectangle(&rect);
92#else
9e691f46 93 M_REGIONDATA->m_region = gdk_region_rectangle( &rect );
9dc44eff 94#endif
ff7b1510 95}
c801d85f 96
9dc44eff
PC
97#ifndef __WXGTK3__
98wxRegion::wxRegion(const GdkRegion* region)
b15ed747
RR
99{
100 m_refData = new wxRegionRefData();
9dc44eff 101 M_REGIONDATA->m_region = gdk_region_copy(const_cast<GdkRegion*>(region));
b15ed747 102}
9dc44eff 103#endif
b15ed747 104
03647350 105wxRegion::wxRegion( size_t n, const wxPoint *points,
89efaf2b 106 wxPolygonFillMode fillStyle )
5549e9f7 107{
9dc44eff
PC
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
5549e9f7
VZ
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;
9dc44eff 178#endif
5549e9f7
VZ
179}
180
1e6feb95 181wxRegion::~wxRegion()
c801d85f 182{
e0f0b197 183 // m_refData unrefed in ~wxObject
ff7b1510 184}
c801d85f 185
8f884a0d 186wxGDIRefData *wxRegion::CreateGDIRefData() const
e0f0b197 187{
9dc44eff
PC
188 // should never be called
189 wxFAIL;
190 return NULL;
e0f0b197
RR
191}
192
8f884a0d 193wxGDIRefData *wxRegion::CloneGDIRefData(const wxGDIRefData *data) const
e0f0b197 194{
9dc44eff 195 return new wxRegionRefData(*static_cast<const wxRegionRefData*>(data));
e0f0b197 196}
c89f5c02 197
9fe4c99c
VZ
198// ----------------------------------------------------------------------------
199// wxRegion comparison
200// ----------------------------------------------------------------------------
201
8a16d737 202bool wxRegion::DoIsEqual(const wxRegion& region) const
c801d85f 203{
9dc44eff
PC
204#ifdef __WXGTK3__
205 return cairo_region_equal(
206 M_REGIONDATA->m_region, M_REGIONDATA_OF(region)->m_region);
207#else
1e6feb95 208 return gdk_region_equal(M_REGIONDATA->m_region,
d5027818 209 M_REGIONDATA_OF(region)->m_region) != 0;
9dc44eff 210#endif
ff7b1510 211}
c801d85f 212
1e6feb95
VZ
213// ----------------------------------------------------------------------------
214// wxRegion operations
215// ----------------------------------------------------------------------------
216
bf57d1ad 217void wxRegion::Clear()
c801d85f 218{
bbe0af5b 219 UnRef();
ff7b1510 220}
c801d85f 221
8a16d737 222bool wxRegion::DoUnionWithRect(const wxRect& r)
c801d85f 223{
57351df0
VZ
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
8a16d737 227 if ( r.IsEmpty() )
b3a44e05 228 return true;
57351df0 229
2b5f62a0 230 if ( !m_refData )
e1208c31 231 {
8a16d737 232 InitRect(r.x, r.y, r.width, r.height);
e1208c31
RR
233 }
234 else
235 {
9fe4c99c 236 AllocExclusive();
1e6feb95 237
2b5f62a0 238 GdkRectangle rect;
8a16d737
VZ
239 rect.x = r.x;
240 rect.y = r.y;
241 rect.width = r.width;
242 rect.height = r.height;
2b5f62a0 243
9dc44eff
PC
244#ifdef __WXGTK3__
245 cairo_region_union_rectangle(M_REGIONDATA->m_region, &rect);
246#else
b7c2d6ff 247 gdk_region_union_with_rect( M_REGIONDATA->m_region, &rect );
9dc44eff 248#endif
e1208c31 249 }
1e6feb95 250
b3a44e05 251 return true;
ff7b1510 252}
c801d85f 253
8a16d737 254bool wxRegion::DoUnionWithRegion( const wxRegion& region )
c801d85f 255{
9dc44eff
PC
256 if (region.m_refData == NULL)
257 { }
258 else if (m_refData == NULL)
48850fa7 259 {
dd4eefcb 260 m_refData = new wxRegionRefData(*M_REGIONDATA_OF(region));
48850fa7
RR
261 }
262 else
263 {
264 AllocExclusive();
9dc44eff
PC
265#ifdef __WXGTK3__
266 cairo_region_union(M_REGIONDATA->m_region, M_REGIONDATA_OF(region)->m_region);
267#else
dd4eefcb 268 gdk_region_union( M_REGIONDATA->m_region, region.GetRegion() );
9dc44eff 269#endif
48850fa7 270 }
e1208c31 271
b3a44e05 272 return true;
ff7b1510 273}
c801d85f 274
8a16d737 275bool wxRegion::DoIntersect( const wxRegion& region )
c801d85f 276{
9dc44eff 277 if (region.m_refData == NULL || m_refData == NULL)
b3a44e05 278 return false;
1e6feb95 279
2b5f62a0
VZ
280 AllocExclusive();
281
9dc44eff
PC
282#ifdef __WXGTK3__
283 cairo_region_intersect(M_REGIONDATA->m_region, M_REGIONDATA_OF(region)->m_region);
284#else
48850fa7 285 gdk_region_intersect( M_REGIONDATA->m_region, region.GetRegion() );
9dc44eff 286#endif
9fe4c99c 287
b3a44e05 288 return true;
ff7b1510 289}
c801d85f 290
8a16d737 291bool wxRegion::DoSubtract( const wxRegion& region )
c801d85f 292{
9dc44eff 293 if (region.m_refData == NULL || m_refData == NULL)
b3a44e05 294 return false;
1e6feb95 295
2b5f62a0
VZ
296 AllocExclusive();
297
9dc44eff
PC
298#ifdef __WXGTK3__
299 cairo_region_subtract(M_REGIONDATA->m_region, M_REGIONDATA_OF(region)->m_region);
300#else
b7c2d6ff 301 gdk_region_subtract( M_REGIONDATA->m_region, region.GetRegion() );
9dc44eff 302#endif
1e6feb95 303
b3a44e05 304 return true;
ff7b1510 305}
c801d85f 306
8a16d737 307bool wxRegion::DoXor( const wxRegion& region )
c801d85f 308{
9dc44eff
PC
309 if (region.m_refData == NULL)
310 { }
311 else if (m_refData == NULL)
e1208c31 312 {
dd4eefcb
VZ
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));
1e6feb95 316 }
dd4eefcb
VZ
317 else
318 {
319 AllocExclusive();
e1208c31 320
9dc44eff
PC
321#ifdef __WXGTK3__
322 cairo_region_xor(M_REGIONDATA->m_region, M_REGIONDATA_OF(region)->m_region);
323#else
dd4eefcb 324 gdk_region_xor( M_REGIONDATA->m_region, region.GetRegion() );
9dc44eff 325#endif
dd4eefcb 326 }
5fc7ede9 327
b3a44e05 328 return true;
ff7b1510 329}
c801d85f 330
8a16d737 331bool wxRegion::DoOffset( wxCoord x, wxCoord y )
2b5f62a0 332{
dd4eefcb 333 wxCHECK_MSG( m_refData, false, wxS("invalid region") );
2b5f62a0
VZ
334
335 AllocExclusive();
336
9dc44eff
PC
337#ifdef __WXGTK3__
338 cairo_region_translate(M_REGIONDATA->m_region, x, y);
339#else
2b5f62a0 340 gdk_region_offset( M_REGIONDATA->m_region, x, y );
9dc44eff 341#endif
2b5f62a0 342
b3a44e05 343 return true;
2b5f62a0
VZ
344}
345
1e6feb95
VZ
346// ----------------------------------------------------------------------------
347// wxRegion tests
348// ----------------------------------------------------------------------------
349
8a16d737 350bool wxRegion::DoGetBox( wxCoord &x, wxCoord &y, wxCoord &w, wxCoord &h ) const
c801d85f 351{
1e6feb95
VZ
352 if ( m_refData )
353 {
354 GdkRectangle rect;
9dc44eff
PC
355#ifdef __WXGTK3__
356 cairo_region_get_extents(M_REGIONDATA->m_region, &rect);
357#else
1e6feb95 358 gdk_region_get_clipbox( M_REGIONDATA->m_region, &rect );
9dc44eff 359#endif
1e6feb95
VZ
360 x = rect.x;
361 y = rect.y;
362 w = rect.width;
363 h = rect.height;
8a16d737
VZ
364
365 return true;
1e6feb95
VZ
366 }
367 else
368 {
369 x = 0;
370 y = 0;
371 w = -1;
372 h = -1;
c801d85f 373
8a16d737
VZ
374 return false;
375 }
ff7b1510 376}
c801d85f 377
8a16d737 378bool wxRegion::IsEmpty() const
c801d85f 379{
9dc44eff
PC
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
ff7b1510 385}
c801d85f 386
8a16d737 387wxRegionContain wxRegion::DoContainsPoint( wxCoord x, wxCoord y ) const
c801d85f 388{
9dc44eff
PC
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
e1208c31
RR
394 return wxOutRegion;
395
9dc44eff 396 return wxInRegion;
ff7b1510 397}
c801d85f 398
8a16d737 399wxRegionContain wxRegion::DoContainsRect(const wxRect& r) const
c801d85f 400{
e1208c31
RR
401 if (!m_refData)
402 return wxOutRegion;
403
bbe0af5b 404 GdkRectangle rect;
8a16d737
VZ
405 rect.x = r.x;
406 rect.y = r.y;
407 rect.width = r.width;
408 rect.height = r.height;
9dc44eff
PC
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
bbe0af5b
RR
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 }
9dc44eff 424#endif
bbe0af5b 425 return wxOutRegion;
ff7b1510 426}
c801d85f 427
9dc44eff
PC
428#ifdef __WXGTK3__
429cairo_region_t* wxRegion::GetRegion() const
430#else
bf57d1ad 431GdkRegion *wxRegion::GetRegion() const
9dc44eff 432#endif
c801d85f 433{
e1208c31 434 if (!m_refData)
d3b9f782 435 return NULL;
e1208c31 436
bbe0af5b 437 return M_REGIONDATA->m_region;
ff7b1510 438}
c801d85f 439
1e6feb95 440// ----------------------------------------------------------------------------
3d0c4d2e 441// wxRegionIterator
1e6feb95 442// ----------------------------------------------------------------------------
8429bec1 443
55ccdb93 444wxRegionIterator::wxRegionIterator()
3d0c4d2e 445{
55ccdb93
VZ
446 Init();
447 Reset();
448}
3d0c4d2e 449
55ccdb93
VZ
450wxRegionIterator::wxRegionIterator( const wxRegion& region )
451{
452 Init();
453 Reset(region);
454}
3d0c4d2e 455
55ccdb93 456void wxRegionIterator::Init()
3d0c4d2e 457{
55ccdb93
VZ
458 m_rects = NULL;
459 m_numRects = 0;
3d0c4d2e
RR
460}
461
55ccdb93 462wxRegionIterator::~wxRegionIterator()
3d0c4d2e 463{
55ccdb93
VZ
464 wxDELETEA(m_rects);
465}
48850fa7 466
55ccdb93
VZ
467void wxRegionIterator::CreateRects( const wxRegion& region )
468{
469 wxDELETEA(m_rects);
470 m_numRects = 0;
57f2b902 471
9dc44eff
PC
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
48850fa7 493 GdkRegion *gdkregion = region.GetRegion();
3f0fb1d4
VZ
494 if (!gdkregion)
495 return;
57f2b902 496
46a1983a
PC
497 GdkRectangle* gdkrects;
498 gdk_region_get_rectangles(gdkregion, &gdkrects, &m_numRects);
57f2b902 499
46a1983a 500 if (m_numRects)
48850fa7
RR
501 {
502 m_rects = new wxRect[m_numRects];
46a1983a 503 for (int i = 0; i < m_numRects; ++i)
3d0c4d2e 504 {
48850fa7
RR
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;
3d0c4d2e 511 }
3d0c4d2e 512 }
9e691f46 513 g_free( gdkrects );
9dc44eff 514#endif
3d0c4d2e
RR
515}
516
3d0c4d2e
RR
517void wxRegionIterator::Reset( const wxRegion& region )
518{
519 m_region = region;
55ccdb93 520 CreateRects(region);
3d0c4d2e
RR
521 Reset();
522}
523
524bool wxRegionIterator::HaveRects() const
525{
55ccdb93 526 return m_current < m_numRects;
3d0c4d2e
RR
527}
528
2b5f62a0 529wxRegionIterator& wxRegionIterator::operator ++ ()
3d0c4d2e 530{
2b5f62a0
VZ
531 if (HaveRects())
532 ++m_current;
3d0c4d2e 533
2b5f62a0 534 return *this;
3d0c4d2e
RR
535}
536
2b5f62a0 537wxRegionIterator wxRegionIterator::operator ++ (int)
3d0c4d2e 538{
2b5f62a0 539 wxRegionIterator tmp = *this;
55ccdb93 540
2b5f62a0
VZ
541 if (HaveRects())
542 ++m_current;
543
544 return tmp;
3d0c4d2e
RR
545}
546
547wxCoord wxRegionIterator::GetX() const
548{
9a83f860 549 wxCHECK_MSG( HaveRects(), 0, wxT("invalid wxRegionIterator") );
2b5f62a0 550
55ccdb93 551 return m_rects[m_current].x;
3d0c4d2e
RR
552}
553
554wxCoord wxRegionIterator::GetY() const
555{
9a83f860 556 wxCHECK_MSG( HaveRects(), 0, wxT("invalid wxRegionIterator") );
2b5f62a0 557
55ccdb93 558 return m_rects[m_current].y;
3d0c4d2e
RR
559}
560
561wxCoord wxRegionIterator::GetW() const
562{
9a83f860 563 wxCHECK_MSG( HaveRects(), 0, wxT("invalid wxRegionIterator") );
2b5f62a0 564
55ccdb93 565 return m_rects[m_current].width;
3d0c4d2e
RR
566}
567
568wxCoord wxRegionIterator::GetH() const
569{
9a83f860 570 wxCHECK_MSG( HaveRects(), 0, wxT("invalid wxRegionIterator") );
2b5f62a0 571
55ccdb93 572 return m_rects[m_current].height;
3d0c4d2e
RR
573}
574
1e6feb95
VZ
575wxRect wxRegionIterator::GetRect() const
576{
577 wxRect r;
3379ed37 578 if( HaveRects() )
55ccdb93 579 r = m_rects[m_current];
1e6feb95
VZ
580
581 return r;
582}
ac7d3dd1
RR
583
584wxRegionIterator& wxRegionIterator::operator=(const wxRegionIterator& ri)
585{
701871dc 586 if (this != &ri)
ac7d3dd1 587 {
701871dc 588 wxDELETEA(m_rects);
ac7d3dd1 589
701871dc
PC
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 }
ac7d3dd1
RR
598 return *this;
599}