///////////////////////////////////////////////////////////////////////////////
// Name:        wx/msw/uxtheme.h
// Purpose:     wxUxThemeEngine class: support for XP themes
// Author:      John Platts, Vadim Zeitlin
// Created:     2003
// Copyright:   (c) 2003 John Platts, Vadim Zeitlin
// Licence:     wxWindows licence
///////////////////////////////////////////////////////////////////////////////

#ifndef _WX_UXTHEME_H_
#define _WX_UXTHEME_H_

#include "wx/defs.h"

#include "wx/msw/private.h"     // we use GetHwndOf()
#include <uxtheme.h>

#if defined(DTPB_WINDOWDC)
// DTPB_WINDOWDC has been added for Vista so it's save to assume that an SDK
// including it has vssym32.h available
#define HAVE_VSSYM32
#endif

#if defined(HAVE_VSSYM32)
#include <vssym32.h>
#else
#include <tmschema.h>
#endif

// ----------------------------------------------------------------------------
// Definitions for legacy Windows SDKs
// ----------------------------------------------------------------------------
// Some definitions introduced with Windows Vista might be missing in older SDKs
// Missing definitions are added here for compatibility

#ifndef VSCLASS_LISTVIEW
#define LISS_NORMAL 1
#define LISS_HOT 2
#define LISS_SELECTED 3
#define LISS_DISABLED 4
#define LISS_SELECTEDNOTFOCUS 5
#define LISS_HOTSELECTED 6
#endif

#ifndef DTT_TEXTCOLOR
#define DTT_TEXTCOLOR       (1UL << 0)      // crText has been specified
#define DTT_STATEID         (1UL << 8)      // IStateId has been specified

// DTTOPTS and the associated callback type are only defined by the SDK headers
// when targeting Vista or later, but we still use the type (e.g. with
// DrawThemeTextEx() loaded dynamically) when building for XP, so define it here.
typedef int (WINAPI * DTT_CALLBACK_PROC)(HDC hdc, LPWSTR pszText, int cchText,
                                         LPRECT prc, UINT dwFlags,
                                         LPARAM lParam);

typedef struct _DTTOPTS
{
    DWORD             dwSize;
    DWORD             dwFlags;
    COLORREF          crText;
    COLORREF          crBorder;
    COLORREF          crShadow;
    int               iTextShadowType;
    POINT             ptShadowOffset;
    int               iBorderSize;
    int               iFontPropId;
    int               iColorPropId;
    int               iStateId;
    BOOL              fApplyOverlay;
    int               iGlowSize;
    DTT_CALLBACK_PROC pfnDrawTextCallback;
    LPARAM            lParam;
} DTTOPTS, *PDTTOPTS;
#endif

#ifndef DSS_HIDEPREFIX
#define DSS_HIDEPREFIX  0x0200
#define DSS_PREFIXONLY  0x0400
#endif

#ifndef TMT_FONT
#define TMT_FONT    210
#endif

#ifndef HAVE_VSSYM32
enum EXPANDOBUTTONSTATES {
    TDLGEBS_NORMAL = 1,
    TDLGEBS_HOVER = 2,
    TDLGEBS_PRESSED = 3,
    TDLGEBS_EXPANDEDNORMAL = 4,
    TDLGEBS_EXPANDEDHOVER = 5,
    TDLGEBS_EXPANDEDPRESSED = 6,
    TDLGEBS_NORMALDISABLED = 7,
    TDLGEBS_EXPANDEDDISABLED = 8,
};

enum TASKDIALOGPARTS {
    TDLG_PRIMARYPANEL = 1,
    TDLG_MAININSTRUCTIONPANE = 2,
    TDLG_MAINICON = 3,
    TDLG_CONTENTPANE = 4,
    TDLG_CONTENTICON = 5,
    TDLG_EXPANDEDCONTENT = 6,
    TDLG_COMMANDLINKPANE = 7,
    TDLG_SECONDARYPANEL = 8,
    TDLG_CONTROLPANE = 9,
    TDLG_BUTTONSECTION = 10,
    TDLG_BUTTONWRAPPER = 11,
    TDLG_EXPANDOTEXT = 12,
    TDLG_EXPANDOBUTTON = 13,
    TDLG_VERIFICATIONTEXT = 14,
    TDLG_FOOTNOTEPANE = 15,
    TDLG_FOOTNOTEAREA = 16,
    TDLG_FOOTNOTESEPARATOR = 17,
    TDLG_EXPANDEDFOOTERAREA = 18,
    TDLG_PROGRESSBAR = 19,
    TDLG_IMAGEALIGNMENT = 20,
    TDLG_RADIOBUTTONPANE = 21,
};

