diff options
Diffstat (limited to 'vcl/win/gdi/salnativewidgets-luna.cxx')
-rw-r--r-- | vcl/win/gdi/salnativewidgets-luna.cxx | 1559 |
1 files changed, 1559 insertions, 0 deletions
diff --git a/vcl/win/gdi/salnativewidgets-luna.cxx b/vcl/win/gdi/salnativewidgets-luna.cxx new file mode 100644 index 000000000..68a18b020 --- /dev/null +++ b/vcl/win/gdi/salnativewidgets-luna.cxx @@ -0,0 +1,1559 @@ +/* -*- 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 <rtl/ustring.h> + +#include <osl/diagnose.h> +#include <osl/module.h> +#include <o3tl/char16_t2wchar_t.hxx> + +#include <opengl/win/gdiimpl.hxx> +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> + +#include <win/svsys.h> +#include <win/salgdi.h> +#include <win/saldata.hxx> +#include <win/scoped_gdi.hxx> + +#include <uxtheme.h> +#include <vssym32.h> + +#include <map> +#include <string> +#include <optional> +#include <ControlCacheKey.hxx> + +using namespace std; + +typedef map< wstring, HTHEME > ThemeMap; +static ThemeMap aThemeMap; + +/**************************************************** + wrap visual styles API to avoid linking against it + it is not available on all Windows platforms +*****************************************************/ + +namespace { + +class VisualStylesAPI +{ +private: + typedef HTHEME (WINAPI * OpenThemeData_Proc_T) ( HWND hwnd, LPCWSTR pszClassList ); + typedef HRESULT (WINAPI * CloseThemeData_Proc_T) ( HTHEME hTheme ); + typedef HRESULT (WINAPI * GetThemeBackgroundContentRect_Proc_T) ( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pBoundingRect, RECT *pContentRect ); + typedef HRESULT (WINAPI * DrawThemeBackground_Proc_T) ( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, const RECT *pClipRect ); + typedef HRESULT (WINAPI * DrawThemeText_Proc_T) ( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCWSTR pszText, int iCharCount, DWORD dwTextFlags, DWORD dwTextFlags2, const RECT *pRect ); + typedef HRESULT (WINAPI * GetThemePartSize_Proc_T) ( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, RECT *prc, THEMESIZE eSize, SIZE *psz ); + typedef BOOL (WINAPI * IsThemeActive_Proc_T) ( void ); + + OpenThemeData_Proc_T lpfnOpenThemeData; + CloseThemeData_Proc_T lpfnCloseThemeData; + GetThemeBackgroundContentRect_Proc_T lpfnGetThemeBackgroundContentRect; + DrawThemeBackground_Proc_T lpfnDrawThemeBackground; + DrawThemeText_Proc_T lpfnDrawThemeText; + GetThemePartSize_Proc_T lpfnGetThemePartSize; + IsThemeActive_Proc_T lpfnIsThemeActive; + + oslModule mhModule; + +public: + VisualStylesAPI(); + ~VisualStylesAPI(); + + HTHEME OpenThemeData( HWND hwnd, LPCWSTR pszClassList ); + HRESULT CloseThemeData( HTHEME hTheme ); + HRESULT GetThemeBackgroundContentRect( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pBoundingRect, RECT *pContentRect ); + HRESULT DrawThemeBackground( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, const RECT *pClipRect ); + HRESULT DrawThemeText( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCWSTR pszText, int iCharCount, DWORD dwTextFlags, DWORD dwTextFlags2, const RECT *pRect ); + HRESULT GetThemePartSize( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, RECT *prc, THEMESIZE eSize, SIZE *psz ); + bool IsThemeActive(); +}; + +} + +static VisualStylesAPI vsAPI; + +VisualStylesAPI::VisualStylesAPI() + : lpfnOpenThemeData( nullptr ), + lpfnCloseThemeData( nullptr ), + lpfnGetThemeBackgroundContentRect( nullptr ), + lpfnDrawThemeBackground( nullptr ), + lpfnDrawThemeText( nullptr ), + lpfnGetThemePartSize( nullptr ), + lpfnIsThemeActive( nullptr ) +{ + OUString aLibraryName( "uxtheme.dll" ); + mhModule = osl_loadModule( aLibraryName.pData, SAL_LOADMODULE_DEFAULT ); + + if ( mhModule ) + { + lpfnOpenThemeData = reinterpret_cast<OpenThemeData_Proc_T>(osl_getAsciiFunctionSymbol( mhModule, "OpenThemeData" )); + lpfnCloseThemeData = reinterpret_cast<CloseThemeData_Proc_T>(osl_getAsciiFunctionSymbol( mhModule, "CloseThemeData" )); + lpfnGetThemeBackgroundContentRect = reinterpret_cast<GetThemeBackgroundContentRect_Proc_T>(osl_getAsciiFunctionSymbol( mhModule, "GetThemeBackgroundContentRect" )); + lpfnDrawThemeBackground = reinterpret_cast<DrawThemeBackground_Proc_T>(osl_getAsciiFunctionSymbol( mhModule, "DrawThemeBackground" )); + lpfnDrawThemeText = reinterpret_cast<DrawThemeText_Proc_T>(osl_getAsciiFunctionSymbol( mhModule, "DrawThemeText" )); + lpfnGetThemePartSize = reinterpret_cast<GetThemePartSize_Proc_T>(osl_getAsciiFunctionSymbol( mhModule, "GetThemePartSize" )); + lpfnIsThemeActive = reinterpret_cast<IsThemeActive_Proc_T>(osl_getAsciiFunctionSymbol( mhModule, "IsThemeActive" )); + } +} + +VisualStylesAPI::~VisualStylesAPI() +{ + if( mhModule ) + osl_unloadModule( mhModule ); +} + +HTHEME VisualStylesAPI::OpenThemeData( HWND hwnd, LPCWSTR pszClassList ) +{ + if(lpfnOpenThemeData) + return (*lpfnOpenThemeData) (hwnd, pszClassList); + else + return nullptr; +} + +HRESULT VisualStylesAPI::CloseThemeData( HTHEME hTheme ) +{ + if(lpfnCloseThemeData) + return (*lpfnCloseThemeData) (hTheme); + else + return S_FALSE; +} + +HRESULT VisualStylesAPI::GetThemeBackgroundContentRect( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pBoundingRect, RECT *pContentRect ) +{ + if(lpfnGetThemeBackgroundContentRect) + return (*lpfnGetThemeBackgroundContentRect) ( hTheme, hdc, iPartId, iStateId, pBoundingRect, pContentRect ); + else + return S_FALSE; +} + +HRESULT VisualStylesAPI::DrawThemeBackground( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, const RECT *pClipRect ) +{ + if(lpfnDrawThemeBackground) + return (*lpfnDrawThemeBackground) (hTheme, hdc, iPartId, iStateId, pRect, pClipRect); + else + return S_FALSE; +} + +HRESULT VisualStylesAPI::DrawThemeText( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCWSTR pszText, int iCharCount, DWORD dwTextFlags, DWORD dwTextFlags2, const RECT *pRect ) +{ + if(lpfnDrawThemeText) + return (*lpfnDrawThemeText) (hTheme, hdc, iPartId, iStateId, pszText, iCharCount, dwTextFlags, dwTextFlags2, pRect); + else + return S_FALSE; +} + +HRESULT VisualStylesAPI::GetThemePartSize( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, RECT *prc, THEMESIZE eSize, SIZE *psz ) +{ + if(lpfnGetThemePartSize) + return (*lpfnGetThemePartSize) (hTheme, hdc, iPartId, iStateId, prc, eSize, psz); + else + return S_FALSE; +} + +bool VisualStylesAPI::IsThemeActive() +{ + if(lpfnIsThemeActive) + return (*lpfnIsThemeActive) (); + else + return false; +} + +/********************************************************* + * 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() +{ + for( auto& rEntry : aThemeMap ) + vsAPI.CloseThemeData(rEntry.second); + aThemeMap.clear(); +} + +static HTHEME getThemeHandle( HWND hWnd, LPCWSTR name ) +{ + if( GetSalData()->mbThemeChanged ) + { + // throw away invalid theme handles + SalData::deInitNWF(); + 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 = vsAPI.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"); + 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"); + 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"); + else if( nPart == ControlPart::ButtonDown ) + hTheme = getThemeHandle( mhWnd, L"Combobox"); + break; + case ControlType::Spinbox: + if( nPart == ControlPart::Entire ) + hTheme = getThemeHandle( mhWnd, L"Edit"); + else if( nPart == ControlPart::AllButtons || + nPart == ControlPart::ButtonUp || nPart == ControlPart::ButtonDown || + nPart == ControlPart::ButtonLeft|| nPart == ControlPart::ButtonRight ) + hTheme = getThemeHandle( mhWnd, L"Spin"); + break; + case ControlType::SpinButtons: + if( nPart == ControlPart::Entire || nPart == ControlPart::AllButtons ) + hTheme = getThemeHandle( mhWnd, L"Spin"); + 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"); + 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"); + else if( nPart == ControlPart::ButtonDown ) + hTheme = getThemeHandle( mhWnd, L"Combobox"); + break; + case ControlType::TabPane: + case ControlType::TabBody: + case ControlType::TabItem: + if( nPart == ControlPart::Entire ) + hTheme = getThemeHandle( mhWnd, L"Tab"); + break; + case ControlType::Toolbar: + if( nPart == ControlPart::Entire || nPart == ControlPart::Button ) + hTheme = getThemeHandle( mhWnd, L"Toolbar"); + else + // use rebar theme for grip and background + hTheme = getThemeHandle( mhWnd, L"Rebar"); + break; + case ControlType::Menubar: + if( nPart == ControlPart::Entire ) + hTheme = getThemeHandle( mhWnd, L"Rebar"); + else if( GetSalData()->mbThemeMenuSupport ) + { + if( nPart == ControlPart::MenuItem ) + hTheme = getThemeHandle( mhWnd, L"Menu" ); + } + 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" ); + } + break; + case ControlType::Progress: + if( nPart == ControlPart::Entire ) + hTheme = getThemeHandle( mhWnd, L"Progress"); + break; + case ControlType::Slider: + if( nPart == ControlPart::TrackHorzArea || nPart == ControlPart::TrackVertArea ) + hTheme = getThemeHandle( mhWnd, L"Trackbar" ); + break; + case ControlType::ListNode: + if( nPart == ControlPart::Entire ) + hTheme = getThemeHandle( mhWnd, L"TreeView" ); + 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 = vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, nullptr); + + if( aStr.getLength() ) + { + RECT rcContent; + hr = vsAPI.GetThemeBackgroundContentRect( hTheme, hDC, iPart, iState, &rc, &rcContent); + hr = vsAPI.DrawThemeText( hTheme, hDC, iPart, iState, + o3tl::toW(aStr.getStr()), -1, + DT_CENTER | DT_VCENTER | DT_SINGLELINE, + 0, &rcContent); + } + return (hr == S_OK); +} + +static tools::Rectangle ImplGetThemeRect( HTHEME hTheme, HDC hDC, int iPart, int iState, const tools::Rectangle& /* aRect */, THEMESIZE eTS = TS_TRUE ) +{ + SIZE aSz; + HRESULT hr = vsAPI.GetThemePartSize( hTheme, hDC, iPart, iState, nullptr, eTS, &aSz ); // TS_TRUE returns optimal size + if( hr == S_OK ) + return tools::Rectangle( 0, 0, aSz.cx, aSz.cy ); + else + return tools::Rectangle(); +} + +// Helper functions + +static void ImplConvertSpinbuttonValues( ControlPart nControlPart, const ControlState& 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 long 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 ); + } + } +} + +/** + * Gives the actual rectangle used for rendering by ControlType::MenuPopup's + * ControlPart::MenuItemCheckMark or ControlPart::MenuItemRadioMark. + */ +static tools::Rectangle GetMenuPopupMarkRegion(const ImplControlValue& rValue) +{ + tools::Rectangle aRet; + + auto pMVal = dynamic_cast<const MenupopupValue*>(&rValue); + if (!pMVal) + return aRet; + + aRet.SetTop(pMVal->maItemRect.Top()); + aRet.SetBottom(pMVal->maItemRect.Bottom() + 1); // see below in drawNativeControl + if (AllSettings::GetLayoutRTL()) + { + aRet.SetRight(pMVal->maItemRect.Right() + 1); + aRet.SetLeft(aRet.Right() - (pMVal->getNumericVal() - pMVal->maItemRect.Left())); + } + else + { + aRet.SetRight(pMVal->getNumericVal()); + aRet.SetLeft(pMVal->maItemRect.Left()); + } + + return aRet; +} + +static bool ImplDrawNativeControl( HDC hDC, HTHEME hTheme, RECT rc, + ControlType nType, + ControlPart nPart, + ControlState nState, + const ImplControlValue& aValue, + OUString const & aCaption ) +{ + // 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; + + 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; + hr = vsAPI.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; + hr = vsAPI.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; + hr = vsAPI.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; + hr = vsAPI.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; + vsAPI.GetThemePartSize(hTheme, hDC, iPart, iState, nullptr, TS_MIN, &sz); + vsAPI.GetThemePartSize(hTheme, hDC, iPart, iState, nullptr, TS_TRUE, &sz); + vsAPI.GetThemePartSize(hTheme, hDC, iPart, iState, nullptr, TS_DRAW, &sz); + + hr = vsAPI.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; + vsAPI.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; + default: break; + } + + 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; + hr = vsAPI.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; + + 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 + //vsAPI.GetThemePartSize( hTheme, hDC, iPart, iState, &rc, eSize, &sz); + + return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption); + } + + if( ( nType == ControlType::Editbox ) || ( 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 ) + { + iPart = TABP_PANE; + return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption); + } + + if( nType == ControlType::TabBody ) + { + 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; + 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; + 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 + } + + // make it more compatible with Aero + if( ImplGetSVData()->maNWFData.mbDockingAreaAvoidTBFrames ) + { + 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 + + // make it more compatible with Aero + if( ImplGetSVData()->maNWFData.mbDockingAreaAvoidTBFrames ) + { + 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; + } + 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 ) + { + if( nPart != ControlPart::Entire ) + return false; + + if( ! ImplDrawTheme( hTheme, hDC, PP_BAR, iState, rc, aCaption) ) + return false; + RECT aProgressRect = rc; + if( vsAPI.GetThemeBackgroundContentRect( hTheme, hDC, PP_BAR, iState, &rc, &aProgressRect) != S_OK ) + return false; + + 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; + + 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 ) + { + long nH = aTrackRect.GetHeight(); + aTRect.top += (rc.bottom - rc.top - nH)/2; + aTRect.bottom = aTRect.top + nH; + } + else + { + 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: + 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; + } + 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; + return ImplDrawTheme( hTheme, hDC, MENU_POPUPITEM, iState, rc, aCaption ); + } + else if( nPart == ControlPart::MenuItemCheckMark || nPart == ControlPart::MenuItemRadioMark ) + { + if( nState & ControlState::PRESSED ) + { + RECT aBGRect = rc; + if( aValue.getType() == ControlType::MenuPopup ) + { + tools::Rectangle aRectangle = GetMenuPopupMarkRegion(aValue); + aBGRect.top = aRectangle.Top(); + aBGRect.left = aRectangle.Left(); + aBGRect.bottom = aRectangle.Bottom(); + aBGRect.right = aRectangle.Right(); + rc = aBGRect; + } + iState = (nState & ControlState::ENABLED) ? MCB_NORMAL : MCB_DISABLED; + ImplDrawTheme( hTheme, hDC, MENU_POPUPCHECKBACKGROUND, iState, aBGRect, aCaption ); + if( nPart == ControlPart::MenuItemCheckMark ) + iState = (nState & ControlState::ENABLED) ? MC_CHECKMARKNORMAL : MC_CHECKMARKDISABLED; + else + iState = (nState & ControlState::ENABLED) ? MC_BULLETNORMAL : MC_BULLETDISABLED; + return ImplDrawTheme( hTheme, hDC, MENU_POPUPCHECK, iState, rc, 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 + long 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 = dynamic_cast<WinSalGraphicsImplBase*>(mpImpl.get()); + 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(); + } + } + + if (pImpl && nType == ControlType::MenuPopup && (nPart == ControlPart::MenuItemCheckMark || nPart == ControlPart::MenuItemRadioMark)) + { + tools::Rectangle aRectangle = GetMenuPopupMarkRegion(aValue); + if (!aRectangle.IsEmpty()) + { + cacheRect = GetMenuPopupMarkRegion(aValue); + buttonRect = cacheRect; + keySize = cacheRect.GetSize(); + } + } + + + ControlCacheKey aControlCacheKey(nType, nPart, nState, keySize); + if (pImpl != nullptr && pImpl->TryRenderCachedNativeControl(aControlCacheKey, buttonRect.Left(), buttonRect.Top())) + { + return true; + } + + switch( nType ) + { + case ControlType::Pushbutton: + case ControlType::Radiobutton: + case ControlType::Checkbox: + hTheme = getThemeHandle( mhWnd, L"Button"); + break; + case ControlType::Scrollbar: + hTheme = getThemeHandle( mhWnd, L"Scrollbar"); + break; + case ControlType::Combobox: + if( nPart == ControlPart::Entire ) + hTheme = getThemeHandle( mhWnd, L"Edit"); + else if( nPart == ControlPart::ButtonDown ) + hTheme = getThemeHandle( mhWnd, L"Combobox"); + break; + case ControlType::Spinbox: + if( nPart == ControlPart::Entire ) + hTheme = getThemeHandle( mhWnd, L"Edit"); + else + hTheme = getThemeHandle( mhWnd, L"Spin"); + break; + case ControlType::SpinButtons: + hTheme = getThemeHandle( mhWnd, L"Spin"); + break; + case ControlType::Editbox: + case ControlType::MultilineEditbox: + hTheme = getThemeHandle( mhWnd, L"Edit"); + break; + case ControlType::Listbox: + if( nPart == ControlPart::Entire || nPart == ControlPart::ListboxWindow ) + hTheme = getThemeHandle( mhWnd, L"Listview"); + else if( nPart == ControlPart::ButtonDown ) + hTheme = getThemeHandle( mhWnd, L"Combobox"); + break; + case ControlType::TabPane: + case ControlType::TabBody: + case ControlType::TabItem: + hTheme = getThemeHandle( mhWnd, L"Tab"); + break; + case ControlType::Toolbar: + if( nPart == ControlPart::Entire || nPart == ControlPart::Button ) + hTheme = getThemeHandle( mhWnd, L"Toolbar"); + else + // use rebar for grip and background + hTheme = getThemeHandle( mhWnd, L"Rebar"); + break; + case ControlType::Menubar: + if( nPart == ControlPart::Entire ) + hTheme = getThemeHandle( mhWnd, L"Rebar"); + else if( GetSalData()->mbThemeMenuSupport ) + { + if( nPart == ControlPart::MenuItem ) + hTheme = getThemeHandle( mhWnd, L"Menu" ); + } + break; + case ControlType::Progress: + if( nPart == ControlPart::Entire ) + hTheme = getThemeHandle( mhWnd, L"Progress"); + break; + case ControlType::ListNode: + if( nPart == ControlPart::Entire ) + hTheme = getThemeHandle( mhWnd, L"TreeView"); + break; + case ControlType::Slider: + if( nPart == ControlPart::TrackHorzArea || nPart == ControlPart::TrackVertArea ) + hTheme = getThemeHandle( mhWnd, L"Trackbar" ); + 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" ); + } + break; + default: + hTheme = nullptr; + break; + } + + if( !hTheme ) + return false; + + RECT rc; + rc.left = buttonRect.Left(); + rc.right = buttonRect.Right()+1; + rc.top = buttonRect.Top(); + rc.bottom = buttonRect.Bottom()+1; + + OUString aCaptionStr(aCaption.replace('~', '&')); // translate mnemonics + + if (pImpl == nullptr) + { + // set default text alignment + int ta = SetTextAlign(getHDC(), TA_LEFT|TA_TOP|TA_NOUPDATECP); + + bOk = ImplDrawNativeControl(getHDC(), hTheme, rc, nType, nPart, nState, aValue, aCaptionStr); + + // restore alignment + SetTextAlign(getHDC(), ta); + } + else + { + // We can do OpenGL/Skia + std::unique_ptr<CompatibleDC> aBlackDC(CompatibleDC::create(*this, cacheRect.Left(), cacheRect.Top(), cacheRect.GetWidth()+1, cacheRect.GetHeight()+1)); + SetTextAlign(aBlackDC->getCompatibleHDC(), TA_LEFT|TA_TOP|TA_NOUPDATECP); + aBlackDC->fill(RGB(0, 0, 0)); + + std::unique_ptr<CompatibleDC> aWhiteDC(CompatibleDC::create(*this, cacheRect.Left(), cacheRect.Top(), cacheRect.GetWidth()+1, cacheRect.GetHeight()+1)); + SetTextAlign(aWhiteDC->getCompatibleHDC(), TA_LEFT|TA_TOP|TA_NOUPDATECP); + aWhiteDC->fill(RGB(0xff, 0xff, 0xff)); + + if (ImplDrawNativeControl(aBlackDC->getCompatibleHDC(), hTheme, rc, nType, nPart, nState, aValue, aCaptionStr) && + ImplDrawNativeControl(aWhiteDC->getCompatibleHDC(), hTheme, rc, nType, nPart, nState, aValue, aCaptionStr)) + { + bOk = pImpl->RenderAndCacheNativeControl(*aWhiteDC, *aBlackDC, cacheRect.Left(), cacheRect.Top(), aControlCacheKey); + } + } + + return bOk; +} + +bool WinSalGraphics::getNativeControlRegion( ControlType nType, + ControlPart nPart, + const tools::Rectangle& rControlRegion, + ControlState nState, + const ImplControlValue& rControlValue, + const OUString&, + tools::Rectangle &rNativeBoundingRegion, + tools::Rectangle &rNativeContentRegion ) +{ + bool bRet = false; + + // FIXME: rNativeBoundingRegion has a different origin + // depending on which part is used; horrors. + + HDC hDC = GetDC( mhWnd ); + if( nType == ControlType::Toolbar ) + { + 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 + + HTHEME hTheme = getThemeHandle( mhWnd, L"Rebar"); + if( hTheme ) + { + tools::Rectangle aRect( ImplGetThemeRect( hTheme, hDC, nPart == ControlPart::ThumbHorz ? RP_GRIPPERVERT : RP_GRIPPER, + 0, rControlRegion.GetBoundRect() ) ); + if( nPart == ControlPart::ThumbHorz && !aRect.IsEmpty() ) + { + tools::Rectangle aVertRect( 0, 0, aRect.getHeight(), aRect.getWidth() ); + rNativeContentRegion = aVertRect; + } + else + rNativeContentRegion = aRect; + rNativeBoundingRegion = rNativeContentRegion; + if( !rNativeContentRegion.IsEmpty() ) + bRet = TRUE; + } + */ + } + if( nPart == ControlPart::Button ) + { + HTHEME hTheme = getThemeHandle( mhWnd, L"Toolbar"); + if( hTheme ) + { + tools::Rectangle aRect( ImplGetThemeRect( hTheme, hDC, TP_SPLITBUTTONDROPDOWN, + TS_HOT, rControlRegion ) ); + rNativeContentRegion = aRect; + rNativeBoundingRegion = rNativeContentRegion; + if( !rNativeContentRegion.IsEmpty() ) + bRet = true; + } + } + } + if( nType == ControlType::Progress && nPart == ControlPart::Entire ) + { + HTHEME hTheme = getThemeHandle( mhWnd, L"Progress"); + if( hTheme ) + { + tools::Rectangle aRect( ImplGetThemeRect( hTheme, hDC, PP_BAR, + 0, rControlRegion ) ); + rNativeContentRegion = aRect; + rNativeBoundingRegion = rNativeContentRegion; + if( !rNativeContentRegion.IsEmpty() ) + bRet = true; + } + } + if( (nType == ControlType::Listbox || nType == ControlType::Combobox ) && nPart == ControlPart::Entire ) + { + HTHEME hTheme = getThemeHandle( mhWnd, L"Combobox"); + if( hTheme ) + { + tools::Rectangle aBoxRect( rControlRegion ); + tools::Rectangle aRect( ImplGetThemeRect( hTheme, hDC, CP_DROPDOWNBUTTON, + CBXS_NORMAL, aBoxRect ) ); + if( aRect.GetHeight() > aBoxRect.GetHeight() ) + aBoxRect.SetBottom( aBoxRect.Top() + aRect.GetHeight() ); + if( aRect.GetWidth() > aBoxRect.GetWidth() ) + aBoxRect.SetRight( aBoxRect.Left() + aRect.GetWidth() ); + rNativeContentRegion = aBoxRect; + rNativeBoundingRegion = rNativeContentRegion; + if( !aRect.IsEmpty() ) + bRet = true; + } + } + + if( (nType == ControlType::Editbox || nType == ControlType::Spinbox) && nPart == ControlPart::Entire ) + { + HTHEME hTheme = getThemeHandle( mhWnd, L"Edit"); + if( hTheme ) + { + // get border size + tools::Rectangle aBoxRect( rControlRegion ); + tools::Rectangle aRect( ImplGetThemeRect( hTheme, hDC, EP_BACKGROUNDWITHBORDER, + EBWBS_HOT, aBoxRect ) ); + // ad app font height + NONCLIENTMETRICSW aNonClientMetrics; + aNonClientMetrics.cbSize = sizeof( aNonClientMetrics ); + if ( SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, sizeof( aNonClientMetrics ), &aNonClientMetrics, 0 ) ) + { + long nFontHeight = aNonClientMetrics.lfMessageFont.lfHeight; + if( nFontHeight < 0 ) + nFontHeight = -nFontHeight; + + if( aRect.GetHeight() && nFontHeight ) + { + aRect.AdjustBottom(aRect.GetHeight()); + aRect.AdjustBottom(nFontHeight); + if( aRect.GetHeight() > aBoxRect.GetHeight() ) + aBoxRect.SetBottom( aBoxRect.Top() + aRect.GetHeight() ); + if( aRect.GetWidth() > aBoxRect.GetWidth() ) + aBoxRect.SetRight( aBoxRect.Left() + aRect.GetWidth() ); + rNativeContentRegion = aBoxRect; + rNativeBoundingRegion = rNativeContentRegion; + bRet = true; + } + } + } + } + + if( GetSalData()->mbThemeMenuSupport ) + { + if( nType == ControlType::MenuPopup ) + { + if( nPart == ControlPart::MenuItemCheckMark || + nPart == ControlPart::MenuItemRadioMark ) + { + HTHEME hTheme = getThemeHandle( mhWnd, L"Menu"); + tools::Rectangle aBoxRect( rControlRegion ); + tools::Rectangle aRect( ImplGetThemeRect( hTheme, hDC, + MENU_POPUPCHECK, + MC_CHECKMARKNORMAL, + aBoxRect ) ); + if( aBoxRect.GetWidth() && aBoxRect.GetHeight() ) + { + rNativeContentRegion = aRect; + rNativeBoundingRegion = rNativeContentRegion; + bRet = true; + } + } + } + } + + if( nType == ControlType::Slider && ( (nPart == ControlPart::ThumbHorz) || (nPart == ControlPart::ThumbVert) ) ) + { + HTHEME hTheme = getThemeHandle( mhWnd, L"Trackbar"); + if( hTheme ) + { + int iPart = (nPart == ControlPart::ThumbHorz) ? TKP_THUMB : TKP_THUMBVERT; + int iState = (nPart == ControlPart::ThumbHorz) ? static_cast<int>(TUS_NORMAL) : static_cast<int>(TUVS_NORMAL); + tools::Rectangle aThumbRect = ImplGetThemeRect( hTheme, hDC, iPart, iState, tools::Rectangle() ); + if( nPart == ControlPart::ThumbHorz ) + { + long nW = aThumbRect.GetWidth(); + tools::Rectangle aRect( rControlRegion ); + aRect.SetRight( aRect.Left() + nW - 1 ); + rNativeContentRegion = aRect; + rNativeBoundingRegion = rNativeContentRegion; + } + else + { + long nH = aThumbRect.GetHeight(); + tools::Rectangle aRect( rControlRegion ); + aRect.SetBottom( aRect.Top() + nH - 1 ); + rNativeContentRegion = aRect; + rNativeBoundingRegion = rNativeContentRegion; + } + bRet = true; + } + } + + if ( ( nType == ControlType::TabItem ) && ( nPart == ControlPart::Entire ) ) + { + tools::Rectangle aControlRect( rControlRegion ); + rNativeContentRegion = aControlRect; + + aControlRect.AdjustBottom(-1); + + if( rControlValue.getType() == ControlType::TabItem ) + { + const TabitemValue& rValue = static_cast<const TabitemValue&>(rControlValue); + if (rValue.isBothAligned()) + aControlRect.AdjustRight(-1); + + if ( nState & ControlState::SELECTED ) + { + aControlRect.AdjustLeft(-2); + if (!rValue.isBothAligned()) + { + if (rValue.isLeftAligned() || rValue.isNotAligned()) + aControlRect.AdjustRight(2); + if (rValue.isRightAligned()) + aControlRect.AdjustRight(1); + } + aControlRect.AdjustTop(-2); + aControlRect.AdjustBottom(2); + } + } + rNativeBoundingRegion = aControlRect; + bRet = true; + } + + ReleaseDC( mhWnd, hDC ); + return bRet; +} + +void WinSalGraphics::updateSettingsNative( AllSettings& rSettings ) +{ + if ( !vsAPI.IsThemeActive() ) + return; + + StyleSettings aStyleSettings = rSettings.GetStyleSettings(); + ImplSVData* pSVData = ImplGetSVData(); + + // don't draw frame around each and every toolbar + pSVData->maNWFData.mbDockingAreaAvoidTBFrames = true; + + // FIXME get the color directly from the theme, not from the settings + Color aMenuBarTextColor = aStyleSettings.GetPersonaMenuBarTextColor().value_or( aStyleSettings.GetMenuTextColor() ); + // in aero menuitem highlight text is drawn in the same color as normal + aStyleSettings.SetMenuHighlightTextColor( aStyleSettings.GetMenuTextColor() ); + aStyleSettings.SetMenuBarRolloverTextColor( aMenuBarTextColor ); + aStyleSettings.SetMenuBarHighlightTextColor( aMenuBarTextColor ); + pSVData->maNWFData.mnMenuFormatBorderX = 2; + pSVData->maNWFData.mnMenuFormatBorderY = 2; + pSVData->maNWFData.maMenuBarHighlightTextColor = aMenuBarTextColor; + GetSalData()->mbThemeMenuSupport = true; + + rSettings.SetStyleSettings( aStyleSettings ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |