1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 // http://msdn.microsoft.com/en-us/library/windows/desktop/hh270423%28v=vs.85%29.aspx
22 // http://msdn.microsoft.com/en-us/library/windows/desktop/bb773178%28v=vs.85%29.aspx
24 // Useful tool to explore the themes & their rendering:
25 // http://privat.rejbrand.se/UxExplore.exe
26 // (found at http://stackoverflow.com/questions/4009701/windows-visual-themes-gallery-of-parts-and-states/4009712#4009712)
29 // http://msdn.microsoft.com/en-us/library/windows/desktop/bb773218%28v=vs.85%29.aspx
31 // Drawing in non-client area (general DWM-related info):
32 // http://msdn.microsoft.com/en-us/library/windows/desktop/bb688195%28v=vs.85%29.aspx
34 #include <rtl/ustring.h>
36 #include <osl/diagnose.h>
37 #include <osl/module.h>
38 #include <o3tl/char16_t2wchar_t.hxx>
40 #include <vcl/svapp.hxx>
41 #include <vcl/settings.hxx>
42 #include <toolbarvalue.hxx>
43 #include <menubarvalue.hxx>
45 #include <win/svsys.h>
46 #include <win/salgdi.h>
47 #include <win/saldata.hxx>
48 #include <win/salframe.h>
49 #include <win/scoped_gdi.hxx>
50 #include <win/wingdiimpl.hxx>
58 #include <ControlCacheKey.hxx>
60 typedef std::map
< std::wstring
, HTHEME
> ThemeMap
;
61 static ThemeMap aThemeMap
;
63 /*********************************************************
64 * Initialize XP theming and local stuff
65 *********************************************************/
66 void SalData::initNWF()
68 ImplSVData
* pSVData
= ImplGetSVData();
70 // the menu bar and the top docking area should have a common background (gradient)
71 pSVData
->maNWFData
.mbMenuBarDockingAreaCommonBG
= true;
74 // *********************************************************
75 // * Release theming handles
76 // ********************************************************
77 void SalData::deInitNWF()
79 for( auto& rEntry
: aThemeMap
)
80 CloseThemeData(rEntry
.second
);
84 static HTHEME
getThemeHandle(HWND hWnd
, LPCWSTR name
, WinSalGraphicsImplBase
* pGraphicsImpl
)
86 if( GetSalData()->mbThemeChanged
)
88 // throw away invalid theme handles
90 // throw away native control cache
91 pGraphicsImpl
->ClearNativeControlCache();
92 GetSalData()->mbThemeChanged
= false;
95 ThemeMap::iterator iter
;
96 if( (iter
= aThemeMap
.find( name
)) != aThemeMap
.end() )
98 // theme not found -> add it to map
99 HTHEME hTheme
= OpenThemeData( hWnd
, name
);
100 if( hTheme
!= nullptr )
101 aThemeMap
[name
] = hTheme
;
105 bool WinSalGraphics::isNativeControlSupported( ControlType nType
, ControlPart nPart
)
107 HTHEME hTheme
= nullptr;
111 case ControlType::Pushbutton
:
112 case ControlType::Radiobutton
:
113 case ControlType::Checkbox
:
114 if( nPart
== ControlPart::Entire
)
115 hTheme
= getThemeHandle(mhWnd
, L
"Button", mWinSalGraphicsImplBase
);
117 case ControlType::Scrollbar
:
118 if( nPart
== ControlPart::DrawBackgroundHorz
|| nPart
== ControlPart::DrawBackgroundVert
)
119 return false; // no background painting needed
120 if( nPart
== ControlPart::Entire
)
121 hTheme
= getThemeHandle(mhWnd
, L
"Scrollbar", mWinSalGraphicsImplBase
);
123 case ControlType::Combobox
:
124 if( nPart
== ControlPart::HasBackgroundTexture
)
125 return false; // we do not paint the inner part (ie the selection background/focus indication)
126 if( nPart
== ControlPart::Entire
)
127 hTheme
= getThemeHandle(mhWnd
, L
"Edit", mWinSalGraphicsImplBase
);
128 else if( nPart
== ControlPart::ButtonDown
)
129 hTheme
= getThemeHandle(mhWnd
, L
"Combobox", mWinSalGraphicsImplBase
);
131 case ControlType::Spinbox
:
132 if( nPart
== ControlPart::Entire
)
133 hTheme
= getThemeHandle(mhWnd
, L
"Edit", mWinSalGraphicsImplBase
);
134 else if( nPart
== ControlPart::AllButtons
||
135 nPart
== ControlPart::ButtonUp
|| nPart
== ControlPart::ButtonDown
||
136 nPart
== ControlPart::ButtonLeft
|| nPart
== ControlPart::ButtonRight
)
137 hTheme
= getThemeHandle(mhWnd
, L
"Spin", mWinSalGraphicsImplBase
);
139 case ControlType::SpinButtons
:
140 if( nPart
== ControlPart::Entire
|| nPart
== ControlPart::AllButtons
)
141 hTheme
= getThemeHandle(mhWnd
, L
"Spin", mWinSalGraphicsImplBase
);
143 case ControlType::Editbox
:
144 case ControlType::MultilineEditbox
:
145 if( nPart
== ControlPart::HasBackgroundTexture
)
146 return false; // we do not paint the inner part (ie the selection background/focus indication)
148 if( nPart
== ControlPart::Entire
)
149 hTheme
= getThemeHandle(mhWnd
, L
"Edit", mWinSalGraphicsImplBase
);
151 case ControlType::Listbox
:
152 if( nPart
== ControlPart::HasBackgroundTexture
)
153 return false; // we do not paint the inner part (ie the selection background/focus indication)
154 if( nPart
== ControlPart::Entire
|| nPart
== ControlPart::ListboxWindow
)
155 hTheme
= getThemeHandle(mhWnd
, L
"Listview", mWinSalGraphicsImplBase
);
156 else if( nPart
== ControlPart::ButtonDown
)
157 hTheme
= getThemeHandle(mhWnd
, L
"Combobox", mWinSalGraphicsImplBase
);
159 case ControlType::TabPane
:
160 case ControlType::TabBody
:
161 case ControlType::TabItem
:
162 if( nPart
== ControlPart::Entire
)
163 hTheme
= getThemeHandle(mhWnd
, L
"Tab", mWinSalGraphicsImplBase
);
165 case ControlType::Toolbar
:
166 if( nPart
== ControlPart::Entire
|| nPart
== ControlPart::Button
)
167 hTheme
= getThemeHandle(mhWnd
, L
"Toolbar", mWinSalGraphicsImplBase
);
169 // use rebar theme for grip and background
170 hTheme
= getThemeHandle(mhWnd
, L
"Rebar", mWinSalGraphicsImplBase
);
172 case ControlType::Menubar
:
173 if( nPart
== ControlPart::Entire
)
174 hTheme
= getThemeHandle(mhWnd
, L
"Rebar", mWinSalGraphicsImplBase
);
175 else if( GetSalData()->mbThemeMenuSupport
)
177 if( nPart
== ControlPart::MenuItem
)
178 hTheme
= getThemeHandle(mhWnd
, L
"Menu", mWinSalGraphicsImplBase
);
181 case ControlType::MenuPopup
:
182 if( GetSalData()->mbThemeMenuSupport
)
184 if( nPart
== ControlPart::Entire
||
185 nPart
== ControlPart::MenuItem
||
186 nPart
== ControlPart::MenuItemCheckMark
||
187 nPart
== ControlPart::MenuItemRadioMark
||
188 nPart
== ControlPart::Separator
)
189 hTheme
= getThemeHandle(mhWnd
, L
"Menu", mWinSalGraphicsImplBase
);
192 case ControlType::Progress
:
193 case ControlType::LevelBar
:
194 if( nPart
== ControlPart::Entire
)
195 hTheme
= getThemeHandle(mhWnd
, L
"Progress", mWinSalGraphicsImplBase
);
197 case ControlType::Slider
:
198 if( nPart
== ControlPart::TrackHorzArea
|| nPart
== ControlPart::TrackVertArea
)
199 hTheme
= getThemeHandle(mhWnd
, L
"Trackbar", mWinSalGraphicsImplBase
);
201 case ControlType::ListNode
:
202 if( nPart
== ControlPart::Entire
)
203 hTheme
= getThemeHandle(mhWnd
, L
"TreeView", mWinSalGraphicsImplBase
);
210 return (hTheme
!= nullptr);
213 bool WinSalGraphics::hitTestNativeControl( ControlType
,
215 const tools::Rectangle
&,
222 static bool ImplDrawTheme( HTHEME hTheme
, HDC hDC
, int iPart
, int iState
, RECT rc
, const OUString
& aStr
)
224 HRESULT hr
= DrawThemeBackground( hTheme
, hDC
, iPart
, iState
, &rc
, nullptr);
226 if( aStr
.getLength() )
229 hr
= GetThemeBackgroundContentRect( hTheme
, hDC
, iPart
, iState
, &rc
, &rcContent
);
230 hr
= DrawThemeText( hTheme
, hDC
, iPart
, iState
,
231 o3tl::toW(aStr
.getStr()), -1,
232 DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
,
238 // TS_TRUE returns optimal size
239 static std::optional
<Size
> ImplGetThemeSize(HTHEME hTheme
, HDC hDC
, int iPart
, int iState
, LPCRECT pRect
, THEMESIZE eTS
= TS_TRUE
)
241 if (SIZE aSz
; SUCCEEDED(GetThemePartSize(hTheme
, hDC
, iPart
, iState
, pRect
, eTS
, &aSz
)))
242 return Size(aSz
.cx
, aSz
.cy
);
246 static tools::Rectangle
ImplGetThemeRect( HTHEME hTheme
, HDC hDC
, int iPart
, int iState
, const tools::Rectangle
& /* aRect */, THEMESIZE eTS
= TS_TRUE
)
248 if (const std::optional
<Size
> oSz
= ImplGetThemeSize(hTheme
, hDC
, iPart
, iState
, nullptr, eTS
))
249 return tools::Rectangle( 0, 0, oSz
->Width(), oSz
->Height() );
251 return tools::Rectangle();
256 static void ImplConvertSpinbuttonValues( ControlPart nControlPart
, const ControlState
& rState
, const tools::Rectangle
& rRect
,
257 int* pLunaPart
, int *pLunaState
, RECT
*pRect
)
259 if( nControlPart
== ControlPart::ButtonDown
)
261 *pLunaPart
= SPNP_DOWN
;
262 if( rState
& ControlState::PRESSED
)
263 *pLunaState
= DNS_PRESSED
;
264 else if( !(rState
& ControlState::ENABLED
) )
265 *pLunaState
= DNS_DISABLED
;
266 else if( rState
& ControlState::ROLLOVER
)
267 *pLunaState
= DNS_HOT
;
269 *pLunaState
= DNS_NORMAL
;
271 if( nControlPart
== ControlPart::ButtonUp
)
273 *pLunaPart
= SPNP_UP
;
274 if( rState
& ControlState::PRESSED
)
275 *pLunaState
= UPS_PRESSED
;
276 else if( !(rState
& ControlState::ENABLED
) )
277 *pLunaState
= UPS_DISABLED
;
278 else if( rState
& ControlState::ROLLOVER
)
279 *pLunaState
= UPS_HOT
;
281 *pLunaState
= UPS_NORMAL
;
283 if( nControlPart
== ControlPart::ButtonRight
)
285 *pLunaPart
= SPNP_UPHORZ
;
286 if( rState
& ControlState::PRESSED
)
287 *pLunaState
= DNHZS_PRESSED
;
288 else if( !(rState
& ControlState::ENABLED
) )
289 *pLunaState
= DNHZS_DISABLED
;
290 else if( rState
& ControlState::ROLLOVER
)
291 *pLunaState
= DNHZS_HOT
;
293 *pLunaState
= DNHZS_NORMAL
;
295 if( nControlPart
== ControlPart::ButtonLeft
)
297 *pLunaPart
= SPNP_DOWNHORZ
;
298 if( rState
& ControlState::PRESSED
)
299 *pLunaState
= UPHZS_PRESSED
;
300 else if( !(rState
& ControlState::ENABLED
) )
301 *pLunaState
= UPHZS_DISABLED
;
302 else if( rState
& ControlState::ROLLOVER
)
303 *pLunaState
= UPHZS_HOT
;
305 *pLunaState
= UPHZS_NORMAL
;
308 pRect
->left
= rRect
.Left();
309 pRect
->right
= rRect
.Right()+1;
310 pRect
->top
= rRect
.Top();
311 pRect
->bottom
= rRect
.Bottom()+1;
314 /// Draw an own toolbar style on Windows Vista or later, looks better there
315 static void impl_drawAeroToolbar( HDC hDC
, RECT rc
, bool bHorizontal
)
317 if ( rc
.top
== 0 && bHorizontal
)
319 const int GRADIENT_HEIGHT
= 32;
321 LONG gradient_break
= rc
.top
;
322 LONG gradient_bottom
= rc
.bottom
- 1;
323 GRADIENT_RECT g_rect
[1] = { { 0, 1 } };
325 // very slow gradient at the top (if we have space for that)
326 if ( gradient_bottom
- rc
.top
> GRADIENT_HEIGHT
)
328 gradient_break
= gradient_bottom
- GRADIENT_HEIGHT
;
330 TRIVERTEX vert
[2] = {
331 { rc
.left
, rc
.top
, 0xff00, 0xff00, 0xff00, 0xff00 },
332 { rc
.right
, gradient_break
, 0xfa00, 0xfa00, 0xfa00, 0xff00 },
334 GdiGradientFill( hDC
, vert
, 2, g_rect
, 1, GRADIENT_FILL_RECT_V
);
337 // gradient at the bottom
338 TRIVERTEX vert
[2] = {
339 { rc
.left
, gradient_break
, 0xfa00, 0xfa00, 0xfa00, 0xff00 },
340 { rc
.right
, gradient_bottom
, 0xf000, 0xf000, 0xf000, 0xff00 }
342 GdiGradientFill( hDC
, vert
, 2, g_rect
, 1, GRADIENT_FILL_RECT_V
);
344 // and a darker horizontal line under that
345 ScopedSelectedHPEN
hPen(hDC
, CreatePen(PS_SOLID
, 1, RGB( 0xb0, 0xb0, 0xb0)));
347 MoveToEx( hDC
, rc
.left
, gradient_bottom
, nullptr );
348 LineTo( hDC
, rc
.right
, gradient_bottom
);
352 ScopedHBRUSH
hbrush(CreateSolidBrush(RGB(0xf0, 0xf0, 0xf0)));
353 FillRect(hDC
, &rc
, hbrush
.get());
355 // darker line to distinguish the toolbar and viewshell
356 // it is drawn only for the horizontal toolbars; it did not look well
357 // when done for the vertical ones too
360 LONG from_x
, from_y
, to_x
, to_y
;
364 from_y
= to_y
= rc
.top
;
366 ScopedSelectedHPEN
hPen(hDC
, CreatePen(PS_SOLID
, 1, RGB( 0xb0, 0xb0, 0xb0)));
368 MoveToEx( hDC
, from_x
, from_y
, nullptr );
369 LineTo( hDC
, to_x
, to_y
);
374 static bool implDrawNativeMenuMark(HDC hDC
, HTHEME hTheme
, RECT rc
, ControlPart nPart
,
375 ControlState nState
, OUString
const& aCaption
)
377 int iState
= (nState
& ControlState::ENABLED
) ? MCB_NORMAL
: MCB_DISABLED
;
378 ImplDrawTheme(hTheme
, hDC
, MENU_POPUPCHECKBACKGROUND
, iState
, rc
, aCaption
);
379 if (nPart
== ControlPart::MenuItemCheckMark
)
380 iState
= (nState
& ControlState::ENABLED
) ? MC_CHECKMARKNORMAL
: MC_CHECKMARKDISABLED
;
382 iState
= (nState
& ControlState::ENABLED
) ? MC_BULLETNORMAL
: MC_BULLETDISABLED
;
383 // tdf#133697: Get true size of mark, to avoid stretching
384 if (auto oSize
= ImplGetThemeSize(hTheme
, hDC
, MENU_POPUPCHECK
, iState
, &rc
))
386 // center the mark inside the passed rectangle
387 if (const auto dx
= (rc
.right
- rc
.left
- oSize
->Width() + 1) / 2; dx
> 0)
390 rc
.right
= rc
.left
+ oSize
->Width();
392 if (const auto dy
= (rc
.bottom
- rc
.top
- oSize
->Height() + 1) / 2; dy
> 0)
395 rc
.bottom
= rc
.top
+ oSize
->Height();
398 return ImplDrawTheme(hTheme
, hDC
, MENU_POPUPCHECK
, iState
, rc
, aCaption
);
403 static bool bOSSupportsDarkMode
= OSSupportsDarkMode();
404 if (!bOSSupportsDarkMode
)
408 switch (MiscSettings::GetDarkMode())
413 HINSTANCE hUxthemeLib
= LoadLibraryExW(L
"uxtheme.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32
);
417 typedef bool(WINAPI
* ShouldAppsUseDarkMode_t
)();
418 if (auto ShouldAppsUseDarkMode
= reinterpret_cast<ShouldAppsUseDarkMode_t
>(GetProcAddress(hUxthemeLib
, MAKEINTRESOURCEA(132))))
419 bRet
= ShouldAppsUseDarkMode();
421 FreeLibrary(hUxthemeLib
);
435 static bool ImplDrawNativeControl( HDC hDC
, HTHEME hTheme
, RECT rc
,
439 const ImplControlValue
& aValue
,
440 OUString
const & aCaption
,
443 // a listbox dropdown is actually a combobox dropdown
444 if( nType
== ControlType::Listbox
)
445 if( nPart
== ControlPart::ButtonDown
)
446 nType
= ControlType::Combobox
;
448 // draw entire combobox as a large edit box
449 if( nType
== ControlType::Combobox
)
450 if( nPart
== ControlPart::Entire
)
451 nType
= ControlType::Editbox
;
453 // draw entire spinbox as a large edit box
454 if( nType
== ControlType::Spinbox
)
455 if( nPart
== ControlPart::Entire
)
456 nType
= ControlType::Editbox
;
458 int iPart(0), iState(0);
459 if( nType
== ControlType::Scrollbar
)
462 if( nPart
== ControlPart::ButtonUp
)
464 iPart
= SBP_ARROWBTN
;
465 if( nState
& ControlState::PRESSED
)
466 iState
= ABS_UPPRESSED
;
467 else if( !(nState
& ControlState::ENABLED
) )
468 iState
= ABS_UPDISABLED
;
469 else if( nState
& ControlState::ROLLOVER
)
472 iState
= ABS_UPNORMAL
;
473 hr
= DrawThemeBackground( hTheme
, hDC
, iPart
, iState
, &rc
, nullptr);
476 if( nPart
== ControlPart::ButtonDown
)
478 iPart
= SBP_ARROWBTN
;
479 if( nState
& ControlState::PRESSED
)
480 iState
= ABS_DOWNPRESSED
;
481 else if( !(nState
& ControlState::ENABLED
) )
482 iState
= ABS_DOWNDISABLED
;
483 else if( nState
& ControlState::ROLLOVER
)
484 iState
= ABS_DOWNHOT
;
486 iState
= ABS_DOWNNORMAL
;
487 hr
= DrawThemeBackground( hTheme
, hDC
, iPart
, iState
, &rc
, nullptr);
490 if( nPart
== ControlPart::ButtonLeft
)
492 iPart
= SBP_ARROWBTN
;
493 if( nState
& ControlState::PRESSED
)
494 iState
= ABS_LEFTPRESSED
;
495 else if( !(nState
& ControlState::ENABLED
) )
496 iState
= ABS_LEFTDISABLED
;
497 else if( nState
& ControlState::ROLLOVER
)
498 iState
= ABS_LEFTHOT
;
500 iState
= ABS_LEFTNORMAL
;
501 hr
= DrawThemeBackground( hTheme
, hDC
, iPart
, iState
, &rc
, nullptr);
504 if( nPart
== ControlPart::ButtonRight
)
506 iPart
= SBP_ARROWBTN
;
507 if( nState
& ControlState::PRESSED
)
508 iState
= ABS_RIGHTPRESSED
;
509 else if( !(nState
& ControlState::ENABLED
) )
510 iState
= ABS_RIGHTDISABLED
;
511 else if( nState
& ControlState::ROLLOVER
)
512 iState
= ABS_RIGHTHOT
;
514 iState
= ABS_RIGHTNORMAL
;
515 hr
= DrawThemeBackground( hTheme
, hDC
, iPart
, iState
, &rc
, nullptr);
518 if( nPart
== ControlPart::ThumbHorz
|| nPart
== ControlPart::ThumbVert
)
520 iPart
= (nPart
== ControlPart::ThumbHorz
) ? SBP_THUMBBTNHORZ
: SBP_THUMBBTNVERT
;
521 if( nState
& ControlState::PRESSED
)
522 iState
= SCRBS_PRESSED
;
523 else if( !(nState
& ControlState::ENABLED
) )
524 iState
= SCRBS_DISABLED
;
525 else if( nState
& ControlState::ROLLOVER
)
528 iState
= SCRBS_NORMAL
;
531 GetThemePartSize(hTheme
, hDC
, iPart
, iState
, nullptr, TS_MIN
, &sz
);
532 GetThemePartSize(hTheme
, hDC
, iPart
, iState
, nullptr, TS_TRUE
, &sz
);
533 GetThemePartSize(hTheme
, hDC
, iPart
, iState
, nullptr, TS_DRAW
, &sz
);
535 hr
= DrawThemeBackground( hTheme
, hDC
, iPart
, iState
, &rc
, nullptr);
536 // paint gripper on thumb if enough space
537 if( ( (nPart
== ControlPart::ThumbVert
) && (rc
.bottom
-rc
.top
> 12) ) ||
538 ( (nPart
== ControlPart::ThumbHorz
) && (rc
.right
-rc
.left
> 12) ) )
540 iPart
= (nPart
== ControlPart::ThumbHorz
) ? SBP_GRIPPERHORZ
: SBP_GRIPPERVERT
;
542 DrawThemeBackground( hTheme
, hDC
, iPart
, iState
, &rc
, nullptr);
546 if( nPart
== ControlPart::TrackHorzLeft
|| nPart
== ControlPart::TrackHorzRight
|| nPart
== ControlPart::TrackVertUpper
|| nPart
== ControlPart::TrackVertLower
)
550 case ControlPart::TrackHorzLeft
: iPart
= SBP_UPPERTRACKHORZ
; break;
551 case ControlPart::TrackHorzRight
: iPart
= SBP_LOWERTRACKHORZ
; break;
552 case ControlPart::TrackVertUpper
: iPart
= SBP_UPPERTRACKVERT
; break;
553 case ControlPart::TrackVertLower
: iPart
= SBP_LOWERTRACKVERT
; break;
557 if( nState
& ControlState::PRESSED
)
558 iState
= SCRBS_PRESSED
;
559 else if( !(nState
& ControlState::ENABLED
) )
560 iState
= SCRBS_DISABLED
;
561 else if( nState
& ControlState::ROLLOVER
)
564 iState
= SCRBS_NORMAL
;
565 hr
= DrawThemeBackground( hTheme
, hDC
, iPart
, iState
, &rc
, nullptr);
569 if( nType
== ControlType::SpinButtons
&& nPart
== ControlPart::AllButtons
)
571 if( aValue
.getType() == ControlType::SpinButtons
)
573 const SpinbuttonValue
* pValue
= (aValue
.getType() == ControlType::SpinButtons
) ? static_cast<const SpinbuttonValue
*>(&aValue
) : nullptr;
576 ImplConvertSpinbuttonValues( pValue
->mnUpperPart
, pValue
->mnUpperState
, pValue
->maUpperRect
, &iPart
, &iState
, &rect
);
577 bool bOk
= ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, rect
, aCaption
);
581 ImplConvertSpinbuttonValues( pValue
->mnLowerPart
, pValue
->mnLowerState
, pValue
->maLowerRect
, &iPart
, &iState
, &rect
);
582 bOk
= ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, rect
, aCaption
);
588 if( nType
== ControlType::Spinbox
)
590 if( nPart
== ControlPart::AllButtons
)
592 if( aValue
.getType() == ControlType::SpinButtons
)
594 const SpinbuttonValue
*pValue
= static_cast<const SpinbuttonValue
*>(&aValue
);
597 ImplConvertSpinbuttonValues( pValue
->mnUpperPart
, pValue
->mnUpperState
, pValue
->maUpperRect
, &iPart
, &iState
, &rect
);
598 bool bOk
= ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, rect
, aCaption
);
602 ImplConvertSpinbuttonValues( pValue
->mnLowerPart
, pValue
->mnLowerState
, pValue
->maLowerRect
, &iPart
, &iState
, &rect
);
603 bOk
= ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, rect
, aCaption
);
610 if( nPart
== ControlPart::ButtonDown
)
613 if( nState
& ControlState::PRESSED
)
614 iState
= DNS_PRESSED
;
615 else if( !(nState
& ControlState::ENABLED
) )
616 iState
= DNS_DISABLED
;
617 else if( nState
& ControlState::ROLLOVER
)
622 if( nPart
== ControlPart::ButtonUp
)
625 if( nState
& ControlState::PRESSED
)
626 iState
= UPS_PRESSED
;
627 else if( !(nState
& ControlState::ENABLED
) )
628 iState
= UPS_DISABLED
;
629 else if( nState
& ControlState::ROLLOVER
)
634 if( nPart
== ControlPart::ButtonRight
)
636 iPart
= SPNP_DOWNHORZ
;
637 if( nState
& ControlState::PRESSED
)
638 iState
= DNHZS_PRESSED
;
639 else if( !(nState
& ControlState::ENABLED
) )
640 iState
= DNHZS_DISABLED
;
641 else if( nState
& ControlState::ROLLOVER
)
644 iState
= DNHZS_NORMAL
;
646 if( nPart
== ControlPart::ButtonLeft
)
649 if( nState
& ControlState::PRESSED
)
650 iState
= UPHZS_PRESSED
;
651 else if( !(nState
& ControlState::ENABLED
) )
652 iState
= UPHZS_DISABLED
;
653 else if( nState
& ControlState::ROLLOVER
)
656 iState
= UPHZS_NORMAL
;
658 if( nPart
== ControlPart::ButtonLeft
|| nPart
== ControlPart::ButtonRight
|| nPart
== ControlPart::ButtonUp
|| nPart
== ControlPart::ButtonDown
)
659 return ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, rc
, aCaption
);
661 if( nType
== ControlType::Combobox
)
663 if( nPart
== ControlPart::ButtonDown
)
665 iPart
= CP_DROPDOWNBUTTON
;
666 if( nState
& ControlState::PRESSED
)
667 iState
= CBXS_PRESSED
;
668 else if( !(nState
& ControlState::ENABLED
) )
669 iState
= CBXS_DISABLED
;
670 else if( nState
& ControlState::ROLLOVER
)
673 iState
= CBXS_NORMAL
;
674 return ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, rc
, aCaption
);
677 if( nType
== ControlType::Pushbutton
)
679 iPart
= BP_PUSHBUTTON
;
680 if( nState
& ControlState::PRESSED
)
681 iState
= PBS_PRESSED
;
682 else if( !(nState
& ControlState::ENABLED
) )
683 iState
= PBS_DISABLED
;
684 else if( nState
& ControlState::ROLLOVER
)
686 else if( nState
& ControlState::DEFAULT
)
687 iState
= PBS_DEFAULTED
;
688 //else if( nState & ControlState::FOCUSED )
689 // iState = PBS_DEFAULTED; // may need to draw focus rect
693 return ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, rc
, aCaption
);
696 if( nType
== ControlType::Radiobutton
)
698 iPart
= BP_RADIOBUTTON
;
699 bool bChecked
= ( aValue
.getTristateVal() == ButtonValue::On
);
701 if( nState
& ControlState::PRESSED
)
702 iState
= bChecked
? RBS_CHECKEDPRESSED
: RBS_UNCHECKEDPRESSED
;
703 else if( !(nState
& ControlState::ENABLED
) )
704 iState
= bChecked
? RBS_CHECKEDDISABLED
: RBS_UNCHECKEDDISABLED
;
705 else if( nState
& ControlState::ROLLOVER
)
706 iState
= bChecked
? RBS_CHECKEDHOT
: RBS_UNCHECKEDHOT
;
708 iState
= bChecked
? RBS_CHECKEDNORMAL
: RBS_UNCHECKEDNORMAL
;
710 //if( nState & ControlState::FOCUSED )
711 // iState |= PBS_DEFAULTED; // may need to draw focus rect
713 return ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, rc
, aCaption
);
716 if( nType
== ControlType::Checkbox
)
719 ButtonValue v
= aValue
.getTristateVal();
721 if( nState
& ControlState::PRESSED
)
722 iState
= (v
== ButtonValue::On
) ? CBS_CHECKEDPRESSED
:
723 ( (v
== ButtonValue::Off
) ? CBS_UNCHECKEDPRESSED
: CBS_MIXEDPRESSED
);
724 else if( !(nState
& ControlState::ENABLED
) )
725 iState
= (v
== ButtonValue::On
) ? CBS_CHECKEDDISABLED
:
726 ( (v
== ButtonValue::Off
) ? CBS_UNCHECKEDDISABLED
: CBS_MIXEDDISABLED
);
727 else if( nState
& ControlState::ROLLOVER
)
728 iState
= (v
== ButtonValue::On
) ? CBS_CHECKEDHOT
:
729 ( (v
== ButtonValue::Off
) ? CBS_UNCHECKEDHOT
: CBS_MIXEDHOT
);
731 iState
= (v
== ButtonValue::On
) ? CBS_CHECKEDNORMAL
:
732 ( (v
== ButtonValue::Off
) ? CBS_UNCHECKEDNORMAL
: CBS_MIXEDNORMAL
);
734 //if( nState & ControlState::FOCUSED )
735 // iState |= PBS_DEFAULTED; // may need to draw focus rect
738 //THEMESIZE eSize = TS_DRAW; // TS_MIN, TS_TRUE, TS_DRAW
739 //GetThemePartSize( hTheme, hDC, iPart, iState, &rc, eSize, &sz);
741 return ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, rc
, aCaption
);
744 if (nType
== ControlType::Editbox
)
746 iPart
= EP_EDITBORDER_NOSCROLL
;
747 if( !(nState
& ControlState::ENABLED
) )
748 iState
= EPSN_DISABLED
;
749 else if( nState
& ControlState::FOCUSED
)
750 iState
= EPSN_FOCUSED
;
751 else if( nState
& ControlState::ROLLOVER
)
754 iState
= EPSN_NORMAL
;
756 return ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, rc
, aCaption
);
759 if (nType
== ControlType::MultilineEditbox
)
762 if( !(nState
& ControlState::ENABLED
) )
763 iState
= ETS_DISABLED
;
764 else if( nState
& ControlState::FOCUSED
)
765 iState
= ETS_FOCUSED
;
766 else if( nState
& ControlState::ROLLOVER
)
771 return ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, rc
, aCaption
);
774 if( nType
== ControlType::Listbox
)
776 if( nPart
== ControlPart::Entire
|| nPart
== ControlPart::ListboxWindow
)
778 iPart
= LVP_EMPTYTEXT
; // ??? no idea which part to choose here
779 return ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, rc
, aCaption
);
783 if( nType
== ControlType::TabPane
)
785 // tabpane in tabcontrols gets drawn in "darkmode" as if it was a
786 // a "light" theme, so bodge this by drawing a frame directly
789 Color
aColor(Application::GetSettings().GetStyleSettings().GetDisableColor());
790 ScopedHBRUSH
hbrush(CreateSolidBrush(RGB(aColor
.GetRed(),
793 FrameRect(hDC
, &rc
, hbrush
.get());
797 return ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, rc
, aCaption
);
800 if( nType
== ControlType::TabBody
)
802 // tabbody in main window gets drawn in white in "darkmode", so bodge this here
805 Color
aColor(Application::GetSettings().GetStyleSettings().GetWindowColor());
806 ScopedHBRUSH
hbrush(CreateSolidBrush(RGB(aColor
.GetRed(),
809 FillRect(hDC
, &rc
, hbrush
.get());
814 return ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, rc
, aCaption
);
817 if( nType
== ControlType::TabItem
)
819 iPart
= TABP_TABITEMLEFTEDGE
;
822 OSL_ASSERT( aValue
.getType() == ControlType::TabItem
);
824 const TabitemValue
& rValue
= static_cast<const TabitemValue
&>(aValue
);
825 if (rValue
.isBothAligned())
827 iPart
= TABP_TABITEMLEFTEDGE
;
830 else if (rValue
.isLeftAligned())
831 iPart
= TABP_TABITEMLEFTEDGE
;
832 else if (rValue
.isRightAligned())
833 iPart
= TABP_TABITEMRIGHTEDGE
;
835 iPart
= TABP_TABITEM
;
837 if( !(nState
& ControlState::ENABLED
) )
838 iState
= TILES_DISABLED
;
839 else if( nState
& ControlState::SELECTED
)
841 iState
= TILES_SELECTED
;
842 // increase the selected tab
844 if (rValue
.isBothAligned())
846 if (rValue
.isLeftAligned() || rValue
.isNotAligned())
848 if (rValue
.isRightAligned())
854 else if( nState
& ControlState::ROLLOVER
)
856 else if( nState
& ControlState::FOCUSED
)
857 iState
= TILES_FOCUSED
; // may need to draw focus rect
859 iState
= TILES_NORMAL
;
861 // tabitem in tabcontrols gets drawn in "darkmode" as if it was a
862 // a "light" theme, so bodge this by drawing with a button instead
866 if (iState
== TILES_SELECTED
)
867 aColor
= Application::GetSettings().GetStyleSettings().GetActiveTabColor();
869 aColor
= Application::GetSettings().GetStyleSettings().GetInactiveTabColor();
870 ScopedHBRUSH
hbrush(CreateSolidBrush(RGB(aColor
.GetRed(),
873 FillRect(hDC
, &rc
, hbrush
.get());
875 aColor
= Application::GetSettings().GetStyleSettings().GetDisableColor();
876 ScopedSelectedHPEN
hPen(hDC
, CreatePen(PS_SOLID
, 1, RGB(aColor
.GetRed(),
881 apt
[0].y
= rc
.bottom
- (iPart
== TABP_TABITEMLEFTEDGE
? 1 : 2);
887 apt
[3].y
= rc
.bottom
- 1;
888 Polyline(hDC
, apt
, SAL_N_ELEMENTS(apt
));
892 return ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, rc
, aCaption
);
895 if( nType
== ControlType::Toolbar
)
897 if( nPart
== ControlPart::Button
)
900 bool bChecked
= ( aValue
.getTristateVal() == ButtonValue::On
);
901 if( !(nState
& ControlState::ENABLED
) )
902 //iState = TS_DISABLED;
903 // disabled buttons are typically not painted at all but we need visual
904 // feedback when travelling by keyboard over disabled entries
906 else if( nState
& ControlState::PRESSED
)
908 else if( nState
& ControlState::ROLLOVER
)
909 iState
= bChecked
? TS_HOTCHECKED
: TS_HOT
;
911 iState
= bChecked
? TS_CHECKED
: TS_NORMAL
;
912 return ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, rc
, aCaption
);
914 else if( nPart
== ControlPart::ThumbHorz
|| nPart
== ControlPart::ThumbVert
)
916 // the vertical gripper is not supported in most themes and it makes no
917 // sense to only support horizontal gripper
918 //iPart = (nPart == ControlPart::ThumbHorz) ? RP_GRIPPERVERT : RP_GRIPPER;
919 //return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
921 else if( nPart
== ControlPart::DrawBackgroundHorz
|| nPart
== ControlPart::DrawBackgroundVert
)
923 if( aValue
.getType() == ControlType::Toolbar
)
925 const ToolbarValue
*pValue
= static_cast<const ToolbarValue
*>(&aValue
);
926 if( pValue
->mbIsTopDockingArea
)
927 rc
.top
= 0; // extend potential gradient to cover menu bar as well
930 // toolbar in main window gets drawn in white in "darkmode", so bodge this here
933 Color
aColor(Application::GetSettings().GetStyleSettings().GetWindowColor());
934 ScopedHBRUSH
hbrush(CreateSolidBrush(RGB(aColor
.GetRed(),
937 FillRect(hDC
, &rc
, hbrush
.get());
941 // make it more compatible with Aero
942 if (ImplGetSVData()->maNWFData
.mbDockingAreaAvoidTBFrames
&&
943 !Application::GetSettings().GetStyleSettings().GetHighContrastMode())
945 impl_drawAeroToolbar( hDC
, rc
, nPart
== ControlPart::DrawBackgroundHorz
);
949 return ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, rc
, aCaption
);
953 if( nType
== ControlType::Menubar
)
955 if( nPart
== ControlPart::Entire
)
957 if( aValue
.getType() == ControlType::Menubar
)
959 const MenubarValue
*pValue
= static_cast<const MenubarValue
*>(&aValue
);
960 rc
.bottom
+= pValue
->maTopDockingAreaHeight
; // extend potential gradient to cover docking area as well
962 // menubar in main window gets drawn in white in "darkmode", so bodge this here
965 Color
aColor(Application::GetSettings().GetStyleSettings().GetWindowColor());
966 ScopedHBRUSH
hbrush(CreateSolidBrush(RGB(aColor
.GetRed(),
969 FillRect(hDC
, &rc
, hbrush
.get());
973 // make it more compatible with Aero
974 if (ImplGetSVData()->maNWFData
.mbDockingAreaAvoidTBFrames
&&
975 !Application::GetSettings().GetStyleSettings().GetHighContrastMode())
977 impl_drawAeroToolbar( hDC
, rc
, true );
981 return ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, rc
, aCaption
);
983 else if( nPart
== ControlPart::MenuItem
)
985 if( nState
& ControlState::ENABLED
)
987 if( nState
& ControlState::SELECTED
)
989 else if( nState
& ControlState::ROLLOVER
)
994 if(GetSalData()->mbThemeMenuSupport
&& Application::GetSettings().GetStyleSettings().GetHighContrastMode()
995 && ( nState
& (ControlState::SELECTED
| nState
& ControlState::ROLLOVER
)))
997 Color
aColor(Application::GetSettings().GetStyleSettings().GetHighlightColor());
998 ScopedHBRUSH
hbrush(CreateSolidBrush(RGB(aColor
.GetRed(),
1000 aColor
.GetBlue())));
1001 FillRect(hDC
, &rc
, hbrush
.get());
1007 if( nState
& ControlState::SELECTED
)
1008 iState
= MBI_DISABLEDPUSHED
;
1009 else if( nState
& ControlState::ROLLOVER
)
1010 iState
= MBI_DISABLEDHOT
;
1012 iState
= MBI_DISABLED
;
1014 return ImplDrawTheme( hTheme
, hDC
, MENU_BARITEM
, iState
, rc
, aCaption
);
1018 if( nType
== ControlType::Progress
|| nType
== ControlType::LevelBar
)
1020 if( nPart
!= ControlPart::Entire
)
1023 int nPartIdBackground
= PP_BAR
;
1024 if( nType
== ControlType::LevelBar
)
1026 nPartIdBackground
= PP_TRANSPARENTBAR
;
1027 iState
= PBBS_PARTIAL
;
1030 if( ! ImplDrawTheme( hTheme
, hDC
, nPartIdBackground
, iState
, rc
, aCaption
) )
1032 RECT aProgressRect
= rc
;
1033 if( GetThemeBackgroundContentRect( hTheme
, hDC
, PP_BAR
, iState
, &rc
, &aProgressRect
) != S_OK
)
1036 tools::Long nProgressWidth
= aValue
.getNumericVal();
1037 nProgressWidth
*= (aProgressRect
.right
- aProgressRect
.left
);
1038 nProgressWidth
/= (rc
.right
- rc
.left
);
1039 if( AllSettings::GetLayoutRTL() )
1040 aProgressRect
.left
= aProgressRect
.right
- nProgressWidth
;
1042 aProgressRect
.right
= aProgressRect
.left
+ nProgressWidth
;
1044 if (nType
== ControlType::LevelBar
)
1046 const auto nPercentage
1047 = aValue
.getNumericVal() * 100 / std::max(LONG
{ 1 }, (rc
.right
- rc
.left
));
1049 COLORREF aBrushColor
{};
1050 if (nPercentage
< 25)
1051 aBrushColor
= RGB(255, 0, 0);
1052 else if (nPercentage
< 50)
1053 aBrushColor
= RGB(255, 255, 0);
1054 else if (nPercentage
< 75)
1055 aBrushColor
= RGB(0, 0, 255);
1057 aBrushColor
= RGB(0, 255, 0);
1059 ScopedHBRUSH
hBrush(CreateSolidBrush(aBrushColor
));
1060 FillRect(hDC
, &aProgressRect
, hBrush
.get());
1064 return ImplDrawTheme( hTheme
, hDC
, PP_CHUNK
, iState
, aProgressRect
, aCaption
);
1067 if( nType
== ControlType::Slider
)
1069 iPart
= (nPart
== ControlPart::TrackHorzArea
) ? TKP_TRACK
: TKP_TRACKVERT
;
1070 iState
= (nPart
== ControlPart::TrackHorzArea
) ? static_cast<int>(TRS_NORMAL
) : static_cast<int>(TRVS_NORMAL
);
1072 tools::Rectangle aTrackRect
= ImplGetThemeRect( hTheme
, hDC
, iPart
, iState
, tools::Rectangle() );
1074 if( nPart
== ControlPart::TrackHorzArea
)
1076 tools::Long nH
= aTrackRect
.GetHeight();
1077 aTRect
.top
+= (rc
.bottom
- rc
.top
- nH
)/2;
1078 aTRect
.bottom
= aTRect
.top
+ nH
;
1082 tools::Long nW
= aTrackRect
.GetWidth();
1083 aTRect
.left
+= (rc
.right
- rc
.left
- nW
)/2;
1084 aTRect
.right
= aTRect
.left
+ nW
;
1086 ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, aTRect
, aCaption
);
1089 OSL_ASSERT( aValue
.getType() == ControlType::Slider
);
1090 const SliderValue
* pVal
= static_cast<const SliderValue
*>(&aValue
);
1091 aThumbRect
.left
= pVal
->maThumbRect
.Left();
1092 aThumbRect
.top
= pVal
->maThumbRect
.Top();
1093 aThumbRect
.right
= pVal
->maThumbRect
.Right();
1094 aThumbRect
.bottom
= pVal
->maThumbRect
.Bottom();
1095 iPart
= (nPart
== ControlPart::TrackHorzArea
) ? TKP_THUMB
: TKP_THUMBVERT
;
1096 iState
= (nState
& ControlState::ENABLED
) ? TUS_NORMAL
: TUS_DISABLED
;
1097 return ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, aThumbRect
, aCaption
);
1100 if( nType
== ControlType::ListNode
)
1102 if( nPart
!= ControlPart::Entire
)
1105 ButtonValue aButtonValue
= aValue
.getTristateVal();
1107 switch( aButtonValue
)
1109 case ButtonValue::On
:
1110 iState
= GLPS_OPENED
;
1112 case ButtonValue::Off
:
1113 iState
= GLPS_CLOSED
;
1118 return ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, rc
, aCaption
);
1121 if( GetSalData()->mbThemeMenuSupport
)
1123 if( nType
== ControlType::MenuPopup
)
1125 if( nPart
== ControlPart::Entire
)
1127 RECT aGutterRC
= rc
;
1128 if( AllSettings::GetLayoutRTL() )
1130 aGutterRC
.right
-= aValue
.getNumericVal()+1;
1131 aGutterRC
.left
= aGutterRC
.right
-3;
1135 aGutterRC
.left
+= aValue
.getNumericVal();
1136 aGutterRC
.right
= aGutterRC
.left
+3;
1139 ImplDrawTheme( hTheme
, hDC
, MENU_POPUPBACKGROUND
, 0, rc
, aCaption
) &&
1140 ImplDrawTheme( hTheme
, hDC
, MENU_POPUPGUTTER
, 0, aGutterRC
, aCaption
)
1143 else if( nPart
== ControlPart::MenuItem
)
1145 if( nState
& ControlState::ENABLED
)
1146 iState
= (nState
& ControlState::SELECTED
) ? MPI_HOT
: MPI_NORMAL
;
1148 iState
= (nState
& ControlState::SELECTED
) ? MPI_DISABLEDHOT
: MPI_DISABLED
;
1149 return ImplDrawTheme( hTheme
, hDC
, MENU_POPUPITEM
, iState
, rc
, aCaption
);
1151 else if( nPart
== ControlPart::MenuItemCheckMark
|| nPart
== ControlPart::MenuItemRadioMark
)
1153 if (nState
& ControlState::PRESSED
)
1154 return implDrawNativeMenuMark(hDC
, hTheme
, rc
, nPart
, nState
, aCaption
);
1156 return true; // unchecked: do nothing
1158 else if( nPart
== ControlPart::Separator
)
1160 // adjust for gutter position
1161 if( AllSettings::GetLayoutRTL() )
1162 rc
.right
-= aValue
.getNumericVal()+1;
1164 rc
.left
+= aValue
.getNumericVal()+1;
1165 tools::Rectangle
aRect( ImplGetThemeRect( hTheme
, hDC
,
1166 MENU_POPUPSEPARATOR
, 0, tools::Rectangle( rc
.left
, rc
.top
, rc
.right
, rc
.bottom
) ) );
1167 // center the separator inside the passed rectangle
1168 auto const nDY
= ((rc
.bottom
- rc
.top
+ 1) - aRect
.GetHeight()) / 2;
1170 rc
.bottom
= rc
.top
+aRect
.GetHeight()-1;
1171 return ImplDrawTheme( hTheme
, hDC
, MENU_POPUPSEPARATOR
, 0, rc
, aCaption
);
1179 bool WinSalGraphics::drawNativeControl( ControlType nType
,
1181 const tools::Rectangle
& rControlRegion
,
1182 ControlState nState
,
1183 const ImplControlValue
& aValue
,
1184 const OUString
& aCaption
,
1185 const Color
& /*rBackgroundColor*/ )
1188 HTHEME hTheme
= nullptr;
1190 tools::Rectangle buttonRect
= rControlRegion
;
1191 tools::Rectangle cacheRect
= rControlRegion
;
1192 Size keySize
= cacheRect
.GetSize();
1194 WinSalGraphicsImplBase
* pImpl
= mWinSalGraphicsImplBase
;
1195 if( !pImpl
->UseRenderNativeControl())
1198 // tdf#95618 - A few controls render outside the region they're given.
1199 if (pImpl
&& nType
== ControlType::TabItem
)
1201 tools::Rectangle rNativeBoundingRegion
;
1202 tools::Rectangle rNativeContentRegion
;
1203 if (getNativeControlRegion(nType
, nPart
, rControlRegion
, nState
, aValue
, aCaption
,
1204 rNativeBoundingRegion
, rNativeContentRegion
))
1206 cacheRect
= rNativeBoundingRegion
;
1207 keySize
= rNativeBoundingRegion
.GetSize();
1212 ControlCacheKey
aControlCacheKey(nType
, nPart
, nState
, keySize
);
1213 if (pImpl
!= nullptr && pImpl
->TryRenderCachedNativeControl(aControlCacheKey
, buttonRect
.Left(), buttonRect
.Top()))
1218 const bool bUseDarkMode
= UseDarkMode();
1220 SetWindowTheme(mhWnd
, L
"Explorer", nullptr);
1224 case ControlType::Pushbutton
:
1225 case ControlType::Radiobutton
:
1226 case ControlType::Checkbox
:
1227 hTheme
= getThemeHandle(mhWnd
, L
"Button", mWinSalGraphicsImplBase
);
1229 case ControlType::Scrollbar
:
1232 // tdf#153273 undo the earlier SetWindowTheme, and use an explicit Explorer::Scrollbar
1233 // a) with "Scrollbar" and SetWindowTheme(... "Explorer" ...) then scrollbars in dialog
1234 // and main windows are dark, but dropdowns are light
1235 // b) with "Explorer::Scrollbar" and SetWindowTheme(... "Explorer" ...) then scrollbars
1236 // in dropdowns are dark, but scrollbars in dialogs and main windows are sort of "extra
1238 // c) with "Explorer::Scrollbar" and no SetWindowTheme both cases are dark
1239 SetWindowTheme(mhWnd
, nullptr, nullptr);
1240 hTheme
= getThemeHandle(mhWnd
, L
"Explorer::Scrollbar", mWinSalGraphicsImplBase
);
1243 hTheme
= getThemeHandle(mhWnd
, L
"Scrollbar", mWinSalGraphicsImplBase
);
1245 case ControlType::Combobox
:
1246 if( nPart
== ControlPart::Entire
)
1248 if (bUseDarkMode
&& !(nState
& ControlState::FOCUSED
))
1249 SetWindowTheme(mhWnd
, L
"CFD", nullptr);
1250 hTheme
= getThemeHandle(mhWnd
, L
"Edit", mWinSalGraphicsImplBase
);
1252 else if( nPart
== ControlPart::ButtonDown
)
1255 SetWindowTheme(mhWnd
, L
"CFD", nullptr);
1256 hTheme
= getThemeHandle(mhWnd
, L
"Combobox", mWinSalGraphicsImplBase
);
1259 case ControlType::Spinbox
:
1260 if( nPart
== ControlPart::Entire
)
1262 if (bUseDarkMode
&& !(nState
& ControlState::FOCUSED
))
1263 SetWindowTheme(mhWnd
, L
"CFD", nullptr);
1264 hTheme
= getThemeHandle(mhWnd
, L
"Edit", mWinSalGraphicsImplBase
);
1267 hTheme
= getThemeHandle(mhWnd
, L
"Spin", mWinSalGraphicsImplBase
);
1269 case ControlType::SpinButtons
:
1270 hTheme
= getThemeHandle(mhWnd
, L
"Spin", mWinSalGraphicsImplBase
);
1272 case ControlType::Editbox
:
1273 if (bUseDarkMode
&& !(nState
& ControlState::FOCUSED
))
1274 SetWindowTheme(mhWnd
, L
"CFD", nullptr);
1275 hTheme
= getThemeHandle(mhWnd
, L
"Edit", mWinSalGraphicsImplBase
);
1277 case ControlType::MultilineEditbox
:
1278 hTheme
= getThemeHandle(mhWnd
, L
"Edit", mWinSalGraphicsImplBase
);
1280 case ControlType::Listbox
:
1281 if( nPart
== ControlPart::Entire
|| nPart
== ControlPart::ListboxWindow
)
1282 hTheme
= getThemeHandle(mhWnd
, L
"Listview", mWinSalGraphicsImplBase
);
1283 else if( nPart
== ControlPart::ButtonDown
)
1286 SetWindowTheme(mhWnd
, L
"CFD", nullptr);
1287 hTheme
= getThemeHandle(mhWnd
, L
"Combobox", mWinSalGraphicsImplBase
);
1290 case ControlType::TabBody
:
1291 hTheme
= getThemeHandle(mhWnd
, L
"Tab", mWinSalGraphicsImplBase
);
1293 case ControlType::TabPane
:
1294 case ControlType::TabItem
:
1295 hTheme
= getThemeHandle(mhWnd
, L
"Tab", mWinSalGraphicsImplBase
);
1297 case ControlType::Toolbar
:
1298 if( nPart
== ControlPart::Entire
|| nPart
== ControlPart::Button
)
1299 hTheme
= getThemeHandle(mhWnd
, L
"Toolbar", mWinSalGraphicsImplBase
);
1301 // use rebar for grip and background
1302 hTheme
= getThemeHandle(mhWnd
, L
"Rebar", mWinSalGraphicsImplBase
);
1304 case ControlType::Menubar
:
1305 if( nPart
== ControlPart::Entire
)
1306 hTheme
= getThemeHandle(mhWnd
, L
"Rebar", mWinSalGraphicsImplBase
);
1307 else if( GetSalData()->mbThemeMenuSupport
)
1309 if( nPart
== ControlPart::MenuItem
)
1310 hTheme
= getThemeHandle(mhWnd
, L
"Menu", mWinSalGraphicsImplBase
);
1313 case ControlType::Progress
:
1314 case ControlType::LevelBar
:
1315 if( nPart
== ControlPart::Entire
)
1316 hTheme
= getThemeHandle(mhWnd
, L
"Progress", mWinSalGraphicsImplBase
);
1318 case ControlType::ListNode
:
1319 if( nPart
== ControlPart::Entire
)
1320 hTheme
= getThemeHandle(mhWnd
, L
"TreeView", mWinSalGraphicsImplBase
);
1322 case ControlType::Slider
:
1323 if( nPart
== ControlPart::TrackHorzArea
|| nPart
== ControlPart::TrackVertArea
)
1324 hTheme
= getThemeHandle(mhWnd
, L
"Trackbar", mWinSalGraphicsImplBase
);
1326 case ControlType::MenuPopup
:
1327 if( GetSalData()->mbThemeMenuSupport
)
1329 if( nPart
== ControlPart::Entire
|| nPart
== ControlPart::MenuItem
||
1330 nPart
== ControlPart::MenuItemCheckMark
|| nPart
== ControlPart::MenuItemRadioMark
||
1331 nPart
== ControlPart::Separator
1333 hTheme
= getThemeHandle(mhWnd
, L
"Menu", mWinSalGraphicsImplBase
);
1344 SetWindowTheme(mhWnd
, nullptr, nullptr);
1349 rc
.left
= buttonRect
.Left();
1350 rc
.right
= buttonRect
.Right()+1;
1351 rc
.top
= buttonRect
.Top();
1352 rc
.bottom
= buttonRect
.Bottom()+1;
1354 OUString
aCaptionStr(aCaption
.replace('~', '&')); // translate mnemonics
1356 if (pImpl
== nullptr)
1358 // set default text alignment
1359 int ta
= SetTextAlign(getHDC(), TA_LEFT
|TA_TOP
|TA_NOUPDATECP
);
1361 bOk
= ImplDrawNativeControl(getHDC(), hTheme
, rc
, nType
, nPart
, nState
, aValue
, aCaptionStr
, bUseDarkMode
);
1363 // restore alignment
1364 SetTextAlign(getHDC(), ta
);
1368 // We can do OpenGL/Skia
1369 std::unique_ptr
<CompatibleDC
> aBlackDC(CompatibleDC::create(*this, cacheRect
.Left(), cacheRect
.Top(), cacheRect
.GetWidth()+1, cacheRect
.GetHeight()+1));
1370 SetTextAlign(aBlackDC
->getCompatibleHDC(), TA_LEFT
|TA_TOP
|TA_NOUPDATECP
);
1371 aBlackDC
->fill(RGB(0, 0, 0));
1373 std::unique_ptr
<CompatibleDC
> aWhiteDC(CompatibleDC::create(*this, cacheRect
.Left(), cacheRect
.Top(), cacheRect
.GetWidth()+1, cacheRect
.GetHeight()+1));
1374 SetTextAlign(aWhiteDC
->getCompatibleHDC(), TA_LEFT
|TA_TOP
|TA_NOUPDATECP
);
1375 aWhiteDC
->fill(RGB(0xff, 0xff, 0xff));
1377 if (ImplDrawNativeControl(aBlackDC
->getCompatibleHDC(), hTheme
, rc
, nType
, nPart
, nState
, aValue
, aCaptionStr
, bUseDarkMode
) &&
1378 ImplDrawNativeControl(aWhiteDC
->getCompatibleHDC(), hTheme
, rc
, nType
, nPart
, nState
, aValue
, aCaptionStr
, bUseDarkMode
))
1380 bOk
= pImpl
->RenderAndCacheNativeControl(*aWhiteDC
, *aBlackDC
, cacheRect
.Left(), cacheRect
.Top(), aControlCacheKey
);
1385 SetWindowTheme(mhWnd
, nullptr, nullptr);
1389 bool WinSalGraphics::getNativeControlRegion( ControlType nType
,
1391 const tools::Rectangle
& rControlRegion
,
1392 ControlState nState
,
1393 const ImplControlValue
& rControlValue
,
1395 tools::Rectangle
&rNativeBoundingRegion
,
1396 tools::Rectangle
&rNativeContentRegion
)
1400 // FIXME: rNativeBoundingRegion has a different origin
1401 // depending on which part is used; horrors.
1403 HDC hDC
= GetDC( mhWnd
);
1404 if( nType
== ControlType::Toolbar
)
1406 if( nPart
== ControlPart::ThumbHorz
|| nPart
== ControlPart::ThumbVert
)
1409 // the vertical gripper is not supported in most themes and it makes no
1410 // sense to only support horizontal gripper
1412 HTHEME hTheme = getThemeHandle(mhWnd, L"Rebar", mWinSalGraphicsImplBase);
1415 tools::Rectangle aRect( ImplGetThemeRect( hTheme, hDC, nPart == ControlPart::ThumbHorz ? RP_GRIPPERVERT : RP_GRIPPER,
1416 0, rControlRegion.GetBoundRect() ) );
1417 if( nPart == ControlPart::ThumbHorz && !aRect.IsEmpty() )
1419 tools::Rectangle aVertRect( 0, 0, aRect.getHeight(), aRect.getWidth() );
1420 rNativeContentRegion = aVertRect;
1423 rNativeContentRegion = aRect;
1424 rNativeBoundingRegion = rNativeContentRegion;
1425 if( !rNativeContentRegion.IsEmpty() )
1430 if( nPart
== ControlPart::Button
)
1432 HTHEME hTheme
= getThemeHandle(mhWnd
, L
"Toolbar", mWinSalGraphicsImplBase
);
1435 tools::Rectangle
aRect( ImplGetThemeRect( hTheme
, hDC
, TP_SPLITBUTTONDROPDOWN
,
1436 TS_HOT
, rControlRegion
) );
1437 rNativeContentRegion
= aRect
;
1438 rNativeBoundingRegion
= rNativeContentRegion
;
1439 if( !rNativeContentRegion
.IsEmpty() )
1444 if( nType
== ControlType::Progress
&& nPart
== ControlPart::Entire
)
1446 HTHEME hTheme
= getThemeHandle(mhWnd
, L
"Progress", mWinSalGraphicsImplBase
);
1449 tools::Rectangle
aRect( ImplGetThemeRect( hTheme
, hDC
, PP_BAR
,
1450 0, rControlRegion
) );
1451 rNativeContentRegion
= aRect
;
1452 rNativeBoundingRegion
= rNativeContentRegion
;
1453 if( !rNativeContentRegion
.IsEmpty() )
1457 if( (nType
== ControlType::Listbox
|| nType
== ControlType::Combobox
) && nPart
== ControlPart::Entire
)
1459 HTHEME hTheme
= getThemeHandle(mhWnd
, L
"Combobox", mWinSalGraphicsImplBase
);
1462 tools::Rectangle
aBoxRect( rControlRegion
);
1463 tools::Rectangle
aRect( ImplGetThemeRect( hTheme
, hDC
, CP_DROPDOWNBUTTON
,
1464 CBXS_NORMAL
, aBoxRect
) );
1465 if( aRect
.GetHeight() > aBoxRect
.GetHeight() )
1466 aBoxRect
.SetBottom( aBoxRect
.Top() + aRect
.GetHeight() );
1467 if( aRect
.GetWidth() > aBoxRect
.GetWidth() )
1468 aBoxRect
.SetRight( aBoxRect
.Left() + aRect
.GetWidth() );
1469 rNativeContentRegion
= aBoxRect
;
1470 rNativeBoundingRegion
= rNativeContentRegion
;
1471 if( !aRect
.IsEmpty() )
1476 if( (nType
== ControlType::Editbox
|| nType
== ControlType::Spinbox
) && nPart
== ControlPart::Entire
)
1478 HTHEME hTheme
= getThemeHandle(mhWnd
, L
"Edit", mWinSalGraphicsImplBase
);
1482 tools::Rectangle
aBoxRect( rControlRegion
);
1483 tools::Rectangle
aRect( ImplGetThemeRect( hTheme
, hDC
, EP_BACKGROUNDWITHBORDER
,
1484 EBWBS_HOT
, aBoxRect
) );
1485 // ad app font height
1486 NONCLIENTMETRICSW aNonClientMetrics
;
1487 aNonClientMetrics
.cbSize
= sizeof( aNonClientMetrics
);
1488 if ( SystemParametersInfoW( SPI_GETNONCLIENTMETRICS
, sizeof( aNonClientMetrics
), &aNonClientMetrics
, 0 ) )
1490 LONG nFontHeight
= aNonClientMetrics
.lfMessageFont
.lfHeight
;
1491 if( nFontHeight
< 0 )
1492 nFontHeight
= -nFontHeight
;
1494 if( aRect
.GetHeight() && nFontHeight
)
1496 aRect
.AdjustBottom(aRect
.GetHeight());
1497 aRect
.AdjustBottom(nFontHeight
);
1498 if( aRect
.GetHeight() > aBoxRect
.GetHeight() )
1499 aBoxRect
.SetBottom( aBoxRect
.Top() + aRect
.GetHeight() );
1500 if( aRect
.GetWidth() > aBoxRect
.GetWidth() )
1501 aBoxRect
.SetRight( aBoxRect
.Left() + aRect
.GetWidth() );
1502 rNativeContentRegion
= aBoxRect
;
1503 rNativeBoundingRegion
= rNativeContentRegion
;
1510 if( GetSalData()->mbThemeMenuSupport
)
1512 if( nType
== ControlType::MenuPopup
)
1514 if( nPart
== ControlPart::MenuItemCheckMark
||
1515 nPart
== ControlPart::MenuItemRadioMark
)
1517 HTHEME hTheme
= getThemeHandle(mhWnd
, L
"Menu", mWinSalGraphicsImplBase
);
1518 tools::Rectangle
aBoxRect( rControlRegion
);
1519 tools::Rectangle
aRect( ImplGetThemeRect( hTheme
, hDC
,
1523 if (!aRect
.IsEmpty())
1526 SUCCEEDED(GetThemeMargins(hTheme
, hDC
, MENU_POPUPCHECK
, MC_CHECKMARKNORMAL
,
1527 TMT_CONTENTMARGINS
, nullptr, &mg
)))
1529 aRect
.AdjustLeft(-mg
.cxLeftWidth
);
1530 aRect
.AdjustRight(mg
.cxRightWidth
);
1531 aRect
.AdjustTop(-mg
.cyTopHeight
);
1532 aRect
.AdjustBottom(mg
.cyBottomHeight
);
1534 rNativeContentRegion
= rNativeBoundingRegion
= aRect
;
1541 if( nType
== ControlType::Slider
&& ( (nPart
== ControlPart::ThumbHorz
) || (nPart
== ControlPart::ThumbVert
) ) )
1543 HTHEME hTheme
= getThemeHandle(mhWnd
, L
"Trackbar", mWinSalGraphicsImplBase
);
1546 int iPart
= (nPart
== ControlPart::ThumbHorz
) ? TKP_THUMB
: TKP_THUMBVERT
;
1547 int iState
= (nPart
== ControlPart::ThumbHorz
) ? static_cast<int>(TUS_NORMAL
) : static_cast<int>(TUVS_NORMAL
);
1548 tools::Rectangle aThumbRect
= ImplGetThemeRect( hTheme
, hDC
, iPart
, iState
, tools::Rectangle() );
1549 if( nPart
== ControlPart::ThumbHorz
)
1551 tools::Long nW
= aThumbRect
.GetWidth();
1552 tools::Rectangle
aRect( rControlRegion
);
1553 aRect
.SetRight( aRect
.Left() + nW
- 1 );
1554 rNativeContentRegion
= aRect
;
1555 rNativeBoundingRegion
= rNativeContentRegion
;
1559 tools::Long nH
= aThumbRect
.GetHeight();
1560 tools::Rectangle
aRect( rControlRegion
);
1561 aRect
.SetBottom( aRect
.Top() + nH
- 1 );
1562 rNativeContentRegion
= aRect
;
1563 rNativeBoundingRegion
= rNativeContentRegion
;
1569 if ( ( nType
== ControlType::TabItem
) && ( nPart
== ControlPart::Entire
) )
1571 tools::Rectangle
aControlRect( rControlRegion
);
1572 rNativeContentRegion
= aControlRect
;
1574 aControlRect
.AdjustBottom(-1);
1576 if( rControlValue
.getType() == ControlType::TabItem
)
1578 const TabitemValue
& rValue
= static_cast<const TabitemValue
&>(rControlValue
);
1579 if (rValue
.isBothAligned())
1580 aControlRect
.AdjustRight(-1);
1582 if ( nState
& ControlState::SELECTED
)
1584 aControlRect
.AdjustLeft(-2);
1585 if (!rValue
.isBothAligned())
1587 if (rValue
.isLeftAligned() || rValue
.isNotAligned())
1588 aControlRect
.AdjustRight(2);
1589 if (rValue
.isRightAligned())
1590 aControlRect
.AdjustRight(1);
1592 aControlRect
.AdjustTop(-2);
1593 aControlRect
.AdjustBottom(2);
1596 rNativeBoundingRegion
= aControlRect
;
1600 ReleaseDC( mhWnd
, hDC
);
1604 void WinSalGraphics::updateSettingsNative( AllSettings
& rSettings
)
1606 if ( !IsThemeActive() )
1609 StyleSettings aStyleSettings
= rSettings
.GetStyleSettings();
1610 ImplSVData
* pSVData
= ImplGetSVData();
1612 // don't draw frame around each and every toolbar
1613 pSVData
->maNWFData
.mbDockingAreaAvoidTBFrames
= true;
1615 // FIXME get the color directly from the theme, not from the settings
1616 Color aMenuBarTextColor
= aStyleSettings
.GetPersonaMenuBarTextColor().value_or( aStyleSettings
.GetMenuTextColor() );
1617 // in aero menuitem highlight text is drawn in the same color as normal
1618 // high contrast highlight color is not related to persona and not apply blur or transparency
1619 if( !aStyleSettings
.GetHighContrastMode() )
1621 aStyleSettings
.SetMenuHighlightTextColor( aStyleSettings
.GetMenuTextColor() );
1622 aStyleSettings
.SetMenuBarRolloverTextColor( aMenuBarTextColor
);
1623 aStyleSettings
.SetMenuBarHighlightTextColor( aMenuBarTextColor
);
1626 pSVData
->maNWFData
.mnMenuFormatBorderX
= 2;
1627 pSVData
->maNWFData
.mnMenuFormatBorderY
= 2;
1628 pSVData
->maNWFData
.maMenuBarHighlightTextColor
= aMenuBarTextColor
;
1629 GetSalData()->mbThemeMenuSupport
= true;
1631 rSettings
.SetStyleSettings( aStyleSettings
);
1634 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */