]>
Commit | Line | Data |
---|---|---|
1 | ///////////////////////////////////////////////////////////////////////////// | |
2 | // File: region.cpp | |
3 | // Purpose: Region class | |
4 | // Author: Julian Smart | |
5 | // Created: Fri Oct 24 10:46:34 MET 1997 | |
6 | // RCS-ID: $Id$ | |
7 | // Copyright: (c) 1997 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.GetCount() > 0); | |
86 | if (m_usingRects) | |
87 | { | |
88 | m_rectCount = rectList.GetCount(); | |
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 | |
204 | wxRegion::Combine(wxCoord x, wxCoord y, | |
205 | wxCoord width, wxCoord height, | |
206 | wxRegionOp op) | |
207 | { | |
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 | ||
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 | } | |
222 | // If ref count is 1, that means it's 'ours' anyway so no action. | |
223 | ||
224 | Region rectRegion = XCreateRegion(); | |
225 | ||
226 | XRectangle rect; | |
227 | rect.x = x; | |
228 | rect.y = y; | |
229 | rect.width = width; | |
230 | rect.height = height; | |
231 | XUnionRectWithRegion(&rect, rectRegion, rectRegion); | |
232 | ||
233 | switch (op) | |
234 | { | |
235 | case wxRGN_AND: | |
236 | XIntersectRegion(M_REGION, rectRegion, M_REGION); | |
237 | break ; | |
238 | case wxRGN_OR: | |
239 | XUnionRegion(M_REGION, rectRegion, M_REGION); | |
240 | break ; | |
241 | case wxRGN_XOR: | |
242 | // TODO | |
243 | break ; | |
244 | case wxRGN_DIFF: | |
245 | // TODO | |
246 | break ; | |
247 | case wxRGN_COPY: // Don't have to do this one | |
248 | default: | |
249 | // TODO | |
250 | break ; | |
251 | } | |
252 | ||
253 | return FALSE; | |
254 | } | |
255 | ||
256 | //! Union /e region with this. | |
257 | bool wxRegion::Combine(const wxRegion& region, wxRegionOp op) | |
258 | { | |
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 | ||
271 | switch (op) | |
272 | { | |
273 | case wxRGN_AND: | |
274 | XIntersectRegion(M_REGION, ((wxRegionRefData*)region.m_refData)->m_region, | |
275 | M_REGION); | |
276 | break ; | |
277 | case wxRGN_OR: | |
278 | XUnionRegion(M_REGION, ((wxRegionRefData*)region.m_refData)->m_region, | |
279 | M_REGION); | |
280 | break ; | |
281 | case wxRGN_XOR: | |
282 | // TODO | |
283 | break ; | |
284 | case wxRGN_DIFF: | |
285 | // TODO | |
286 | break ; | |
287 | case wxRGN_COPY: // Don't have to do this one | |
288 | default: | |
289 | // TODO | |
290 | break ; | |
291 | } | |
292 | ||
293 | return FALSE; | |
294 | } | |
295 | ||
296 | bool 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 | |
306 | void wxRegion::GetBox(wxCoord& x, wxCoord& y, wxCoord&w, wxCoord &h) const | |
307 | { | |
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 | } | |
318 | } | |
319 | ||
320 | wxRect wxRegion::GetBox() const | |
321 | { | |
322 | wxCoord x, y, w, h; | |
323 | GetBox(x, y, w, h); | |
324 | return wxRect(x, y, w, h); | |
325 | } | |
326 | ||
327 | // Is region empty? | |
328 | bool wxRegion::Empty() const | |
329 | { | |
330 | return m_refData ? XEmptyRegion(M_REGION) : TRUE; | |
331 | } | |
332 | ||
333 | //----------------------------------------------------------------------------- | |
334 | //# Tests | |
335 | //----------------------------------------------------------------------------- | |
336 | ||
337 | // Does the region contain the point (x,y)? | |
338 | wxRegionContain wxRegion::Contains(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y)) const | |
339 | { | |
340 | if (!m_refData) | |
341 | return wxOutRegion; | |
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? | |
350 | wxRegionContain wxRegion::Contains(const wxPoint& pt) const | |
351 | { | |
352 | if (!m_refData) | |
353 | return wxOutRegion; | |
354 | ||
355 | return XPointInRegion(M_REGION, pt.x, pt.y) ? wxInRegion : wxOutRegion; | |
356 | } | |
357 | ||
358 | // Does the region contain the rectangle (x, y, w, h)? | |
359 | wxRegionContain wxRegion::Contains(wxCoord x, wxCoord y, wxCoord w, wxCoord h) const | |
360 | { | |
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; | |
369 | } | |
370 | ||
371 | // Does the region contain the rectangle rect | |
372 | wxRegionContain wxRegion::Contains(const wxRect& rect) const | |
373 | { | |
374 | if (!m_refData) | |
375 | return wxOutRegion; | |
376 | ||
377 | wxCoord x, y, w, h; | |
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 | ||
385 | bool wxRegion::UsingRects() const | |
386 | { | |
387 | return ((wxRegionRefData*)m_refData)->UsingRects(); | |
388 | } | |
389 | ||
390 | /* | |
391 | wxRectList& wxRegion::GetRectList() | |
392 | { | |
393 | return ((wxRegionRefData*)m_refData)->GetRectList(); | |
394 | } | |
395 | */ | |
396 | ||
397 | wxRect* wxRegion::GetRects() | |
398 | { | |
399 | return ((wxRegionRefData*)m_refData)->GetRects(); | |
400 | } | |
401 | ||
402 | int wxRegion::GetRectCount() const | |
403 | { | |
404 | return ((wxRegionRefData*)m_refData)->GetRectCount(); | |
405 | } | |
406 | ||
407 | void wxRegion::SetRects(const wxRectList& rectList) | |
408 | { | |
409 | ((wxRegionRefData*)m_refData)->SetRects(rectList); | |
410 | } | |
411 | ||
412 | void wxRegion::SetRects(int count, const wxRect* rects) | |
413 | { | |
414 | ((wxRegionRefData*)m_refData)->SetRects(count, rects); | |
415 | } | |
416 | ||
417 | /////////////////////////////////////////////////////////////////////////////// | |
418 | // // | |
419 | // wxRegionIterator // | |
420 | // // | |
421 | /////////////////////////////////////////////////////////////////////////////// | |
422 | ||
423 | /*! | |
424 | * Initialize empty iterator | |
425 | */ | |
426 | wxRegionIterator::wxRegionIterator() : m_current(0), m_numRects(0), m_rects(NULL) | |
427 | { | |
428 | } | |
429 | ||
430 | wxRegionIterator::~wxRegionIterator() | |
431 | { | |
432 | if (m_rects) | |
433 | delete[] m_rects; | |
434 | } | |
435 | ||
436 | /*! | |
437 | * Initialize iterator for region | |
438 | */ | |
439 | wxRegionIterator::wxRegionIterator(const wxRegion& region) | |
440 | { | |
441 | m_rects = NULL; | |
442 | ||
443 | Reset(region); | |
444 | } | |
445 | ||
446 | /*! | |
447 | * Reset iterator for a new /e region. | |
448 | */ | |
449 | void wxRegionIterator::Reset(const wxRegion& region) | |
450 | { | |
451 | m_current = 0; | |
452 | m_region = region; | |
453 | ||
454 | if (m_rects) | |
455 | delete[] m_rects; | |
456 | ||
457 | m_rects = NULL; | |
458 | ||
459 | if (m_region.Empty()) | |
460 | m_numRects = 0; | |
461 | else | |
462 | { | |
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 | ||
474 | for (size_t i = 0; i < m_numRects; i++) | |
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 | } | |
495 | } | |
496 | } | |
497 | ||
498 | /*! | |
499 | * Increment iterator. The rectangle returned is the one after the | |
500 | * incrementation. | |
501 | */ | |
502 | void wxRegionIterator::operator ++ () | |
503 | { | |
504 | if (m_current < m_numRects) | |
505 | ++m_current; | |
506 | } | |
507 | ||
508 | /*! | |
509 | * Increment iterator. The rectangle returned is the one before the | |
510 | * incrementation. | |
511 | */ | |
512 | void wxRegionIterator::operator ++ (int) | |
513 | { | |
514 | if (m_current < m_numRects) | |
515 | ++m_current; | |
516 | } | |
517 | ||
518 | wxCoord wxRegionIterator::GetX() const | |
519 | { | |
520 | if (m_current < m_numRects) | |
521 | return m_rects[m_current].x; | |
522 | return 0; | |
523 | } | |
524 | ||
525 | wxCoord wxRegionIterator::GetY() const | |
526 | { | |
527 | if (m_current < m_numRects) | |
528 | return m_rects[m_current].y; | |
529 | return 0; | |
530 | } | |
531 | ||
532 | wxCoord wxRegionIterator::GetW() const | |
533 | { | |
534 | if (m_current < m_numRects) | |
535 | return m_rects[m_current].width ; | |
536 | return 0; | |
537 | } | |
538 | ||
539 | wxCoord wxRegionIterator::GetH() const | |
540 | { | |
541 | if (m_current < m_numRects) | |
542 | return m_rects[m_current].height; | |
543 | return 0; | |
544 | } | |
545 |