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