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