]> git.saurik.com Git - wxWidgets.git/blob - src/x11/region.cpp
Don't crash when laying out wxGridBagSizer with only hidden elements.
[wxWidgets.git] / src / x11 / region.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // File: src/x11/region.cpp
3 // Purpose: Region class
4 // Author: Julian Smart, Robert Roebling
5 // Created: Fri Oct 24 10:46:34 MET 1997
6 // Copyright: (c) 1997 Julian Smart, Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // for compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
12
13 #include "wx/region.h"
14
15 #ifndef WX_PRECOMP
16 #include "wx/log.h"
17 #include "wx/gdicmn.h"
18 #endif
19
20 #ifdef __VMS__
21 #pragma message disable nosimpint
22 #endif
23 #include "wx/x11/private.h"
24 #include "X11/Xutil.h"
25 #ifdef __VMS__
26 #pragma message enable nosimpint
27 #endif
28
29 // ----------------------------------------------------------------------------
30 // wxRegionRefData: private class containing the information about the region
31 // ----------------------------------------------------------------------------
32
33 class wxRegionRefData : public wxGDIRefData
34 {
35 public:
36 wxRegionRefData()
37 {
38 m_region = NULL;
39 }
40
41 wxRegionRefData(const wxRegionRefData& refData)
42 {
43 m_region = XCreateRegion();
44 XUnionRegion( refData.m_region, m_region, m_region );
45 }
46
47 virtual ~wxRegionRefData()
48 {
49 if (m_region)
50 XDestroyRegion( m_region );
51 }
52
53 Region m_region;
54 };
55
56 // ----------------------------------------------------------------------------
57 // macros
58 // ----------------------------------------------------------------------------
59
60 #define M_REGIONDATA ((wxRegionRefData *)m_refData)
61 #define M_REGIONDATA_OF(rgn) ((wxRegionRefData *)(rgn.m_refData))
62
63 IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject)
64 IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator,wxObject)
65
66 // ----------------------------------------------------------------------------
67 // wxRegion construction
68 // ----------------------------------------------------------------------------
69
70 #define M_REGIONDATA ((wxRegionRefData *)m_refData)
71
72 void wxRegion::InitRect(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
73 {
74 XRectangle rect;
75 rect.x = (short)x;
76 rect.y = (short)y;
77 rect.width = (unsigned short)w;
78 rect.height = (unsigned short)h;
79
80 m_refData = new wxRegionRefData();
81
82 M_REGIONDATA->m_region = XCreateRegion();
83 XUnionRectWithRegion( &rect, M_REGIONDATA->m_region, M_REGIONDATA->m_region );
84 }
85
86 wxRegion::wxRegion( size_t WXUNUSED(n), const wxPoint *WXUNUSED(points), wxPolygonFillMode WXUNUSED(fillStyle) )
87 {
88 #if 0
89 XPoint *xpoints = new XPoint[n];
90 for ( size_t i = 0 ; i < n ; i++ )
91 {
92 xpoints[i].x = points[i].x;
93 xpoints[i].y = points[i].y;
94 }
95
96 m_refData = new wxRegionRefData();
97
98 Region* reg = gdk_region_polygon
99 (
100 gdkpoints,
101 n,
102 fillStyle == wxWINDING_RULE ? GDK_WINDING_RULE
103 : GDK_EVEN_ODD_RULE
104 );
105
106 M_REGIONDATA->m_region = reg;
107
108 delete [] xpoints;
109 #endif
110 }
111
112 wxRegion::~wxRegion()
113 {
114 // m_refData unrefed in ~wxObject
115 }
116
117 wxGDIRefData *wxRegion::CreateGDIRefData() const
118 {
119 return new wxRegionRefData;
120 }
121
122 wxGDIRefData *wxRegion::CloneGDIRefData(const wxGDIRefData *data) const
123 {
124 return new wxRegionRefData(*(wxRegionRefData *)data);
125 }
126
127 // ----------------------------------------------------------------------------
128 // wxRegion comparison
129 // ----------------------------------------------------------------------------
130
131 bool wxRegion::DoIsEqual(const wxRegion& region) const
132 {
133 return XEqualRegion( M_REGIONDATA->m_region,
134 M_REGIONDATA_OF(region)->m_region ) == True;
135 }
136
137 // ----------------------------------------------------------------------------
138 // wxRegion operations
139 // ----------------------------------------------------------------------------
140
141 void wxRegion::Clear()
142 {
143 UnRef();
144 }
145
146 bool wxRegion::DoUnionWithRect(const wxRect& r)
147 {
148 // work around for XUnionRectWithRegion() bug: taking a union with an empty
149 // rect results in an empty region (at least XFree 3.3.6 and 4.0 have this
150 // problem)
151 if ( r.IsEmpty() )
152 return true;
153
154 XRectangle rect;
155 rect.x = (short)r.x;
156 rect.y = (short)r.y;
157 rect.width = (unsigned short)r.width;
158 rect.height = (unsigned short)r.height;
159
160 if (!m_refData)
161 {
162 m_refData = new wxRegionRefData();
163 M_REGIONDATA->m_region = XCreateRegion();
164 }
165 else
166 {
167 AllocExclusive();
168 }
169
170 XUnionRectWithRegion( &rect, M_REGIONDATA->m_region, M_REGIONDATA->m_region );
171
172 return true;
173 }
174
175 bool wxRegion::DoUnionWithRegion( const wxRegion& region )
176 {
177 wxCHECK_MSG( region.IsOk(), false, wxT("invalid region") );
178
179 if (!m_refData)
180 {
181 m_refData = new wxRegionRefData();
182 M_REGIONDATA->m_region = XCreateRegion();
183 }
184 else
185 {
186 AllocExclusive();
187 }
188
189 XUnionRegion( M_REGIONDATA->m_region,
190 M_REGIONDATA_OF(region)->m_region,
191 M_REGIONDATA->m_region );
192
193 return true;
194 }
195
196 bool wxRegion::DoIntersect( const wxRegion& region )
197 {
198 wxCHECK_MSG( region.IsOk(), false, wxT("invalid region") );
199
200 if (!m_refData)
201 {
202 m_refData = new wxRegionRefData();
203 M_REGIONDATA->m_region = XCreateRegion();
204
205 // leave here
206 return true;
207 }
208 else
209 {
210 AllocExclusive();
211 }
212
213 XIntersectRegion( M_REGIONDATA->m_region,
214 M_REGIONDATA_OF(region)->m_region,
215 M_REGIONDATA->m_region );
216
217 return true;
218 }
219
220 bool wxRegion::DoSubtract( const wxRegion& region )
221 {
222 wxCHECK_MSG( region.IsOk(), false, wxT("invalid region") );
223
224 if (!m_refData)
225 {
226 m_refData = new wxRegionRefData();
227 M_REGIONDATA->m_region = XCreateRegion();
228 }
229 else
230 {
231 AllocExclusive();
232 }
233
234 XSubtractRegion( M_REGIONDATA->m_region,
235 M_REGIONDATA_OF(region)->m_region,
236 M_REGIONDATA->m_region );
237
238 return true;
239 }
240
241 bool wxRegion::DoXor( const wxRegion& region )
242 {
243 wxCHECK_MSG( region.IsOk(), false, wxT("invalid region") );
244
245 if (!m_refData)
246 {
247 m_refData = new wxRegionRefData();
248 M_REGIONDATA->m_region = XCreateRegion();
249 }
250 else
251 {
252 AllocExclusive();
253 }
254
255 XXorRegion( M_REGIONDATA->m_region,
256 M_REGIONDATA_OF(region)->m_region,
257 M_REGIONDATA->m_region );
258
259 return true;
260 }
261
262 // ----------------------------------------------------------------------------
263 // wxRegion tests
264 // ----------------------------------------------------------------------------
265
266 bool wxRegion::DoGetBox( wxCoord &x, wxCoord &y, wxCoord &w, wxCoord &h ) const
267 {
268 if (m_refData)
269 {
270 XRectangle rect;
271 XClipBox( M_REGIONDATA->m_region, &rect );
272 x = rect.x;
273 y = rect.y;
274 w = rect.width;
275 h = rect.height;
276
277 return true;
278 }
279 else
280 {
281 x = 0;
282 y = 0;
283 w = -1;
284 h = -1;
285
286 return false;
287 }
288 }
289
290 bool wxRegion::DoOffset( wxCoord x, wxCoord y )
291 {
292 if (!m_refData)
293 return false;
294
295 AllocExclusive();
296
297 XOffsetRegion( M_REGIONDATA->m_region, x, y );
298
299 return true;
300 }
301
302 bool wxRegion::IsEmpty() const
303 {
304 if (!m_refData)
305 return true;
306
307 return XEmptyRegion( M_REGIONDATA->m_region ) == True;
308 }
309
310 wxRegionContain wxRegion::DoContainsPoint( wxCoord x, wxCoord y ) const
311 {
312 if (!m_refData)
313 return wxOutRegion;
314
315 if (XPointInRegion( M_REGIONDATA->m_region, x, y ))
316 return wxInRegion;
317 else
318 return wxOutRegion;
319 }
320
321 wxRegionContain wxRegion::DoContainsRect(const wxRect& r) const
322 {
323 if (!m_refData)
324 return wxOutRegion;
325
326 int res = XRectInRegion(M_REGIONDATA->m_region, r.x, r.y, r.width, r.height);
327 switch (res)
328 {
329 case RectangleIn: return wxInRegion;
330 case RectangleOut: return wxOutRegion;
331 case RectanglePart: return wxPartRegion;
332 }
333 return wxOutRegion;
334 }
335
336 WXRegion *wxRegion::GetX11Region() const
337 {
338 if (!m_refData)
339 return NULL;
340
341 return (WXRegion*) M_REGIONDATA->m_region;
342 }
343
344 // ----------------------------------------------------------------------------
345 // wxRegionIterator
346 // ----------------------------------------------------------------------------
347
348 // the following structures must match the private structures
349 // in X11 region code ( xc/lib/X11/region.h )
350
351 // this makes the Region type transparent
352 // and we have access to the region rectangles
353
354 struct _XBox {
355 short x1, x2, y1, y2;
356 };
357
358 struct _XRegion {
359 long size , numRects;
360 _XBox *rects, extents;
361 };
362
363 class wxRIRefData: public wxGDIRefData
364 {
365 public:
366
367 wxRIRefData() : m_rects(0), m_numRects(0){}
368 virtual ~wxRIRefData();
369
370 wxRect *m_rects;
371 size_t m_numRects;
372
373 void CreateRects( const wxRegion& r );
374 };
375
376 wxRIRefData::~wxRIRefData()
377 {
378 delete [] m_rects;
379 }
380
381 void wxRIRefData::CreateRects( const wxRegion& region )
382 {
383 if (m_rects)
384 delete [] m_rects;
385
386 m_rects = 0;
387 m_numRects = 0;
388
389 if (region.IsEmpty()) return;
390
391 Region r = (Region) region.GetX11Region();
392 if (r)
393 {
394 #if wxUSE_NANOX
395 GR_RECT rect;
396 GrGetRegionBox(r, & rect);
397 m_numRects = 1;
398 m_rects = new wxRect[1];
399 m_rects[0].x = rect.x;
400 m_rects[0].y = rect.y;
401 m_rects[0].width = rect.width;
402 m_rects[0].height = rect.height;
403 #else
404 m_numRects = r->numRects;
405 if (m_numRects)
406 {
407 m_rects = new wxRect[m_numRects];
408 for (size_t i=0; i < m_numRects; ++i)
409 {
410 _XBox &xr = r->rects[i];
411 wxRect &wr = m_rects[i];
412 wr.x = xr.x1;
413 wr.y = xr.y1;
414 wr.width = xr.x2-xr.x1;
415 wr.height = xr.y2-xr.y1;
416 }
417 }
418 #endif
419 }
420 }
421
422 wxRegionIterator::wxRegionIterator()
423 {
424 m_refData = new wxRIRefData();
425 Reset();
426 }
427
428 wxRegionIterator::wxRegionIterator( const wxRegion& region )
429 {
430 m_refData = new wxRIRefData();
431 Reset(region);
432 }
433
434 void wxRegionIterator::Reset( const wxRegion& region )
435 {
436 m_region = region;
437 ((wxRIRefData*)m_refData)->CreateRects(region);
438 Reset();
439 }
440
441 bool wxRegionIterator::HaveRects() const
442 {
443 return m_current < ((wxRIRefData*)m_refData)->m_numRects;
444 }
445
446 wxRegionIterator::operator bool () const
447 {
448 return HaveRects();
449 }
450
451 void wxRegionIterator::operator ++ ()
452 {
453 if (HaveRects()) ++m_current;
454 }
455
456 void wxRegionIterator::operator ++ (int)
457 {
458 if (HaveRects()) ++m_current;
459 }
460
461 wxCoord wxRegionIterator::GetX() const
462 {
463 if( !HaveRects() ) return 0;
464 return ((wxRIRefData*)m_refData)->m_rects[m_current].x;
465 }
466
467 wxCoord wxRegionIterator::GetY() const
468 {
469 if( !HaveRects() ) return 0;
470 return ((wxRIRefData*)m_refData)->m_rects[m_current].y;
471 }
472
473 wxCoord wxRegionIterator::GetW() const
474 {
475 if( !HaveRects() ) return -1;
476 return ((wxRIRefData*)m_refData)->m_rects[m_current].width;
477 }
478
479 wxCoord wxRegionIterator::GetH() const
480 {
481 if( !HaveRects() ) return -1;
482 return ((wxRIRefData*)m_refData)->m_rects[m_current].height;
483 }
484
485 wxRect wxRegionIterator::GetRect() const
486 {
487 wxRect r;
488 if( HaveRects() )
489 r = ((wxRIRefData*)m_refData)->m_rects[m_current];
490
491 return r;
492 }