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