Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/vcl/win/gdi/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 78 kB image not shown  

Quelle  salnativewidgets-luna.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */


// General info:
//   http://msdn.microsoft.com/en-us/library/windows/desktop/hh270423%28v=vs.85%29.aspx
//   http://msdn.microsoft.com/en-us/library/windows/desktop/bb773178%28v=vs.85%29.aspx

// Useful tool to explore the themes & their rendering:
//   http://privat.rejbrand.se/UxExplore.exe
// (found at http://stackoverflow.com/questions/4009701/windows-visual-themes-gallery-of-parts-and-states/4009712#4009712)

// Theme subclasses:
//   http://msdn.microsoft.com/en-us/library/windows/desktop/bb773218%28v=vs.85%29.aspx

// Drawing in non-client area (general DWM-related info):
//   http://msdn.microsoft.com/en-us/library/windows/desktop/bb688195%28v=vs.85%29.aspx

#include <config_features.h>

#include <rtl/ustring.h>

#include <osl/diagnose.h>
#include <osl/module.h>
#include <o3tl/char16_t2wchar_t.hxx>

#include <vcl/svapp.hxx>
#include <vcl/settings.hxx>
#include <vcl/themecolors.hxx>
#include <vcl/skia/skiahelper.hxx>
#include <salinst.hxx>
#include <toolbarvalue.hxx>
#include <menubarvalue.hxx>

#include <win/svsys.h>
#include <win/salgdi.h>
#include <win/saldata.hxx>
#include <win/salframe.h>
#include <win/salinst.h>
#include <win/scoped_gdi.hxx>
#include <win/wingdiimpl.hxx>
#if HAVE_FEATURE_SKIA
#include <skia/win/gdiimpl.hxx>
#endif

#include <uxtheme.h>
#include <vssym32.h>

#include <map>
#include <string>
#include <optional>
#include <ControlCacheKey.hxx>

typedef std::map< std::wstring, HTHEME > ThemeMap;
static ThemeMap aThemeMap;

/*********************************************************
 * Initialize XP theming and local stuff
 *********************************************************/

void SalData::initNWF()
{
    ImplSVData* pSVData = ImplGetSVData();

    // the menu bar and the top docking area should have a common background (gradient)
    pSVData->maNWFData.mbMenuBarDockingAreaCommonBG = true;
}

// *********************************************************
// * Release theming handles
// ********************************************************
void SalData::deInitNWF()
{
    forauto& rEntry : aThemeMap )
        CloseThemeData(rEntry.second);
    aThemeMap.clear();
}

static HTHEME getThemeHandle(HWND hWnd, LPCWSTR name, WinSalGraphicsImplBase* pGraphicsImpl)
{
    if( GetSalData()->mbThemeChanged )
    {
        // throw away invalid theme handles
        SalData::deInitNWF();
        // throw away native control cache
        pGraphicsImpl->ClearNativeControlCache();
        GetSalData()->mbThemeChanged = false;
    }

    ThemeMap::iterator iter;
    if( (iter = aThemeMap.find( name )) != aThemeMap.end() )
        return iter->second;
    // theme not found -> add it to map
    HTHEME hTheme = OpenThemeData( hWnd, name );
    if( hTheme != nullptr )
        aThemeMap[name] = hTheme;
    return hTheme;
}

bool WinSalGraphics::isNativeControlSupported( ControlType nType, ControlPart nPart )
{
    HTHEME hTheme = nullptr;

    switch( nType )
    {
        case ControlType::Pushbutton:
        case ControlType::Radiobutton:
        case ControlType::Checkbox:
            if( nPart == ControlPart::Entire )
                hTheme = getThemeHandle(mhWnd, L"Button", mWinSalGraphicsImplBase);
            break;
        case ControlType::Scrollbar:
            if( nPart == ControlPart::DrawBackgroundHorz || nPart == ControlPart::DrawBackgroundVert )
                return false;   // no background painting needed
            if( nPart == ControlPart::Entire )
                hTheme = getThemeHandle(mhWnd, L"Scrollbar", mWinSalGraphicsImplBase);
            break;
        case ControlType::Combobox:
            if( nPart == ControlPart::HasBackgroundTexture )
                return false;   // we do not paint the inner part (ie the selection background/focus indication)
            if( nPart == ControlPart::Entire )
                hTheme = getThemeHandle(mhWnd, L"Edit", mWinSalGraphicsImplBase);
            else if( nPart == ControlPart::ButtonDown )
                hTheme = getThemeHandle(mhWnd, L"Combobox", mWinSalGraphicsImplBase);
            break;
        case ControlType::Spinbox:
            if( nPart == ControlPart::Entire )
                hTheme = getThemeHandle(mhWnd, L"Edit", mWinSalGraphicsImplBase);
            else if( nPart == ControlPart::AllButtons ||
                nPart == ControlPart::ButtonUp || nPart == ControlPart::ButtonDown ||
                nPart == ControlPart::ButtonLeft|| nPart == ControlPart::ButtonRight )
                hTheme = getThemeHandle(mhWnd, L"Spin", mWinSalGraphicsImplBase);
            break;
        case ControlType::SpinButtons:
            if( nPart == ControlPart::Entire || nPart == ControlPart::AllButtons )
                hTheme = getThemeHandle(mhWnd, L"Spin", mWinSalGraphicsImplBase);
            break;
        case ControlType::Editbox:
        case ControlType::MultilineEditbox:
            if( nPart == ControlPart::HasBackgroundTexture )
                return false;   // we do not paint the inner part (ie the selection background/focus indication)
                //return TRUE;
            if( nPart == ControlPart::Entire )
                hTheme = getThemeHandle(mhWnd, L"Edit", mWinSalGraphicsImplBase);
            break;
        case ControlType::Listbox:
            if( nPart == ControlPart::HasBackgroundTexture )
                return false;   // we do not paint the inner part (ie the selection background/focus indication)
            if( nPart == ControlPart::Entire || nPart == ControlPart::ListboxWindow )
                hTheme = getThemeHandle(mhWnd, L"Listview", mWinSalGraphicsImplBase);
            else if( nPart == ControlPart::ButtonDown )
                hTheme = getThemeHandle(mhWnd, L"Combobox", mWinSalGraphicsImplBase);
            break;
        case ControlType::TabPane:
        case ControlType::TabBody:
        case ControlType::TabItem:
            if( nPart == ControlPart::Entire )
                hTheme = getThemeHandle(mhWnd, L"Tab", mWinSalGraphicsImplBase);
            break;
        case ControlType::Toolbar:
            if( nPart == ControlPart::Entire || nPart == ControlPart::Button )
                hTheme = getThemeHandle(mhWnd, L"Toolbar", mWinSalGraphicsImplBase);
            else
                // use rebar theme for grip and background
                hTheme = getThemeHandle(mhWnd, L"Rebar", mWinSalGraphicsImplBase);
            break;
        case ControlType::Menubar:
            if( nPart == ControlPart::Entire )
                hTheme = getThemeHandle(mhWnd, L"Rebar", mWinSalGraphicsImplBase);
            else if( GetSalData()->mbThemeMenuSupport )
            {
                if( nPart == ControlPart::MenuItem )
                    hTheme = getThemeHandle(mhWnd, L"Menu", mWinSalGraphicsImplBase);
            }
            break;
        case ControlType::MenuPopup:
            if( GetSalData()->mbThemeMenuSupport )
            {
                if( nPart == ControlPart::Entire ||
                    nPart == ControlPart::MenuItem ||
                    nPart == ControlPart::MenuItemCheckMark ||
                    nPart == ControlPart::MenuItemRadioMark ||
                    nPart == ControlPart::Separator )
                    hTheme = getThemeHandle(mhWnd, L"Menu", mWinSalGraphicsImplBase);
            }
            break;
        case ControlType::Progress:
        case ControlType::LevelBar:
            if( nPart == ControlPart::Entire )
                hTheme = getThemeHandle(mhWnd, L"Progress", mWinSalGraphicsImplBase);
            break;
        case ControlType::Slider:
            if( nPart == ControlPart::TrackHorzArea || nPart == ControlPart::TrackVertArea )
                hTheme = getThemeHandle(mhWnd, L"Trackbar", mWinSalGraphicsImplBase);
            break;
        case ControlType::ListNode:
            if( nPart == ControlPart::Entire )
                hTheme = getThemeHandle(mhWnd, L"TreeView", mWinSalGraphicsImplBase);
            break;
        default:
            hTheme = nullptr;
            break;
    }

    return (hTheme != nullptr);
}

