]> git.saurik.com Git - wxWidgets.git/blob - src/motif/region.cpp
implemented 'shaft scrolling' of children in wxUnivWindow::ScrollWindow
[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 #ifdef __VMS__
19 #pragma message disable nosimpint
20 #endif
21 #include <Xm/Xm.h>
22 #ifdef __VMS__
23 #pragma message enable nosimpint
24 #endif
25 // #include "wx/motif/private.h"
26
27 IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject)
28 IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator, wxObject)
29
30 // ----------------------------------------------------------------------------
31 // list types
32 // ----------------------------------------------------------------------------
33
34 #include "wx/listimpl.cpp"
35
36 WX_DEFINE_LIST(wxRectList);
37
38 //-----------------------------------------------------------------------------
39 // wxRegionRefData implementation
40 //-----------------------------------------------------------------------------
41
42 class WXDLLEXPORT wxRegionRefData : public wxGDIRefData {
43 public:
44 wxRegionRefData()
45 {
46 m_region = XCreateRegion();
47 m_usingRects = FALSE;
48 m_rects = (wxRect*) NULL;
49 m_rectCount = 0;
50 }
51
52 wxRegionRefData(const wxRegionRefData& data)
53 {
54 m_region = XCreateRegion();
55 m_rects = (wxRect*) NULL;
56 m_rectCount = 0;
57 XUnionRegion(m_region, data.m_region, m_region);
58
59 SetRects(data.m_rectCount, data.m_rects);
60 }
61
62 ~wxRegionRefData()
63 {
64 XDestroyRegion(m_region);
65 DeleteRects();
66 }
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.
80 };
81
82 void 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
102 void 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
116 void 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
127 #define M_REGION (((wxRegionRefData*)m_refData)->m_region)
128
129 //-----------------------------------------------------------------------------
130 // wxRegion
131 //-----------------------------------------------------------------------------
132
133 /*!
134 * Create an empty region.
135 */
136 wxRegion::wxRegion()
137 {
138 }
139
140 wxRegion::wxRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
141 {
142 m_refData = new wxRegionRefData;
143
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);
150 }
151
152 wxRegion::wxRegion(const wxPoint& topLeft, const wxPoint& bottomRight)
153 {
154 m_refData = new wxRegionRefData;
155
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);
162 }
163
164 wxRegion::wxRegion(const wxRect& rect)
165 {
166 m_refData = new wxRegionRefData;
167
168 XRectangle rect1;
169 rect1.x = rect.x;
170 rect1.y = rect.y;
171 rect1.width = rect.width;
172 rect1.height = rect.height;
173 XUnionRectWithRegion(&rect1, M_REGION, M_REGION);
174 }
175
176 /*!
177 * Destroy the region.
178 */
179 wxRegion::~wxRegion()
180 {
181 // m_refData unrefed in ~wxObject
182 }
183
184 // Get the internal region handle
185 WXRegion wxRegion::GetXRegion() const
186 {
187 wxASSERT( m_refData !=NULL );
188
189 return (WXRegion) ((wxRegionRefData*)m_refData)->m_region;
190 }
191
192 //-----------------------------------------------------------------------------
193 //# Modify region
194 //-----------------------------------------------------------------------------
195
196 //! Clear current region
197 void wxRegion::Clear()
198 {
199 UnRef();
200 }
201
202 //! Combine rectangle (x, y, w, h) with this.
203 bool wxRegion::Combine(wxCoord x, wxCoord y, wxCoord width, wxCoord height, wxRegionOp op)
204 {
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 }
213 // If ref count is 1, that means it's 'ours' anyway so no action.
214
215 Region rectRegion = XCreateRegion();
216
217 XRectangle rect;
218 rect.x = x;
219 rect.y = y;
220 rect.width = width;
221 rect.height = height;
222 XUnionRectWithRegion(&rect, rectRegion, rectRegion);
223
224 switch (op)
225 {
226 case wxRGN_AND:
227 XIntersectRegion(M_REGION, rectRegion, M_REGION);
228 break ;
229 case wxRGN_OR:
230 XUnionRegion(M_REGION, rectRegion, M_REGION);
231 break ;
232 case wxRGN_XOR:
233 // TODO
234 break ;
235 case wxRGN_DIFF:
236 // TODO
237 break ;
238 case wxRGN_COPY: // Don't have to do this one
239 default:
240 // TODO
241 break ;
242 }
243
244 return FALSE;
245 }
246
247 //! Union /e region with this.
248 bool wxRegion::Combine(const wxRegion& region, wxRegionOp op)
249 {
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
262 switch (op)
263 {
264 case wxRGN_AND:
265 XIntersectRegion(M_REGION, ((wxRegionRefData*)region.m_refData)->m_region,
266 M_REGION);
267 break ;
268 case wxRGN_OR:
269 XUnionRegion(M_REGION, ((wxRegionRefData*)region.m_refData)->m_region,
270 M_REGION);
271 break ;
272 case wxRGN_XOR:
273 // TODO
274 break ;
275 case wxRGN_DIFF:
276 // TODO
277 break ;
278 case wxRGN_COPY: // Don't have to do this one
279 default:
280 // TODO
281 break ;
282 }
283
284 return FALSE;
285 }
286
287 bool 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
297 void wxRegion::GetBox(wxCoord& x, wxCoord& y, wxCoord&w, wxCoord &h) const
298 {
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 }
309 }
310
311 wxRect wxRegion::GetBox() const
312 {
313 wxCoord x, y, w, h;
314 GetBox(x, y, w, h);
315 return wxRect(x, y, w, h);
316 }
317
318 // Is region empty?
319 bool wxRegion::Empty() const
320 {
321 return m_refData ? XEmptyRegion(M_REGION) : TRUE;
322 }
323
324 //-----------------------------------------------------------------------------
325 //# Tests
326 //-----------------------------------------------------------------------------
327
328 // Does the region contain the point (x,y)?
329 wxRegionContain wxRegion::Contains(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y)) const
330 {
331 if (!m_refData)
332 return wxOutRegion;
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?
341 wxRegionContain wxRegion::Contains(const wxPoint& pt) const
342 {
343 if (!m_refData)
344 return wxOutRegion;
345
346 return XPointInRegion(M_REGION, pt.x, pt.y) ? wxInRegion : wxOutRegion;
347 }
348
349 // Does the region contain the rectangle (x, y, w, h)?
350 wxRegionContain wxRegion::Contains(wxCoord x, wxCoord y, wxCoord w, wxCoord h) const
351 {
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;
360 }
361
362 // Does the region contain the rectangle rect
363 wxRegionContain wxRegion::Contains(const wxRect& rect) const
364 {
365 if (!m_refData)
366 return wxOutRegion;
367
368 wxCoord x, y, w, h;
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
376 bool wxRegion::UsingRects() const
377 {
378 return ((wxRegionRefData*)m_refData)->UsingRects();
379 }
380
381 /*
382 wxRectList& wxRegion::GetRectList()
383 {
384 return ((wxRegionRefData*)m_refData)->GetRectList();
385 }
386 */
387
388 wxRect* wxRegion::GetRects()
389 {
390 return ((wxRegionRefData*)m_refData)->GetRects();
391 }
392
393 int wxRegion::GetRectCount() const
394 {
395 return ((wxRegionRefData*)m_refData)->GetRectCount();
396 }
397
398 void wxRegion::SetRects(const wxRectList& rectList)
399 {
400 ((wxRegionRefData*)m_refData)->SetRects(rectList);
401 }
402
403 void wxRegion::SetRects(int count, const wxRect* rects)
404 {
405 ((wxRegionRefData*)m_refData)->SetRects(count, rects);
406 }
407
408 ///////////////////////////////////////////////////////////////////////////////
409 // //
410 // wxRegionIterator //
411 // //
412 ///////////////////////////////////////////////////////////////////////////////
413
414 /*!
415 * Initialize empty iterator
416 */
417 wxRegionIterator::wxRegionIterator() : m_current(0), m_numRects(0), m_rects(NULL)
418 {
419 }
420
421 wxRegionIterator::~wxRegionIterator()
422 {
423 if (m_rects)
424 delete[] m_rects;
425 }
426
427 /*!
428 * Initialize iterator for region
429 */
430 wxRegionIterator::wxRegionIterator(const wxRegion& region)
431 {
432 m_rects = NULL;
433
434 Reset(region);
435 }
436
437 /*!
438 * Reset iterator for a new /e region.
439 */
440 void wxRegionIterator::Reset(const wxRegion& region)
441 {
442 m_current = 0;
443 m_region = region;
444
445 if (m_rects)
446 delete[] m_rects;
447
448 m_rects = NULL;
449
450 if (m_region.Empty())
451 m_numRects = 0;
452 else
453 {
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
465 for (size_t i = 0; i < m_numRects; i++)
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 }
486 }
487 }
488
489 /*!
490 * Increment iterator. The rectangle returned is the one after the
491 * incrementation.
492 */
493 void wxRegionIterator::operator ++ ()
494 {
495 if (m_current < m_numRects)
496 ++m_current;
497 }
498
499 /*!
500 * Increment iterator. The rectangle returned is the one before the
501 * incrementation.
502 */
503 void wxRegionIterator::operator ++ (int)
504 {
505 if (m_current < m_numRects)
506 ++m_current;
507 }
508
509 wxCoord wxRegionIterator::GetX() const
510 {
511 if (m_current < m_numRects)
512 return m_rects[m_current].x;
513 return 0;
514 }
515
516 wxCoord wxRegionIterator::GetY() const
517 {
518 if (m_current < m_numRects)
519 return m_rects[m_current].y;
520 return 0;
521 }
522
523 wxCoord wxRegionIterator::GetW() const
524 {
525 if (m_current < m_numRects)
526 return m_rects[m_current].width ;
527 return 0;
528 }
529
530 wxCoord wxRegionIterator::GetH() const
531 {
532 if (m_current < m_numRects)
533 return m_rects[m_current].height;
534 return 0;
535 }
536