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