]> git.saurik.com Git - wxWidgets.git/blob - src/os2/region.cpp
wxRegion fixes (off by one)
[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 //-----------------------------------------------------------------------------
224 //# Modify region
225 //-----------------------------------------------------------------------------
226
227 //
228 // Clear current region
229 //
230 void wxRegion::Clear()
231 {
232 UnRef();
233 } // end of wxRegion::Clear
234
235 //
236 // Combine rectangle (x, y, w, h) with this.
237 //
238 bool wxRegion::Combine(
239 wxCoord x
240 , wxCoord y
241 , wxCoord vWidth
242 , wxCoord vHeight
243 , wxRegionOp eOp
244 )
245 {
246 //
247 // Don't change shared data
248 //
249 if (!m_refData)
250 {
251 m_refData = new wxRegionRefData();
252 }
253 else if (m_refData->GetRefCount() > 1)
254 {
255 wxRegionRefData* pRef = (wxRegionRefData*)m_refData;
256
257 UnRef();
258 m_refData = new wxRegionRefData(*pRef);
259 }
260
261 //
262 // If ref count is 1, that means it's 'ours' anyway so no action.
263 //
264 RECTL vRect;
265
266 vRect.xLeft = x;
267 vRect.xRight = x + vWidth;
268 vRect.yBottom = y;
269 vRect.yTop = y + vHeight;
270
271 HRGN hRgn = ::GpiCreateRegion( ((wxRegionRefData*)m_refData)->m_hPS
272 ,1
273 ,&vRect
274 );
275 LONG lMode = 0L;
276
277 switch (eOp)
278 {
279 case wxRGN_AND:
280 lMode = CRGN_AND;
281 break;
282
283 case wxRGN_OR:
284 lMode = CRGN_OR;
285 break;
286
287 case wxRGN_XOR:
288 lMode = CRGN_XOR;
289 break;
290
291 case wxRGN_DIFF:
292 lMode = CRGN_DIFF;
293 break;
294
295 case wxRGN_COPY:
296 default:
297 lMode = CRGN_COPY;
298 break;
299 }
300 bool bSuccess = ::GpiCombineRegion( ((wxRegionRefData*)m_refData)->m_hPS
301 ,M_REGION
302 ,M_REGION
303 ,hRgn
304 ,lMode
305 );
306 ::GpiDestroyRegion ( ((wxRegionRefData*)m_refData)->m_hPS
307 ,hRgn
308 );
309
310 return bSuccess;
311 } // end of wxRegion::Combine
312
313 //
314 // Union region with this.
315 //
316 bool wxRegion::Combine(
317 const wxRegion& rRegion
318 , wxRegionOp eOp
319 )
320 {
321 if (rRegion.Empty())
322 return FALSE;
323
324 //
325 // Don't change shared data
326 //
327 if (!m_refData)
328 {
329 m_refData = new wxRegionRefData();
330 }
331 else if (m_refData->GetRefCount() > 1)
332 {
333 wxRegionRefData* pRef = (wxRegionRefData*)m_refData;
334
335 UnRef();
336 m_refData = new wxRegionRefData(*pRef);
337 }
338
339 LONG lMode = 0;
340
341 switch (eOp)
342 {
343 case wxRGN_AND:
344 lMode = CRGN_AND;
345 break;
346
347 case wxRGN_OR:
348 lMode = CRGN_OR;
349 break;
350
351 case wxRGN_XOR:
352 lMode = CRGN_XOR;
353 break;
354
355 case wxRGN_DIFF:
356 lMode = CRGN_DIFF;
357 break;
358
359 case wxRGN_COPY:
360 default:
361 lMode = CRGN_COPY;
362 break;
363 }
364 return (::GpiCombineRegion( ((wxRegionRefData*)rRegion.m_refData)->m_hPS
365 ,M_REGION
366 ,M_REGION
367 ,((wxRegionRefData*)rRegion.m_refData)->m_hRegion
368 ,lMode
369 ) != RGN_ERROR);
370 } // end of wxRegion::Combine
371
372 bool wxRegion::Combine(
373 const wxRect& rRect
374 , wxRegionOp eOp
375 )
376 {
377 return Combine( rRect.GetLeft()
378 ,rRect.GetTop()
379 ,rRect.GetWidth()
380 ,rRect.GetHeight()
381 ,eOp
382 );
383 } // end of wxRegion::Combine
384
385 //-----------------------------------------------------------------------------
386 //# Information on region
387 //-----------------------------------------------------------------------------
388
389 //
390 // Outer bounds of region
391 //
392 void wxRegion::GetBox(
393 wxCoord& x
394 , wxCoord& y
395 , wxCoord& vWidth
396 , wxCoord& vHeight
397 ) const
398 {
399 if (m_refData)
400 {
401 RECTL vRect;
402 APIRET rc;
403
404 rc = ::GpiQueryRegionBox( ((wxRegionRefData*)m_refData)->m_hPS
405 ,M_REGION
406 ,&vRect
407 );
408 x = vRect.xLeft;
409 y = vRect.yTop;
410 vWidth = vRect.xRight - vRect.xLeft;
411 vHeight = vRect.yTop - vRect.yBottom;
412 }
413 else
414 {
415 x = y = vWidth = vHeight = 0L;
416 }
417 } // end of wxRegion::GetBox
418
419 wxRect wxRegion::GetBox() const
420 {
421 wxCoord x, y, w, h;
422 GetBox(x, y, w, h);
423 return wxRect(x, y, w, h);
424 }
425
426 //
427 // Is region empty?
428 //
429 bool wxRegion::Empty() const
430 {
431 wxCoord x;
432 wxCoord y;
433 wxCoord vWidth;
434 wxCoord vHeight;
435
436 if (M_REGION == 0)
437 return TRUE;
438
439 GetBox( x
440 ,y
441 ,vWidth
442 ,vHeight
443 );
444 return ((vWidth == 0) && (vHeight == 0));
445 } // end of wxRegion::Empty
446
447 //-----------------------------------------------------------------------------
448 // Tests
449 //-----------------------------------------------------------------------------
450
451 //
452 // Does the region contain the point (x,y)?
453 wxRegionContain wxRegion::Contains(
454 wxCoord x
455 , wxCoord y
456 ) const
457 {
458 bool bOK = FALSE;
459 POINTL vPoint;
460
461 vPoint.x = x;
462 vPoint.y = y;
463
464 if (!m_refData)
465 return wxOutRegion;
466
467 LONG lInside = ::GpiPtInRegion( ((wxRegionRefData*)m_refData)->m_hPS
468 ,M_REGION
469 ,&vPoint
470 );
471 if (lInside == PRGN_INSIDE)
472 return wxInRegion;
473 return wxOutRegion;
474 } // end of wxRegion::Contains
475
476 //
477 // Does the region contain the point pt?
478 //
479 wxRegionContain wxRegion::Contains(
480 const wxPoint& rPoint
481 ) const
482 {
483 POINTL vPoint = { rPoint.x, rPoint.y };
484
485 if (!m_refData)
486 return wxOutRegion;
487
488 LONG lInside = ::GpiPtInRegion( ((wxRegionRefData*)m_refData)->m_hPS
489 ,M_REGION
490 ,&vPoint
491 );
492 if (lInside == PRGN_INSIDE)
493 return wxInRegion;
494 else
495 return wxOutRegion;
496 } // end of wxRegion::Contains
497
498 //
499 // Does the region contain the rectangle (x, y, w, h)?
500 //
501 wxRegionContain wxRegion::Contains(
502 wxCoord x
503 , wxCoord y
504 , wxCoord vWidth
505 , wxCoord vHeight
506 ) const
507 {
508 RECTL vRect;
509
510 if (!m_refData)
511 return wxOutRegion;
512
513 vRect.xLeft = x;
514 vRect.yTop = y;
515 vRect.xRight = x + vWidth;
516 vRect.yBottom = y + vHeight;
517
518 if (PRGN_INSIDE == ::GpiRectInRegion( ((wxRegionRefData*)m_refData)->m_hPS
519 ,M_REGION
520 ,&vRect
521 ))
522 return wxInRegion;
523 else
524 return wxOutRegion;
525 } // end of wxRegion::Contains
526
527 //
528 // Does the region contain the rectangle rect
529 //
530 wxRegionContain wxRegion::Contains(
531 const wxRect& rRect
532 ) const
533 {
534 if (!m_refData)
535 return wxOutRegion;
536
537 wxCoord x;
538 wxCoord y;
539 wxCoord vWidth;
540 wxCoord vHeight;
541
542 x = rRect.x;
543 y = rRect.y;
544 vWidth = rRect.GetWidth();
545 vHeight = rRect.GetHeight();
546 return Contains( x
547 ,y
548 ,vWidth
549 ,vHeight
550 );
551 } // end of wxRegion::Contains
552
553 //
554 // Get internal region handle
555 //
556 WXHRGN wxRegion::GetHRGN() const
557 {
558 if (!m_refData)
559 return (WXHRGN) 0;
560 return (WXHRGN) M_REGION;
561 }
562
563 //
564 // Set a new PS, this means we have to recreate the old region in the new
565 // PS
566 //
567 void wxRegion::SetPS(
568 HPS hPS
569 )
570 {
571 RGNRECT vRgnData;
572 PRECTL pRect = NULL;
573
574 if (::GpiQueryRegionRects( ((wxRegionRefData*)m_refData)->m_hPS
575 ,((wxRegionRefData*)m_refData)->m_hRegion
576 ,NULL
577 ,&vRgnData
578 ,NULL
579 ))
580 {
581 pRect = new RECTL[vRgnData.crcReturned];
582 vRgnData.crc = vRgnData.crcReturned;
583 vRgnData.ircStart = 1;
584 if (::GpiQueryRegionRects( ((wxRegionRefData*)m_refData)->m_hPS
585 ,((wxRegionRefData*)m_refData)->m_hRegion
586 ,NULL
587 ,&vRgnData
588 ,pRect
589 ))
590 {
591 //
592 // First destroy the region out of the old PS
593 // and then create it in the new and set the new to current
594 //
595 ::GpiDestroyRegion( ((wxRegionRefData*)m_refData)->m_hPS
596 ,M_REGION
597 );
598 ((wxRegionRefData*)m_refData)->m_hRegion = ::GpiCreateRegion( hPS
599 ,vRgnData.crcReturned
600 ,pRect
601 );
602 ((wxRegionRefData*)m_refData)->m_hPS = hPS;
603 }
604 delete [] pRect;
605 }
606 } // end of wxRegion::SetPS
607
608 ///////////////////////////////////////////////////////////////////////////////
609 // //
610 // wxRegionIterator //
611 // //
612 ///////////////////////////////////////////////////////////////////////////////
613
614 //
615 // Initialize empty iterator
616 //
617 wxRegionIterator::wxRegionIterator()
618 : m_lCurrent(0)
619 , m_lNumRects(0)
620 , m_pRects(NULL)
621 {
622 } // end of wxRegionIterator::wxRegionIterator
623
624 wxRegionIterator::~wxRegionIterator()
625 {
626 if (m_pRects)
627 delete[] m_pRects;
628 } // end of wxRegionIterator::~wxRegionIterator
629
630 //
631 // Initialize iterator for region
632 //
633 wxRegionIterator::wxRegionIterator(
634 const wxRegion& rRegion
635 )
636 {
637 m_pRects = NULL;
638 Reset(rRegion);
639 } // end of wxRegionIterator::wxRegionIterator
640
641 //
642 // Reset iterator for a new /e region.
643 //
644 void wxRegionIterator::Reset(
645 const wxRegion& rRegion
646 )
647 {
648 m_lCurrent = 0;
649 m_vRegion = rRegion;
650
651 if (m_pRects)
652 delete[] m_pRects;
653
654 m_pRects = NULL;
655
656 if (m_vRegion.Empty())
657 m_lNumRects = 0;
658 else
659 {
660 RGNRECT vRgnData;
661 PRECTL pRect;
662
663 if (::GpiQueryRegionRects( ((wxRegionRefData*)rRegion.m_refData)->m_hPS // Pres space
664 ,((wxRegionRefData*)rRegion.m_refData)->m_hRegion // Handle of region to query
665 ,NULL // Return all RECTs
666 ,&vRgnData // Will contain number or RECTs in region
667 ,NULL // NULL to return number of RECTs
668 ))
669 {
670 pRect = new RECTL[vRgnData.crcReturned];
671 m_pRects = new wxRect[vRgnData.crcReturned];
672 vRgnData.crc = vRgnData.crcReturned;
673 m_lNumRects = vRgnData.crcReturned;
674 vRgnData.ircStart = 1;
675 if (::GpiQueryRegionRects( ((wxRegionRefData*)rRegion.m_refData)->m_hPS // Pres space of source
676 ,((wxRegionRefData*)rRegion.m_refData)->m_hRegion // Handle of source region
677 ,NULL // Return all RECTs
678 ,&vRgnData // Operations set to return rects
679 ,pRect // Will contain the actual RECTS
680 ))
681 {
682 M_REGION = ::GpiCreateRegion( ((wxRegionRefData*)rRegion.m_refData)->m_hPS
683 ,vRgnData.crcReturned
684 ,pRect
685 );
686 for( LONG i = 0; i < m_lNumRects; i++)
687 {
688 m_pRects[i].x = pRect[i].xLeft;
689 m_pRects[i].width = pRect[i].xRight - pRect[i].xLeft;
690 m_pRects[i].y = pRect[i].yBottom;
691 m_pRects[i].height = pRect[i].yTop - pRect[i].yBottom;
692 }
693 ((wxRegionRefData*)m_refData)->m_hPS = ((wxRegionRefData*)rRegion.m_refData)->m_hPS;
694 }
695 }
696 }
697 } // end of wxRegionIterator::Reset
698
699 //
700 // Increment iterator. The rectangle returned is the one after the
701 // incrementation.
702 //
703 void wxRegionIterator::operator++ ()
704 {
705 if (m_lCurrent < m_lNumRects)
706 ++m_lCurrent;
707 } // end of wxRegionIterator::operator ++
708
709 //
710 // Increment iterator. The rectangle returned is the one before the
711 // incrementation.
712 //
713 void wxRegionIterator::operator++ (int)
714 {
715 if (m_lCurrent < m_lNumRects)
716 ++m_lCurrent;
717 } // end of wxRegionIterator::operator++
718
719 wxCoord wxRegionIterator::GetX() const
720 {
721 if (m_lCurrent < m_lNumRects)
722 return m_pRects[m_lCurrent].x;
723 return 0L;
724 } // end of wxRegionIterator::GetX
725
726 wxCoord wxRegionIterator::GetY() const
727 {
728 if (m_lCurrent < m_lNumRects)
729 return m_pRects[m_lCurrent].y;
730 return 0L;
731 } // end of wxRegionIterator::GetY
732
733 wxCoord wxRegionIterator::GetW() const
734 {
735 if (m_lCurrent < m_lNumRects)
736 return m_pRects[m_lCurrent].width ;
737 return 0L;
738 } // end of wxRegionIterator::GetW
739
740 wxCoord wxRegionIterator::GetH() const
741 {
742 if (m_lCurrent < m_lNumRects)
743 return m_pRects[m_lCurrent].height;
744 return 0L;
745 } // end of wxRegionIterator::GetH
746