wxToolBar API changes; now frames manage their toolbar & statusbar properly;
[wxWidgets.git] / src / msw / region.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // File: region.cpp
3 // Purpose: Region handling for wxWindows/X11
4 // Author: Markus Holzem
5 // Created: Fri Oct 24 10:46:34 MET 1997
6 // RCS-ID: $Id$
7 // Copyright: (c) 1997 Julian Smart and Markus Holzem
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 #ifdef __GNUG__
12 #pragma implementation "region.h"
13 #endif
14
15 #include "wx/wxprec.h"
16
17 #ifdef __BORLANDC__
18 #pragma hdrstop
19 #endif
20
21 #include "wx/msw/region.h"
22 #include "wx/gdicmn.h"
23
24 #include <windows.h>
25
26 #if !USE_SHARED_LIBRARY
27 IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject)
28 IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator, wxObject)
29 #endif
30
31 //-----------------------------------------------------------------------------
32 // wxRegionRefData implementation
33 //-----------------------------------------------------------------------------
34
35 class WXDLLEXPORT wxRegionRefData : public wxGDIRefData {
36 public:
37 wxRegionRefData(void)
38 {
39 }
40
41 wxRegionRefData(const wxRegionRefData& data)
42 {
43 #if defined(__WIN32__)
44 DWORD noBytes = ::GetRegionData(data.m_region, 0, NULL);
45 RGNDATA *rgnData = (RGNDATA*) new char[noBytes];
46 ::GetRegionData(data.m_region, noBytes, rgnData);
47 m_region = ::ExtCreateRegion(NULL, noBytes, rgnData);
48 delete[] (char*) rgnData;
49 #else
50 RECT rect;
51 ::GetRgnBox(data.m_region, &rect);
52 m_region = ::CreateRectRgnIndirect(&rect);
53 #endif
54 }
55
56 ~wxRegionRefData(void)
57 {
58 ::DeleteObject(m_region);
59 m_region = 0;
60 }
61
62 HRGN m_region;
63 };
64
65 #define M_REGION (((wxRegionRefData*)m_refData)->m_region)
66
67 //-----------------------------------------------------------------------------
68 // wxRegion
69 //-----------------------------------------------------------------------------
70
71 /*!
72 * Create an empty region.
73 */
74 wxRegion::wxRegion(void)
75 {
76 m_refData = new wxRegionRefData;
77 M_REGION = ::CreateRectRgn(0, 0, 0, 0);
78 }
79
80 wxRegion::wxRegion(WXHRGN hRegion)
81 {
82 m_refData = new wxRegionRefData;
83 M_REGION = (HRGN) hRegion;
84 }
85
86 wxRegion::wxRegion(long x, long y, long w, long h)
87 {
88 m_refData = new wxRegionRefData;
89 M_REGION = ::CreateRectRgn(x, y, x + w, y + h);
90 }
91
92 wxRegion::wxRegion(const wxPoint& topLeft, const wxPoint& bottomRight)
93 {
94 m_refData = new wxRegionRefData;
95 M_REGION = ::CreateRectRgn(topLeft.x, topLeft.y, bottomRight.x, bottomRight.y);
96 }
97
98 wxRegion::wxRegion(const wxRect& rect)
99 {
100 m_refData = new wxRegionRefData;
101 M_REGION = ::CreateRectRgn(rect.GetLeft(), rect.GetTop(), rect.GetRight(), rect.GetBottom());
102 }
103
104 /*!
105 * Destroy the region.
106 */
107 wxRegion::~wxRegion(void)
108 {
109 // m_refData unrefed in ~wxObject
110 }
111
112 //-----------------------------------------------------------------------------
113 //# Modify region
114 //-----------------------------------------------------------------------------
115
116 //! Clear current region
117 void wxRegion::Clear(void)
118 {
119 UnRef();
120 }
121
122 //! Combine rectangle (x, y, w, h) with this.
123 bool wxRegion::Combine(long x, long y, long width, long height, wxRegionOp op)
124 {
125 // Don't change shared data
126 if (!m_refData) {
127 m_refData = new wxRegionRefData();
128 } else if (m_refData->GetRefCount() > 1) {
129 wxRegionRefData* ref = (wxRegionRefData*)m_refData;
130 UnRef();
131 m_refData = new wxRegionRefData(*ref);
132 }
133 // If ref count is 1, that means it's 'ours' anyway so no action.
134
135 HRGN rectRegion = ::CreateRectRgn(x, y, x + width, y + height);
136
137 int mode = 0;
138 switch (op)
139 {
140 case wxRGN_AND: mode = RGN_AND; break ;
141 case wxRGN_OR: mode = RGN_OR; break ;
142 case wxRGN_XOR: mode = RGN_XOR; break ;
143 case wxRGN_DIFF: mode = RGN_DIFF; break ;
144 case wxRGN_COPY:
145 default:
146 mode = RGN_COPY; break ;
147 }
148
149 bool success = (ERROR != ::CombineRgn(M_REGION, M_REGION, rectRegion, mode));
150
151 ::DeleteObject(rectRegion);
152
153 return success;
154 }
155
156 //! Union /e region with this.
157 bool wxRegion::Combine(const wxRegion& region, wxRegionOp op)
158 {
159 if (region.Empty())
160 return FALSE;
161
162 // Don't change shared data
163 if (!m_refData) {
164 m_refData = new wxRegionRefData();
165 } else if (m_refData->GetRefCount() > 1) {
166 wxRegionRefData* ref = (wxRegionRefData*)m_refData;
167 UnRef();
168 m_refData = new wxRegionRefData(*ref);
169 }
170
171 int mode = 0;
172 switch (op)
173 {
174 case wxRGN_AND: mode = RGN_AND; break ;
175 case wxRGN_OR: mode = RGN_OR; break ;
176 case wxRGN_XOR: mode = RGN_XOR; break ;
177 case wxRGN_DIFF: mode = RGN_DIFF; break ;
178 case wxRGN_COPY:
179 default:
180 mode = RGN_COPY; break ;
181 }
182
183 return (ERROR != ::CombineRgn(M_REGION, M_REGION, ((wxRegionRefData*)region.m_refData)->m_region, mode));
184 }
185
186 bool wxRegion::Combine(const wxRect& rect, wxRegionOp op)
187 {
188 return Combine(rect.GetLeft(), rect.GetTop(), rect.GetWidth(), rect.GetHeight(), op);
189 }
190
191 //-----------------------------------------------------------------------------
192 //# Information on region
193 //-----------------------------------------------------------------------------
194
195 // Outer bounds of region
196 void wxRegion::GetBox(long& x, long& y, long&w, long &h) const
197 {
198 if (m_refData) {
199 RECT rect;
200 ::GetRgnBox(M_REGION, & rect);
201 x = rect.left;
202 y = rect.top;
203 w = rect.right - rect.left;
204 h = rect.bottom - rect.top;
205 } else {
206 x = y = w = h = 0;
207 }
208 }
209
210 wxRect wxRegion::GetBox(void) const
211 {
212 long x, y, w, h;
213 GetBox(x, y, w, h);
214 return wxRect(x, y, w, h);
215 }
216
217 // Is region empty?
218 bool wxRegion::Empty(void) const
219 {
220 if (M_REGION == 0)
221 return TRUE;
222 long x, y, w, h;
223 GetBox(x, y, w, h);
224
225 return ((w == 0) && (h == 0));
226 }
227
228 //-----------------------------------------------------------------------------
229 //# Tests
230 //-----------------------------------------------------------------------------
231
232 // Does the region contain the point (x,y)?
233 wxRegionContain wxRegion::Contains(long x, long y) const
234 {
235 if (!m_refData)
236 return wxOutRegion;
237
238 if (::PtInRegion(M_REGION, (int) x, (int) y))
239 return wxInRegion;
240 else
241 return wxOutRegion;
242 }
243
244 // Does the region contain the point pt?
245 wxRegionContain wxRegion::Contains(const wxPoint& pt) const
246 {
247 if (!m_refData)
248 return wxOutRegion;
249
250 if (::PtInRegion(M_REGION, (int) pt.x, (int) pt.y))
251 return wxInRegion;
252 else
253 return wxOutRegion;
254 }
255
256 // Does the region contain the rectangle (x, y, w, h)?
257 wxRegionContain wxRegion::Contains(long x, long y, long w, long h) const
258 {
259 if (!m_refData)
260 return wxOutRegion;
261
262 RECT rect;
263 rect.left = x;
264 rect.top = y;
265 rect.right = x + w;
266 rect.bottom = y + h;
267
268 if (::RectInRegion(M_REGION, & rect))
269 return wxInRegion;
270 else
271 return wxOutRegion;
272 }
273
274 // Does the region contain the rectangle rect
275 wxRegionContain wxRegion::Contains(const wxRect& rect) const
276 {
277 if (!m_refData)
278 return wxOutRegion;
279
280 long x, y, w, h;
281 x = rect.x;
282 y = rect.y;
283 w = rect.GetWidth();
284 h = rect.GetHeight();
285 return Contains(x, y, w, h);
286 }
287
288 ///////////////////////////////////////////////////////////////////////////////
289 // //
290 // wxRegionIterator //
291 // //
292 ///////////////////////////////////////////////////////////////////////////////
293
294 /*!
295 * Initialize empty iterator
296 */
297 wxRegionIterator::wxRegionIterator(void) : m_current(0), m_numRects(0), m_rects(NULL)
298 {
299 }
300
301 wxRegionIterator::~wxRegionIterator(void)
302 {
303 if (m_rects)
304 delete[] m_rects;
305 }
306
307 /*!
308 * Initialize iterator for region
309 */
310 wxRegionIterator::wxRegionIterator(const wxRegion& region)
311 {
312 m_rects = NULL;
313
314 Reset(region);
315 }
316
317 /*!
318 * Reset iterator for a new /e region.
319 */
320 void wxRegionIterator::Reset(const wxRegion& region)
321 {
322 m_current = 0;
323 m_region = region;
324
325 if (m_rects)
326 delete[] m_rects;
327
328 m_rects = NULL;
329
330 if (m_region.Empty())
331 m_numRects = 0;
332 else
333 {
334 #if defined(__WIN32__)
335 DWORD noBytes = ::GetRegionData(((wxRegionRefData*)region.m_refData)->m_region, 0, NULL);
336 RGNDATA *rgnData = (RGNDATA*) new char[noBytes];
337 ::GetRegionData(((wxRegionRefData*)region.m_refData)->m_region, noBytes, rgnData);
338
339 RGNDATAHEADER* header = (RGNDATAHEADER*) rgnData;
340
341 m_rects = new wxRect[header->nCount];
342
343 RECT* rect = (RECT*) (rgnData + sizeof(RGNDATAHEADER)) ;
344 uint i;
345 for (i = 0; i < header->nCount; i++)
346 {
347 m_rects[i] = wxRect(rect->left, rect->top,
348 rect->right - rect->left, rect->bottom - rect->top);
349 rect += sizeof(RECT);
350 }
351
352 m_numRects = header->nCount;
353
354 delete[] (char*) rgnData;
355 #else
356 RECT rect;
357 ::GetRgnBox(((wxRegionRefData*)region.m_refData)->m_region, &rect);
358 m_rects = new wxRect[1];
359 m_rects[0].x = rect.left;
360 m_rects[0].y = rect.top;
361 m_rects[0].width = rect.right - rect.left;
362 m_rects[0].height = rect.bottom - rect.top;
363
364 m_numRects = 1;
365 #endif
366 }
367 }
368
369 /*!
370 * Increment iterator. The rectangle returned is the one after the
371 * incrementation.
372 */
373 void wxRegionIterator::operator ++ (void)
374 {
375 if (m_current < m_numRects)
376 ++m_current;
377 }
378
379 /*!
380 * Increment iterator. The rectangle returned is the one before the
381 * incrementation.
382 */
383 void wxRegionIterator::operator ++ (int)
384 {
385 if (m_current < m_numRects)
386 ++m_current;
387 }
388
389 long wxRegionIterator::GetX(void) const
390 {
391 if (m_current < m_numRects)
392 return m_rects[m_current].x;
393 return 0;
394 }
395
396 long wxRegionIterator::GetY(void) const
397 {
398 if (m_current < m_numRects)
399 return m_rects[m_current].y;
400 return 0;
401 }
402
403 long wxRegionIterator::GetW(void) const
404 {
405 if (m_current < m_numRects)
406 return m_rects[m_current].width ;
407 return 0;
408 }
409
410 long wxRegionIterator::GetH(void) const
411 {
412 if (m_current < m_numRects)
413 return m_rects[m_current].height;
414 return 0;
415 }
416