/////////////////////////////////////////////////////////////////////////////
// Name:        wx/region.h
// Purpose:     Base header for wxRegion
// Author:      Julian Smart
// Created:
// Copyright:   (c) Julian Smart
// Licence:     wxWindows Licence
/////////////////////////////////////////////////////////////////////////////

#ifndef _WX_REGION_H_BASE_
#define _WX_REGION_H_BASE_

#include "wx/gdiobj.h"
#include "wx/gdicmn.h"

class WXDLLIMPEXP_FWD_CORE wxBitmap;
class WXDLLIMPEXP_FWD_CORE wxColour;
class WXDLLIMPEXP_FWD_CORE wxRegion;

// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------

// result of wxRegion::Contains() call
enum wxRegionContain
{
    wxOutRegion = 0,
    wxPartRegion = 1,
    wxInRegion = 2
};

// these constants are used with wxRegion::Combine() in the ports which have
// this method
enum wxRegionOp
{
    // Creates the intersection of the two combined regions.
    wxRGN_AND,

    // Creates a copy of the region
    wxRGN_COPY,

    // Combines the parts of first region that are not in the second one
    wxRGN_DIFF,

    // Creates the union of two combined regions.
    wxRGN_OR,

    // Creates the union of two regions except for any overlapping areas.
    wxRGN_XOR
};

// ----------------------------------------------------------------------------
// wxRegionBase defines wxRegion API
// ----------------------------------------------------------------------------

class WXDLLIMPEXP_CORE wxRegionBase : public wxGDIObject
{
public:
    // ctors
    // -----

    // none are defined here but the following should be available:
#if 0
    wxRegion();
    wxRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h);
    wxRegion(const wxPoint& topLeft, const wxPoint& bottomRight);
    wxRegion(const wxRect& rect);
    wxRegion(size_t n, const wxPoint *points, wxPolygonFillMode fillStyle = wxODDEVEN_RULE);
    wxRegion(const wxBitmap& bmp);
    wxRegion(const wxBitmap& bmp, const wxColour& transp, int tolerance = 0);
#endif // 0

    // operators
    // ---------

    bool operator==(const wxRegion& region) const { return IsEqual(region); }
    bool operator!=(const wxRegion& region) const { return !(*this == region); }


    // accessors
    // ---------

    // Is region empty?
    virtual bool IsEmpty() const = 0;
    bool Empty() const { return IsEmpty(); }

    // Is region equal (i.e. covers the same area as another one)?
    bool IsEqual(const wxRegion& region) const;

    // Get the bounding box
    bool GetBox(wxCoord& x, wxCoord& y, wxCoord& w, wxCoord& h) const
        { return DoGetBox(x, y, w, h); }
    wxRect GetBox() const
    {
        wxCoord x, y, w, h;
        return DoGetBox(x, y, w, h) ? wxRect(x, y, w, h) : wxRect();
    }

    // Test if the given point or rectangle is inside this region
    wxRegionContain Contains(wxCoord x, wxCoord y) const
        { return DoContainsPoint(x, y); }
    wxRegionContain Contains(const wxPoint& pt) const
        { return DoContainsPoint(pt.x, pt.y); }
    wxRegionContain Contains(wxCoord x, wxCoord y, wxCoord w, wxCoord h) const
        { return DoContainsRect(wxRect(x, y, w, h)); }
    wxRegionContain Contains(const wxRect& rect) const
        { return DoContainsRect(rect); }


    // operations
    // ----------

    virtual void Clear() = 0;

    // Move the region
    bool Offset(wxCoord x, wxCoord y)
        { return DoOffset(x, y); }
    bool Offset(const wxPoint& pt)
        { return DoOffset(pt.x, pt.y); }

    // Union rectangle or region with this region.
    bool Union(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
        { return DoUnionWithRect(wxRect(x, y, w, h)); }
    bool Union(const wxRect& rect)
        { return DoUnionWithRect(rect); }
    bool Union(const wxRegion& region)
        { return DoUnionWithRegion(region); }

#if wxUSE_IMAGE
    // Use the non-transparent pixels of a wxBitmap for the region to combine
    // with this region.  First version takes transparency from bitmap's mask,
    // second lets the user specify the colour to be treated as transparent
    // along with an optional tolerance value.
    // NOTE: implemented in common/rgncmn.cpp
    bool Union(const wxBitmap& bmp);
    bool Union(const wxBitmap& bmp, const wxColour& transp, int tolerance = 0);
#endif // wxUSE_IMAGE

    // Intersect rectangle or region with this one.
    bool Intersect(wxCoord x, wxCoord y, wxCoord w, wxCoord h);
    bool Intersect(const wxRect& rect);
    bool Intersect(const wxRegion& region)
        { return DoIntersect(region); }

    // Subtract rectangle or region from this:
    // Combines the parts of 'this' that are not part of the second region.
    bool Subtract(wxCoord x, wxCoord y, wxCoord w, wxCoord h);
    bool Subtract(const wxRect& rect);
    bool Subtract(const wxRegion& region)
        { return DoSubtract(region); }

    // XOR: the union of two combined regions except for any overlapping areas.
    bool Xor(wxCoord x, wxCoord y, wxCoord w, wxCoord h);
    bool Xor(const wxRect& rect);
    bool Xor(const wxRegion& region)
        { return DoXor(region); }


    // Convert the region to a B&W bitmap with the white pixels being inside
    // the region.
    wxBitmap ConvertToBitmap() const;

protected:
    virtual bool DoIsEqual(const wxRegion& region) const = 0;
    virtual bool DoGetBox(wxCoord& x, wxCoord& y, wxCoord& w, wxCoord& h) const = 0;
    virtual wxRegionContain DoContainsPoint(wxCoord x, wxCoord y) const = 0;
    virtual wxRegionContain DoContainsRect(const wxRect& rect) const = 0;

    virtual bool DoOffset(wxCoord x, wxCoord y) = 0;

    virtual bool DoUnionWithRect(const wxRect& rect) = 0;
    virtual bool DoUnionWithRegion(const wxRegion& region) = 0;

    virtual bool DoIntersect(const wxRegion& region) = 0;
    virtual bool DoSubtract(const wxRegion& region) = 0;
    virtual bool DoXor(const wxRegion& region) = 0;
};