#define CP_BACKGROUND 2
#define CP_TRANSPARENTBACKGROUND 3
#define CP_BORDER 4
#define CP_READONLY 5
#define CP_DROPDOWNBUTTONRIGHT 6
#define CP_DROPDOWNBUTTONLEFT 7
#define CP_CUEBANNER 8

#define RP_BACKGROUND 6
#define RP_SPLITTER 7
#define RP_SPLITTERVERT 8

enum BORDERSTATES {
    CBB_NORMAL = 1,
    CBB_HOT = 2,
    CBB_FOCUSED = 3,
    CBB_DISABLED = 4,
};

// The MENUPARTS enum is defined in MSVS 2005 SDK, even though it doesn't have
// vssym32.h, but it doesn't define the constants we use, so still define them,
// but make the enum unnamed for compatibility.
enum /* MENUPARTS -- FIXME-VC8: uncomment this when support for it is dropped */
{
    MENU_MENUITEM_TMSCHEMA = 1,
    MENU_SEPARATOR_TMSCHEMA = 6,
    MENU_BARITEM = 8,
    MENU_POPUPBACKGROUND = 9,
    MENU_POPUPBORDERS = 10,
    MENU_POPUPCHECK = 11,
    MENU_POPUPCHECKBACKGROUND = 12,
    MENU_POPUPGUTTER = 13,
    MENU_POPUPITEM = 14,
    MENU_POPUPSEPARATOR = 15,
    MENU_POPUPSUBMENU = 16,
};

enum POPUPITEMSTATES
{
    MPI_NORMAL = 1,
    MPI_HOT = 2,
    MPI_DISABLED = 3,
    MPI_DISABLEDHOT = 4,
};

enum POPUPCHECKBACKGROUNDSTATES
{
    MCB_DISABLED = 1,
    MCB_NORMAL = 2,
    MCB_BITMAP = 3,
};

enum POPUPCHECKSTATES
{
    MC_CHECKMARKNORMAL = 1,
    MC_CHECKMARKDISABLED = 2,
    MC_BULLETNORMAL = 3,
    MC_BULLETDISABLED = 4,
};

#endif

// ----------------------------------------------------------------------------
// End definitions for legacy Windows SDKs
// ----------------------------------------------------------------------------

WXDLLIMPEXP_CORE bool wxUxThemeIsActive();

// Wrapper for DrawThemeTextEx() taking the same arguments as it.
//
// This function only appeared in Vista and, more importantly, can't be even
// statically imported without breaking loading of the application under XP, so
// it is always loaded dynamically. If it's not available, i.e. when running
// under XP, this wrapper falls back to the simpler DrawThemeText() which
// doesn't support the extended options: notably the text colour possibly
// specified in DTTOPTS is not honoured there, but this is the best we can do.
WXDLLIMPEXP_CORE HRESULT
wxDrawThemeTextEx(HTHEME hTheme, HDC hdc, int iPartId, int iStateId,
                  const wchar_t* pszText, int cchText, DWORD dwTextFlags,
                  RECT* pRect, const DTTOPTS* pOptions);

// ----------------------------------------------------------------------------
// wxUxThemeHandle: encapsulates ::Open/CloseThemeData()
// ----------------------------------------------------------------------------

class WXDLLIMPEXP_CORE wxUxThemeHandle
{
public:
    // For all factory functions, HWND doesn't need to be valid and may be
    // entirely omitted when using NewAtStdDPI(). However DPI must be valid if
    // it's specified, i.e. NewForStdDPI() can be used if the DPI doesn't
    // matter at all (which is the case if the theme is only used to query some
    // colours, for example), but otherwise (e.g. when using the theme to get
    // any metrics) the actual DPI of the window must be passed to NewForDPI().
    static wxUxThemeHandle
    NewAtDPI(HWND hwnd,
             const wchar_t *classes,
             const wchar_t *classesDark,
             int dpi)
    {
        return wxUxThemeHandle(hwnd, classes, classesDark, dpi);
    }

