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