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