]> git.saurik.com Git - wxWidgets.git/blob - src/motif/region.cpp
allow TABbing into multiline text controls even if they're not editable
[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
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