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