bool WinSalGraphics::hitTestNativeControl( ControlType,
                              ControlPart,
                              const tools::Rectangle&,
                              const Point&,
                              bool& )
{
    return false;
}

static bool ImplDrawTheme( HTHEME hTheme, HDC hDC, int iPart, int iState, RECT rc, const OUString& aStr)
{
    HRESULT hr = DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, nullptr);

    if( aStr.getLength() )
    {
        RECT rcContent;
        hr = GetThemeBackgroundContentRect( hTheme, hDC, iPart, iState, &rc, &rcContent);
        hr = DrawThemeText( hTheme, hDC, iPart, iState,
            o3tl::toW(aStr.getStr()), -1,
            DT_CENTER | DT_VCENTER | DT_SINGLELINE,
            0, &rcContent);
    }
    return (hr == S_OK);
}

// TS_TRUE returns optimal size
static std::optional<Size> ImplGetThemeSize(HTHEME hTheme, HDC hDC, int iPart, int iState, LPCRECT pRect, THEMESIZE eTS = TS_TRUE)
{
    if (SIZE aSz; SUCCEEDED(GetThemePartSize(hTheme, hDC, iPart, iState, pRect, eTS, &aSz)))
        return Size(aSz.cx, aSz.cy);
    return {};
}

static tools::Rectangle ImplGetThemeRect( HTHEME hTheme, HDC hDC, int iPart, int iState, const tools::Rectangle& /* aRect */, THEMESIZE eTS = TS_TRUE )
{
    if (const std::optional<Size> oSz = ImplGetThemeSize(hTheme, hDC, iPart, iState, nullptr, eTS))
        return tools::Rectangle( 0, 0, oSz->Width(), oSz->Height() );
    else
        return tools::Rectangle();
}

// Helper functions

static void ImplConvertSpinbuttonValues( ControlPart nControlPart, const ControlState&&nbsp;rState, const tools::Rectangle& rRect,
                                 int* pLunaPart, int *pLunaState, RECT *pRect )
{
    if( nControlPart == ControlPart::ButtonDown )
    {
        *pLunaPart = SPNP_DOWN;
        if( rState & ControlState::PRESSED )
            *pLunaState = DNS_PRESSED;
        else if( !(rState & ControlState::ENABLED) )
            *pLunaState = DNS_DISABLED;
        else if( rState & ControlState::ROLLOVER )
            *pLunaState = DNS_HOT;
        else
            *pLunaState = DNS_NORMAL;
    }
    if( nControlPart == ControlPart::ButtonUp )
    {
        *pLunaPart = SPNP_UP;
        if( rState & ControlState::PRESSED )
            *pLunaState = UPS_PRESSED;
        else if( !(rState & ControlState::ENABLED) )
            *pLunaState = UPS_DISABLED;
        else if( rState & ControlState::ROLLOVER )
            *pLunaState = UPS_HOT;
        else
            *pLunaState = UPS_NORMAL;
    }
    if( nControlPart == ControlPart::ButtonRight )
    {
        *pLunaPart = SPNP_UPHORZ;
        if( rState & ControlState::PRESSED )
            *pLunaState = DNHZS_PRESSED;
        else if( !(rState & ControlState::ENABLED) )
            *pLunaState = DNHZS_DISABLED;
        else if( rState & ControlState::ROLLOVER )
            *pLunaState = DNHZS_HOT;
        else
            *pLunaState = DNHZS_NORMAL;
    }
    if( nControlPart == ControlPart::ButtonLeft )
    {
        *pLunaPart = SPNP_DOWNHORZ;
        if( rState & ControlState::PRESSED )
            *pLunaState = UPHZS_PRESSED;
        else if( !(rState & ControlState::ENABLED) )
            *pLunaState = UPHZS_DISABLED;
        else if( rState & ControlState::ROLLOVER )
            *pLunaState = UPHZS_HOT;
        else
            *pLunaState = UPHZS_NORMAL;
    }

    pRect->left   = rRect.Left();
    pRect->right  = rRect.Right()+1;
    pRect->top    = rRect.Top();
    pRect->bottom = rRect.Bottom()+1;
}

/// Draw an own toolbar style on Windows Vista or later, looks better there
static void impl_drawAeroToolbar( HDC hDC, RECT rc, bool bHorizontal )
{
    if ( rc.top == 0 && bHorizontal )
    {
        const int GRADIENT_HEIGHT = 32;

        LONG gradient_break = rc.top;
        LONG gradient_bottom = rc.bottom - 1;
        GRADIENT_RECT g_rect[1] = { { 0, 1 } };

        // very slow gradient at the top (if we have space for that)
        if ( gradient_bottom - rc.top > GRADIENT_HEIGHT )
        {
            gradient_break = gradient_bottom - GRADIENT_HEIGHT;

            TRIVERTEX vert[2] = {
                { rc.left, rc.top,          0xff00, 0xff00, 0xff00, 0xff00 },
                { rc.right, gradient_break, 0xfa00, 0xfa00, 0xfa00, 0xff00 },
            };
            GdiGradientFill( hDC, vert, 2, g_rect, 1, GRADIENT_FILL_RECT_V );
        }

        // gradient at the bottom
        TRIVERTEX vert[2] = {
            { rc.left, gradient_break,   0xfa00, 0xfa00, 0xfa00, 0xff00 },
            { rc.right, gradient_bottom, 0xf000, 0xf000, 0xf000, 0xff00 }
        };
        GdiGradientFill( hDC, vert, 2, g_rect, 1, GRADIENT_FILL_RECT_V );

        // and a darker horizontal line under that
        ScopedSelectedHPEN hPen(hDC, CreatePen(PS_SOLID, 1, RGB( 0xb0, 0xb0, 0xb0)));

        MoveToEx( hDC, rc.left, gradient_bottom, nullptr );
        LineTo( hDC, rc.right, gradient_bottom );
    }
    else
    {
        ScopedHBRUSH hbrush(CreateSolidBrush(RGB(0xf0, 0xf0, 0xf0)));
        FillRect(hDC, &rc, hbrush.get());

        // darker line to distinguish the toolbar and viewshell
        // it is drawn only for the horizontal toolbars; it did not look well
        // when done for the vertical ones too
        if ( bHorizontal )
        {
            LONG from_x, from_y, to_x, to_y;

            from_x = rc.left;
            to_x = rc.right;
            from_y = to_y = rc.top;

            ScopedSelectedHPEN hPen(hDC, CreatePen(PS_SOLID, 1, RGB( 0xb0, 0xb0, 0xb0)));

            MoveToEx( hDC, from_x, from_y, nullptr );
            LineTo( hDC, to_x, to_y );
        }
    }
}

static bool implDrawNativeMenuMark(HDC hDC, HTHEME hTheme, RECT rc, ControlPart nPart,
                                   ControlState nState, OUString const& aCaption)
{
    int iState = (nState & ControlState::ENABLED) ? MCB_NORMAL : MCB_DISABLED;
    ImplDrawTheme(hTheme, hDC, MENU_POPUPCHECKBACKGROUND, iState, rc, aCaption);
    if (nPart == ControlPart::MenuItemCheckMark)
        iState = (nState & ControlState::ENABLED) ? MC_CHECKMARKNORMAL : MC_CHECKMARKDISABLED;
    else
        iState = (nState & ControlState::ENABLED) ? MC_BULLETNORMAL : MC_BULLETDISABLED;
    // tdf#133697: Get true size of mark, to avoid stretching
    if (auto oSize = ImplGetThemeSize(hTheme, hDC, MENU_POPUPCHECK, iState, &rc))
    {
        // center the mark inside the passed rectangle
        if (const auto dx = (rc.right - rc.left - oSize->Width() + 1) / 2; dx > 0)
        {
            rc.left += dx;
            rc.right = rc.left + oSize->Width();
        }
        if (const auto dy = (rc.bottom - rc.top - oSize->Height() + 1) / 2; dy > 0)
        {
            rc.top += dy;
            rc.bottom = rc.top + oSize->Height();
        }
    }
    return ImplDrawTheme(hTheme, hDC, MENU_POPUPCHECK, iState, rc, aCaption);
}

