]> git.saurik.com Git - wxWidgets.git/blame - src/motif/region.cpp
* Apply patch #735595. Add miminumAcceptable{Height,Width}
[wxWidgets.git] / src / motif / region.cpp
CommitLineData
4bb6408c
JS
1/////////////////////////////////////////////////////////////////////////////
2// File: region.cpp
3// Purpose: Region class
2e579471 4// Author: Julian Smart
4bb6408c 5// Created: Fri Oct 24 10:46:34 MET 1997
6aa89a22 6// RCS-ID: $Id$
2e579471 7// Copyright: (c) 1997 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();
1bc822df 85 m_usingRects = (rectList.GetCount() > 0);
25f47127
JS
86 if (m_usingRects)
87 {
1bc822df 88 m_rectCount = rectList.GetCount();
25f47127
JS
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.
9afe6c17
VZ
203bool
204wxRegion::Combine(wxCoord x, wxCoord y,
205 wxCoord width, wxCoord height,
206 wxRegionOp op)
4bb6408c 207{
9afe6c17
VZ
208 // work around for XUnionRectWithRegion() bug: taking a union with an empty
209 // rect results in an empty region (at least XFree 3.3.6 and 4.0 have this
210 // problem)
211 if ( op == wxRGN_OR && (!width || !height) )
212 return TRUE;
213
dfe1eee3
VZ
214 // Don't change shared data
215 if (!m_refData) {
216 m_refData = new wxRegionRefData();
217 } else if (m_refData->GetRefCount() > 1) {
218 wxRegionRefData* ref = (wxRegionRefData*)m_refData;
219 UnRef();
220 m_refData = new wxRegionRefData(*ref);
221 }
4bb6408c
JS
222 // If ref count is 1, that means it's 'ours' anyway so no action.
223
f97c9854
JS
224 Region rectRegion = XCreateRegion();
225
dfe1eee3
VZ
226 XRectangle rect;
227 rect.x = x;
228 rect.y = y;
229 rect.width = width;
230 rect.height = height;
231 XUnionRectWithRegion(&rect, rectRegion, rectRegion);
4bb6408c 232
4bb6408c
JS
233 switch (op)
234 {
235 case wxRGN_AND:
dfe1eee3 236 XIntersectRegion(M_REGION, rectRegion, M_REGION);
4bb6408c
JS
237 break ;
238 case wxRGN_OR:
dfe1eee3 239 XUnionRegion(M_REGION, rectRegion, M_REGION);
4bb6408c
JS
240 break ;
241 case wxRGN_XOR:
242 // TODO
243 break ;
244 case wxRGN_DIFF:
245 // TODO
246 break ;
f97c9854 247 case wxRGN_COPY: // Don't have to do this one
4bb6408c
JS
248 default:
249 // TODO
250 break ;
251 }
252
4bb6408c
JS
253 return FALSE;
254}
255
256//! Union /e region with this.
257bool wxRegion::Combine(const wxRegion& region, wxRegionOp op)
258{
dfe1eee3
VZ
259 if (region.Empty())
260 return FALSE;
261
262 // Don't change shared data
263 if (!m_refData) {
264 m_refData = new wxRegionRefData();
265 } else if (m_refData->GetRefCount() > 1) {
266 wxRegionRefData* ref = (wxRegionRefData*)m_refData;
267 UnRef();
268 m_refData = new wxRegionRefData(*ref);
269 }
270
4bb6408c
JS
271 switch (op)
272 {
273 case wxRGN_AND:
dfe1eee3
VZ
274 XIntersectRegion(M_REGION, ((wxRegionRefData*)region.m_refData)->m_region,
275 M_REGION);
4bb6408c
JS
276 break ;
277 case wxRGN_OR:
dfe1eee3
VZ
278 XUnionRegion(M_REGION, ((wxRegionRefData*)region.m_refData)->m_region,
279 M_REGION);
4bb6408c
JS
280 break ;
281 case wxRGN_XOR:
282 // TODO
283 break ;
284 case wxRGN_DIFF:
285 // TODO
286 break ;
f97c9854 287 case wxRGN_COPY: // Don't have to do this one
4bb6408c
JS
288 default:
289 // TODO
290 break ;
291 }
292
a724d789 293 return FALSE;
4bb6408c
JS
294}
295
296bool wxRegion::Combine(const wxRect& rect, wxRegionOp op)
297{
298 return Combine(rect.GetLeft(), rect.GetTop(), rect.GetWidth(), rect.GetHeight(), op);
299}
300
301//-----------------------------------------------------------------------------
302//# Information on region
303//-----------------------------------------------------------------------------
304
305// Outer bounds of region
3ccf6cd7 306void wxRegion::GetBox(wxCoord& x, wxCoord& y, wxCoord&w, wxCoord &h) const
4bb6408c 307{
dfe1eee3
VZ
308 if (m_refData) {
309 XRectangle rect;
310 XClipBox(M_REGION, &rect);
311 x = rect.x;
312 y = rect.y;
313 w = rect.width;
314 h = rect.height;
315 } else {
316 x = y = w = h = 0;
317 }
4bb6408c
JS
318}
319
320wxRect wxRegion::GetBox() const
321{
3ccf6cd7 322 wxCoord x, y, w, h;
4bb6408c
JS
323 GetBox(x, y, w, h);
324 return wxRect(x, y, w, h);
325}
326
327// Is region empty?
328bool wxRegion::Empty() const
329{
dfe1eee3 330 return m_refData ? XEmptyRegion(M_REGION) : TRUE;
4bb6408c
JS
331}
332
333//-----------------------------------------------------------------------------
334//# Tests
335//-----------------------------------------------------------------------------
336
337// Does the region contain the point (x,y)?
3ccf6cd7 338wxRegionContain wxRegion::Contains(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y)) const
4bb6408c 339{
dfe1eee3
VZ
340 if (!m_refData)
341 return wxOutRegion;
4bb6408c
JS
342
343 // TODO. Return wxInRegion if within region.
344 if (0)
345 return wxInRegion;
346 return wxOutRegion;
347}
348
349// Does the region contain the point pt?
350wxRegionContain wxRegion::Contains(const wxPoint& pt) const
351{
dfe1eee3
VZ
352 if (!m_refData)
353 return wxOutRegion;
4bb6408c 354
dfe1eee3 355 return XPointInRegion(M_REGION, pt.x, pt.y) ? wxInRegion : wxOutRegion;
4bb6408c
JS
356}
357
358// Does the region contain the rectangle (x, y, w, h)?
3ccf6cd7 359wxRegionContain wxRegion::Contains(wxCoord x, wxCoord y, wxCoord w, wxCoord h) const
4bb6408c 360{
dfe1eee3
VZ
361 if (!m_refData)
362 return wxOutRegion;
363
364 switch (XRectInRegion(M_REGION, x, y, w, h)) {
365 case RectangleIn: return wxInRegion;
366 case RectanglePart: return wxPartRegion;
367 }
368 return wxOutRegion;
4bb6408c
JS
369}
370
371// Does the region contain the rectangle rect
372wxRegionContain wxRegion::Contains(const wxRect& rect) const
373{
dfe1eee3
VZ
374 if (!m_refData)
375 return wxOutRegion;
4bb6408c 376
3ccf6cd7 377 wxCoord x, y, w, h;
4bb6408c
JS
378 x = rect.x;
379 y = rect.y;
380 w = rect.GetWidth();
381 h = rect.GetHeight();
382 return Contains(x, y, w, h);
383}
384
25f47127
JS
385bool wxRegion::UsingRects() const
386{
387 return ((wxRegionRefData*)m_refData)->UsingRects();
388}
389
390/*
391wxRectList& wxRegion::GetRectList()
392{
393 return ((wxRegionRefData*)m_refData)->GetRectList();
394}
395*/
396
397wxRect* wxRegion::GetRects()
398{
399 return ((wxRegionRefData*)m_refData)->GetRects();
400}
401
402int wxRegion::GetRectCount() const
403{
404 return ((wxRegionRefData*)m_refData)->GetRectCount();
405}
406
407void wxRegion::SetRects(const wxRectList& rectList)
408{
409 ((wxRegionRefData*)m_refData)->SetRects(rectList);
410}
411
412void wxRegion::SetRects(int count, const wxRect* rects)
413{
414 ((wxRegionRefData*)m_refData)->SetRects(count, rects);
415}
416
4bb6408c 417///////////////////////////////////////////////////////////////////////////////
dfe1eee3
VZ
418// //
419// wxRegionIterator //
420// //
4bb6408c
JS
421///////////////////////////////////////////////////////////////////////////////
422
423/*!
424 * Initialize empty iterator
425 */
426wxRegionIterator::wxRegionIterator() : m_current(0), m_numRects(0), m_rects(NULL)
427{
428}
429
430wxRegionIterator::~wxRegionIterator()
431{
432 if (m_rects)
433 delete[] m_rects;
434}
435
436/*!
437 * Initialize iterator for region
438 */
439wxRegionIterator::wxRegionIterator(const wxRegion& region)
440{
441 m_rects = NULL;
442
dfe1eee3 443 Reset(region);
4bb6408c
JS
444}
445
446/*!
447 * Reset iterator for a new /e region.
448 */
449void wxRegionIterator::Reset(const wxRegion& region)
450{
dfe1eee3
VZ
451 m_current = 0;
452 m_region = region;
4bb6408c
JS
453
454 if (m_rects)
455 delete[] m_rects;
456
457 m_rects = NULL;
458
dfe1eee3
VZ
459 if (m_region.Empty())
460 m_numRects = 0;
461 else
4bb6408c 462 {
25f47127
JS
463 // Create m_rects and fill with rectangles for this region.
464 // Since we can't find the rectangles in a region, we cheat
465 // by retrieving the rectangles explicitly set in wxPaintDC::wxPaintDC
466 // (dcclient.cpp).
467 if (m_region.UsingRects())
468 {
469 wxRect* rects = m_region.GetRects();
470 int count = m_region.GetRectCount();
471 m_numRects = count;
472 m_rects = new wxRect[m_numRects];
473
b3a7510d 474 for (size_t i = 0; i < m_numRects; i++)
25f47127
JS
475 m_rects[i] = rects[i];
476
477 /*
478 int i = 0;
479 wxRectList::Node* node = rectList.GetFirst();
480 while (node) {
481 wxRect* rect = node->GetData();
482 m_rects[i] = * rect;
483 node = node->GetNext();
484 i ++;
485 }
486 */
487 }
488 else
489 {
490 // For now, fudge by getting the whole bounding box.
491 m_rects = new wxRect[1];
492 m_numRects = 1;
493 m_rects[0] = m_region.GetBox();
494 }
4bb6408c
JS
495 }
496}
497
498/*!
499 * Increment iterator. The rectangle returned is the one after the
500 * incrementation.
501 */
502void wxRegionIterator::operator ++ ()
503{
dfe1eee3
VZ
504 if (m_current < m_numRects)
505 ++m_current;
4bb6408c
JS
506}
507
508/*!
509 * Increment iterator. The rectangle returned is the one before the
510 * incrementation.
511 */
512void wxRegionIterator::operator ++ (int)
513{
dfe1eee3
VZ
514 if (m_current < m_numRects)
515 ++m_current;
4bb6408c
JS
516}
517
3ccf6cd7 518wxCoord wxRegionIterator::GetX() const
4bb6408c 519{
dfe1eee3
VZ
520 if (m_current < m_numRects)
521 return m_rects[m_current].x;
522 return 0;
4bb6408c
JS
523}
524
3ccf6cd7 525wxCoord wxRegionIterator::GetY() const
4bb6408c 526{
dfe1eee3
VZ
527 if (m_current < m_numRects)
528 return m_rects[m_current].y;
529 return 0;
4bb6408c
JS
530}
531
3ccf6cd7 532wxCoord wxRegionIterator::GetW() const
4bb6408c 533{
dfe1eee3
VZ
534 if (m_current < m_numRects)
535 return m_rects[m_current].width ;
536 return 0;
4bb6408c
JS
537}
538
3ccf6cd7 539wxCoord wxRegionIterator::GetH() const
4bb6408c 540{
dfe1eee3
VZ
541 if (m_current < m_numRects)
542 return m_rects[m_current].height;
543 return 0;
4bb6408c
JS
544}
545