    static wxUxThemeHandle
    NewAtDPI(HWND hwnd,
             const wchar_t *classes,
             int dpi)
    {
        return NewAtDPI(hwnd, classes, nullptr, dpi);
    }

    static wxUxThemeHandle
    NewAtStdDPI(HWND hwnd,
                const wchar_t *classes,
                const wchar_t *classesDark = nullptr)
    {
        return NewAtDPI(hwnd, classes, classesDark, STD_DPI);
    }

    static wxUxThemeHandle
    NewAtStdDPI(const wchar_t *classes,
                const wchar_t *classesDark = nullptr)
    {
        return NewAtStdDPI(0, classes, classesDark);
    }

    // Default ctor, use move assignment to really initialize this object later.
    wxUxThemeHandle() = default;

    // wxWindow pointer here must be valid and its DPI is always used.
    // If classesDark is non-nullptr and the dark mode is active, it's used
    // instead of classes.
    //
    // Prefer using factory functions above instead of this ctor for clarity.
    wxUxThemeHandle(const wxWindowMSW* win,
                    const wchar_t* classes,
                    const wchar_t* classesDark = nullptr);

    wxUxThemeHandle(wxUxThemeHandle&& other)
        : m_hTheme{other.m_hTheme}
    {
        other.m_hTheme = 0;
    }

    wxUxThemeHandle& operator=(wxUxThemeHandle&& other)
    {
        Free();
        m_hTheme = other.m_hTheme;
        other.m_hTheme = 0;

        return *this;
    }

    operator HTHEME() const { return m_hTheme; }

    ~wxUxThemeHandle()
    {
        Free();
    }

    // Return the colour for the given part, property and state.
    //
    // Note that the order of arguments here is _not_ the same as for
    // GetThemeColor() because we want to default the state.
    wxColour GetColour(int part, int prop, int state = 0) const;

    // Return the size of a theme element, either "as is" (TS_TRUE size) or as
    // it would be used for drawing (TS_DRAW size).
    //
    // For now we don't allow specifying the rectangle as it doesn't seem to be
    // useful.
    wxSize GetTrueSize(int part, int state = 0, HDC hdc = 0) const
    {
        return DoGetSize(hdc, part, state, TS_TRUE);
    }

    wxSize GetDrawSize(int part, int state = 0, HDC hdc = 0) const
    {
        return DoGetSize(hdc, part, state, TS_DRAW);
    }

    // Get the margins of a theme element in the output parameter.
    //
    // The output parameter is not modified if the function fails, so it can be
    // initialized with some default values before calling this function.
    bool
    GetMargins(MARGINS& margins,
               int part, int prop, int state = 0, HDC hdc = 0) const;

    // Get the font of a theme element.
    bool GetFont(LOGFONTW& lf, HDC hdc, int part, int state = 0) const;


    // Draw theme background: if the caller already has a RECT, it can be
    // provided directly, otherwise wxRect is converted to it.
    void DrawBackground(HDC hdc, const RECT& rc, int part, int state = 0,
                        const RECT* rcClip = nullptr);
    void DrawBackground(HDC hdc, const wxRect& rect, int part, int state = 0);

private:
    static const int STD_DPI = 96;

    static HTHEME
    DoOpenThemeData(HWND hwnd,
                    const wchar_t *classes,
                    const wchar_t *classesDark,
                    int dpi);

    wxUxThemeHandle(HWND hwnd,
                    const wchar_t *classes,
                    const wchar_t* classesDark,
                    int dpi)
        : m_hTheme{DoOpenThemeData(hwnd, classes, classesDark, dpi)}
    {
    }

    void Free()
    {
        if ( m_hTheme )
        {
            ::CloseThemeData(m_hTheme);
        }
    }

    wxSize DoGetSize(HDC hdc, int part, int state, THEMESIZE ts) const;


    HTHEME m_hTheme = 0;

    wxDECLARE_NO_COPY_CLASS(wxUxThemeHandle);
};

#endif // _WX_UXTHEME_H_