bool UseDarkMode()
{
    static bool bOSSupportsDarkMode = OSSupportsDarkMode();
    if (!bOSSupportsDarkMode)
        return false;

    bool bRet(false);
    switch (MiscSettings::GetAppColorMode())
    {
        case AppearanceMode::AUTO:
        default:
        {
            HINSTANCE hUxthemeLib = LoadLibraryExW(L"uxtheme.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
            if (!hUxthemeLib)
                return false;

            typedef bool(WINAPI* ShouldAppsUseDarkMode_t)();
            if (auto ShouldAppsUseDarkMode = reinterpret_cast<ShouldAppsUseDarkMode_t>(GetProcAddress(hUxthemeLib, MAKEINTRESOURCEA(132))))
                bRet = ShouldAppsUseDarkMode();

            FreeLibrary(hUxthemeLib);
            break;
        }
        case AppearanceMode::LIGHT:
            bRet = false;
            break;
        case AppearanceMode::DARK:
            bRet = true;
            break;
    }

    return bRet;
}

static bool drawThemedControl(HDC hDC, ControlType nType, int iPart, int iState, RECT rc)
{
    if (nType == ControlType::Scrollbar)
    {
        if (iPart == SBP_ARROWBTN)
        {
            const Color& rBackColor = ThemeColors::GetThemeColors().GetWindowColor();
            const Color& rArrowFillColor = ThemeColors::GetThemeColors().GetBaseColor();

            ScopedHBRUSH hbrush(CreateSolidBrush(RGB(rBackColor.GetRed(),
                                                     rBackColor.GetGreen(),
                                                     rBackColor.GetBlue())));
            FillRect(hDC, &rc, hbrush.get());

            bool bDrawArrow = false;
            POINT aArrowPoints[3];

            if (iState == ABS_UPHOT || iState == ABS_UPPRESSED)
            {
                aArrowPoints[0] = { rc.left + (rc.right - rc.left) / 4, rc.bottom - (rc.bottom - rc.top) / 4 };
                aArrowPoints[1] = { rc.right - (rc.right - rc.left) / 4, rc.bottom - (rc.bottom - rc.top) / 4 };
                aArrowPoints[2] = { rc.left + (rc.right - rc.left) / 2, rc.top + (rc.bottom - rc.top) / 4 };
                bDrawArrow = true;
            }
            else if (iState == ABS_DOWNHOT || iState == ABS_DOWNPRESSED)
            {
                aArrowPoints[0] = { rc.left + (rc.right - rc.left) / 4, rc.top + (rc.bottom - rc.top) / 4 };
                aArrowPoints[1] = { rc.right - (rc.right - rc.left) / 4, rc.top + (rc.bottom - rc.top) / 4 };
                aArrowPoints[2] = { rc.left + (rc.right - rc.left) / 2, rc.bottom - (rc.bottom - rc.top) / 4 };
                bDrawArrow = true;
            }
            else if (iState == ABS_RIGHTHOT || iState == ABS_RIGHTPRESSED)
            {
                aArrowPoints[0] = { rc.left + (rc.right - rc.left) / 4, rc.top + (rc.bottom - rc.top) / 4 };
                aArrowPoints[1] = { rc.right - (rc.right - rc.left) / 4, rc.top + (rc.bottom - rc.top) / 2 };
                aArrowPoints[2] = { rc.left + (rc.right - rc.left) / 4, rc.bottom - (rc.bottom - rc.top) / 4 };
                bDrawArrow = true;
            }
            else if (iState == ABS_LEFTHOT || iState == ABS_LEFTPRESSED)
            {
                aArrowPoints[0] = { rc.right - (rc.right - rc.left) / 4, rc.top + (rc.bottom - rc.top) / 4 };
                aArrowPoints[1] = { rc.right - (rc.right - rc.left) / 4, rc.bottom - (rc.bottom - rc.top) / 4 };
                aArrowPoints[2] = { rc.left + (rc.right - rc.left) / 4, rc.top + (rc.bottom - rc.top) / 2 };
                bDrawArrow = true;
            }

            if (bDrawArrow)
            {
                ScopedHPEN hpen(CreatePen(PS_SOLID, 1, RGB(0, 0, 0)));
                ScopedHBRUSH hbrushArrow(CreateSolidBrush(RGB(rArrowFillColor.GetRed(),
                                                              rArrowFillColor.GetGreen(),
                                                              rArrowFillColor.GetBlue())));
                SelectObject(hDC, hpen.get());
                SelectObject(hDC, hbrushArrow.get());
                Polygon(hDC, aArrowPoints, ARRAYSIZE(aArrowPoints));
            }
            return true;
        }
        else if (iPart == SBP_THUMBBTNHORZ || iPart == SBP_THUMBBTNVERT)
        {
            Color aScrollBarThumbColor = ThemeColors::GetThemeColors().GetBaseColor();
            const Color& rBackgroundColor = ThemeColors::GetThemeColors().GetWindowColor();

            bool bUseDarkMode = UseDarkMode();
            if (iState == SCRBS_PRESSED)
                if (bUseDarkMode)
                    aScrollBarThumbColor.IncreaseLuminance(60);
                else
                    aScrollBarThumbColor.DecreaseLuminance(60);
            else if (iState = SCRBS_HOT)
                if (bUseDarkMode)
                    aScrollBarThumbColor.IncreaseLuminance(30);
                else
                    aScrollBarThumbColor.DecreaseLuminance(30);

            ScopedHBRUSH hbrush(CreateSolidBrush(RGB(rBackgroundColor.GetRed(),
                                                     rBackgroundColor.GetGreen(),
                                                     rBackgroundColor.GetBlue())));
            FillRect(hDC, &rc, hbrush.get());

            RECT thumb = rc;
            if (iPart == SBP_THUMBBTNHORZ)
            {
                thumb.top += 3;
                thumb.bottom -= 3;
            }
            else
            {
                thumb.left += 3;
                thumb.right -= 3;
            }

            hbrush = ScopedHBRUSH(CreateSolidBrush(RGB(aScrollBarThumbColor.GetRed(),
                                                       aScrollBarThumbColor.GetGreen(),
                                                       aScrollBarThumbColor.GetBlue())));
            FillRect(hDC, &thumb, hbrush.get());
            return true;
        }
        else if (iPart == SBP_UPPERTRACKHORZ || iPart == SBP_LOWERTRACKHORZ
                || iPart == SBP_UPPERTRACKVERT || iPart == SBP_LOWERTRACKVERT)
        {
            const Color& rWindowColor = ThemeColors::GetThemeColors().GetWindowColor();
            ScopedHBRUSH hbrush(CreateSolidBrush(RGB(rWindowColor.GetRed(),
                                                     rWindowColor.GetGreen(),
                                                     rWindowColor.GetBlue())));
            FillRect(hDC, &rc, hbrush.get());
            FrameRect(hDC, &rc, hbrush.get());
            return true;
        }
    }
    else if (nType == ControlType::Pushbutton)
    {
        if (iPart == BP_PUSHBUTTON)
        {
            Color aButtonColor = ThemeColors::GetThemeColors().GetButtonColor();
            Color aButtonRectColor = ThemeColors::GetThemeColors().GetDisabledColor();

            if (iState == PBS_PRESSED)
                aButtonColor.Merge(aButtonRectColor, 230);
            else if (iState == PBS_DISABLED)
                if (UseDarkMode())
                    aButtonRectColor.DecreaseLuminance(150);
                else
                    aButtonRectColor.IncreaseLuminance(150);
            else if (iState == PBS_HOT)
                aButtonColor.Merge(aButtonRectColor, 170);
            else if (iState == PBS_DEFAULTED)
                aButtonColor.Merge(aButtonRectColor, 150);

            ScopedHBRUSH hbrush(CreateSolidBrush(RGB(aButtonColor.GetRed(),
                                                     aButtonColor.GetGreen(),
                                                     aButtonColor.GetBlue())));
            FillRect(hDC, &rc, hbrush.get());

            hbrush = ScopedHBRUSH(CreateSolidBrush(RGB(aButtonRectColor.GetRed(),
                                                       aButtonRectColor.GetGreen(),
                                                       aButtonRectColor.GetBlue())));
            FrameRect(hDC, &rc, hbrush.get());
            return true;
        }
    }
    else if (nType == ControlType::Editbox)
    {
        if (iPart == EP_EDITBORDER_NOSCROLL)
        {
            const Color& rColor = ThemeColors::GetThemeColors().GetSeparatorColor();
            ScopedHBRUSH hbrush(CreateSolidBrush(RGB(rColor.GetRed(),
                                                     rColor.GetGreen(),
                                                     rColor.GetBlue())));
            FrameRect(hDC, &rc, hbrush.get());
            return true;
        }
    }
    else if (nType == ControlType::Toolbar)
    {
        if (iPart == TP_BUTTON)
        {
            Color aButtonColor = ThemeColors::GetThemeColors().GetAccentColor();
            const Color& rWindowColor = ThemeColors::GetThemeColors().GetWindowColor();
            Color aFrameOutline = aButtonColor;

            if (iState == TS_PRESSED)
                aButtonColor.Merge(rWindowColor, 100);
            else if (iState == TS_HOTCHECKED || iState == TS_HOT)
                aButtonColor.Merge(rWindowColor, 60);
            else if (iState == TS_CHECKED || iState == TS_NORMAL)
                aButtonColor.Merge(rWindowColor, 100);

            ScopedHBRUSH hbrush(CreateSolidBrush(RGB(aButtonColor.GetRed(),
                                                     aButtonColor.GetGreen(),
                                                     aButtonColor.GetBlue())));
            FillRect(hDC, &rc, hbrush.get());

            hbrush = ScopedHBRUSH(CreateSolidBrush(RGB(aFrameOutline.GetRed(),
                                                       aFrameOutline.GetGreen(),
                                                       aFrameOutline.GetBlue())));
            FrameRect(hDC, &rc, hbrush.get());
            return true;
        }
    }
    else if (nType == ControlType::MenuPopup)
    {
        if (iPart == MENU_POPUPBACKGROUND)
        {
            Color aColor(ThemeColors::GetThemeColors().GetMenuColor());
            ScopedHBRUSH hbrush(CreateSolidBrush(RGB(aColor.GetRed(),
                                                     aColor.GetGreen(),
                                                     aColor.GetBlue())));
            FillRect(hDC, &rc, hbrush.get());

            aColor = ThemeColors::GetThemeColors().GetMenuBorderColor();
            hbrush = ScopedHBRUSH(CreateSolidBrush( RGB(aColor.GetRed(),
                                                        aColor.GetGreen(),
                                                        aColor.GetBlue())));
            FrameRect(hDC, &rc, hbrush.get());
            return true;
        }
        else if (iPart == MENU_POPUPITEM)
        {
            Color aBackgroundColor;
            if (iState == MPI_HOT || iState == MPI_NORMAL)
                aBackgroundColor = ThemeColors::GetThemeColors().GetMenuHighlightColor();
            else if (iState == MPI_DISABLEDHOT || MPI_DISABLED)
                aBackgroundColor = ThemeColors::GetThemeColors().GetDisabledColor();

            ScopedHBRUSH hbrush(CreateSolidBrush(RGB(aBackgroundColor.GetRed(),
                                                     aBackgroundColor.GetGreen(),
                                                     aBackgroundColor.GetBlue())));
            FillRect(hDC, &rc, hbrush.get());
            return true;
        }
    }
    return false;
}

static bool ImplDrawNativeControl( HDC hDC, HTHEME hTheme, RECT rc,
                            ControlType nType,
                            ControlPart nPart,
                            ControlState nState,
                            const ImplControlValue& aValue,
                            OUString const & aCaption,
                            bool bUseDarkMode )
{
    // a listbox dropdown is actually a combobox dropdown
    if( nType == ControlType::Listbox )
        if( nPart == ControlPart::ButtonDown )
            nType = ControlType::Combobox;

    // draw entire combobox as a large edit box
    if( nType == ControlType::Combobox )
        if( nPart == ControlPart::Entire )
            nType = ControlType::Editbox;

    // draw entire spinbox as a large edit box
    if( nType == ControlType::Spinbox )
        if( nPart == ControlPart::Entire )
            nType = ControlType::Editbox;

    bool bCanUseThemeColors = ThemeColors::VclPluginCanUseThemeColors();
    int iPart(0), iState(0);
    if( nType == ControlType::Scrollbar )
    {
        HRESULT hr;
        if( nPart == ControlPart::ButtonUp )
        {
            iPart = SBP_ARROWBTN;
            if( nState & ControlState::PRESSED )
                iState = ABS_UPPRESSED;
            else if( !(nState & ControlState::ENABLED) )
                iState = ABS_UPDISABLED;
            else if( nState & ControlState::ROLLOVER )
                iState = ABS_UPHOT;
            else
                iState = ABS_UPNORMAL;

            if (bCanUseThemeColors)
                return drawThemedControl(hDC, nType, iPart, iState, rc);

            hr = DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, nullptr);
            return (hr == S_OK);
        }
        if( nPart == ControlPart::ButtonDown )
        {
            iPart = SBP_ARROWBTN;
            if( nState & ControlState::PRESSED )
                iState = ABS_DOWNPRESSED;
            else if( !(nState & ControlState::ENABLED) )
                iState = ABS_DOWNDISABLED;
            else if( nState & ControlState::ROLLOVER )
                iState = ABS_DOWNHOT;
            else
                iState = ABS_DOWNNORMAL;

            if (bCanUseThemeColors)
                return drawThemedControl(hDC, nType, iPart, iState, rc);

            hr = DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, nullptr);
            return (hr == S_OK);
        }
        if( nPart == ControlPart::ButtonLeft )
        {
            iPart = SBP_ARROWBTN;
            if( nState & ControlState::PRESSED )
                iState = ABS_LEFTPRESSED;
            else if( !(nState & ControlState::ENABLED) )
                iState = ABS_LEFTDISABLED;
            else if( nState & ControlState::ROLLOVER )
                iState = ABS_LEFTHOT;
            else
                iState = ABS_LEFTNORMAL;

            if (bCanUseThemeColors)
                return drawThemedControl(hDC, nType, iPart, iState, rc);

            hr = DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, nullptr);
            return (hr == S_OK);
        }
        if( nPart == ControlPart::ButtonRight )
        {
            iPart = SBP_ARROWBTN;
            if( nState & ControlState::PRESSED )
                iState = ABS_RIGHTPRESSED;
            else if( !(nState & ControlState::ENABLED) )
                iState = ABS_RIGHTDISABLED;
            else if( nState & ControlState::ROLLOVER )
                iState = ABS_RIGHTHOT;
            else
                iState = ABS_RIGHTNORMAL;

            if (bCanUseThemeColors)
                return drawThemedControl(hDC, nType, iPart, iState, rc);

            hr = DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, nullptr);
            return (hr == S_OK);
        }
        if( nPart == ControlPart::ThumbHorz || nPart == ControlPart::ThumbVert )
        {
            iPart = (nPart == ControlPart::ThumbHorz) ? SBP_THUMBBTNHORZ : SBP_THUMBBTNVERT;
            if( nState & ControlState::PRESSED )
                iState = SCRBS_PRESSED;
            else if( !(nState & ControlState::ENABLED) )
                iState = SCRBS_DISABLED;
            else if( nState & ControlState::ROLLOVER )
                iState = SCRBS_HOT;
            else
                iState = SCRBS_NORMAL;

            SIZE sz;
            GetThemePartSize(hTheme, hDC, iPart, iState, nullptr, TS_MIN, &sz);
            GetThemePartSize(hTheme, hDC, iPart, iState, nullptr, TS_TRUE, &sz);
            GetThemePartSize(hTheme, hDC, iPart, iState, nullptr, TS_DRAW, &sz);

            if (bCanUseThemeColors)
                return drawThemedControl(hDC, nType, iPart, iState, rc);

            hr = DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, nullptr);
            // paint gripper on thumb if enough space
            if( ( (nPart == ControlPart::ThumbVert) && (rc.bottom-rc.top > 12) ) ||
                ( (nPart == ControlPart::ThumbHorz) && (rc.right-rc.left > 12) ) )
            {
                iPart = (nPart == ControlPart::ThumbHorz) ? SBP_GRIPPERHORZ : SBP_GRIPPERVERT;
                iState = 0;
                DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, nullptr);
            }
            return (hr == S_OK);
        }
        if( nPart == ControlPart::TrackHorzLeft || nPart == ControlPart::TrackHorzRight || nPart == ControlPart::TrackVertUpper || nPart == ControlPart::TrackVertLower )
        {
            switch( nPart )
            {
                case ControlPart::TrackHorzLeft:  iPart = SBP_UPPERTRACKHORZ; break;
                case ControlPart::TrackHorzRight: iPart = SBP_LOWERTRACKHORZ; break;
                case ControlPart::TrackVertUpper: iPart = SBP_UPPERTRACKVERT; break;
                case ControlPart::TrackVertLower: iPart = SBP_LOWERTRACKVERT; break;
                defaultbreak;
            }

            if( nState & ControlState::PRESSED )
                iState = SCRBS_PRESSED;
            else if( !(nState & ControlState::ENABLED) )
                iState = SCRBS_DISABLED;
            else if( nState & ControlState::ROLLOVER )
                iState = SCRBS_HOT;
            else
                iState = SCRBS_NORMAL;

            if (bCanUseThemeColors)
                return drawThemedControl(hDC, nType, iPart, iState, rc);

            hr = DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, nullptr);
            return (hr == S_OK);
        }
    }
    if( nType == ControlType::SpinButtons && nPart == ControlPart::AllButtons )
    {
        if( aValue.getType() == ControlType::SpinButtons )
        {
            const SpinbuttonValue* pValue = (aValue.getType() == ControlType::SpinButtons) ? static_cast<const SpinbuttonValue*>(&aValue) : nullptr;

            RECT rect;
            ImplConvertSpinbuttonValues( pValue->mnUpperPart, pValue->mnUpperState, pValue->maUpperRect, &iPart, &iState, &rect );
            bool bOk = ImplDrawTheme( hTheme, hDC, iPart, iState, rect, aCaption);

            if( bOk )
            {
                ImplConvertSpinbuttonValues( pValue->mnLowerPart, pValue->mnLowerState, pValue->maLowerRect, &iPart, &iState, &rect );
                bOk = ImplDrawTheme( hTheme, hDC, iPart, iState, rect, aCaption);
            }

            return bOk;
        }
    }
    if( nType == ControlType::Spinbox )
    {
        if( nPart == ControlPart::AllButtons )
        {
            if( aValue.getType() == ControlType::SpinButtons )
            {
                const SpinbuttonValue *pValue = static_cast<const SpinbuttonValue*>(&aValue);

                RECT rect;
                ImplConvertSpinbuttonValues( pValue->mnUpperPart, pValue->mnUpperState, pValue->maUpperRect, &iPart, &iState, &rect );
                bool bOk = ImplDrawTheme( hTheme, hDC, iPart, iState, rect, aCaption);

                if( bOk )
                {
                    ImplConvertSpinbuttonValues( pValue->mnLowerPart, pValue->mnLowerState, pValue->maLowerRect, &iPart, &iState, &rect );
                    bOk = ImplDrawTheme( hTheme, hDC, iPart, iState, rect, aCaption);
                }

                return bOk;
            }
        }

        if( nPart == ControlPart::ButtonDown )
        {
            iPart = SPNP_DOWN;
            if( nState & ControlState::PRESSED )
                iState = DNS_PRESSED;
            else if( !(nState & ControlState::ENABLED) )
                iState = DNS_DISABLED;
            else if( nState & ControlState::ROLLOVER )
                iState = DNS_HOT;
            else
                iState = DNS_NORMAL;
        }
        if( nPart == ControlPart::ButtonUp )
        {
            iPart = SPNP_UP;
            if( nState & ControlState::PRESSED )
                iState = UPS_PRESSED;
            else if( !(nState & ControlState::ENABLED) )
                iState = UPS_DISABLED;
            else if( nState & ControlState::ROLLOVER )
                iState = UPS_HOT;
            else
                iState = UPS_NORMAL;
        }
        if( nPart == ControlPart::ButtonRight )
        {
            iPart = SPNP_DOWNHORZ;
            if( nState & ControlState::PRESSED )
                iState = DNHZS_PRESSED;
            else if( !(nState & ControlState::ENABLED) )
                iState = DNHZS_DISABLED;
            else if( nState & ControlState::ROLLOVER )
                iState = DNHZS_HOT;
            else
                iState = DNHZS_NORMAL;
        }
        if( nPart == ControlPart::ButtonLeft )
        {
            iPart = SPNP_UPHORZ;
            if( nState & ControlState::PRESSED )
                iState = UPHZS_PRESSED;
            else if( !(nState & ControlState::ENABLED) )
                iState = UPHZS_DISABLED;
            else if( nState & ControlState::ROLLOVER )
                iState = UPHZS_HOT;
            else
                iState = UPHZS_NORMAL;
        }
        if( nPart == ControlPart::ButtonLeft || nPart == ControlPart::ButtonRight || nPart == ControlPart::ButtonUp || nPart == ControlPart::ButtonDown )
            return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
    }
    if( nType == ControlType::Combobox )
    {
        if( nPart == ControlPart::ButtonDown )
        {
            iPart = CP_DROPDOWNBUTTON;
            if( nState & ControlState::PRESSED )
                iState = CBXS_PRESSED;
            else if( !(nState & ControlState::ENABLED) )
                iState = CBXS_DISABLED;
            else if( nState & ControlState::ROLLOVER )
                iState = CBXS_HOT;
            else
                iState = CBXS_NORMAL;
            return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
        }
    }
    if( nType == ControlType::Pushbutton )
    {
        iPart = BP_PUSHBUTTON;
        if( nState & ControlState::PRESSED )
            iState = PBS_PRESSED;
        else if( !(nState & ControlState::ENABLED) )
            iState = PBS_DISABLED;
        else if( nState & ControlState::ROLLOVER )
            iState = PBS_HOT;
        else if( nState & ControlState::DEFAULT )
            iState = PBS_DEFAULTED;
        //else if( nState & ControlState::FOCUSED )
        //    iState = PBS_DEFAULTED;    // may need to draw focus rect
        else
            iState = PBS_NORMAL;

        if (bCanUseThemeColors)
            return drawThemedControl(hDC, nType, iPart, iState, rc);

        return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
    }

    if( nType == ControlType::Radiobutton )
    {
        iPart = BP_RADIOBUTTON;
        bool bChecked = ( aValue.getTristateVal() == ButtonValue::On );

        if( nState & ControlState::PRESSED )
            iState = bChecked ? RBS_CHECKEDPRESSED : RBS_UNCHECKEDPRESSED;
        else if( !(nState & ControlState::ENABLED) )
            iState = bChecked ? RBS_CHECKEDDISABLED : RBS_UNCHECKEDDISABLED;
        else if( nState & ControlState::ROLLOVER )
            iState = bChecked ? RBS_CHECKEDHOT : RBS_UNCHECKEDHOT;
        else
            iState = bChecked ? RBS_CHECKEDNORMAL : RBS_UNCHECKEDNORMAL;

        //if( nState & ControlState::FOCUSED )
        //    iState |= PBS_DEFAULTED;    // may need to draw focus rect

        return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
    }

    if( nType == ControlType::Checkbox )
    {
        iPart = BP_CHECKBOX;
        ButtonValue v = aValue.getTristateVal();

        if( nState & ControlState::PRESSED )
            iState = (v == ButtonValue::On)  ? CBS_CHECKEDPRESSED :
                    ( (v == ButtonValue::Off) ? CBS_UNCHECKEDPRESSED : CBS_MIXEDPRESSED );
        else if( !(nState & ControlState::ENABLED) )
            iState = (v == ButtonValue::On)  ? CBS_CHECKEDDISABLED :
                    ( (v == ButtonValue::Off) ? CBS_UNCHECKEDDISABLED : CBS_MIXEDDISABLED );
        else if( nState & ControlState::ROLLOVER )
            iState = (v == ButtonValue::On)  ? CBS_CHECKEDHOT :
                    ( (v == ButtonValue::Off) ? CBS_UNCHECKEDHOT : CBS_MIXEDHOT );
        else
            iState = (v == ButtonValue::On)  ? CBS_CHECKEDNORMAL :
                    ( (v == ButtonValue::Off) ? CBS_UNCHECKEDNORMAL : CBS_MIXEDNORMAL );

        //if( nState & ControlState::FOCUSED )
        //    iState |= PBS_DEFAULTED;    // may need to draw focus rect

        //SIZE sz;
        //THEMESIZE eSize = TS_DRAW; // TS_MIN, TS_TRUE, TS_DRAW
        //GetThemePartSize( hTheme, hDC, iPart, iState, &rc, eSize, &sz);

        return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
    }

    if (nType == ControlType::Editbox)
    {
        iPart = EP_EDITBORDER_NOSCROLL;
        if( !(nState & ControlState::ENABLED) )
            iState = EPSN_DISABLED;
        else if( nState & ControlState::FOCUSED )
            iState = EPSN_FOCUSED;
        else if( nState & ControlState::ROLLOVER )
            iState = EPSN_HOT;
        else
            iState = EPSN_NORMAL;

        if (bCanUseThemeColors)
            return drawThemedControl(hDC, nType, iPart, iState, rc);

        return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
    }

    if (nType == ControlType::MultilineEditbox)
    {
        iPart = EP_EDITTEXT;
        if( !(nState & ControlState::ENABLED) )
            iState = ETS_DISABLED;
        else if( nState & ControlState::FOCUSED )
            iState = ETS_FOCUSED;
        else if( nState & ControlState::ROLLOVER )
            iState = ETS_HOT;
        else
            iState = ETS_NORMAL;

        return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
    }

    if( nType == ControlType::Listbox )
    {
        if( nPart == ControlPart::Entire || nPart == ControlPart::ListboxWindow )
        {
            iPart = LVP_EMPTYTEXT; // ??? no idea which part to choose here
            return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
        }
    }

    if( nType == ControlType::TabPane )
    {
        // tabpane in tabcontrols gets drawn in "darkmode" as if it was a
        // a "light" theme, so bodge this by drawing a frame directly
        if (bCanUseThemeColors || bUseDarkMode)
        {
            Color aColor(Application::GetSettings().GetStyleSettings().GetDisableColor());
            ScopedHBRUSH hbrush(CreateSolidBrush(RGB(aColor.GetRed(),
                                                     aColor.GetGreen(),
                                                     aColor.GetBlue())));
            FrameRect(hDC, &rc, hbrush.get());
            return true;
        }
        iPart = TABP_PANE;
        return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
    }

    if( nType == ControlType::TabBody )
    {
        // tabbody in main window gets drawn in white in "darkmode", so bodge this here
        if (bCanUseThemeColors || bUseDarkMode)
        {
            Color aColor(Application::GetSettings().GetStyleSettings().GetWindowColor());
            ScopedHBRUSH hbrush(CreateSolidBrush(RGB(aColor.GetRed(),
                                                     aColor.GetGreen(),
                                                     aColor.GetBlue())));
            FillRect(hDC, &rc, hbrush.get());
            return true;
        }

        iPart = TABP_BODY;
        return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
    }

    if( nType == ControlType::TabItem )
    {
        iPart = TABP_TABITEMLEFTEDGE;
        rc.bottom--;

        OSL_ASSERT( aValue.getType() == ControlType::TabItem );

        const TabitemValue& rValue = static_cast<const TabitemValue&>(aValue);
        if (rValue.isBothAligned())
        {
            iPart = TABP_TABITEMLEFTEDGE;
            rc.right--;
        }
        else if (rValue.isLeftAligned())
            iPart = TABP_TABITEMLEFTEDGE;
        else if (rValue.isRightAligned())
            iPart = TABP_TABITEMRIGHTEDGE;
        else
            iPart = TABP_TABITEM;

        if( !(nState & ControlState::ENABLED) )
            iState = TILES_DISABLED;
        else if( nState & ControlState::SELECTED )
        {
            iState = TILES_SELECTED;
            // increase the selected tab
            rc.left-=2;
            if (rValue.isBothAligned())
            {
                if (rValue.isLeftAligned() || rValue.isNotAligned())
                    rc.right+=2;
                if (rValue.isRightAligned())
                    rc.right+=1;
            }
            rc.top-=2;
            rc.bottom+=2;
        }
        else if( nState & ControlState::ROLLOVER )
            iState = TILES_HOT;
        else if( nState & ControlState::FOCUSED )
            iState = TILES_FOCUSED;    // may need to draw focus rect
        else
            iState = TILES_NORMAL;

        // tabitem in tabcontrols gets drawn in "darkmode" as if it was a
        // a "light" theme, so bodge this by drawing with a button instead
        if (bCanUseThemeColors || bUseDarkMode)
        {
            Color aColor;
            if (iState == TILES_SELECTED)
                aColor = Application::GetSettings().GetStyleSettings().GetActiveTabColor();
            else
                aColor = Application::GetSettings().GetStyleSettings().GetInactiveTabColor();
            ScopedHBRUSH hbrush(CreateSolidBrush(RGB(aColor.GetRed(),
                                                     aColor.GetGreen(),
                                                     aColor.GetBlue())));
            FillRect(hDC, &rc, hbrush.get());

            aColor = Application::GetSettings().GetStyleSettings().GetDisableColor();
            ScopedSelectedHPEN hPen(hDC, CreatePen(PS_SOLID, 1, RGB(aColor.GetRed(),
                                                                    aColor.GetGreen(),
                                                                    aColor.GetBlue())));
            POINT apt[4];
            apt[0].x = rc.left;
            apt[0].y = rc.bottom - (iPart == TABP_TABITEMLEFTEDGE ? 1 : 2);
            apt[1].x = rc.left;
            apt[1].y = rc.top;
            apt[2].x = rc.right;
            apt[2].y = rc.top;
            apt[3].x = rc.right;
            apt[3].y = rc.bottom - 1;
            Polyline(hDC, apt, SAL_N_ELEMENTS(apt));
            return true;
        }

        return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
    }

    if( nType == ControlType::Toolbar )
    {
        if( nPart == ControlPart::Button )
        {
            iPart = TP_BUTTON;
            bool bChecked = ( aValue.getTristateVal() == ButtonValue::On );
            if( !(nState & ControlState::ENABLED) )
                //iState = TS_DISABLED;
                // disabled buttons are typically not painted at all but we need visual
                // feedback when travelling by keyboard over disabled entries
                iState = TS_HOT;
            else if( nState & ControlState::PRESSED )
                iState = TS_PRESSED;
            else if( nState & ControlState::ROLLOVER )
                iState = bChecked ? TS_HOTCHECKED : TS_HOT;
            else
                iState = bChecked ? TS_CHECKED : TS_NORMAL;

            if (bCanUseThemeColors)
                return drawThemedControl(hDC, nType, iPart, iState, rc);

            if (bUseDarkMode && (bChecked || (nState & (ControlState::PRESSED) || (nState & ControlState::ROLLOVER))))
            {
                if (WinSalInstance::getWindowsBuildNumber() >= 22000)
                {
                    // tdf#152534 workaround bug with Windows 11 Dark theme using
                    // light blue as highlight color which gives insufficient
                    // contrast for hovered-over or pressed/checked toolbar buttons:
                    // manually draw background (using color a bit lighter than background
                    // for non-highlighted items) and draw a frame around it
                    ScopedHBRUSH aBgColorBrush(CreateSolidBrush(RGB(38, 38, 38)));
                    FillRect(hDC, &rc, aBgColorBrush.get());
                    const Color aFrameColor = Application::GetSettings().GetStyleSettings().GetDisableColor();
                    ScopedHBRUSH aFrameBrush(CreateSolidBrush(
                        RGB(aFrameColor.GetRed(), aFrameColor.GetGreen(), aFrameColor.GetBlue())));
                    FrameRect(hDC, &rc, aFrameBrush.get());

                    DrawThemeText(hTheme, hDC, iPart, iState, o3tl::toW(aCaption.getStr()), -1,
                                  DT_CENTER | DT_VCENTER | DT_SINGLELINE, 0, &rc);
                    return true;
                }
            }

            return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
        }
        else if( nPart == ControlPart::ThumbHorz || nPart == ControlPart::ThumbVert )
        {
            // the vertical gripper is not supported in most themes and it makes no
            // sense to only support horizontal gripper
            //iPart = (nPart == ControlPart::ThumbHorz) ? RP_GRIPPERVERT : RP_GRIPPER;
            //return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
        }
        else if( nPart == ControlPart::DrawBackgroundHorz || nPart == ControlPart::DrawBackgroundVert )
        {
            if( aValue.getType() == ControlType::Toolbar )
            {
                const ToolbarValue *pValue = static_cast<const ToolbarValue*>(&aValue);
                if( pValue->mbIsTopDockingArea )
                    rc.top = 0; // extend potential gradient to cover menu bar as well
            }

            // toolbar in main window gets drawn in white in "darkmode", so bodge this here
            if (bCanUseThemeColors || bUseDarkMode)
            {
                Color aColor(Application::GetSettings().GetStyleSettings().GetWindowColor());
                ScopedHBRUSH hbrush(CreateSolidBrush(RGB(aColor.GetRed(),
                                                         aColor.GetGreen(),
                                                         aColor.GetBlue())));
                FillRect(hDC, &rc, hbrush.get());
                return true;
            }

            // make it more compatible with Aero
            if (ImplGetSVData()->maNWFData.mbDockingAreaAvoidTBFrames &&
               !Application::GetSettings().GetStyleSettings().GetHighContrastMode())
            {
                impl_drawAeroToolbar( hDC, rc, nPart == ControlPart::DrawBackgroundHorz );
                return true;
            }

            return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
        }
    }

    if( nType == ControlType::Menubar )
    {
        if( nPart == ControlPart::Entire )
        {
            if( aValue.getType() == ControlType::Menubar )
            {
                const MenubarValue *pValue = static_cast<const MenubarValue*>(&aValue);
                rc.bottom += pValue->maTopDockingAreaHeight;    // extend potential gradient to cover docking area as well

                // menubar in main window gets drawn in white in "darkmode", so bodge this here
                if (bCanUseThemeColors || bUseDarkMode)
                {
                    Color aColor
                        = bCanUseThemeColors
                              ? ThemeColors::GetThemeColors().GetMenuBarColor()
                              : Application::GetSettings().GetStyleSettings().GetWindowColor();
                    ScopedHBRUSH hbrush(CreateSolidBrush(RGB(aColor.GetRed(),
                                                             aColor.GetGreen(),
                                                             aColor.GetBlue())));
                    FillRect(hDC, &rc, hbrush.get());
                    return true;
                }

                // make it more compatible with Aero
                if (ImplGetSVData()->maNWFData.mbDockingAreaAvoidTBFrames &&
                    !Application::GetSettings().GetStyleSettings().GetHighContrastMode())
                {
                    impl_drawAeroToolbar( hDC, rc, true );
                    return true;
                }
            }
            return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
        }
        else if( nPart == ControlPart::MenuItem )
        {
            if( nState & ControlState::ENABLED )
            {
                if( nState & ControlState::SELECTED )
                    iState = MBI_PUSHED;
                else if( nState & ControlState::ROLLOVER )
                    iState = MBI_HOT;
                else
                    iState = MBI_NORMAL;

                if (bCanUseThemeColors
                    || (GetSalData()->mbThemeMenuSupport
                        && Application::GetSettings().GetStyleSettings().GetHighContrastMode()
                        && (nState & (ControlState::SELECTED | nState & ControlState::ROLLOVER))))
                {
                    Color aColor = bCanUseThemeColors
                              ? ThemeColors::GetThemeColors().GetMenuBarHighlightColor()
                              : Application::GetSettings().GetStyleSettings().GetHighlightColor();

                    ScopedHBRUSH hbrush(CreateSolidBrush(RGB(aColor.GetRed(),
                                                             aColor.GetGreen(),
                                                             aColor.GetBlue())));
                    FillRect(hDC, &rc, hbrush.get());
                    return true;
                }
            }
            else
            {
                if( nState & ControlState::SELECTED )
                    iState = MBI_DISABLEDPUSHED;
                else if( nState & ControlState::ROLLOVER )
                    iState = MBI_DISABLEDHOT;
                else
                    iState = MBI_DISABLED;
            }
            return ImplDrawTheme( hTheme, hDC, MENU_BARITEM, iState, rc, aCaption );
        }
    }

    if( nType == ControlType::Progress || nType == ControlType::LevelBar )
    {
        if( nPart != ControlPart::Entire )
            return false;

        int nPartIdBackground = PP_BAR;
        if( nType == ControlType::LevelBar )
        {
            nPartIdBackground = PP_TRANSPARENTBAR;
            iState = PBBS_PARTIAL;
        }

        if( ! ImplDrawTheme( hTheme, hDC, nPartIdBackground, iState, rc, aCaption) )
            return false;
        RECT aProgressRect = rc;
        if( GetThemeBackgroundContentRect( hTheme, hDC, PP_BAR, iState, &rc, &aProgressRect) != S_OK )
            return false;

        tools::Long nProgressWidth = aValue.getNumericVal();
        nProgressWidth *= (aProgressRect.right - aProgressRect.left);
        nProgressWidth /= (rc.right - rc.left);
        if( AllSettings::GetLayoutRTL() )
            aProgressRect.left = aProgressRect.right - nProgressWidth;
        else
            aProgressRect.right = aProgressRect.left + nProgressWidth;

        if (nType == ControlType::LevelBar)
        {
            const auto nPercentage
                = aValue.getNumericVal() * 100 / std::max(LONG{ 1 }, (rc.right - rc.left));

            COLORREF aBrushColor{};
            if (nPercentage < 25)
                aBrushColor = RGB(255, 0, 0);
            else if (nPercentage < 50)
                aBrushColor = RGB(255, 255, 0);
            else if (nPercentage < 75)
                aBrushColor = RGB(0, 0, 255);
            else
                aBrushColor = RGB(0, 255, 0);

            ScopedHBRUSH hBrush(CreateSolidBrush(aBrushColor));
            FillRect(hDC, &aProgressRect, hBrush.get());
            return true;
        }

        return ImplDrawTheme( hTheme, hDC, PP_CHUNK, iState, aProgressRect, aCaption );
    }

    if( nType == ControlType::Slider )
    {
        iPart = (nPart == ControlPart::TrackHorzArea) ? TKP_TRACK : TKP_TRACKVERT;
        iState = (nPart == ControlPart::TrackHorzArea) ? static_cast<int>(TRS_NORMAL) : static_cast<int>(TRVS_NORMAL);

        tools::Rectangle aTrackRect = ImplGetThemeRect( hTheme, hDC, iPart, iState, tools::Rectangle() );
        RECT aTRect = rc;
        if( nPart == ControlPart::TrackHorzArea )
        {
            tools::Long nH = aTrackRect.GetHeight();
            aTRect.top += (rc.bottom - rc.top - nH)/2;
            aTRect.bottom = aTRect.top + nH;
        }
        else
        {
            tools::Long nW = aTrackRect.GetWidth();
            aTRect.left += (rc.right - rc.left - nW)/2;
            aTRect.right = aTRect.left + nW;
        }
        ImplDrawTheme( hTheme, hDC, iPart, iState, aTRect, aCaption );

        RECT aThumbRect;
        OSL_ASSERT( aValue.getType() == ControlType::Slider );
        const SliderValue* pVal = static_cast<const SliderValue*>(&aValue);
        aThumbRect.left   = pVal->maThumbRect.Left();
        aThumbRect.top    = pVal->maThumbRect.Top();
        aThumbRect.right  = pVal->maThumbRect.Right();
        aThumbRect.bottom = pVal->maThumbRect.Bottom();
        iPart = (nPart == ControlPart::TrackHorzArea) ? TKP_THUMB : TKP_THUMBVERT;
        iState = (nState & ControlState::ENABLED) ? TUS_NORMAL : TUS_DISABLED;
        return ImplDrawTheme( hTheme, hDC, iPart, iState, aThumbRect, aCaption );
    }

    if( nType == ControlType::ListNode )
    {
        if( nPart != ControlPart::Entire )
            return false;

        ButtonValue aButtonValue = aValue.getTristateVal();
        iPart = TVP_GLYPH;
        switch( aButtonValue )
        {
        case ButtonValue::On:
            iState = GLPS_OPENED;
            break;
        case ButtonValue::Off:
        case ButtonValue::DontKnow: // SvTLEntryFlags::CHILDREN_ON_DEMAND
            iState = GLPS_CLOSED;
            break;
        default:
            return false;
        }
        return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption );
    }

    if( GetSalData()->mbThemeMenuSupport )
    {
        if( nType == ControlType::MenuPopup )
        {
            if( nPart == ControlPart::Entire )
            {
                RECT aGutterRC = rc;
                if( AllSettings::GetLayoutRTL() )
                {
                    aGutterRC.right -= aValue.getNumericVal()+1;
                    aGutterRC.left = aGutterRC.right-3;
                }
                else
                {
                    aGutterRC.left += aValue.getNumericVal();
                    aGutterRC.right = aGutterRC.left+3;
                }

                if (bCanUseThemeColors)
                    return drawThemedControl(hDC, nType, MENU_POPUPBACKGROUND, iState, rc);

                return
                ImplDrawTheme( hTheme, hDC, MENU_POPUPBACKGROUND, 0, rc, aCaption ) &&
                ImplDrawTheme( hTheme, hDC, MENU_POPUPGUTTER, 0, aGutterRC, aCaption )
                ;
            }
            else if( nPart == ControlPart::MenuItem )
            {
                if( nState & ControlState::ENABLED )
                    iState = (nState & ControlState::SELECTED) ? MPI_HOT : MPI_NORMAL;
                else
                    iState = (nState & ControlState::SELECTED) ? MPI_DISABLEDHOT : MPI_DISABLED;

                if (bCanUseThemeColors)
                    return drawThemedControl(hDC, nType, MENU_POPUPITEM, iState, rc);

                return ImplDrawTheme( hTheme, hDC, MENU_POPUPITEM, iState, rc, aCaption );
            }
            else if( nPart == ControlPart::MenuItemCheckMark || nPart == ControlPart::MenuItemRadioMark )
            {
                if (nState & ControlState::PRESSED)
                    return implDrawNativeMenuMark(hDC, hTheme, rc, nPart, nState, aCaption);
                else
                    return true// unchecked: do nothing
            }
            else if( nPart == ControlPart::Separator )
            {
                // adjust for gutter position
                if( AllSettings::GetLayoutRTL() )
                    rc.right -= aValue.getNumericVal()+1;
                else
                    rc.left += aValue.getNumericVal()+1;
                tools::Rectangle aRect( ImplGetThemeRect( hTheme, hDC,
                    MENU_POPUPSEPARATOR, 0, tools::Rectangle( rc.left, rc.top, rc.right, rc.bottom ) ) );
                // center the separator inside the passed rectangle
                auto const nDY = ((rc.bottom - rc.top + 1) - aRect.GetHeight()) / 2;
                rc.top += nDY;
                rc.bottom = rc.top+aRect.GetHeight()-1;
                return ImplDrawTheme( hTheme, hDC, MENU_POPUPSEPARATOR, 0, rc, aCaption );
            }
        }
    }

    return false;
}