// some ports implement a generic Combine() function while others only
// implement individual wxRegion operations, factor out the common code for the
// ports with Combine() in this class
#if defined(__WXMSW__) || \
    ( defined(__WXMAC__) && wxOSX_USE_COCOA_OR_CARBON )

#define wxHAS_REGION_COMBINE

class WXDLLIMPEXP_CORE wxRegionWithCombine : public wxRegionBase
{
public:
    // these methods are not part of public API as they're not implemented on
    // all ports
    bool Combine(wxCoord x, wxCoord y, wxCoord w, wxCoord h, wxRegionOp op);
    bool Combine(const wxRect& rect, wxRegionOp op);
    bool Combine(const wxRegion& region, wxRegionOp op)
        { return DoCombine(region, op); }


protected:
    // the real Combine() method, to be defined in the derived class
    virtual bool DoCombine(const wxRegion& region, wxRegionOp op) = 0;

    // implement some wxRegionBase pure virtuals in terms of Combine()
    virtual bool DoUnionWithRect(const wxRect& rect) override;
    virtual bool DoUnionWithRegion(const wxRegion& region) override;
    virtual bool DoIntersect(const wxRegion& region) override;
    virtual bool DoSubtract(const wxRegion& region) override;
    virtual bool DoXor(const wxRegion& region) override;
};

#endif // ports with wxRegion::Combine()

#if defined(__WXMSW__)
    #include "wx/msw/region.h"
#elif defined(__WXGTK__)
    #include "wx/gtk/region.h"
#elif defined(__WXX11__)
    #include "wx/x11/region.h"
#elif defined(__WXDFB__)
    #include "wx/dfb/region.h"
#elif defined(__WXMAC__)
    #include "wx/osx/region.h"
#elif defined(__WXQT__)
    #include "wx/qt/region.h"
#endif

// ----------------------------------------------------------------------------
// inline functions implementation
// ----------------------------------------------------------------------------

// NB: these functions couldn't be defined in the class declaration as they use
//     wxRegion and so can be only defined after including the header declaring
//     the real class

inline bool wxRegionBase::Intersect(const wxRect& rect)
{
    return DoIntersect(wxRegion(rect));
}

inline bool wxRegionBase::Subtract(const wxRect& rect)
{
    return DoSubtract(wxRegion(rect));
}

inline bool wxRegionBase::Xor(const wxRect& rect)
{
    return DoXor(wxRegion(rect));
}

// ...and these functions are here because they call the ones above, and its
// not really proper to call an inline function before its defined inline.

inline bool wxRegionBase::Intersect(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
{
    return Intersect(wxRect(x, y, w, h));
}

inline bool wxRegionBase::Subtract(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
{
    return Subtract(wxRect(x, y, w, h));
}

inline bool wxRegionBase::Xor(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
{
    return Xor(wxRect(x, y, w, h));
}

#ifdef wxHAS_REGION_COMBINE

inline bool wxRegionWithCombine::Combine(wxCoord x,
                                         wxCoord y,
                                         wxCoord w,
                                         wxCoord h,
                                         wxRegionOp op)
{
    return DoCombine(wxRegion(x, y, w, h), op);
}

inline bool wxRegionWithCombine::Combine(const wxRect& rect, wxRegionOp op)
{
    return DoCombine(wxRegion(rect), op);
}

#endif // wxHAS_REGION_COMBINE

#endif // _WX_REGION_H_BASE_
