Commit | Line | Data |
---|---|---|
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 | ||
36 | WX_DEFINE_LIST(wxRectList); | |
37 | ||
4bb6408c JS |
38 | //----------------------------------------------------------------------------- |
39 | // wxRegionRefData implementation | |
40 | //----------------------------------------------------------------------------- | |
41 | ||
42 | class WXDLLEXPORT wxRegionRefData : public wxGDIRefData { | |
43 | public: | |
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 |
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 | ||
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 | */ | |
136 | wxRegion::wxRegion() | |
137 | { | |
4bb6408c JS |
138 | } |
139 | ||
3ccf6cd7 | 140 | wxRegion::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 | ||
152 | wxRegion::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 | ||
164 | wxRegion::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 | */ | |
179 | wxRegion::~wxRegion() | |
180 | { | |
181 | // m_refData unrefed in ~wxObject | |
182 | } | |
183 | ||
55acd85e | 184 | // Get the internal region handle |
45d49251 | 185 | WXRegion 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 | |
197 | void wxRegion::Clear() | |
198 | { | |
199 | UnRef(); | |
200 | } | |
201 | ||
202 | //! Combine rectangle (x, y, w, h) with this. | |
3ccf6cd7 | 203 | bool 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. | |
248 | bool 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 | ||
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 | |
3ccf6cd7 | 297 | void 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 | ||
311 | wxRect 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? | |
319 | bool 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 | 329 | wxRegionContain 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? | |
341 | wxRegionContain 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 | 350 | wxRegionContain 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 | |
363 | wxRegionContain 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 |
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 | ||
4bb6408c | 408 | /////////////////////////////////////////////////////////////////////////////// |
dfe1eee3 VZ |
409 | // // |
410 | // wxRegionIterator // | |
411 | // // | |
4bb6408c JS |
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 | ||
dfe1eee3 | 434 | Reset(region); |
4bb6408c JS |
435 | } |
436 | ||
437 | /*! | |
438 | * Reset iterator for a new /e region. | |
439 | */ | |
440 | void 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 | */ | |
493 | void 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 | */ | |
503 | void wxRegionIterator::operator ++ (int) | |
504 | { | |
dfe1eee3 VZ |
505 | if (m_current < m_numRects) |
506 | ++m_current; | |
4bb6408c JS |
507 | } |
508 | ||
3ccf6cd7 | 509 | wxCoord 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 | 516 | wxCoord 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 | 523 | wxCoord 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 | 530 | wxCoord 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 |