bool WinSalGraphics::drawNativeControl( ControlType nType,
                                        ControlPart nPart,
                                        const tools::Rectangle& rControlRegion,
                                        ControlState nState,
                                        const ImplControlValue& aValue,
                                        const OUString& aCaption,
                                        const Color& /*rBackgroundColor*/ )
{
    bool bOk = false;
    HTHEME hTheme = nullptr;

    tools::Rectangle buttonRect = rControlRegion;
    tools::Rectangle cacheRect = rControlRegion;
    Size keySize = cacheRect.GetSize();

    WinSalGraphicsImplBase* pImpl = mWinSalGraphicsImplBase;
    if( !pImpl->UseRenderNativeControl())
        pImpl = nullptr;

    // tdf#95618 - A few controls render outside the region they're given.
    if (pImpl && nType == ControlType::TabItem)
    {
        tools::Rectangle rNativeBoundingRegion;
        tools::Rectangle rNativeContentRegion;
        if (getNativeControlRegion(nType, nPart, rControlRegion, nState, aValue, aCaption,
                                   rNativeBoundingRegion, rNativeContentRegion))
        {
            cacheRect = rNativeBoundingRegion;
            keySize = rNativeBoundingRegion.GetSize();
        }
    }


    ControlCacheKey aControlCacheKey(nType, nPart, nState, keySize);
    if (pImpl != nullptr && pImpl->TryRenderCachedNativeControl(aControlCacheKey, buttonRect.Left(), buttonRect.Top()))
    {
        return true;
    }

    const bool bUseDarkMode = UseDarkMode();
    if (bUseDarkMode)
        SetWindowTheme(mhWnd, L"Explorer", nullptr);

    switch( nType )
    {
        case ControlType::Pushbutton:
        case ControlType::Radiobutton:
        case ControlType::Checkbox:
            hTheme = getThemeHandle(mhWnd, L"Button", mWinSalGraphicsImplBase);
            break;
        case ControlType::Scrollbar:
            if (bUseDarkMode)
            {
                // tdf#153273 undo the earlier SetWindowTheme, and use an explicit Explorer::Scrollbar
                // a) with "Scrollbar" and SetWindowTheme(... "Explorer" ...) then scrollbars in dialog
                // and main windows are dark, but dropdowns are light
                // b) with "Explorer::Scrollbar" and SetWindowTheme(... "Explorer" ...) then scrollbars
                // in dropdowns are dark, but scrollbars in dialogs and main windows are sort of "extra
                // dark"
                // c) with "Explorer::Scrollbar" and no SetWindowTheme both cases are dark
                SetWindowTheme(mhWnd, nullptr, nullptr);
                hTheme = getThemeHandle(mhWnd, L"Explorer::Scrollbar", mWinSalGraphicsImplBase);
            }
            else
                hTheme = getThemeHandle(mhWnd, L"Scrollbar", mWinSalGraphicsImplBase);
            break;
        case ControlType::Combobox:
            if( nPart == ControlPart::Entire )
            {
                if (bUseDarkMode && !(nState & ControlState::FOCUSED))
                    SetWindowTheme(mhWnd, L"CFD", nullptr);
                hTheme = getThemeHandle(mhWnd, L"Edit", mWinSalGraphicsImplBase);
            }
            else if( nPart == ControlPart::ButtonDown )
            {
                if (bUseDarkMode)
                    SetWindowTheme(mhWnd, L"CFD", nullptr);
                hTheme = getThemeHandle(mhWnd, L"Combobox", mWinSalGraphicsImplBase);
            }
            break;
        case ControlType::Spinbox:
            if( nPart == ControlPart::Entire )
            {
                if (bUseDarkMode && !(nState & ControlState::FOCUSED))
                    SetWindowTheme(mhWnd, L"CFD", nullptr);
                hTheme = getThemeHandle(mhWnd, L"Edit", mWinSalGraphicsImplBase);
            }
            else
                hTheme = getThemeHandle(mhWnd, L"Spin", mWinSalGraphicsImplBase);
            break;
        case ControlType::SpinButtons:
            hTheme = getThemeHandle(mhWnd, L"Spin", mWinSalGraphicsImplBase);
            break;
        case ControlType::Editbox:
            if (bUseDarkMode && !(nState & ControlState::FOCUSED))
                SetWindowTheme(mhWnd, L"CFD", nullptr);
            hTheme = getThemeHandle(mhWnd, L"Edit", mWinSalGraphicsImplBase);
            break;
        case ControlType::MultilineEditbox:
            hTheme = getThemeHandle(mhWnd, L"Edit", mWinSalGraphicsImplBase);
            break;
        case ControlType::Listbox:
            if( nPart == ControlPart::Entire || nPart == ControlPart::ListboxWindow )
                hTheme = getThemeHandle(mhWnd, L"Listview", mWinSalGraphicsImplBase);
            else if( nPart == ControlPart::ButtonDown )
            {
                if (bUseDarkMode)
                    SetWindowTheme(mhWnd, L"CFD", nullptr);
                hTheme = getThemeHandle(mhWnd, L"Combobox", mWinSalGraphicsImplBase);
            }
            break;
        case ControlType::TabBody:
            hTheme = getThemeHandle(mhWnd, L"Tab", mWinSalGraphicsImplBase);
            break;
        case ControlType::TabPane:
        case ControlType::TabItem:
            hTheme = getThemeHandle(mhWnd, L"Tab", mWinSalGraphicsImplBase);
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=91 H=99 G=94

¤ Dauer der Verarbeitung: 0.37 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.