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

// ============================================================================
// declarations
// ============================================================================

// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------

// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"


#ifndef WX_PRECOMP
    #include "wx/app.h"
    #include "wx/toplevel.h"
    #include "wx/string.h"
    #include "wx/log.h"
    #include "wx/module.h"
#endif //WX_PRECOMP

#include "wx/dynlib.h"

#include "wx/msw/uxtheme.h"
#include "wx/msw/private/darkmode.h"

bool wxUxThemeIsActive()
{
    static int s_isActive = -1;
    if ( s_isActive == -1 )
    {
        s_isActive = ::IsAppThemed() && ::IsThemeActive() ? 1 : 0;
    }

    return s_isActive != 0;
}

wxUxThemeHandle::wxUxThemeHandle(const wxWindowMSW* win,
                                 const wchar_t* classes,
                                 const wchar_t* classesDark)
    : m_hTheme{DoOpenThemeData(GetHwndOf(win),
                               classes,
                               classesDark,
                               win->GetDPI().y)}
{
}

/* static */
HTHEME
wxUxThemeHandle::DoOpenThemeData(HWND hwnd,
                                 const wchar_t *classes,
                                 const wchar_t *classesDark,
                                 int dpi)
{
    if ( classesDark && wxMSWDarkMode::IsActive() )
    {
        classes = classesDark;

        // When using dark mode and using dark mode-specific classes we have to
        // use the handle of a control which is *not* in dark mode, and as we
        // don't have any, just use 0.
        hwnd = 0;
    }

    // If DPI is the default one, we can use the old function.
    if ( dpi != STD_DPI )
    {
        // We need to use OpenThemeDataForDpi() which is not available under
        // all supported systems, so try to load it dynamically if not done yet.
        typedef HTHEME (WINAPI *OpenThemeDataForDpi_t)(HWND, LPCWSTR, UINT);
        static OpenThemeDataForDpi_t s_pfnOpenThemeDataForDpi = nullptr;
        static bool s_initDone = false;

        if ( !s_initDone )
        {
            wxLoadedDLL dllUxTheme(wxS("uxtheme.dll"));
            wxDL_INIT_FUNC(s_pfn, OpenThemeDataForDpi, dllUxTheme);
            s_initDone = true;
        }

        if ( s_pfnOpenThemeDataForDpi )
            return s_pfnOpenThemeDataForDpi(hwnd, classes, dpi);
    }

    return ::OpenThemeData(hwnd, classes);
}

wxColour wxUxThemeHandle::GetColour(int part, int prop, int state) const
{
    COLORREF col;

    HRESULT hr = ::GetThemeColor(m_hTheme, part, state, prop, &col);
    if ( FAILED(hr) )
    {
        wxLogApiError(
            wxString::Format("GetThemeColor(%i, %i, %i)", part, state, prop),
            hr
        );
        return wxColour{};
    }

    return wxRGBToColour(col);
}

wxSize
wxUxThemeHandle::DoGetSize(HDC hdc, int part, int state, THEMESIZE ts) const
{
    SIZE size;
    HRESULT hr = ::GetThemePartSize(m_hTheme, hdc, part, state, nullptr, ts,
                                    &size);
    if ( FAILED(hr) )
    {
        wxLogApiError(
            wxString::Format("GetThemePartSize(%i, %i)", part, state),
            hr
        );
        return {};
    }

    return wxSize{size.cx, size.cy};
}

bool
wxUxThemeHandle::GetMargins(MARGINS& margins,
                            int part,
                            int prop,
                            int state,
                            HDC hdc) const
{
    HRESULT hr = ::GetThemeMargins(m_hTheme, hdc, part, state, prop, nullptr,
                                   &margins);
    if ( FAILED(hr) )
    {
        wxLogApiError(
            wxString::Format("GetThemeMargins(%i, %i, %i)", part, state, prop),
            hr
        );
        return false;
    }

    return true;
}

bool
wxUxThemeHandle::GetFont(LOGFONTW& lf, HDC hdc, int part, int state) const
{
    HRESULT hr = ::GetThemeFont(m_hTheme, hdc, part, state, TMT_FONT, &lf);
    if ( FAILED(hr) )
    {
        wxLogApiError(
            wxString::Format("GetThemeFont(%i, %i)", part, state),
            hr
        );
        return false;
    }

    return true;
}

void
wxUxThemeHandle::DrawBackground(HDC hdc,
                                const RECT& rc,
                                int part,
                                int state,
                                const RECT* rcClip)
{
    HRESULT hr = ::DrawThemeBackground(m_hTheme, hdc, part, state, &rc, rcClip);
    if ( FAILED(hr) )
    {
        wxLogApiError(
            wxString::Format("DrawThemeBackground(%i, %i)", part, state),
            hr
        );
    }
}

void
wxUxThemeHandle::DrawBackground(HDC hdc, const wxRect& rect, int part, int state)
{
    RECT rc;
    wxCopyRectToRECT(rect, rc);

    DrawBackground(hdc, rc, part, state);
}
