]> git.saurik.com Git - wxWidgets.git/blob - src/msw/region.cpp
make it possible to associate context help text with individual radiobox items
[wxWidgets.git] / src / msw / region.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: msw/region.cpp
3 // Purpose: wxRegion implementation using Win32 API
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: Fri Oct 24 10:46:34 MET 1997
7 // RCS-ID: $Id$
8 // Copyright: (c) 1997-2002 wxWidgets team
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #include "wx/region.h"
28 #include "wx/gdicmn.h"
29
30 #include "wx/msw/private.h"
31
32 IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject)
33 IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator, wxObject)
34
35 // ----------------------------------------------------------------------------
36 // wxRegionRefData implementation
37 // ----------------------------------------------------------------------------
38
39 class WXDLLEXPORT wxRegionRefData : public wxGDIRefData
40 {
41 public:
42 wxRegionRefData()
43 {
44 m_region = 0;
45 }
46
47 wxRegionRefData(const wxRegionRefData& data) : wxGDIRefData()
48 {
49 #if defined(__WIN32__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
50 DWORD noBytes = ::GetRegionData(data.m_region, 0, NULL);
51 RGNDATA *rgnData = (RGNDATA*) new char[noBytes];
52 ::GetRegionData(data.m_region, noBytes, rgnData);
53 m_region = ::ExtCreateRegion(NULL, noBytes, rgnData);
54 delete[] (char*) rgnData;
55 #else
56 RECT rect;
57 ::GetRgnBox(data.m_region, &rect);
58 m_region = ::CreateRectRgnIndirect(&rect);
59 #endif
60 }
61
62 virtual ~wxRegionRefData()
63 {
64 ::DeleteObject(m_region);
65 m_region = 0;
66 }
67
68 HRGN m_region;
69
70 private:
71 // Cannot use
72 // DECLARE_NO_COPY_CLASS(wxRegionRefData)
73 // because copy constructor is explicitly declared above;
74 // but no copy assignment operator is defined, so declare
75 // it private to prevent the compiler from defining it:
76 wxRegionRefData& operator=(const wxRegionRefData&);
77 };
78
79 #define M_REGION (((wxRegionRefData*)m_refData)->m_region)
80 #define M_REGION_OF(rgn) (((wxRegionRefData*)(rgn.m_refData))->m_region)
81
82 // ============================================================================
83 // wxRegion implementation
84 // ============================================================================
85
86 // ----------------------------------------------------------------------------
87 // ctors and dtor
88 // ----------------------------------------------------------------------------
89
90 wxRegion::wxRegion()
91 {
92 m_refData = (wxRegionRefData *)NULL;
93 }
94
95 wxRegion::wxRegion(WXHRGN hRegion)
96 {
97 m_refData = new wxRegionRefData;
98 M_REGION = (HRGN) hRegion;
99 }
100
101 wxRegion::wxRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
102 {
103 m_refData = new wxRegionRefData;
104 M_REGION = ::CreateRectRgn(x, y, x + w, y + h);
105 }
106
107 wxRegion::wxRegion(const wxPoint& topLeft, const wxPoint& bottomRight)
108 {
109 m_refData = new wxRegionRefData;
110 M_REGION = ::CreateRectRgn(topLeft.x, topLeft.y, bottomRight.x, bottomRight.y);
111 }
112
113 wxRegion::wxRegion(const wxRect& rect)
114 {
115 m_refData = new wxRegionRefData;
116 M_REGION = ::CreateRectRgn(rect.x, rect.y, rect.x + rect.width, rect.y + rect.height);
117 }
118
119 wxRegion::wxRegion(size_t n, const wxPoint *points, int fillStyle)
120 {
121 #if defined(__WXMICROWIN__) || defined(__WXWINCE__)
122 wxUnusedVar(n);
123 wxUnusedVar(points);
124 wxUnusedVar(fillStyle);
125 m_refData = NULL;
126 M_REGION = NULL;
127 #else
128 m_refData = new wxRegionRefData;
129 M_REGION = ::CreatePolygonRgn
130 (
131 (POINT*)points,
132 n,
133 fillStyle == wxODDEVEN_RULE ? ALTERNATE : WINDING
134 );
135 #endif
136 }
137
138 wxRegion::~wxRegion()
139 {
140 // m_refData unrefed in ~wxObject
141 }
142
143 wxObjectRefData *wxRegion::CreateRefData() const
144 {
145 return new wxRegionRefData;
146 }
147
148 wxObjectRefData *wxRegion::CloneRefData(const wxObjectRefData *data) const
149 {
150 return new wxRegionRefData(*(wxRegionRefData *)data);
151 }
152
153 // ----------------------------------------------------------------------------
154 // wxRegion operations
155 // ----------------------------------------------------------------------------
156
157 // Clear current region
158 void wxRegion::Clear()
159 {
160 UnRef();
161 }
162
163 bool wxRegion::Offset(wxCoord x, wxCoord y)
164 {
165 wxCHECK_MSG( M_REGION, false, _T("invalid wxRegion") );
166
167 if ( !x && !y )
168 {
169 // nothing to do
170 return true;
171 }
172
173 AllocExclusive();
174
175 if ( ::OffsetRgn(GetHrgn(), x, y) == ERROR )
176 {
177 wxLogLastError(_T("OffsetRgn"));
178
179 return false;
180 }
181
182 return true;
183 }
184
185 // combine another region with this one
186 bool wxRegion::Combine(const wxRegion& rgn, wxRegionOp op)
187 {
188 // we can't use the API functions if we don't have a valid region handle
189 if ( !m_refData )
190 {
191 // combining with an empty/invalid region works differently depending
192 // on the operation
193 switch ( op )
194 {
195 case wxRGN_COPY:
196 case wxRGN_OR:
197 case wxRGN_XOR:
198 *this = rgn;
199 break;
200
201 default:
202 wxFAIL_MSG( _T("unknown region operation") );
203 // fall through
204
205 case wxRGN_AND:
206 case wxRGN_DIFF:
207 // leave empty/invalid
208 return false;
209 }
210 }
211 else // we have a valid region
212 {
213 AllocExclusive();
214
215 int mode;
216 switch ( op )
217 {
218 case wxRGN_AND:
219 mode = RGN_AND;
220 break;
221
222 case wxRGN_OR:
223 mode = RGN_OR;
224 break;
225
226 case wxRGN_XOR:
227 mode = RGN_XOR;
228 break;
229
230 case wxRGN_DIFF:
231 mode = RGN_DIFF;
232 break;
233
234 default:
235 wxFAIL_MSG( _T("unknown region operation") );
236 // fall through
237
238 case wxRGN_COPY:
239 mode = RGN_COPY;
240 break;
241 }
242
243 if ( ::CombineRgn(M_REGION, M_REGION, M_REGION_OF(rgn), mode) == ERROR )
244 {
245 wxLogLastError(_T("CombineRgn"));
246
247 return false;
248 }
249 }
250
251 return true;
252 }
253
254 // Combine rectangle (x, y, w, h) with this.
255 bool wxRegion::Combine(wxCoord x, wxCoord y,
256 wxCoord width, wxCoord height,
257 wxRegionOp op)
258 {
259 return Combine(wxRegion(x, y, width, height), op);
260 }
261
262 bool wxRegion::Combine(const wxRect& rect, wxRegionOp op)
263 {
264 return Combine(rect.GetLeft(), rect.GetTop(),
265 rect.GetWidth(), rect.GetHeight(), op);
266 }
267
268 // ----------------------------------------------------------------------------
269 // wxRegion bounding box
270 // ----------------------------------------------------------------------------
271
272 // Outer bounds of region
273 void wxRegion::GetBox(wxCoord& x, wxCoord& y, wxCoord&w, wxCoord &h) const
274 {
275 if (m_refData)
276 {
277 RECT rect;
278 ::GetRgnBox(M_REGION, & rect);
279 x = rect.left;
280 y = rect.top;
281 w = rect.right - rect.left;
282 h = rect.bottom - rect.top;
283 }
284 else
285 {
286 x = y = w = h = 0;
287 }
288 }
289
290 wxRect wxRegion::GetBox() const
291 {
292 wxCoord x, y, w, h;
293 GetBox(x, y, w, h);
294 return wxRect(x, y, w, h);
295 }
296
297 // Is region empty?
298 bool wxRegion::Empty() const
299 {
300 wxCoord x, y, w, h;
301 GetBox(x, y, w, h);
302
303 return (w == 0) && (h == 0);
304 }
305
306 // ----------------------------------------------------------------------------
307 // wxRegion hit testing
308 // ----------------------------------------------------------------------------
309
310 // Does the region contain the point (x,y)?
311 wxRegionContain wxRegion::Contains(wxCoord x, wxCoord y) const
312 {
313 if (!m_refData)
314 return wxOutRegion;
315
316 return ::PtInRegion(M_REGION, (int) x, (int) y) ? wxInRegion : wxOutRegion;
317 }
318
319 // Does the region contain the point pt?
320 wxRegionContain wxRegion::Contains(const wxPoint& pt) const
321 {
322 return Contains(pt.x, pt.y);
323 }
324
325 // Does the region contain the rectangle (x, y, w, h)?
326 wxRegionContain wxRegion::Contains(wxCoord x, wxCoord y,
327 wxCoord w, wxCoord h) const
328 {
329 if (!m_refData)
330 return wxOutRegion;
331
332 RECT rect;
333 rect.left = x;
334 rect.top = y;
335 rect.right = x + w;
336 rect.bottom = y + h;
337
338 return ::RectInRegion(M_REGION, &rect) ? wxInRegion : wxOutRegion;
339 }
340
341 // Does the region contain the rectangle rect
342 wxRegionContain wxRegion::Contains(const wxRect& rect) const
343 {
344 return Contains(rect.x, rect.y, rect.width, rect.height);
345 }
346
347 // Get internal region handle
348 WXHRGN wxRegion::GetHRGN() const
349 {
350 return (WXHRGN)(m_refData ? M_REGION : 0);
351 }
352
353 // ============================================================================
354 // wxRegionIterator implementation
355 // ============================================================================
356
357 // ----------------------------------------------------------------------------
358 // wxRegionIterator ctors/dtor
359 // ----------------------------------------------------------------------------
360
361 void wxRegionIterator::Init()
362 {
363 m_current =
364 m_numRects = 0;
365
366 m_rects = NULL;
367 }
368
369 wxRegionIterator::~wxRegionIterator()
370 {
371 delete [] m_rects;
372 }
373
374 // Initialize iterator for region
375 wxRegionIterator::wxRegionIterator(const wxRegion& region)
376 {
377 m_rects = NULL;
378
379 Reset(region);
380 }
381
382 wxRegionIterator& wxRegionIterator::operator=(const wxRegionIterator& ri)
383 {
384 delete [] m_rects;
385
386 m_current = ri.m_current;
387 m_numRects = ri.m_numRects;
388 if ( m_numRects )
389 {
390 m_rects = new wxRect[m_numRects];
391 for ( long n = 0; n < m_numRects; n++ )
392 m_rects[n] = ri.m_rects[n];
393 }
394 else
395 {
396 m_rects = NULL;
397 }
398
399 return *this;
400 }
401
402 // ----------------------------------------------------------------------------
403 // wxRegionIterator operations
404 // ----------------------------------------------------------------------------
405
406 // Reset iterator for a new region.
407 void wxRegionIterator::Reset(const wxRegion& region)
408 {
409 m_current = 0;
410 m_region = region;
411
412 if (m_rects)
413 {
414 delete[] m_rects;
415
416 m_rects = NULL;
417 }
418
419 if (m_region.Empty())
420 m_numRects = 0;
421 else
422 {
423 DWORD noBytes = ::GetRegionData(((wxRegionRefData*)region.m_refData)->m_region, 0, NULL);
424 RGNDATA *rgnData = (RGNDATA*) new char[noBytes];
425 ::GetRegionData(((wxRegionRefData*)region.m_refData)->m_region, noBytes, rgnData);
426
427 RGNDATAHEADER* header = (RGNDATAHEADER*) rgnData;
428
429 m_rects = new wxRect[header->nCount];
430
431 RECT* rect = (RECT*) ((char*)rgnData + sizeof(RGNDATAHEADER));
432 size_t i;
433 for (i = 0; i < header->nCount; i++)
434 {
435 m_rects[i] = wxRect(rect->left, rect->top,
436 rect->right - rect->left, rect->bottom - rect->top);
437 rect ++; // Advances pointer by sizeof(RECT)
438 }
439
440 m_numRects = header->nCount;
441
442 delete[] (char*) rgnData;
443 }
444 }
445
446 wxRegionIterator& wxRegionIterator::operator++()
447 {
448 if (m_current < m_numRects)
449 ++m_current;
450
451 return *this;
452 }
453
454 wxRegionIterator wxRegionIterator::operator ++ (int)
455 {
456 wxRegionIterator tmp = *this;
457 if (m_current < m_numRects)
458 ++m_current;
459
460 return tmp;
461 }
462
463 // ----------------------------------------------------------------------------
464 // wxRegionIterator accessors
465 // ----------------------------------------------------------------------------
466
467 wxCoord wxRegionIterator::GetX() const
468 {
469 wxCHECK_MSG( m_current < m_numRects, 0, _T("invalid wxRegionIterator") );
470
471 return m_rects[m_current].x;
472 }
473
474 wxCoord wxRegionIterator::GetY() const
475 {
476 wxCHECK_MSG( m_current < m_numRects, 0, _T("invalid wxRegionIterator") );
477
478 return m_rects[m_current].y;
479 }
480
481 wxCoord wxRegionIterator::GetW() const
482 {
483 wxCHECK_MSG( m_current < m_numRects, 0, _T("invalid wxRegionIterator") );
484
485 return m_rects[m_current].width;
486 }
487
488 wxCoord wxRegionIterator::GetH() const
489 {
490 wxCHECK_MSG( m_current < m_numRects, 0, _T("invalid wxRegionIterator") );
491
492 return m_rects[m_current].height;
493 }
494