]> git.saurik.com Git - wxWidgets.git/blob - src/x11/region.cpp
wxDC::DoDrawRectangle hack is no longer needed
[wxWidgets.git] / src / x11 / region.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // File: region.cpp
3 // Purpose: Region class
4 // Author: Markus Holzem/Julian Smart
5 // Created: Fri Oct 24 10:46:34 MET 1997
6 // RCS-ID: $Id$
7 // Copyright: (c) 1997 Markus Holzem/Julian Smart
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 #ifdef __GNUG__
12 #pragma implementation "region.h"
13 #endif
14
15 #include "wx/region.h"
16 #include "wx/gdicmn.h"
17 #include "wx/window.h"
18
19 #ifdef __VMS__
20 #pragma message disable nosimpint
21 #endif
22 #include "wx/x11/private.h"
23 #include "X11/Xutil.h"
24 #ifdef __VMS__
25 #pragma message enable nosimpint
26 #endif
27
28
29 IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject)
30 IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator, wxObject)
31
32 // ----------------------------------------------------------------------------
33 // list types
34 // ----------------------------------------------------------------------------
35
36 #include "wx/listimpl.cpp"
37
38 WX_DEFINE_LIST(wxRectList);
39
40 //-----------------------------------------------------------------------------
41 // wxRegionRefData implementation
42 //-----------------------------------------------------------------------------
43
44 class WXDLLEXPORT wxRegionRefData : public wxGDIRefData {
45 public:
46 wxRegionRefData()
47 {
48 m_region = XCreateRegion();
49 m_usingRects = FALSE;
50 m_rects = (wxRect*) NULL;
51 m_rectCount = 0;
52 }
53
54 wxRegionRefData(const wxRegionRefData& data)
55 {
56 m_region = XCreateRegion();
57 m_rects = (wxRect*) NULL;
58 m_rectCount = 0;
59 XUnionRegion(m_region, data.m_region, m_region);
60
61 SetRects(data.m_rectCount, data.m_rects);
62 }
63
64 ~wxRegionRefData()
65 {
66 XDestroyRegion(m_region);
67 DeleteRects();
68 }
69
70 wxRect* GetRects() { return m_rects; };
71 void SetRects(const wxRectList& rectList);
72 void SetRects(int count, const wxRect* rects);
73 bool UsingRects() const { return m_usingRects; }
74 int GetRectCount() const { return m_rectCount; }
75
76 void DeleteRects();
77
78 Region m_region;
79 wxRect* m_rects;
80 int m_rectCount;
81 bool m_usingRects; // TRUE if we're using the above.
82 };
83
84 void wxRegionRefData::SetRects(const wxRectList& rectList)
85 {
86 DeleteRects();
87 m_usingRects = (rectList.Number() > 0);
88 if (m_usingRects)
89 {
90 m_rectCount = rectList.Number();
91 m_rects = new wxRect[m_rectCount];
92 }
93
94 wxRectList::Node* node = rectList.GetFirst();
95 int i = 0;
96 while (node) {
97 wxRect* rect = node->GetData();
98 m_rects[i] = * rect;
99 node = node->GetNext();
100 i ++;
101 }
102 }
103
104 void wxRegionRefData::SetRects(int count, const wxRect* rects)
105 {
106 DeleteRects();
107 m_usingRects = (count > 0);
108 if (m_usingRects)
109 {
110 m_rectCount = count;
111 m_rects = new wxRect[m_rectCount];
112 int i;
113 for (i = 0; i < m_rectCount; i++)
114 m_rects[i] = rects[i];
115 }
116 }
117
118 void wxRegionRefData::DeleteRects()
119 {
120 if (m_rects)
121 {
122 delete[] m_rects;
123 m_rects = (wxRect*) NULL;
124 }
125 m_rectCount = 0;
126 m_usingRects = FALSE;
127 }
128
129 #define M_REGION (((wxRegionRefData*)m_refData)->m_region)
130
131 //-----------------------------------------------------------------------------
132 // wxRegion
133 //-----------------------------------------------------------------------------
134
135 /*!
136 * Create an empty region.
137 */
138 wxRegion::wxRegion()
139 {
140 }
141
142 wxRegion::wxRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
143 {
144 m_refData = new wxRegionRefData;
145
146 XRectangle rect;
147 rect.x = x;
148 rect.y = y;
149 rect.width = w;
150 rect.height = h;
151 XUnionRectWithRegion(&rect, M_REGION, M_REGION);
152 }
153
154 wxRegion::wxRegion(const wxPoint& topLeft, const wxPoint& bottomRight)
155 {
156 m_refData = new wxRegionRefData;
157
158 XRectangle rect;
159 rect.x = topLeft.x;
160 rect.y = topLeft.y;
161 rect.width = bottomRight.x - topLeft.x;
162 rect.height = bottomRight.y - topLeft.y;
163 XUnionRectWithRegion(&rect, M_REGION, M_REGION);
164 }
165
166 wxRegion::wxRegion(const wxRect& rect)
167 {
168 m_refData = new wxRegionRefData;
169
170 XRectangle rect1;
171 rect1.x = rect.x;
172 rect1.y = rect.y;
173 rect1.width = rect.width;
174 rect1.height = rect.height;
175 XUnionRectWithRegion(&rect1, M_REGION, M_REGION);
176 }
177
178 /*!
179 * Destroy the region.
180 */
181 wxRegion::~wxRegion()
182 {
183 // m_refData unrefed in ~wxObject
184 }
185
186 // Get the internal region handle
187 WXRegion wxRegion::GetXRegion() const
188 {
189 wxASSERT( m_refData !=NULL );
190
191 return (WXRegion) ((wxRegionRefData*)m_refData)->m_region;
192 }
193
194 //-----------------------------------------------------------------------------
195 //# Modify region
196 //-----------------------------------------------------------------------------
197
198 //! Clear current region
199 void wxRegion::Clear()
200 {
201 UnRef();
202 }
203
204 //! Combine rectangle (x, y, w, h) with this.
205 bool wxRegion::Combine(wxCoord x, wxCoord y, wxCoord width, wxCoord height, wxRegionOp op)
206 {
207 // Don't change shared data
208 if (!m_refData) {
209 m_refData = new wxRegionRefData();
210 } else if (m_refData->GetRefCount() > 1) {
211 wxRegionRefData* ref = (wxRegionRefData*)m_refData;
212 UnRef();
213 m_refData = new wxRegionRefData(*ref);
214 }
215 // If ref count is 1, that means it's 'ours' anyway so no action.
216
217 Region rectRegion = XCreateRegion();
218
219 XRectangle rect;
220 rect.x = x;
221 rect.y = y;
222 rect.width = width;
223 rect.height = height;
224 XUnionRectWithRegion(&rect, rectRegion, rectRegion);
225
226 switch (op)
227 {
228 case wxRGN_AND:
229 XIntersectRegion(M_REGION, rectRegion, M_REGION);
230 break ;
231 case wxRGN_OR:
232 XUnionRegion(M_REGION, rectRegion, M_REGION);
233 break ;
234 case wxRGN_XOR:
235 // TODO
236 break ;
237 case wxRGN_DIFF:
238 // TODO
239 break ;
240 case wxRGN_COPY: // Don't have to do this one
241 default:
242 // TODO
243 break ;
244 }
245
246 return FALSE;
247 }
248
249 //! Union /e region with this.
250 bool wxRegion::Combine(const wxRegion& region, wxRegionOp op)
251 {
252 if (region.Empty())
253 return FALSE;
254
255 // Don't change shared data
256 if (!m_refData) {
257 m_refData = new wxRegionRefData();
258 } else if (m_refData->GetRefCount() > 1) {
259 wxRegionRefData* ref = (wxRegionRefData*)m_refData;
260 UnRef();
261 m_refData = new wxRegionRefData(*ref);
262 }
263
264 switch (op)
265 {
266 case wxRGN_AND:
267 XIntersectRegion(M_REGION, ((wxRegionRefData*)region.m_refData)->m_region,
268 M_REGION);
269 break ;
270 case wxRGN_OR:
271 XUnionRegion(M_REGION, ((wxRegionRefData*)region.m_refData)->m_region,
272 M_REGION);
273 break ;
274 case wxRGN_XOR:
275 // TODO
276 break ;
277 case wxRGN_DIFF:
278 // TODO
279 break ;
280 case wxRGN_COPY: // Don't have to do this one
281 default:
282 // TODO
283 break ;
284 }
285
286 return FALSE;
287 }
288
289 bool wxRegion::Combine(const wxRect& rect, wxRegionOp op)
290 {
291 return Combine(rect.GetLeft(), rect.GetTop(), rect.GetWidth(), rect.GetHeight(), op);
292 }
293
294 //-----------------------------------------------------------------------------
295 //# Information on region
296 //-----------------------------------------------------------------------------
297
298 // Outer bounds of region
299 void wxRegion::GetBox(wxCoord& x, wxCoord& y, wxCoord&w, wxCoord &h) const
300 {
301 if (m_refData) {
302 XRectangle rect;
303 XClipBox(M_REGION, &rect);
304 x = rect.x;
305 y = rect.y;
306 w = rect.width;
307 h = rect.height;
308 } else {
309 x = y = w = h = 0;
310 }
311 }
312
313 wxRect wxRegion::GetBox() const
314 {
315 wxCoord x, y, w, h;
316 GetBox(x, y, w, h);
317 return wxRect(x, y, w, h);
318 }
319
320 // Is region empty?
321 bool wxRegion::Empty() const
322 {
323 return m_refData ? XEmptyRegion(M_REGION) : TRUE;
324 }
325
326 //-----------------------------------------------------------------------------
327 //# Tests
328 //-----------------------------------------------------------------------------
329
330 // Does the region contain the point (x,y)?
331 wxRegionContain wxRegion::Contains(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y)) const
332 {
333 if (!m_refData)
334 return wxOutRegion;
335
336 // TODO. Return wxInRegion if within region.
337 if (0)
338 return wxInRegion;
339 return wxOutRegion;
340 }
341
342 // Does the region contain the point pt?
343 wxRegionContain wxRegion::Contains(const wxPoint& pt) const
344 {
345 if (!m_refData)
346 return wxOutRegion;
347
348 return XPointInRegion(M_REGION, pt.x, pt.y) ? wxInRegion : wxOutRegion;
349 }
350
351 // Does the region contain the rectangle (x, y, w, h)?
352 wxRegionContain wxRegion::Contains(wxCoord x, wxCoord y, wxCoord w, wxCoord h) const
353 {
354 if (!m_refData)
355 return wxOutRegion;
356
357 switch (XRectInRegion(M_REGION, x, y, w, h)) {
358 case RectangleIn: return wxInRegion;
359 case RectanglePart: return wxPartRegion;
360 }
361 return wxOutRegion;
362 }
363
364 // Does the region contain the rectangle rect
365 wxRegionContain wxRegion::Contains(const wxRect& rect) const
366 {
367 if (!m_refData)
368 return wxOutRegion;
369
370 wxCoord x, y, w, h;
371 x = rect.x;
372 y = rect.y;
373 w = rect.GetWidth();
374 h = rect.GetHeight();
375 return Contains(x, y, w, h);
376 }
377
378 bool wxRegion::UsingRects() const
379 {
380 return ((wxRegionRefData*)m_refData)->UsingRects();
381 }
382
383 /*
384 wxRectList& wxRegion::GetRectList()
385 {
386 return ((wxRegionRefData*)m_refData)->GetRectList();
387 }
388 */
389
390 wxRect* wxRegion::GetRects()
391 {
392 return ((wxRegionRefData*)m_refData)->GetRects();
393 }
394
395 int wxRegion::GetRectCount() const
396 {
397 return ((wxRegionRefData*)m_refData)->GetRectCount();
398 }
399
400 void wxRegion::SetRects(const wxRectList& rectList)
401 {
402 ((wxRegionRefData*)m_refData)->SetRects(rectList);
403 }
404
405 void wxRegion::SetRects(int count, const wxRect* rects)
406 {
407 ((wxRegionRefData*)m_refData)->SetRects(count, rects);
408 }
409
410 ///////////////////////////////////////////////////////////////////////////////
411 // //
412 // wxRegionIterator //
413 // //
414 ///////////////////////////////////////////////////////////////////////////////
415
416 /*!
417 * Initialize empty iterator
418 */
419 wxRegionIterator::wxRegionIterator() : m_current(0), m_numRects(0), m_rects(NULL)
420 {
421 }
422
423 wxRegionIterator::~wxRegionIterator()
424 {
425 if (m_rects)
426 delete[] m_rects;
427 }
428
429 /*!
430 * Initialize iterator for region
431 */
432 wxRegionIterator::wxRegionIterator(const wxRegion& region)
433 {
434 m_rects = NULL;
435
436 Reset(region);
437 }
438
439 /*!
440 * Reset iterator for a new /e region.
441 */
442 void wxRegionIterator::Reset(const wxRegion& region)
443 {
444 m_current = 0;
445 m_region = region;
446
447 if (m_rects)
448 delete[] m_rects;
449
450 m_rects = NULL;
451
452 if (m_region.Empty())
453 m_numRects = 0;
454 else
455 {
456 // Create m_rects and fill with rectangles for this region.
457 // Since we can't find the rectangles in a region, we cheat
458 // by retrieving the rectangles explicitly set in wxPaintDC::wxPaintDC
459 // (dcclient.cpp).
460 if (m_region.UsingRects())
461 {
462 wxRect* rects = m_region.GetRects();
463 int count = m_region.GetRectCount();
464 m_numRects = count;
465 m_rects = new wxRect[m_numRects];
466
467 for (size_t i = 0; i < m_numRects; i++)
468 m_rects[i] = rects[i];
469
470 /*
471 int i = 0;
472 wxRectList::Node* node = rectList.GetFirst();
473 while (node) {
474 wxRect* rect = node->GetData();
475 m_rects[i] = * rect;
476 node = node->GetNext();
477 i ++;
478 }
479 */
480 }
481 else
482 {
483 // For now, fudge by getting the whole bounding box.
484 m_rects = new wxRect[1];
485 m_numRects = 1;
486 m_rects[0] = m_region.GetBox();
487 }
488 }
489 }
490
491 /*!
492 * Increment iterator. The rectangle returned is the one after the
493 * incrementation.
494 */
495 void wxRegionIterator::operator ++ ()
496 {
497 if (m_current < m_numRects)
498 ++m_current;
499 }
500
501 /*!
502 * Increment iterator. The rectangle returned is the one before the
503 * incrementation.
504 */
505 void wxRegionIterator::operator ++ (int)
506 {
507 if (m_current < m_numRects)
508 ++m_current;
509 }
510
511 wxCoord wxRegionIterator::GetX() const
512 {
513 if (m_current < m_numRects)
514 return m_rects[m_current].x;
515 return 0;
516 }
517
518 wxCoord wxRegionIterator::GetY() const
519 {
520 if (m_current < m_numRects)
521 return m_rects[m_current].y;
522 return 0;
523 }
524
525 wxCoord wxRegionIterator::GetW() const
526 {
527 if (m_current < m_numRects)
528 return m_rects[m_current].width ;
529 return 0;
530 }
531
532 wxCoord wxRegionIterator::GetH() const
533 {
534 if (m_current < m_numRects)
535 return m_rects[m_current].height;
536 return 0;
537 }
538