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