]> git.saurik.com Git - wxWidgets.git/blob - src/os2/region.cpp
dumb fix for wxDC::Clear() crash
[wxWidgets.git] / src / os2 / region.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // File: region.cpp
3 // Purpose: Region class
4 // Author: David Webster
5 // Modified by:
6 // Created: 10/15/99
7 // RCS-ID: $Id$
8 // Copyright: (c) Davdi Webster
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14
15 #include "wx/app.h"
16 #include "wx/os2/region.h"
17 #include "wx/gdicmn.h"
18
19 #include "wx/window.h"
20 #include "wx/os2/private.h"
21
22 IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject)
23 IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator, wxObject)
24
25 //-----------------------------------------------------------------------------
26 // wxRegionRefData implementation
27 //-----------------------------------------------------------------------------
28
29 class WXDLLEXPORT wxRegionRefData : public wxGDIRefData {
30 public:
31 wxRegionRefData()
32 {
33 m_hRegion = 0;
34 m_hPS = 0;
35 }
36
37 wxRegionRefData(const wxRegionRefData& rData)
38 {
39 RGNRECT vRgnData;
40 PRECTL pRect = NULL;
41
42 if (::GpiQueryRegionRects( rData.m_hPS // Pres space
43 ,rData.m_hRegion // Handle of region to query
44 ,NULL // Return all RECTs
45 ,&vRgnData // Will contain number or RECTs in region
46 ,NULL // NULL to return number of RECTs
47 ))
48 {
49 pRect = new RECTL[vRgnData.crcReturned];
50 vRgnData.crc = vRgnData.crcReturned;
51 vRgnData.ircStart = 1;
52 if (::GpiQueryRegionRects( rData.m_hPS // Pres space of source
53 ,rData.m_hRegion // Handle of source region
54 ,NULL // Return all RECTs
55 ,&vRgnData // Operations set to return rects
56 ,pRect // Will contain the actual RECTS
57 ))
58 {
59 m_hRegion = ::GpiCreateRegion( rData.m_hPS
60 ,vRgnData.crcReturned
61 ,pRect
62 );
63 m_hPS = rData.m_hPS;
64 }
65 delete [] pRect;
66 }
67 }
68
69 ~wxRegionRefData()
70 {
71 ::GpiDestroyRegion(m_hPS, m_hRegion);
72 }
73
74 HRGN m_hRegion;
75 HPS m_hPS;
76 };
77
78 #define M_REGION (((wxRegionRefData*)m_refData)->m_hRegion)
79
80 //-----------------------------------------------------------------------------
81 // wxRegion
82 //-----------------------------------------------------------------------------
83
84 /*!
85 * Create an empty region.
86 */
87 wxRegion::wxRegion()
88 {
89 m_refData = new wxRegionRefData;
90 } // end of wxRegion::wxRegion
91
92 wxRegion::wxRegion(
93 WXHRGN hRegion,
94 WXHDC hPS
95 )
96 {
97 m_refData = new wxRegionRefData;
98 M_REGION = (HRGN) hRegion;
99 (((wxRegionRefData*)m_refData)->m_hPS) = hPS;
100 } // end of wxRegion::wxRegion
101
102 wxRegion::wxRegion(
103 wxCoord x
104 , wxCoord y
105 , wxCoord vWidth
106 , wxCoord vHeight
107 )
108 {
109 RECTL vRect;
110 SIZEL vSize = {0, 0};
111 DEVOPENSTRUC vDop = {0L, "DISPLAY", NULL, 0L, 0L, 0L, 0L, 0L, 0L};
112 HDC hDC = ::DevOpenDC( vHabmain
113 ,OD_MEMORY
114 ,"*"
115 ,5L
116 ,(PDEVOPENDATA)&vDop
117 ,NULLHANDLE
118 );
119
120
121 vRect.xLeft = x;
122 vRect.xRight = x + vWidth;
123 vRect.yBottom = y;
124 vRect.yTop = y + vHeight;
125
126 m_refData = new wxRegionRefData;
127
128 //
129 // Need a PS to create a Region
130 //
131 ((wxRegionRefData*)m_refData)->m_hPS = ::GpiCreatePS( vHabmain
132 ,hDC
133 ,&vSize
134 ,PU_PELS | GPIT_MICRO | GPIA_ASSOC
135 );
136 M_REGION = ::GpiCreateRegion( ((wxRegionRefData*)m_refData)->m_hPS
137 ,1
138 ,&vRect
139 );
140 } // end of wxRegion::wxRegion
141
142 wxRegion::wxRegion(
143 const wxPoint& rTopLeft
144 , const wxPoint& rBottomRight
145 )
146 {
147 RECTL vRect;
148 SIZEL vSize = {0, 0};
149 DEVOPENSTRUC vDop = {0L, "DISPLAY", NULL, 0L, 0L, 0L, 0L, 0L, 0L};
150 HDC hDC = ::DevOpenDC( vHabmain
151 ,OD_MEMORY
152 ,"*"
153 ,5L
154 ,(PDEVOPENDATA)&vDop
155 ,NULLHANDLE
156 );
157
158 vRect.xLeft = rTopLeft.x;
159 vRect.xRight = rBottomRight.x;
160 vRect.yBottom = rBottomRight.y;
161 vRect.yTop = rTopLeft.y;
162
163 m_refData = new wxRegionRefData;
164
165 //
166 // Need a PS to create a Region
167 //
168 ((wxRegionRefData*)m_refData)->m_hPS = ::GpiCreatePS( vHabmain
169 ,hDC
170 ,&vSize
171 ,PU_PELS | GPIT_MICRO | GPIA_ASSOC
172 );
173 M_REGION = ::GpiCreateRegion( ((wxRegionRefData*)m_refData)->m_hPS
174 ,1
175 ,&vRect
176 );
177 } // end of wxRegion::wxRegion
178
179 wxRegion::wxRegion(
180 const wxRect& rRect
181 )
182 {
183 RECTL vRect;
184 SIZEL vSize = {0, 0};
185 DEVOPENSTRUC vDop = {0L, "DISPLAY", NULL, 0L, 0L, 0L, 0L, 0L, 0L};
186 HDC hDC = ::DevOpenDC( vHabmain
187 ,OD_MEMORY
188 ,"*"
189 ,5L
190 ,(PDEVOPENDATA)&vDop
191 ,NULLHANDLE
192 );
193
194
195 vRect.xLeft = rRect.x;
196 vRect.xRight = rRect.x + rRect.width;
197 vRect.yBottom = rRect.y;
198 vRect.yTop = rRect.y + rRect.height;
199
200 m_refData = new wxRegionRefData;
201
202 //
203 // Need a PS to create a Region
204 //
205 ((wxRegionRefData*)m_refData)->m_hPS = ::GpiCreatePS( vHabmain
206 ,hDC
207 ,&vSize
208 ,PU_PELS | GPIT_MICRO | GPIA_ASSOC
209 );
210 M_REGION = ::GpiCreateRegion( ((wxRegionRefData*)m_refData)->m_hPS
211 ,1
212 ,&vRect
213 );
214 } // end of wxRegion::wxRegion
215
216 //
217 // Destroy the region.
218 //
219 wxRegion::~wxRegion()
220 {
221 } // end of wxRegion::~wxRegion
222
223 wxObjectRefData *wxRegion::CreateData() const
224 {
225 return new wxRegionRefData;
226 }
227
228 wxObjectRefData *wxRegion::CloneData(const wxObjectRefData *data) const
229 {
230 return new wxRegionRefData(*(wxRegionRefData *)data);
231 }
232
233 //-----------------------------------------------------------------------------
234 //# Modify region
235 //-----------------------------------------------------------------------------
236
237 bool wxRegion::Offset(
238 wxCoord x
239 , wxCoord y
240 )
241 {
242 if ( !x && !y )
243 {
244 // nothing to do
245 return TRUE;
246 }
247
248 AllocExclusive();
249
250 #if 0
251 if ( ::OffsetRgn(GetHrgn(), x, y) == ERROR )
252 {
253 wxLogLastError(_T("OffsetRgn"));
254
255 return FALSE;
256 }
257 #endif
258 return TRUE;
259 }
260
261 //
262 // Clear current region
263 //
264 void wxRegion::Clear()
265 {
266 UnRef();
267 } // end of wxRegion::Clear
268
269 //
270 // Combine rectangle (x, y, w, h) with this.
271 //
272 bool wxRegion::Combine(
273 wxCoord x
274 , wxCoord y
275 , wxCoord vWidth
276 , wxCoord vHeight
277 , wxRegionOp eOp
278 )
279 {
280 AllocExclusive();
281
282 //
283 // If ref count is 1, that means it's 'ours' anyway so no action.
284 //
285 RECTL vRect;
286
287 vRect.xLeft = x;
288 vRect.xRight = x + vWidth;
289 vRect.yBottom = y;
290 vRect.yTop = y + vHeight;
291
292 HRGN hRgn = ::GpiCreateRegion( ((wxRegionRefData*)m_refData)->m_hPS
293 ,1
294 ,&vRect
295 );
296 LONG lMode = 0L;
297
298 switch (eOp)
299 {
300 case wxRGN_AND:
301 lMode = CRGN_AND;
302 break;
303
304 case wxRGN_OR:
305 lMode = CRGN_OR;
306 break;
307
308 case wxRGN_XOR:
309 lMode = CRGN_XOR;
310 break;
311
312 case wxRGN_DIFF:
313 lMode = CRGN_DIFF;
314 break;
315
316 case wxRGN_COPY:
317 default:
318 lMode = CRGN_COPY;
319 break;
320 }
321 bool bSuccess = ::GpiCombineRegion( ((wxRegionRefData*)m_refData)->m_hPS
322 ,M_REGION
323 ,M_REGION
324 ,hRgn
325 ,lMode
326 );
327 ::GpiDestroyRegion ( ((wxRegionRefData*)m_refData)->m_hPS
328 ,hRgn
329 );
330
331 return bSuccess;
332 } // end of wxRegion::Combine
333
334 //
335 // Union region with this.
336 //
337 bool wxRegion::Combine(
338 const wxRegion& rRegion
339 , wxRegionOp eOp
340 )
341 {
342 if (rRegion.Empty())
343 return FALSE;
344
345 AllocExclusive();
346
347 LONG lMode = 0;
348
349 switch (eOp)
350 {
351 case wxRGN_AND:
352 lMode = CRGN_AND;
353 break;
354
355 case wxRGN_OR:
356 lMode = CRGN_OR;
357 break;
358
359 case wxRGN_XOR:
360 lMode = CRGN_XOR;
361 break;
362
363 case wxRGN_DIFF:
364 lMode = CRGN_DIFF;
365 break;
366
367 case wxRGN_COPY:
368 default:
369 lMode = CRGN_COPY;
370 break;
371 }
372 return (::GpiCombineRegion( ((wxRegionRefData*)rRegion.m_refData)->m_hPS
373 ,M_REGION
374 ,M_REGION
375 ,((wxRegionRefData*)rRegion.m_refData)->m_hRegion
376 ,lMode
377 ) != RGN_ERROR);
378 } // end of wxRegion::Combine
379
380 bool wxRegion::Combine(
381 const wxRect& rRect
382 , wxRegionOp eOp
383 )
384 {
385 return Combine( rRect.GetLeft()
386 ,rRect.GetTop()
387 ,rRect.GetWidth()
388 ,rRect.GetHeight()
389 ,eOp
390 );
391 } // end of wxRegion::Combine
392
393 //-----------------------------------------------------------------------------
394 //# Information on region
395 //-----------------------------------------------------------------------------
396
397 //
398 // Outer bounds of region
399 //
400 void wxRegion::GetBox(
401 wxCoord& x
402 , wxCoord& y
403 , wxCoord& vWidth
404 , wxCoord& vHeight
405 ) const
406 {
407 if (m_refData)
408 {
409 RECTL vRect;
410 APIRET rc;
411
412 rc = ::GpiQueryRegionBox( ((wxRegionRefData*)m_refData)->m_hPS
413 ,M_REGION
414 ,&vRect
415 );
416 x = vRect.xLeft;
417 y = vRect.yBottom;
418 vWidth = vRect.xRight - vRect.xLeft;
419 vHeight = vRect.yTop - vRect.yBottom;
420 }
421 else
422 {
423 x = y = vWidth = vHeight = 0L;
424 }
425 } // end of wxRegion::GetBox
426
427 wxRect wxRegion::GetBox() const
428 {
429 wxCoord x, y, w, h;
430 GetBox(x, y, w, h);
431 return wxRect(x, y, w, h);
432 }
433
434 //
435 // Is region empty?
436 //
437 bool wxRegion::Empty() const
438 {
439 wxCoord x;
440 wxCoord y;
441 wxCoord vWidth;
442 wxCoord vHeight;
443
444 if (M_REGION == 0)
445 return TRUE;
446
447 GetBox( x
448 ,y
449 ,vWidth
450 ,vHeight
451 );
452 return ((vWidth == 0) && (vHeight == 0));
453 } // end of wxRegion::Empty
454
455 //-----------------------------------------------------------------------------
456 // Tests
457 //-----------------------------------------------------------------------------
458
459 //
460 // Does the region contain the point (x,y)?
461 wxRegionContain wxRegion::Contains(
462 wxCoord x
463 , wxCoord y
464 ) const
465 {
466 bool bOK = FALSE;
467 POINTL vPoint;
468
469 vPoint.x = x;
470 vPoint.y = y;
471
472 if (!m_refData)
473 return wxOutRegion;
474
475 LONG lInside = ::GpiPtInRegion( ((wxRegionRefData*)m_refData)->m_hPS
476 ,M_REGION
477 ,&vPoint
478 );
479 if (lInside == PRGN_INSIDE)
480 return wxInRegion;
481 return wxOutRegion;
482 } // end of wxRegion::Contains
483
484 //
485 // Does the region contain the point pt?
486 //
487 wxRegionContain wxRegion::Contains(
488 const wxPoint& rPoint
489 ) const
490 {
491 POINTL vPoint = { rPoint.x, rPoint.y };
492
493 if (!m_refData)
494 return wxOutRegion;
495
496 LONG lInside = ::GpiPtInRegion( ((wxRegionRefData*)m_refData)->m_hPS
497 ,M_REGION
498 ,&vPoint
499 );
500 if (lInside == PRGN_INSIDE)
501 return wxInRegion;
502 else
503 return wxOutRegion;
504 } // end of wxRegion::Contains
505
506 //
507 // Does the region contain the rectangle (x, y, w, h)?
508 //
509 wxRegionContain wxRegion::Contains(
510 wxCoord x
511 , wxCoord y
512 , wxCoord vWidth
513 , wxCoord vHeight
514 ) const
515 {
516 RECTL vRect;
517
518 if (!m_refData)
519 return wxOutRegion;
520
521 vRect.xLeft = x;
522 vRect.yTop = y;
523 vRect.xRight = x + vWidth;
524 vRect.yBottom = y + vHeight;
525
526 if (PRGN_INSIDE == ::GpiRectInRegion( ((wxRegionRefData*)m_refData)->m_hPS
527 ,M_REGION
528 ,&vRect
529 ))
530 return wxInRegion;
531 else
532 return wxOutRegion;
533 } // end of wxRegion::Contains
534
535 //
536 // Does the region contain the rectangle rect
537 //
538 wxRegionContain wxRegion::Contains(
539 const wxRect& rRect
540 ) const
541 {
542 if (!m_refData)
543 return wxOutRegion;
544
545 wxCoord x;
546 wxCoord y;
547 wxCoord vWidth;
548 wxCoord vHeight;
549
550 x = rRect.x;
551 y = rRect.y;
552 vWidth = rRect.GetWidth();
553 vHeight = rRect.GetHeight();
554 return Contains( x
555 ,y
556 ,vWidth
557 ,vHeight
558 );
559 } // end of wxRegion::Contains
560
561 //
562 // Get internal region handle
563 //
564 WXHRGN wxRegion::GetHRGN() const
565 {
566 if (!m_refData)
567 return (WXHRGN) 0;
568 return (WXHRGN) M_REGION;
569 }
570
571 //
572 // Set a new PS, this means we have to recreate the old region in the new
573 // PS
574 //
575 void wxRegion::SetPS(
576 HPS hPS
577 )
578 {
579 RGNRECT vRgnData;
580 PRECTL pRect = NULL;
581
582 if (::GpiQueryRegionRects( ((wxRegionRefData*)m_refData)->m_hPS
583 ,((wxRegionRefData*)m_refData)->m_hRegion
584 ,NULL
585 ,&vRgnData
586 ,NULL
587 ))
588 {
589 pRect = new RECTL[vRgnData.crcReturned];
590 vRgnData.crc = vRgnData.crcReturned;
591 vRgnData.ircStart = 1;
592 if (::GpiQueryRegionRects( ((wxRegionRefData*)m_refData)->m_hPS
593 ,((wxRegionRefData*)m_refData)->m_hRegion
594 ,NULL
595 ,&vRgnData
596 ,pRect
597 ))
598 {
599 //
600 // First destroy the region out of the old PS
601 // and then create it in the new and set the new to current
602 //
603 ::GpiDestroyRegion( ((wxRegionRefData*)m_refData)->m_hPS
604 ,M_REGION
605 );
606 ((wxRegionRefData*)m_refData)->m_hRegion = ::GpiCreateRegion( hPS
607 ,vRgnData.crcReturned
608 ,pRect
609 );
610 ((wxRegionRefData*)m_refData)->m_hPS = hPS;
611 }
612 delete [] pRect;
613 }
614 } // end of wxRegion::SetPS
615
616 ///////////////////////////////////////////////////////////////////////////////
617 // //
618 // wxRegionIterator //
619 // //
620 ///////////////////////////////////////////////////////////////////////////////
621
622 //
623 // Initialize empty iterator
624 //
625 wxRegionIterator::wxRegionIterator()
626 : m_lCurrent(0)
627 , m_lNumRects(0)
628 , m_pRects(NULL)
629 {
630 } // end of wxRegionIterator::wxRegionIterator
631
632 wxRegionIterator::~wxRegionIterator()
633 {
634 if (m_pRects)
635 delete[] m_pRects;
636 } // end of wxRegionIterator::~wxRegionIterator
637
638 //
639 // Initialize iterator for region
640 //
641 wxRegionIterator::wxRegionIterator(
642 const wxRegion& rRegion
643 )
644 {
645 m_pRects = NULL;
646 Reset(rRegion);
647 } // end of wxRegionIterator::wxRegionIterator
648
649 //
650 // Reset iterator for a new /e region.
651 //
652 void wxRegionIterator::Reset(
653 const wxRegion& rRegion
654 )
655 {
656 m_lCurrent = 0;
657 m_vRegion = rRegion;
658
659 if (m_pRects)
660 delete[] m_pRects;
661
662 m_pRects = NULL;
663
664 if (m_vRegion.Empty())
665 m_lNumRects = 0;
666 else
667 {
668 RGNRECT vRgnData;
669 PRECTL pRect;
670
671 if (::GpiQueryRegionRects( ((wxRegionRefData*)rRegion.m_refData)->m_hPS // Pres space
672 ,((wxRegionRefData*)rRegion.m_refData)->m_hRegion // Handle of region to query
673 ,NULL // Return all RECTs
674 ,&vRgnData // Will contain number or RECTs in region
675 ,NULL // NULL to return number of RECTs
676 ))
677 {
678 pRect = new RECTL[vRgnData.crcReturned];
679 m_pRects = new wxRect[vRgnData.crcReturned];
680 vRgnData.crc = vRgnData.crcReturned;
681 m_lNumRects = vRgnData.crcReturned;
682 vRgnData.ircStart = 1;
683 if (::GpiQueryRegionRects( ((wxRegionRefData*)rRegion.m_refData)->m_hPS // Pres space of source
684 ,((wxRegionRefData*)rRegion.m_refData)->m_hRegion // Handle of source region
685 ,NULL // Return all RECTs
686 ,&vRgnData // Operations set to return rects
687 ,pRect // Will contain the actual RECTS
688 ))
689 {
690 M_REGION = ::GpiCreateRegion( ((wxRegionRefData*)rRegion.m_refData)->m_hPS
691 ,vRgnData.crcReturned
692 ,pRect
693 );
694 for( LONG i = 0; i < m_lNumRects; i++)
695 {
696 m_pRects[i].x = pRect[i].xLeft;
697 m_pRects[i].width = pRect[i].xRight - pRect[i].xLeft;
698 m_pRects[i].y = pRect[i].yBottom;
699 m_pRects[i].height = pRect[i].yTop - pRect[i].yBottom;
700 }
701 ((wxRegionRefData*)m_refData)->m_hPS = ((wxRegionRefData*)rRegion.m_refData)->m_hPS;
702 }
703 }
704 }
705 } // end of wxRegionIterator::Reset
706
707 //
708 // Increment iterator. The rectangle returned is the one after the
709 // incrementation.
710 //
711 void wxRegionIterator::operator++ ()
712 {
713 if (m_lCurrent < m_lNumRects)
714 ++m_lCurrent;
715 } // end of wxRegionIterator::operator ++
716
717 //
718 // Increment iterator. The rectangle returned is the one before the
719 // incrementation.
720 //
721 void wxRegionIterator::operator++ (int)
722 {
723 if (m_lCurrent < m_lNumRects)
724 ++m_lCurrent;
725 } // end of wxRegionIterator::operator++
726
727 wxCoord wxRegionIterator::GetX() const
728 {
729 if (m_lCurrent < m_lNumRects)
730 return m_pRects[m_lCurrent].x;
731 return 0L;
732 } // end of wxRegionIterator::GetX
733
734 wxCoord wxRegionIterator::GetY() const
735 {
736 if (m_lCurrent < m_lNumRects)
737 return m_pRects[m_lCurrent].y;
738 return 0L;
739 } // end of wxRegionIterator::GetY
740
741 wxCoord wxRegionIterator::GetW() const
742 {
743 if (m_lCurrent < m_lNumRects)
744 return m_pRects[m_lCurrent].width ;
745 return 0L;
746 } // end of wxRegionIterator::GetW
747
748 wxCoord wxRegionIterator::GetH() const
749 {
750 if (m_lCurrent < m_lNumRects)
751 return m_pRects[m_lCurrent].height;
752 return 0L;
753 } // end of wxRegionIterator::GetH
754