added some wxMSW stuff
[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(long x, long y, long w, long h)
81 {
82 m_refData = new wxRegionRefData;
83 M_REGION = ::CreateRectRgn(x, y, x + w, y + h);
84 }
85
86 wxRegion::wxRegion(const wxPoint& topLeft, const wxPoint& bottomRight)
87 {
88 m_refData = new wxRegionRefData;
89 M_REGION = ::CreateRectRgn(topLeft.x, topLeft.y, bottomRight.x, bottomRight.y);
90 }
91
92 wxRegion::wxRegion(const wxRect& rect)
93 {
94 m_refData = new wxRegionRefData;
95 M_REGION = ::CreateRectRgn(rect.GetLeft(), rect.GetTop(), rect.GetRight(), rect.GetBottom());
96 }
97
98 /*!
99 * Destroy the region.
100 */
101 wxRegion::~wxRegion(void)
102 {
103 // m_refData unrefed in ~wxObject
104 }
105
106 //-----------------------------------------------------------------------------
107 //# Modify region
108 //-----------------------------------------------------------------------------
109
110 //! Clear current region
111 void wxRegion::Clear(void)
112 {
113 UnRef();
114 }
115
116 //! Combine rectangle (x, y, w, h) with this.
117 bool wxRegion::Combine(long x, long y, long width, long height, wxRegionOp op)
118 {
119 // Don't change shared data
120 if (!m_refData) {
121 m_refData = new wxRegionRefData();
122 } else if (m_refData->GetRefCount() > 1) {
123 wxRegionRefData* ref = (wxRegionRefData*)m_refData;
124 UnRef();
125 m_refData = new wxRegionRefData(*ref);
126 }
127 // If ref count is 1, that means it's 'ours' anyway so no action.
128
129 HRGN rectRegion = ::CreateRectRgn(x, y, x + width, y + height);
130
131 int mode = 0;
132 switch (op)
133 {
134 case wxRGN_AND: mode = RGN_AND; break ;
135 case wxRGN_OR: mode = RGN_OR; break ;
136 case wxRGN_XOR: mode = RGN_XOR; break ;
137 case wxRGN_DIFF: mode = RGN_DIFF; break ;
138 case wxRGN_COPY:
139 default:
140 mode = RGN_COPY; break ;
141 }
142
143 bool success = (ERROR != ::CombineRgn(M_REGION, M_REGION, rectRegion, mode));
144
145 ::DeleteObject(rectRegion);
146
147 return success;
148 }
149
150 //! Union /e region with this.
151 bool wxRegion::Combine(const wxRegion& region, wxRegionOp op)
152 {
153 if (region.Empty())
154 return FALSE;
155
156 // Don't change shared data
157 if (!m_refData) {
158 m_refData = new wxRegionRefData();
159 } else if (m_refData->GetRefCount() > 1) {
160 wxRegionRefData* ref = (wxRegionRefData*)m_refData;
161 UnRef();
162 m_refData = new wxRegionRefData(*ref);
163 }
164
165 int mode = 0;
166 switch (op)
167 {
168 case wxRGN_AND: mode = RGN_AND; break ;
169 case wxRGN_OR: mode = RGN_OR; break ;
170 case wxRGN_XOR: mode = RGN_XOR; break ;
171 case wxRGN_DIFF: mode = RGN_DIFF; break ;
172 case wxRGN_COPY:
173 default:
174 mode = RGN_COPY; break ;
175 }
176
177 return (ERROR != ::CombineRgn(M_REGION, M_REGION, ((wxRegionRefData*)region.m_refData)->m_region, mode));
178 }
179
180 bool wxRegion::Combine(const wxRect& rect, wxRegionOp op)
181 {
182 return Combine(rect.GetLeft(), rect.GetTop(), rect.GetWidth(), rect.GetHeight(), op);
183 }
184
185 //-----------------------------------------------------------------------------
186 //# Information on region
187 //-----------------------------------------------------------------------------
188
189 // Outer bounds of region
190 void wxRegion::GetBox(long& x, long& y, long&w, long &h) const
191 {
192 if (m_refData) {
193 RECT rect;
194 ::GetRgnBox(M_REGION, & rect);
195 x = rect.left;
196 y = rect.top;
197 w = rect.right - rect.left;
198 h = rect.bottom - rect.top;
199 } else {
200 x = y = w = h = 0;
201 }
202 }
203
204 wxRect wxRegion::GetBox(void) const
205 {
206 long x, y, w, h;
207 GetBox(x, y, w, h);
208 return wxRect(x, y, w, h);
209 }
210
211 // Is region empty?
212 bool wxRegion::Empty(void) const
213 {
214 if (M_REGION == 0)
215 return TRUE;
216 long x, y, w, h;
217 GetBox(x, y, w, h);
218
219 return ((w == 0) && (h == 0));
220 }
221
222 //-----------------------------------------------------------------------------
223 //# Tests
224 //-----------------------------------------------------------------------------
225
226 // Does the region contain the point (x,y)?
227 wxRegionContain wxRegion::Contains(long x, long y) const
228 {
229 if (!m_refData)
230 return wxOutRegion;
231
232 if (::PtInRegion(M_REGION, (int) x, (int) y))
233 return wxInRegion;
234 else
235 return wxOutRegion;
236 }
237
238 // Does the region contain the point pt?
239 wxRegionContain wxRegion::Contains(const wxPoint& pt) const
240 {
241 if (!m_refData)
242 return wxOutRegion;
243
244 if (::PtInRegion(M_REGION, (int) pt.x, (int) pt.y))
245 return wxInRegion;
246 else
247 return wxOutRegion;
248 }
249
250 // Does the region contain the rectangle (x, y, w, h)?
251 wxRegionContain wxRegion::Contains(long x, long y, long w, long h) const
252 {
253 if (!m_refData)
254 return wxOutRegion;
255
256 RECT rect;
257 rect.left = x;
258 rect.top = y;
259 rect.right = x + w;
260 rect.bottom = y + h;
261
262 if (::RectInRegion(M_REGION, & rect))
263 return wxInRegion;
264 else
265 return wxOutRegion;
266 }
267
268 // Does the region contain the rectangle rect
269 wxRegionContain wxRegion::Contains(const wxRect& rect) const
270 {
271 if (!m_refData)
272 return wxOutRegion;
273
274 long x, y, w, h;
275 x = rect.x;
276 y = rect.y;
277 w = rect.GetWidth();
278 h = rect.GetHeight();
279 return Contains(x, y, w, h);
280 }
281
282 ///////////////////////////////////////////////////////////////////////////////
283 // //
284 // wxRegionIterator //
285 // //
286 ///////////////////////////////////////////////////////////////////////////////
287
288 /*!
289 * Initialize empty iterator
290 */
291 wxRegionIterator::wxRegionIterator(void) : m_current(0), m_numRects(0), m_rects(NULL)
292 {
293 }
294
295 wxRegionIterator::~wxRegionIterator(void)
296 {
297 if (m_rects)
298 delete[] m_rects;
299 }
300
301 /*!
302 * Initialize iterator for region
303 */
304 wxRegionIterator::wxRegionIterator(const wxRegion& region)
305 {
306 m_rects = NULL;
307
308 Reset(region);
309 }
310
311 /*!
312 * Reset iterator for a new /e region.
313 */
314 void wxRegionIterator::Reset(const wxRegion& region)
315 {
316 m_current = 0;
317 m_region = region;
318
319 if (m_rects)
320 delete[] m_rects;
321
322 m_rects = NULL;
323
324 if (m_region.Empty())
325 m_numRects = 0;
326 else
327 {
328 #if defined(__WIN32__)
329 DWORD noBytes = ::GetRegionData(((wxRegionRefData*)region.m_refData)->m_region, 0, NULL);
330 RGNDATA *rgnData = (RGNDATA*) new char[noBytes];
331 ::GetRegionData(((wxRegionRefData*)region.m_refData)->m_region, noBytes, rgnData);
332
333 RGNDATAHEADER* header = (RGNDATAHEADER*) rgnData;
334
335 m_rects = new wxRect[header->nCount];
336
337 RECT* rect = (RECT*) (rgnData + sizeof(RGNDATAHEADER)) ;
338 uint i;
339 for (i = 0; i < header->nCount; i++)
340 {
341 m_rects[i] = wxRect(rect->left, rect->top,
342 rect->right - rect->left, rect->bottom - rect->top);
343 rect += sizeof(RECT);
344 }
345
346 m_numRects = header->nCount;
347
348 delete[] (char*) rgnData;
349 #else
350 RECT rect;
351 ::GetRgnBox(((wxRegionRefData*)region.m_refData)->m_region, &rect);
352 m_rects = new wxRect[1];
353 m_rects[0].x = rect.left;
354 m_rects[0].y = rect.top;
355 m_rects[0].width = rect.right - rect.left;
356 m_rects[0].height = rect.bottom - rect.top;
357
358 m_numRects = 1;
359 #endif
360 }
361 }
362
363 /*!
364 * Increment iterator. The rectangle returned is the one after the
365 * incrementation.
366 */
367 void wxRegionIterator::operator ++ (void)
368 {
369 if (m_current < m_numRects)
370 ++m_current;
371 }
372
373 /*!
374 * Increment iterator. The rectangle returned is the one before the
375 * incrementation.
376 */
377 void wxRegionIterator::operator ++ (int)
378 {
379 if (m_current < m_numRects)
380 ++m_current;
381 }
382
383 long wxRegionIterator::GetX(void) const
384 {
385 if (m_current < m_numRects)
386 return m_rects[m_current].x;
387 return 0;
388 }
389
390 long wxRegionIterator::GetY(void) const
391 {
392 if (m_current < m_numRects)
393 return m_rects[m_current].y;
394 return 0;
395 }
396
397 long wxRegionIterator::GetW(void) const
398 {
399 if (m_current < m_numRects)
400 return m_rects[m_current].width ;
401 return 0;
402 }
403
404 long wxRegionIterator::GetH(void) const
405 {
406 if (m_current < m_numRects)
407 return m_rects[m_current].height;
408 return 0;
409 }
410