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>
44 #include <win/svsys.h>
45 #include <win/salgdi.h>
46 #include <win/saldata.hxx>
47 #include <win/salframe.h>
48 #include <win/scoped_gdi.hxx>
49 #include <win/wingdiimpl.hxx>
57 #include <ControlCacheKey.hxx>
59 typedef std::map
< std::wstring
, HTHEME
> ThemeMap
;
60 static ThemeMap aThemeMap
;
62 /*********************************************************
63 * Initialize XP theming and local stuff
64 *********************************************************/
65 void SalData::initNWF()
67 ImplSVData
* pSVData
= ImplGetSVData();
69 // the menu bar and the top docking area should have a common background (gradient)
70 pSVData
->maNWFData
.mbMenuBarDockingAreaCommonBG
= true;
73 // *********************************************************
74 // * Release theming handles
75 // ********************************************************
76 void SalData::deInitNWF()
78 for( auto& rEntry
: aThemeMap
)
79 CloseThemeData(rEntry
.second
);
83 static HTHEME
getThemeHandle(HWND hWnd
, LPCWSTR name
, WinSalGraphicsImplBase
* pGraphicsImpl
)
85 if( GetSalData()->mbThemeChanged
)
87 // throw away invalid theme handles
89 // throw away native control cache
90 pGraphicsImpl
->ClearNativeControlCache();
91 GetSalData()->mbThemeChanged
= false;
94 ThemeMap::iterator iter
;
95 if( (iter
= aThemeMap
.find( name
)) != aThemeMap
.end() )
97 // theme not found -> add it to map
98 HTHEME hTheme
= OpenThemeData( hWnd
, name
);
99 if( hTheme
!= nullptr )
100 aThemeMap
[name
] = hTheme
;
104 bool WinSalGraphics::isNativeControlSupported( ControlType nType
, ControlPart nPart
)
106 HTHEME hTheme
= nullptr;
110 case ControlType::Pushbutton
:
111 case ControlType::Radiobutton
:
112 case ControlType::Checkbox
:
113 if( nPart
== ControlPart::Entire
)
114 hTheme
= getThemeHandle(mhWnd
, L
"Button", mWinSalGraphicsImplBase
);
116 case ControlType::Scrollbar
:
117 if( nPart
== ControlPart::DrawBackgroundHorz
|| nPart
== ControlPart::DrawBackgroundVert
)
118 return false; // no background painting needed
119 if( nPart
== ControlPart::Entire
)
120 hTheme
= getThemeHandle(mhWnd
, L
"Scrollbar", mWinSalGraphicsImplBase
);
122 case ControlType::Combobox
:
123 if( nPart
== ControlPart::HasBackgroundTexture
)
124 return false; // we do not paint the inner part (ie the selection background/focus indication)
125 if( nPart
== ControlPart::Entire
)
126 hTheme
= getThemeHandle(mhWnd
, L
"Edit", mWinSalGraphicsImplBase
);
127 else if( nPart
== ControlPart::ButtonDown
)
128 hTheme
= getThemeHandle(mhWnd
, L
"Combobox", mWinSalGraphicsImplBase
);
130 case ControlType::Spinbox
:
131 if( nPart
== ControlPart::Entire
)
132 hTheme
= getThemeHandle(mhWnd
, L
"Edit", mWinSalGraphicsImplBase
);
133 else if( nPart
== ControlPart::AllButtons
||
134 nPart
== ControlPart::ButtonUp
|| nPart
== ControlPart::ButtonDown
||
135 nPart
== ControlPart::ButtonLeft
|| nPart
== ControlPart::ButtonRight
)
136 hTheme
= getThemeHandle(mhWnd
, L
"Spin", mWinSalGraphicsImplBase
);
138 case ControlType::SpinButtons
:
139 if( nPart
== ControlPart::Entire
|| nPart
== ControlPart::AllButtons
)
140 hTheme
= getThemeHandle(mhWnd
, L
"Spin", mWinSalGraphicsImplBase
);
142 case ControlType::Editbox
:
143 case ControlType::MultilineEditbox
:
144 if( nPart
== ControlPart::HasBackgroundTexture
)
145 return false; // we do not paint the inner part (ie the selection background/focus indication)
147 if( nPart
== ControlPart::Entire
)
148 hTheme
= getThemeHandle(mhWnd
, L
"Edit", mWinSalGraphicsImplBase
);
150 case ControlType::Listbox
:
151 if( nPart
== ControlPart::HasBackgroundTexture
)
152 return false; // we do not paint the inner part (ie the selection background/focus indication)
153 if( nPart
== ControlPart::Entire
|| nPart
== ControlPart::ListboxWindow
)
154 hTheme
= getThemeHandle(mhWnd
, L
"Listview", mWinSalGraphicsImplBase
);
155 else if( nPart
== ControlPart::ButtonDown
)
156 hTheme
= getThemeHandle(mhWnd
, L
"Combobox", mWinSalGraphicsImplBase
);
158 case ControlType::TabPane
:
159 case ControlType::TabBody
:
160 case ControlType::TabItem
:
161 if( nPart
== ControlPart::Entire
)
162 hTheme
= getThemeHandle(mhWnd
, L
"Tab", mWinSalGraphicsImplBase
);
164 case ControlType::Toolbar
:
165 if( nPart
== ControlPart::Entire
|| nPart
== ControlPart::Button
)
166 hTheme
= getThemeHandle(mhWnd
, L
"Toolbar", mWinSalGraphicsImplBase
);
168 // use rebar theme for grip and background
169 hTheme
= getThemeHandle(mhWnd
, L
"Rebar", mWinSalGraphicsImplBase
);
171 case ControlType::Menubar
:
172 if( nPart
== ControlPart::Entire
)
173 hTheme
= getThemeHandle(mhWnd
, L
"Rebar", mWinSalGraphicsImplBase
);
174 else if( GetSalData()->mbThemeMenuSupport
)
176 if( nPart
== ControlPart::MenuItem
)
177 hTheme
= getThemeHandle(mhWnd
, L
"Menu", mWinSalGraphicsImplBase
);
180 case ControlType::MenuPopup
:
181 if( GetSalData()->mbThemeMenuSupport
)
183 if( nPart
== ControlPart::Entire
||
184 nPart
== ControlPart::MenuItem
||
185 nPart
== ControlPart::MenuItemCheckMark
||
186 nPart
== ControlPart::MenuItemRadioMark
||
187 nPart
== ControlPart::Separator
)
188 hTheme
= getThemeHandle(mhWnd
, L
"Menu", mWinSalGraphicsImplBase
);
191 case ControlType::Progress
:
192 if( nPart
== ControlPart::Entire
)
193 hTheme
= getThemeHandle(mhWnd
, L
"Progress", mWinSalGraphicsImplBase
);
195 case ControlType::Slider
:
196 if( nPart
== ControlPart::TrackHorzArea
|| nPart
== ControlPart::TrackVertArea
)
197 hTheme
= getThemeHandle(mhWnd
, L
"Trackbar", mWinSalGraphicsImplBase
);
199 case ControlType::ListNode
:
200 if( nPart
== ControlPart::Entire
)
201 hTheme
= getThemeHandle(mhWnd
, L
"TreeView", mWinSalGraphicsImplBase
);
208 return (hTheme
!= nullptr);
211 bool WinSalGraphics::hitTestNativeControl( ControlType
,
213 const tools::Rectangle
&,
220 static bool ImplDrawTheme( HTHEME hTheme
, HDC hDC
, int iPart
, int iState
, RECT rc
, const OUString
& aStr
)
222 HRESULT hr
= DrawThemeBackground( hTheme
, hDC
, iPart
, iState
, &rc
, nullptr);
224 if( aStr
.getLength() )
227 hr
= GetThemeBackgroundContentRect( hTheme
, hDC
, iPart
, iState
, &rc
, &rcContent
);
228 hr
= DrawThemeText( hTheme
, hDC
, iPart
, iState
,
229 o3tl::toW(aStr
.getStr()), -1,
230 DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
,
236 // TS_TRUE returns optimal size
237 static std::optional
<Size
> ImplGetThemeSize(HTHEME hTheme
, HDC hDC
, int iPart
, int iState
, LPCRECT pRect
, THEMESIZE eTS
= TS_TRUE
)
239 if (SIZE aSz
; SUCCEEDED(GetThemePartSize(hTheme
, hDC
, iPart
, iState
, pRect
, eTS
, &aSz
)))
240 return Size(aSz
.cx
, aSz
.cy
);
244 static tools::Rectangle
ImplGetThemeRect( HTHEME hTheme
, HDC hDC
, int iPart
, int iState
, const tools::Rectangle
& /* aRect */, THEMESIZE eTS
= TS_TRUE
)
246 if (const std::optional
<Size
> oSz
= ImplGetThemeSize(hTheme
, hDC
, iPart
, iState
, nullptr, eTS
))
247 return tools::Rectangle( 0, 0, oSz
->Width(), oSz
->Height() );
249 return tools::Rectangle();
254 static void ImplConvertSpinbuttonValues( ControlPart nControlPart
, const ControlState
& rState
, const tools::Rectangle
& rRect
,
255 int* pLunaPart
, int *pLunaState
, RECT
*pRect
)
257 if( nControlPart
== ControlPart::ButtonDown
)
259 *pLunaPart
= SPNP_DOWN
;
260 if( rState
& ControlState::PRESSED
)
261 *pLunaState
= DNS_PRESSED
;
262 else if( !(rState
& ControlState::ENABLED
) )
263 *pLunaState
= DNS_DISABLED
;
264 else if( rState
& ControlState::ROLLOVER
)
265 *pLunaState
= DNS_HOT
;
267 *pLunaState
= DNS_NORMAL
;
269 if( nControlPart
== ControlPart::ButtonUp
)
271 *pLunaPart
= SPNP_UP
;
272 if( rState
& ControlState::PRESSED
)
273 *pLunaState
= UPS_PRESSED
;
274 else if( !(rState
& ControlState::ENABLED
) )
275 *pLunaState
= UPS_DISABLED
;
276 else if( rState
& ControlState::ROLLOVER
)
277 *pLunaState
= UPS_HOT
;
279 *pLunaState
= UPS_NORMAL
;
281 if( nControlPart
== ControlPart::ButtonRight
)
283 *pLunaPart
= SPNP_UPHORZ
;
284 if( rState
& ControlState::PRESSED
)
285 *pLunaState
= DNHZS_PRESSED
;
286 else if( !(rState
& ControlState::ENABLED
) )
287 *pLunaState
= DNHZS_DISABLED
;
288 else if( rState
& ControlState::ROLLOVER
)
289 *pLunaState
= DNHZS_HOT
;
291 *pLunaState
= DNHZS_NORMAL
;
293 if( nControlPart
== ControlPart::ButtonLeft
)
295 *pLunaPart
= SPNP_DOWNHORZ
;
296 if( rState
& ControlState::PRESSED
)
297 *pLunaState
= UPHZS_PRESSED
;
298 else if( !(rState
& ControlState::ENABLED
) )
299 *pLunaState
= UPHZS_DISABLED
;
300 else if( rState
& ControlState::ROLLOVER
)
301 *pLunaState
= UPHZS_HOT
;
303 *pLunaState
= UPHZS_NORMAL
;
306 pRect
->left
= rRect
.Left();
307 pRect
->right
= rRect
.Right()+1;
308 pRect
->top
= rRect
.Top();
309 pRect
->bottom
= rRect
.Bottom()+1;
312 /// Draw an own toolbar style on Windows Vista or later, looks better there
313 static void impl_drawAeroToolbar( HDC hDC
, RECT rc
, bool bHorizontal
)
315 if ( rc
.top
== 0 && bHorizontal
)
317 const int GRADIENT_HEIGHT
= 32;
319 LONG gradient_break
= rc
.top
;
320 LONG gradient_bottom
= rc
.bottom
- 1;
321 GRADIENT_RECT g_rect
[1] = { { 0, 1 } };
323 // very slow gradient at the top (if we have space for that)
324 if ( gradient_bottom
- rc
.top
> GRADIENT_HEIGHT
)
326 gradient_break
= gradient_bottom
- GRADIENT_HEIGHT
;
328 TRIVERTEX vert
[2] = {
329 { rc
.left
, rc
.top
, 0xff00, 0xff00, 0xff00, 0xff00 },
330 { rc
.right
, gradient_break
, 0xfa00, 0xfa00, 0xfa00, 0xff00 },
332 GdiGradientFill( hDC
, vert
, 2, g_rect
, 1, GRADIENT_FILL_RECT_V
);
335 // gradient at the bottom
336 TRIVERTEX vert
[2] = {
337 { rc
.left
, gradient_break
, 0xfa00, 0xfa00, 0xfa00, 0xff00 },
338 { rc
.right
, gradient_bottom
, 0xf000, 0xf000, 0xf000, 0xff00 }
340 GdiGradientFill( hDC
, vert
, 2, g_rect
, 1, GRADIENT_FILL_RECT_V
);
342 // and a darker horizontal line under that
343 ScopedSelectedHPEN
hPen(hDC
, CreatePen(PS_SOLID
, 1, RGB( 0xb0, 0xb0, 0xb0)));
345 MoveToEx( hDC
, rc
.left
, gradient_bottom
, nullptr );
346 LineTo( hDC
, rc
.right
, gradient_bottom
);
350 ScopedHBRUSH
hbrush(CreateSolidBrush(RGB(0xf0, 0xf0, 0xf0)));
351 FillRect(hDC
, &rc
, hbrush
.get());
353 // darker line to distinguish the toolbar and viewshell
354 // it is drawn only for the horizontal toolbars; it did not look well
355 // when done for the vertical ones too
358 LONG from_x
, from_y
, to_x
, to_y
;
362 from_y
= to_y
= rc
.top
;
364 ScopedSelectedHPEN
hPen(hDC
, CreatePen(PS_SOLID
, 1, RGB( 0xb0, 0xb0, 0xb0)));
366 MoveToEx( hDC
, from_x
, from_y
, nullptr );
367 LineTo( hDC
, to_x
, to_y
);
372 static bool implDrawNativeMenuMark(HDC hDC
, HTHEME hTheme
, RECT rc
, ControlPart nPart
,
373 ControlState nState
, OUString
const& aCaption
)
375 int iState
= (nState
& ControlState::ENABLED
) ? MCB_NORMAL
: MCB_DISABLED
;
376 ImplDrawTheme(hTheme
, hDC
, MENU_POPUPCHECKBACKGROUND
, iState
, rc
, aCaption
);
377 if (nPart
== ControlPart::MenuItemCheckMark
)
378 iState
= (nState
& ControlState::ENABLED
) ? MC_CHECKMARKNORMAL
: MC_CHECKMARKDISABLED
;
380 iState
= (nState
& ControlState::ENABLED
) ? MC_BULLETNORMAL
: MC_BULLETDISABLED
;
381 // tdf#133697: Get true size of mark, to avoid stretching
382 if (auto oSize
= ImplGetThemeSize(hTheme
, hDC
, MENU_POPUPCHECK
, iState
, &rc
))
384 // center the mark inside the passed rectangle
385 if (const auto dx
= (rc
.right
- rc
.left
- oSize
->Width() + 1) / 2; dx
> 0)
388 rc
.right
= rc
.left
+ oSize
->Width();
390 if (const auto dy
= (rc
.bottom
- rc
.top
- oSize
->Height() + 1) / 2; dy
> 0)
393 rc
.bottom
= rc
.top
+ oSize
->Height();
396 return ImplDrawTheme(hTheme
, hDC
, MENU_POPUPCHECK
, iState
, rc
, aCaption
);
401 static bool bOSSupportsDarkMode
= OSSupportsDarkMode();
402 if (!bOSSupportsDarkMode
)
406 switch (MiscSettings::GetDarkMode())
411 HINSTANCE hUxthemeLib
= LoadLibraryExW(L
"uxtheme.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32
);
415 typedef bool(WINAPI
* ShouldAppsUseDarkMode_t
)();
416 if (auto ShouldAppsUseDarkMode
= reinterpret_cast<ShouldAppsUseDarkMode_t
>(GetProcAddress(hUxthemeLib
, MAKEINTRESOURCEA(132))))
417 bRet
= ShouldAppsUseDarkMode();
419 FreeLibrary(hUxthemeLib
);
433 static bool ImplDrawNativeControl( HDC hDC
, HTHEME hTheme
, RECT rc
,
437 const ImplControlValue
& aValue
,
438 OUString
const & aCaption
,
441 // a listbox dropdown is actually a combobox dropdown
442 if( nType
== ControlType::Listbox
)
443 if( nPart
== ControlPart::ButtonDown
)
444 nType
= ControlType::Combobox
;
446 // draw entire combobox as a large edit box
447 if( nType
== ControlType::Combobox
)
448 if( nPart
== ControlPart::Entire
)
449 nType
= ControlType::Editbox
;
451 // draw entire spinbox as a large edit box
452 if( nType
== ControlType::Spinbox
)
453 if( nPart
== ControlPart::Entire
)
454 nType
= ControlType::Editbox
;
456 int iPart(0), iState(0);
457 if( nType
== ControlType::Scrollbar
)
460 if( nPart
== ControlPart::ButtonUp
)
462 iPart
= SBP_ARROWBTN
;
463 if( nState
& ControlState::PRESSED
)
464 iState
= ABS_UPPRESSED
;
465 else if( !(nState
& ControlState::ENABLED
) )
466 iState
= ABS_UPDISABLED
;
467 else if( nState
& ControlState::ROLLOVER
)
470 iState
= ABS_UPNORMAL
;
471 hr
= DrawThemeBackground( hTheme
, hDC
, iPart
, iState
, &rc
, nullptr);
474 if( nPart
== ControlPart::ButtonDown
)
476 iPart
= SBP_ARROWBTN
;
477 if( nState
& ControlState::PRESSED
)
478 iState
= ABS_DOWNPRESSED
;
479 else if( !(nState
& ControlState::ENABLED
) )
480 iState
= ABS_DOWNDISABLED
;
481 else if( nState
& ControlState::ROLLOVER
)
482 iState
= ABS_DOWNHOT
;
484 iState
= ABS_DOWNNORMAL
;
485 hr
= DrawThemeBackground( hTheme
, hDC
, iPart
, iState
, &rc
, nullptr);
488 if( nPart
== ControlPart::ButtonLeft
)
490 iPart
= SBP_ARROWBTN
;
491 if( nState
& ControlState::PRESSED
)
492 iState
= ABS_LEFTPRESSED
;
493 else if( !(nState
& ControlState::ENABLED
) )
494 iState
= ABS_LEFTDISABLED
;
495 else if( nState
& ControlState::ROLLOVER
)
496 iState
= ABS_LEFTHOT
;
498 iState
= ABS_LEFTNORMAL
;
499 hr
= DrawThemeBackground( hTheme
, hDC
, iPart
, iState
, &rc
, nullptr);
502 if( nPart
== ControlPart::ButtonRight
)
504 iPart
= SBP_ARROWBTN
;
505 if( nState
& ControlState::PRESSED
)
506 iState
= ABS_RIGHTPRESSED
;
507 else if( !(nState
& ControlState::ENABLED
) )
508 iState
= ABS_RIGHTDISABLED
;
509 else if( nState
& ControlState::ROLLOVER
)
510 iState
= ABS_RIGHTHOT
;
512 iState
= ABS_RIGHTNORMAL
;
513 hr
= DrawThemeBackground( hTheme
, hDC
, iPart
, iState
, &rc
, nullptr);
516 if( nPart
== ControlPart::ThumbHorz
|| nPart
== ControlPart::ThumbVert
)
518 iPart
= (nPart
== ControlPart::ThumbHorz
) ? SBP_THUMBBTNHORZ
: SBP_THUMBBTNVERT
;
519 if( nState
& ControlState::PRESSED
)
520 iState
= SCRBS_PRESSED
;
521 else if( !(nState
& ControlState::ENABLED
) )
522 iState
= SCRBS_DISABLED
;
523 else if( nState
& ControlState::ROLLOVER
)
526 iState
= SCRBS_NORMAL
;
529 GetThemePartSize(hTheme
, hDC
, iPart
, iState
, nullptr, TS_MIN
, &sz
);
530 GetThemePartSize(hTheme
, hDC
, iPart
, iState
, nullptr, TS_TRUE
, &sz
);
531 GetThemePartSize(hTheme
, hDC
, iPart
, iState
, nullptr, TS_DRAW
, &sz
);
533 hr
= DrawThemeBackground( hTheme
, hDC
, iPart
, iState
, &rc
, nullptr);
534 // paint gripper on thumb if enough space
535 if( ( (nPart
== ControlPart::ThumbVert
) && (rc
.bottom
-rc
.top
> 12) ) ||
536 ( (nPart
== ControlPart::ThumbHorz
) && (rc
.right
-rc
.left
> 12) ) )
538 iPart
= (nPart
== ControlPart::ThumbHorz
) ? SBP_GRIPPERHORZ
: SBP_GRIPPERVERT
;
540 DrawThemeBackground( hTheme
, hDC
, iPart
, iState
, &rc
, nullptr);
544 if( nPart
== ControlPart::TrackHorzLeft
|| nPart
== ControlPart::TrackHorzRight
|| nPart
== ControlPart::TrackVertUpper
|| nPart
== ControlPart::TrackVertLower
)
548 case ControlPart::TrackHorzLeft
: iPart
= SBP_UPPERTRACKHORZ
; break;
549 case ControlPart::TrackHorzRight
: iPart
= SBP_LOWERTRACKHORZ
; break;
550 case ControlPart::TrackVertUpper
: iPart
= SBP_UPPERTRACKVERT
; break;
551 case ControlPart::TrackVertLower
: iPart
= SBP_LOWERTRACKVERT
; break;
555 if( nState
& ControlState::PRESSED
)
556 iState
= SCRBS_PRESSED
;
557 else if( !(nState
& ControlState::ENABLED
) )
558 iState
= SCRBS_DISABLED
;
559 else if( nState
& ControlState::ROLLOVER
)
562 iState
= SCRBS_NORMAL
;
563 hr
= DrawThemeBackground( hTheme
, hDC
, iPart
, iState
, &rc
, nullptr);
567 if( nType
== ControlType::SpinButtons
&& nPart
== ControlPart::AllButtons
)
569 if( aValue
.getType() == ControlType::SpinButtons
)
571 const SpinbuttonValue
* pValue
= (aValue
.getType() == ControlType::SpinButtons
) ? static_cast<const SpinbuttonValue
*>(&aValue
) : nullptr;
574 ImplConvertSpinbuttonValues( pValue
->mnUpperPart
, pValue
->mnUpperState
, pValue
->maUpperRect
, &iPart
, &iState
, &rect
);
575 bool bOk
= ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, rect
, aCaption
);
579 ImplConvertSpinbuttonValues( pValue
->mnLowerPart
, pValue
->mnLowerState
, pValue
->maLowerRect
, &iPart
, &iState
, &rect
);
580 bOk
= ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, rect
, aCaption
);
586 if( nType
== ControlType::Spinbox
)
588 if( nPart
== ControlPart::AllButtons
)
590 if( aValue
.getType() == ControlType::SpinButtons
)
592 const SpinbuttonValue
*pValue
= static_cast<const SpinbuttonValue
*>(&aValue
);
595 ImplConvertSpinbuttonValues( pValue
->mnUpperPart
, pValue
->mnUpperState
, pValue
->maUpperRect
, &iPart
, &iState
, &rect
);
596 bool bOk
= ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, rect
, aCaption
);
600 ImplConvertSpinbuttonValues( pValue
->mnLowerPart
, pValue
->mnLowerState
, pValue
->maLowerRect
, &iPart
, &iState
, &rect
);
601 bOk
= ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, rect
, aCaption
);
608 if( nPart
== ControlPart::ButtonDown
)
611 if( nState
& ControlState::PRESSED
)
612 iState
= DNS_PRESSED
;
613 else if( !(nState
& ControlState::ENABLED
) )
614 iState
= DNS_DISABLED
;
615 else if( nState
& ControlState::ROLLOVER
)
620 if( nPart
== ControlPart::ButtonUp
)
623 if( nState
& ControlState::PRESSED
)
624 iState
= UPS_PRESSED
;
625 else if( !(nState
& ControlState::ENABLED
) )
626 iState
= UPS_DISABLED
;
627 else if( nState
& ControlState::ROLLOVER
)
632 if( nPart
== ControlPart::ButtonRight
)
634 iPart
= SPNP_DOWNHORZ
;
635 if( nState
& ControlState::PRESSED
)
636 iState
= DNHZS_PRESSED
;
637 else if( !(nState
& ControlState::ENABLED
) )
638 iState
= DNHZS_DISABLED
;
639 else if( nState
& ControlState::ROLLOVER
)
642 iState
= DNHZS_NORMAL
;
644 if( nPart
== ControlPart::ButtonLeft
)
647 if( nState
& ControlState::PRESSED
)
648 iState
= UPHZS_PRESSED
;
649 else if( !(nState
& ControlState::ENABLED
) )
650 iState
= UPHZS_DISABLED
;
651 else if( nState
& ControlState::ROLLOVER
)
654 iState
= UPHZS_NORMAL
;
656 if( nPart
== ControlPart::ButtonLeft
|| nPart
== ControlPart::ButtonRight
|| nPart
== ControlPart::ButtonUp
|| nPart
== ControlPart::ButtonDown
)
657 return ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, rc
, aCaption
);
659 if( nType
== ControlType::Combobox
)
661 if( nPart
== ControlPart::ButtonDown
)
663 iPart
= CP_DROPDOWNBUTTON
;
664 if( nState
& ControlState::PRESSED
)
665 iState
= CBXS_PRESSED
;
666 else if( !(nState
& ControlState::ENABLED
) )
667 iState
= CBXS_DISABLED
;
668 else if( nState
& ControlState::ROLLOVER
)
671 iState
= CBXS_NORMAL
;
672 return ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, rc
, aCaption
);
675 if( nType
== ControlType::Pushbutton
)
677 iPart
= BP_PUSHBUTTON
;
678 if( nState
& ControlState::PRESSED
)
679 iState
= PBS_PRESSED
;
680 else if( !(nState
& ControlState::ENABLED
) )
681 iState
= PBS_DISABLED
;
682 else if( nState
& ControlState::ROLLOVER
)
684 else if( nState
& ControlState::DEFAULT
)
685 iState
= PBS_DEFAULTED
;
686 //else if( nState & ControlState::FOCUSED )
687 // iState = PBS_DEFAULTED; // may need to draw focus rect
691 return ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, rc
, aCaption
);
694 if( nType
== ControlType::Radiobutton
)
696 iPart
= BP_RADIOBUTTON
;
697 bool bChecked
= ( aValue
.getTristateVal() == ButtonValue::On
);
699 if( nState
& ControlState::PRESSED
)
700 iState
= bChecked
? RBS_CHECKEDPRESSED
: RBS_UNCHECKEDPRESSED
;
701 else if( !(nState
& ControlState::ENABLED
) )
702 iState
= bChecked
? RBS_CHECKEDDISABLED
: RBS_UNCHECKEDDISABLED
;
703 else if( nState
& ControlState::ROLLOVER
)
704 iState
= bChecked
? RBS_CHECKEDHOT
: RBS_UNCHECKEDHOT
;
706 iState
= bChecked
? RBS_CHECKEDNORMAL
: RBS_UNCHECKEDNORMAL
;
708 //if( nState & ControlState::FOCUSED )
709 // iState |= PBS_DEFAULTED; // may need to draw focus rect
711 return ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, rc
, aCaption
);
714 if( nType
== ControlType::Checkbox
)
717 ButtonValue v
= aValue
.getTristateVal();
719 if( nState
& ControlState::PRESSED
)
720 iState
= (v
== ButtonValue::On
) ? CBS_CHECKEDPRESSED
:
721 ( (v
== ButtonValue::Off
) ? CBS_UNCHECKEDPRESSED
: CBS_MIXEDPRESSED
);
722 else if( !(nState
& ControlState::ENABLED
) )
723 iState
= (v
== ButtonValue::On
) ? CBS_CHECKEDDISABLED
:
724 ( (v
== ButtonValue::Off
) ? CBS_UNCHECKEDDISABLED
: CBS_MIXEDDISABLED
);
725 else if( nState
& ControlState::ROLLOVER
)
726 iState
= (v
== ButtonValue::On
) ? CBS_CHECKEDHOT
:
727 ( (v
== ButtonValue::Off
) ? CBS_UNCHECKEDHOT
: CBS_MIXEDHOT
);
729 iState
= (v
== ButtonValue::On
) ? CBS_CHECKEDNORMAL
:
730 ( (v
== ButtonValue::Off
) ? CBS_UNCHECKEDNORMAL
: CBS_MIXEDNORMAL
);
732 //if( nState & ControlState::FOCUSED )
733 // iState |= PBS_DEFAULTED; // may need to draw focus rect
736 //THEMESIZE eSize = TS_DRAW; // TS_MIN, TS_TRUE, TS_DRAW
737 //GetThemePartSize( hTheme, hDC, iPart, iState, &rc, eSize, &sz);
739 return ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, rc
, aCaption
);
742 if (nType
== ControlType::Editbox
)
744 iPart
= EP_EDITBORDER_NOSCROLL
;
745 if( !(nState
& ControlState::ENABLED
) )
746 iState
= EPSN_DISABLED
;
747 else if( nState
& ControlState::FOCUSED
)
748 iState
= EPSN_FOCUSED
;
749 else if( nState
& ControlState::ROLLOVER
)
752 iState
= EPSN_NORMAL
;
754 return ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, rc
, aCaption
);
757 if (nType
== ControlType::MultilineEditbox
)
760 if( !(nState
& ControlState::ENABLED
) )
761 iState
= ETS_DISABLED
;
762 else if( nState
& ControlState::FOCUSED
)
763 iState
= ETS_FOCUSED
;
764 else if( nState
& ControlState::ROLLOVER
)
769 return ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, rc
, aCaption
);
772 if( nType
== ControlType::Listbox
)
774 if( nPart
== ControlPart::Entire
|| nPart
== ControlPart::ListboxWindow
)
776 iPart
= LVP_EMPTYTEXT
; // ??? no idea which part to choose here
777 return ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, rc
, aCaption
);
781 if( nType
== ControlType::TabPane
)
783 // tabpane in tabcontrols gets drawn in "darkmode" as if it was a
784 // a "light" theme, so bodge this by drawing a frame directly
787 Color
aColor(Application::GetSettings().GetStyleSettings().GetDisableColor());
788 ScopedHBRUSH
hbrush(CreateSolidBrush(RGB(aColor
.GetRed(),
791 FrameRect(hDC
, &rc
, hbrush
.get());
795 return ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, rc
, aCaption
);
798 if( nType
== ControlType::TabBody
)
800 // tabbody in main window gets drawn in white in "darkmode", so bodge this here
803 Color
aColor(Application::GetSettings().GetStyleSettings().GetWindowColor());
804 ScopedHBRUSH
hbrush(CreateSolidBrush(RGB(aColor
.GetRed(),
807 FillRect(hDC
, &rc
, hbrush
.get());
812 return ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, rc
, aCaption
);
815 if( nType
== ControlType::TabItem
)
817 iPart
= TABP_TABITEMLEFTEDGE
;
820 OSL_ASSERT( aValue
.getType() == ControlType::TabItem
);
822 const TabitemValue
& rValue
= static_cast<const TabitemValue
&>(aValue
);
823 if (rValue
.isBothAligned())
825 iPart
= TABP_TABITEMLEFTEDGE
;
828 else if (rValue
.isLeftAligned())
829 iPart
= TABP_TABITEMLEFTEDGE
;
830 else if (rValue
.isRightAligned())
831 iPart
= TABP_TABITEMRIGHTEDGE
;
833 iPart
= TABP_TABITEM
;
835 if( !(nState
& ControlState::ENABLED
) )
836 iState
= TILES_DISABLED
;
837 else if( nState
& ControlState::SELECTED
)
839 iState
= TILES_SELECTED
;
840 // increase the selected tab
842 if (rValue
.isBothAligned())
844 if (rValue
.isLeftAligned() || rValue
.isNotAligned())
846 if (rValue
.isRightAligned())
852 else if( nState
& ControlState::ROLLOVER
)
854 else if( nState
& ControlState::FOCUSED
)
855 iState
= TILES_FOCUSED
; // may need to draw focus rect
857 iState
= TILES_NORMAL
;
859 // tabitem in tabcontrols gets drawn in "darkmode" as if it was a
860 // a "light" theme, so bodge this by drawing with a button instead
864 if (iState
== TILES_SELECTED
)
865 aColor
= Application::GetSettings().GetStyleSettings().GetActiveTabColor();
867 aColor
= Application::GetSettings().GetStyleSettings().GetInactiveTabColor();
868 ScopedHBRUSH
hbrush(CreateSolidBrush(RGB(aColor
.GetRed(),
871 FillRect(hDC
, &rc
, hbrush
.get());
873 aColor
= Application::GetSettings().GetStyleSettings().GetDisableColor();
874 ScopedSelectedHPEN
hPen(hDC
, CreatePen(PS_SOLID
, 1, RGB(aColor
.GetRed(),
879 apt
[0].y
= rc
.bottom
- (iPart
== TABP_TABITEMLEFTEDGE
? 1 : 2);
885 apt
[3].y
= rc
.bottom
- 1;
886 Polyline(hDC
, apt
, SAL_N_ELEMENTS(apt
));
890 return ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, rc
, aCaption
);
893 if( nType
== ControlType::Toolbar
)
895 if( nPart
== ControlPart::Button
)
898 bool bChecked
= ( aValue
.getTristateVal() == ButtonValue::On
);
899 if( !(nState
& ControlState::ENABLED
) )
900 //iState = TS_DISABLED;
901 // disabled buttons are typically not painted at all but we need visual
902 // feedback when travelling by keyboard over disabled entries
904 else if( nState
& ControlState::PRESSED
)
906 else if( nState
& ControlState::ROLLOVER
)
907 iState
= bChecked
? TS_HOTCHECKED
: TS_HOT
;
909 iState
= bChecked
? TS_CHECKED
: TS_NORMAL
;
910 return ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, rc
, aCaption
);
912 else if( nPart
== ControlPart::ThumbHorz
|| nPart
== ControlPart::ThumbVert
)
914 // the vertical gripper is not supported in most themes and it makes no
915 // sense to only support horizontal gripper
916 //iPart = (nPart == ControlPart::ThumbHorz) ? RP_GRIPPERVERT : RP_GRIPPER;
917 //return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
919 else if( nPart
== ControlPart::DrawBackgroundHorz
|| nPart
== ControlPart::DrawBackgroundVert
)
921 if( aValue
.getType() == ControlType::Toolbar
)
923 const ToolbarValue
*pValue
= static_cast<const ToolbarValue
*>(&aValue
);
924 if( pValue
->mbIsTopDockingArea
)
925 rc
.top
= 0; // extend potential gradient to cover menu bar as well
928 // toolbar in main window gets drawn in white in "darkmode", so bodge this here
931 Color
aColor(Application::GetSettings().GetStyleSettings().GetWindowColor());
932 ScopedHBRUSH
hbrush(CreateSolidBrush(RGB(aColor
.GetRed(),
935 FillRect(hDC
, &rc
, hbrush
.get());
939 // make it more compatible with Aero
940 if (ImplGetSVData()->maNWFData
.mbDockingAreaAvoidTBFrames
&&
941 !Application::GetSettings().GetStyleSettings().GetHighContrastMode())
943 impl_drawAeroToolbar( hDC
, rc
, nPart
== ControlPart::DrawBackgroundHorz
);
947 return ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, rc
, aCaption
);
951 if( nType
== ControlType::Menubar
)
953 if( nPart
== ControlPart::Entire
)
955 if( aValue
.getType() == ControlType::Menubar
)
957 const MenubarValue
*pValue
= static_cast<const MenubarValue
*>(&aValue
);
958 rc
.bottom
+= pValue
->maTopDockingAreaHeight
; // extend potential gradient to cover docking area as well
960 // menubar in main window gets drawn in white in "darkmode", so bodge this here
963 Color
aColor(Application::GetSettings().GetStyleSettings().GetWindowColor());
964 ScopedHBRUSH
hbrush(CreateSolidBrush(RGB(aColor
.GetRed(),
967 FillRect(hDC
, &rc
, hbrush
.get());
971 // make it more compatible with Aero
972 if (ImplGetSVData()->maNWFData
.mbDockingAreaAvoidTBFrames
&&
973 !Application::GetSettings().GetStyleSettings().GetHighContrastMode())
975 impl_drawAeroToolbar( hDC
, rc
, true );
979 return ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, rc
, aCaption
);
981 else if( nPart
== ControlPart::MenuItem
)
983 if( nState
& ControlState::ENABLED
)
985 if( nState
& ControlState::SELECTED
)
987 else if( nState
& ControlState::ROLLOVER
)
994 if( nState
& ControlState::SELECTED
)
995 iState
= MBI_DISABLEDPUSHED
;
996 else if( nState
& ControlState::ROLLOVER
)
997 iState
= MBI_DISABLEDHOT
;
999 iState
= MBI_DISABLED
;
1001 return ImplDrawTheme( hTheme
, hDC
, MENU_BARITEM
, iState
, rc
, aCaption
);
1005 if( nType
== ControlType::Progress
)
1007 if( nPart
!= ControlPart::Entire
)
1010 if( ! ImplDrawTheme( hTheme
, hDC
, PP_BAR
, iState
, rc
, aCaption
) )
1012 RECT aProgressRect
= rc
;
1013 if( GetThemeBackgroundContentRect( hTheme
, hDC
, PP_BAR
, iState
, &rc
, &aProgressRect
) != S_OK
)
1016 tools::Long nProgressWidth
= aValue
.getNumericVal();
1017 nProgressWidth
*= (aProgressRect
.right
- aProgressRect
.left
);
1018 nProgressWidth
/= (rc
.right
- rc
.left
);
1019 if( AllSettings::GetLayoutRTL() )
1020 aProgressRect
.left
= aProgressRect
.right
- nProgressWidth
;
1022 aProgressRect
.right
= aProgressRect
.left
+ nProgressWidth
;
1024 return ImplDrawTheme( hTheme
, hDC
, PP_CHUNK
, iState
, aProgressRect
, aCaption
);
1027 if( nType
== ControlType::Slider
)
1029 iPart
= (nPart
== ControlPart::TrackHorzArea
) ? TKP_TRACK
: TKP_TRACKVERT
;
1030 iState
= (nPart
== ControlPart::TrackHorzArea
) ? static_cast<int>(TRS_NORMAL
) : static_cast<int>(TRVS_NORMAL
);
1032 tools::Rectangle aTrackRect
= ImplGetThemeRect( hTheme
, hDC
, iPart
, iState
, tools::Rectangle() );
1034 if( nPart
== ControlPart::TrackHorzArea
)
1036 tools::Long nH
= aTrackRect
.GetHeight();
1037 aTRect
.top
+= (rc
.bottom
- rc
.top
- nH
)/2;
1038 aTRect
.bottom
= aTRect
.top
+ nH
;
1042 tools::Long nW
= aTrackRect
.GetWidth();
1043 aTRect
.left
+= (rc
.right
- rc
.left
- nW
)/2;
1044 aTRect
.right
= aTRect
.left
+ nW
;
1046 ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, aTRect
, aCaption
);
1049 OSL_ASSERT( aValue
.getType() == ControlType::Slider
);
1050 const SliderValue
* pVal
= static_cast<const SliderValue
*>(&aValue
);
1051 aThumbRect
.left
= pVal
->maThumbRect
.Left();
1052 aThumbRect
.top
= pVal
->maThumbRect
.Top();
1053 aThumbRect
.right
= pVal
->maThumbRect
.Right();
1054 aThumbRect
.bottom
= pVal
->maThumbRect
.Bottom();
1055 iPart
= (nPart
== ControlPart::TrackHorzArea
) ? TKP_THUMB
: TKP_THUMBVERT
;
1056 iState
= (nState
& ControlState::ENABLED
) ? TUS_NORMAL
: TUS_DISABLED
;
1057 return ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, aThumbRect
, aCaption
);
1060 if( nType
== ControlType::ListNode
)
1062 if( nPart
!= ControlPart::Entire
)
1065 ButtonValue aButtonValue
= aValue
.getTristateVal();
1067 switch( aButtonValue
)
1069 case ButtonValue::On
:
1070 iState
= GLPS_OPENED
;
1072 case ButtonValue::Off
:
1073 iState
= GLPS_CLOSED
;
1078 return ImplDrawTheme( hTheme
, hDC
, iPart
, iState
, rc
, aCaption
);
1081 if( GetSalData()->mbThemeMenuSupport
)
1083 if( nType
== ControlType::MenuPopup
)
1085 if( nPart
== ControlPart::Entire
)
1087 RECT aGutterRC
= rc
;
1088 if( AllSettings::GetLayoutRTL() )
1090 aGutterRC
.right
-= aValue
.getNumericVal()+1;
1091 aGutterRC
.left
= aGutterRC
.right
-3;
1095 aGutterRC
.left
+= aValue
.getNumericVal();
1096 aGutterRC
.right
= aGutterRC
.left
+3;
1099 ImplDrawTheme( hTheme
, hDC
, MENU_POPUPBACKGROUND
, 0, rc
, aCaption
) &&
1100 ImplDrawTheme( hTheme
, hDC
, MENU_POPUPGUTTER
, 0, aGutterRC
, aCaption
)
1103 else if( nPart
== ControlPart::MenuItem
)
1105 if( nState
& ControlState::ENABLED
)
1106 iState
= (nState
& ControlState::SELECTED
) ? MPI_HOT
: MPI_NORMAL
;
1108 iState
= (nState
& ControlState::SELECTED
) ? MPI_DISABLEDHOT
: MPI_DISABLED
;
1109 return ImplDrawTheme( hTheme
, hDC
, MENU_POPUPITEM
, iState
, rc
, aCaption
);
1111 else if( nPart
== ControlPart::MenuItemCheckMark
|| nPart
== ControlPart::MenuItemRadioMark
)
1113 if (nState
& ControlState::PRESSED
)
1114 return implDrawNativeMenuMark(hDC
, hTheme
, rc
, nPart
, nState
, aCaption
);
1116 return true; // unchecked: do nothing
1118 else if( nPart
== ControlPart::Separator
)
1120 // adjust for gutter position
1121 if( AllSettings::GetLayoutRTL() )
1122 rc
.right
-= aValue
.getNumericVal()+1;
1124 rc
.left
+= aValue
.getNumericVal()+1;
1125 tools::Rectangle
aRect( ImplGetThemeRect( hTheme
, hDC
,
1126 MENU_POPUPSEPARATOR
, 0, tools::Rectangle( rc
.left
, rc
.top
, rc
.right
, rc
.bottom
) ) );
1127 // center the separator inside the passed rectangle
1128 auto const nDY
= ((rc
.bottom
- rc
.top
+ 1) - aRect
.GetHeight()) / 2;
1130 rc
.bottom
= rc
.top
+aRect
.GetHeight()-1;
1131 return ImplDrawTheme( hTheme
, hDC
, MENU_POPUPSEPARATOR
, 0, rc
, aCaption
);
1139 bool WinSalGraphics::drawNativeControl( ControlType nType
,
1141 const tools::Rectangle
& rControlRegion
,
1142 ControlState nState
,
1143 const ImplControlValue
& aValue
,
1144 const OUString
& aCaption
,
1145 const Color
& /*rBackgroundColor*/ )
1148 HTHEME hTheme
= nullptr;
1150 tools::Rectangle buttonRect
= rControlRegion
;
1151 tools::Rectangle cacheRect
= rControlRegion
;
1152 Size keySize
= cacheRect
.GetSize();
1154 WinSalGraphicsImplBase
* pImpl
= mWinSalGraphicsImplBase
;
1155 if( !pImpl
->UseRenderNativeControl())
1158 // tdf#95618 - A few controls render outside the region they're given.
1159 if (pImpl
&& nType
== ControlType::TabItem
)
1161 tools::Rectangle rNativeBoundingRegion
;
1162 tools::Rectangle rNativeContentRegion
;
1163 if (getNativeControlRegion(nType
, nPart
, rControlRegion
, nState
, aValue
, aCaption
,
1164 rNativeBoundingRegion
, rNativeContentRegion
))
1166 cacheRect
= rNativeBoundingRegion
;
1167 keySize
= rNativeBoundingRegion
.GetSize();
1172 ControlCacheKey
aControlCacheKey(nType
, nPart
, nState
, keySize
);
1173 if (pImpl
!= nullptr && pImpl
->TryRenderCachedNativeControl(aControlCacheKey
, buttonRect
.Left(), buttonRect
.Top()))
1178 const bool bUseDarkMode
= UseDarkMode();
1180 SetWindowTheme(mhWnd
, L
"Explorer", nullptr);
1184 case ControlType::Pushbutton
:
1185 case ControlType::Radiobutton
:
1186 case ControlType::Checkbox
:
1187 hTheme
= getThemeHandle(mhWnd
, L
"Button", mWinSalGraphicsImplBase
);
1189 case ControlType::Scrollbar
:
1192 // tdf#153273 undo the earlier SetWindowTheme, and use an explicit Explorer::Scrollbar
1193 // a) with "Scrollbar" and SetWindowTheme(... "Explorer" ...) then scrollbars in dialog
1194 // and main windows are dark, but dropdowns are light
1195 // b) with "Explorer::Scrollbar" and SetWindowTheme(... "Explorer" ...) then scrollbars
1196 // in dropdowns are dark, but scrollbars in dialogs and main windows are sort of "extra
1198 // c) with "Explorer::Scrollbar" and no SetWindowTheme both cases are dark
1199 SetWindowTheme(mhWnd
, nullptr, nullptr);
1200 hTheme
= getThemeHandle(mhWnd
, L
"Explorer::Scrollbar", mWinSalGraphicsImplBase
);
1203 hTheme
= getThemeHandle(mhWnd
, L
"Scrollbar", mWinSalGraphicsImplBase
);
1205 case ControlType::Combobox
:
1206 if( nPart
== ControlPart::Entire
)
1208 if (bUseDarkMode
&& !(nState
& ControlState::FOCUSED
))
1209 SetWindowTheme(mhWnd
, L
"CFD", nullptr);
1210 hTheme
= getThemeHandle(mhWnd
, L
"Edit", mWinSalGraphicsImplBase
);
1212 else if( nPart
== ControlPart::ButtonDown
)
1215 SetWindowTheme(mhWnd
, L
"CFD", nullptr);
1216 hTheme
= getThemeHandle(mhWnd
, L
"Combobox", mWinSalGraphicsImplBase
);
1219 case ControlType::Spinbox
:
1220 if( nPart
== ControlPart::Entire
)
1222 if (bUseDarkMode
&& !(nState
& ControlState::FOCUSED
))
1223 SetWindowTheme(mhWnd
, L
"CFD", nullptr);
1224 hTheme
= getThemeHandle(mhWnd
, L
"Edit", mWinSalGraphicsImplBase
);
1227 hTheme
= getThemeHandle(mhWnd
, L
"Spin", mWinSalGraphicsImplBase
);
1229 case ControlType::SpinButtons
:
1230 hTheme
= getThemeHandle(mhWnd
, L
"Spin", mWinSalGraphicsImplBase
);
1232 case ControlType::Editbox
:
1233 if (bUseDarkMode
&& !(nState
& ControlState::FOCUSED
))
1234 SetWindowTheme(mhWnd
, L
"CFD", nullptr);
1235 hTheme
= getThemeHandle(mhWnd
, L
"Edit", mWinSalGraphicsImplBase
);
1237 case ControlType::MultilineEditbox
:
1238 hTheme
= getThemeHandle(mhWnd
, L
"Edit", mWinSalGraphicsImplBase
);
1240 case ControlType::Listbox
:
1241 if( nPart
== ControlPart::Entire
|| nPart
== ControlPart::ListboxWindow
)
1242 hTheme
= getThemeHandle(mhWnd
, L
"Listview", mWinSalGraphicsImplBase
);
1243 else if( nPart
== ControlPart::ButtonDown
)
1246 SetWindowTheme(mhWnd
, L
"CFD", nullptr);
1247 hTheme
= getThemeHandle(mhWnd
, L
"Combobox", mWinSalGraphicsImplBase
);
1250 case ControlType::TabBody
:
1251 hTheme
= getThemeHandle(mhWnd
, L
"Tab", mWinSalGraphicsImplBase
);
1253 case ControlType::TabPane
:
1254 case ControlType::TabItem
:
1255 hTheme
= getThemeHandle(mhWnd
, L
"Tab", mWinSalGraphicsImplBase
);
1257 case ControlType::Toolbar
:
1258 if( nPart
== ControlPart::Entire
|| nPart
== ControlPart::Button
)
1259 hTheme
= getThemeHandle(mhWnd
, L
"Toolbar", mWinSalGraphicsImplBase
);
1261 // use rebar for grip and background
1262 hTheme
= getThemeHandle(mhWnd
, L
"Rebar", mWinSalGraphicsImplBase
);
1264 case ControlType::Menubar
:
1265 if( nPart
== ControlPart::Entire
)
1266 hTheme
= getThemeHandle(mhWnd
, L
"Rebar", mWinSalGraphicsImplBase
);
1267 else if( GetSalData()->mbThemeMenuSupport
)
1269 if( nPart
== ControlPart::MenuItem
)
1270 hTheme
= getThemeHandle(mhWnd
, L
"Menu", mWinSalGraphicsImplBase
);
1273 case ControlType::Progress
:
1274 if( nPart
== ControlPart::Entire
)
1275 hTheme
= getThemeHandle(mhWnd
, L
"Progress", mWinSalGraphicsImplBase
);
1277 case ControlType::ListNode
:
1278 if( nPart
== ControlPart::Entire
)
1279 hTheme
= getThemeHandle(mhWnd
, L
"TreeView", mWinSalGraphicsImplBase
);
1281 case ControlType::Slider
:
1282 if( nPart
== ControlPart::TrackHorzArea
|| nPart
== ControlPart::TrackVertArea
)
1283 hTheme
= getThemeHandle(mhWnd
, L
"Trackbar", mWinSalGraphicsImplBase
);
1285 case ControlType::MenuPopup
:
1286 if( GetSalData()->mbThemeMenuSupport
)
1288 if( nPart
== ControlPart::Entire
|| nPart
== ControlPart::MenuItem
||
1289 nPart
== ControlPart::MenuItemCheckMark
|| nPart
== ControlPart::MenuItemRadioMark
||
1290 nPart
== ControlPart::Separator
1292 hTheme
= getThemeHandle(mhWnd
, L
"Menu", mWinSalGraphicsImplBase
);
1303 SetWindowTheme(mhWnd
, nullptr, nullptr);
1308 rc
.left
= buttonRect
.Left();
1309 rc
.right
= buttonRect
.Right()+1;
1310 rc
.top
= buttonRect
.Top();
1311 rc
.bottom
= buttonRect
.Bottom()+1;
1313 OUString
aCaptionStr(aCaption
.replace('~', '&')); // translate mnemonics
1315 if (pImpl
== nullptr)
1317 // set default text alignment
1318 int ta
= SetTextAlign(getHDC(), TA_LEFT
|TA_TOP
|TA_NOUPDATECP
);
1320 bOk
= ImplDrawNativeControl(getHDC(), hTheme
, rc
, nType
, nPart
, nState
, aValue
, aCaptionStr
, bUseDarkMode
);
1322 // restore alignment
1323 SetTextAlign(getHDC(), ta
);
1327 // We can do OpenGL/Skia
1328 std::unique_ptr
<CompatibleDC
> aBlackDC(CompatibleDC::create(*this, cacheRect
.Left(), cacheRect
.Top(), cacheRect
.GetWidth()+1, cacheRect
.GetHeight()+1));
1329 SetTextAlign(aBlackDC
->getCompatibleHDC(), TA_LEFT
|TA_TOP
|TA_NOUPDATECP
);
1330 aBlackDC
->fill(RGB(0, 0, 0));
1332 std::unique_ptr
<CompatibleDC
> aWhiteDC(CompatibleDC::create(*this, cacheRect
.Left(), cacheRect
.Top(), cacheRect
.GetWidth()+1, cacheRect
.GetHeight()+1));
1333 SetTextAlign(aWhiteDC
->getCompatibleHDC(), TA_LEFT
|TA_TOP
|TA_NOUPDATECP
);
1334 aWhiteDC
->fill(RGB(0xff, 0xff, 0xff));
1336 if (ImplDrawNativeControl(aBlackDC
->getCompatibleHDC(), hTheme
, rc
, nType
, nPart
, nState
, aValue
, aCaptionStr
, bUseDarkMode
) &&
1337 ImplDrawNativeControl(aWhiteDC
->getCompatibleHDC(), hTheme
, rc
, nType
, nPart
, nState
, aValue
, aCaptionStr
, bUseDarkMode
))
1339 bOk
= pImpl
->RenderAndCacheNativeControl(*aWhiteDC
, *aBlackDC
, cacheRect
.Left(), cacheRect
.Top(), aControlCacheKey
);
1344 SetWindowTheme(mhWnd
, nullptr, nullptr);
1348 bool WinSalGraphics::getNativeControlRegion( ControlType nType
,
1350 const tools::Rectangle
& rControlRegion
,
1351 ControlState nState
,
1352 const ImplControlValue
& rControlValue
,
1354 tools::Rectangle
&rNativeBoundingRegion
,
1355 tools::Rectangle
&rNativeContentRegion
)
1359 // FIXME: rNativeBoundingRegion has a different origin
1360 // depending on which part is used; horrors.
1362 HDC hDC
= GetDC( mhWnd
);
1363 if( nType
== ControlType::Toolbar
)
1365 if( nPart
== ControlPart::ThumbHorz
|| nPart
== ControlPart::ThumbVert
)
1368 // the vertical gripper is not supported in most themes and it makes no
1369 // sense to only support horizontal gripper
1371 HTHEME hTheme = getThemeHandle(mhWnd, L"Rebar", mWinSalGraphicsImplBase);
1374 tools::Rectangle aRect( ImplGetThemeRect( hTheme, hDC, nPart == ControlPart::ThumbHorz ? RP_GRIPPERVERT : RP_GRIPPER,
1375 0, rControlRegion.GetBoundRect() ) );
1376 if( nPart == ControlPart::ThumbHorz && !aRect.IsEmpty() )
1378 tools::Rectangle aVertRect( 0, 0, aRect.getHeight(), aRect.getWidth() );
1379 rNativeContentRegion = aVertRect;
1382 rNativeContentRegion = aRect;
1383 rNativeBoundingRegion = rNativeContentRegion;
1384 if( !rNativeContentRegion.IsEmpty() )
1389 if( nPart
== ControlPart::Button
)
1391 HTHEME hTheme
= getThemeHandle(mhWnd
, L
"Toolbar", mWinSalGraphicsImplBase
);
1394 tools::Rectangle
aRect( ImplGetThemeRect( hTheme
, hDC
, TP_SPLITBUTTONDROPDOWN
,
1395 TS_HOT
, rControlRegion
) );
1396 rNativeContentRegion
= aRect
;
1397 rNativeBoundingRegion
= rNativeContentRegion
;
1398 if( !rNativeContentRegion
.IsEmpty() )
1403 if( nType
== ControlType::Progress
&& nPart
== ControlPart::Entire
)
1405 HTHEME hTheme
= getThemeHandle(mhWnd
, L
"Progress", mWinSalGraphicsImplBase
);
1408 tools::Rectangle
aRect( ImplGetThemeRect( hTheme
, hDC
, PP_BAR
,
1409 0, rControlRegion
) );
1410 rNativeContentRegion
= aRect
;
1411 rNativeBoundingRegion
= rNativeContentRegion
;
1412 if( !rNativeContentRegion
.IsEmpty() )
1416 if( (nType
== ControlType::Listbox
|| nType
== ControlType::Combobox
) && nPart
== ControlPart::Entire
)
1418 HTHEME hTheme
= getThemeHandle(mhWnd
, L
"Combobox", mWinSalGraphicsImplBase
);
1421 tools::Rectangle
aBoxRect( rControlRegion
);
1422 tools::Rectangle
aRect( ImplGetThemeRect( hTheme
, hDC
, CP_DROPDOWNBUTTON
,
1423 CBXS_NORMAL
, aBoxRect
) );
1424 if( aRect
.GetHeight() > aBoxRect
.GetHeight() )
1425 aBoxRect
.SetBottom( aBoxRect
.Top() + aRect
.GetHeight() );
1426 if( aRect
.GetWidth() > aBoxRect
.GetWidth() )
1427 aBoxRect
.SetRight( aBoxRect
.Left() + aRect
.GetWidth() );
1428 rNativeContentRegion
= aBoxRect
;
1429 rNativeBoundingRegion
= rNativeContentRegion
;
1430 if( !aRect
.IsEmpty() )
1435 if( (nType
== ControlType::Editbox
|| nType
== ControlType::Spinbox
) && nPart
== ControlPart::Entire
)
1437 HTHEME hTheme
= getThemeHandle(mhWnd
, L
"Edit", mWinSalGraphicsImplBase
);
1441 tools::Rectangle
aBoxRect( rControlRegion
);
1442 tools::Rectangle
aRect( ImplGetThemeRect( hTheme
, hDC
, EP_BACKGROUNDWITHBORDER
,
1443 EBWBS_HOT
, aBoxRect
) );
1444 // ad app font height
1445 NONCLIENTMETRICSW aNonClientMetrics
;
1446 aNonClientMetrics
.cbSize
= sizeof( aNonClientMetrics
);
1447 if ( SystemParametersInfoW( SPI_GETNONCLIENTMETRICS
, sizeof( aNonClientMetrics
), &aNonClientMetrics
, 0 ) )
1449 LONG nFontHeight
= aNonClientMetrics
.lfMessageFont
.lfHeight
;
1450 if( nFontHeight
< 0 )
1451 nFontHeight
= -nFontHeight
;
1453 if( aRect
.GetHeight() && nFontHeight
)
1455 aRect
.AdjustBottom(aRect
.GetHeight());
1456 aRect
.AdjustBottom(nFontHeight
);
1457 if( aRect
.GetHeight() > aBoxRect
.GetHeight() )
1458 aBoxRect
.SetBottom( aBoxRect
.Top() + aRect
.GetHeight() );
1459 if( aRect
.GetWidth() > aBoxRect
.GetWidth() )
1460 aBoxRect
.SetRight( aBoxRect
.Left() + aRect
.GetWidth() );
1461 rNativeContentRegion
= aBoxRect
;
1462 rNativeBoundingRegion
= rNativeContentRegion
;
1469 if( GetSalData()->mbThemeMenuSupport
)
1471 if( nType
== ControlType::MenuPopup
)
1473 if( nPart
== ControlPart::MenuItemCheckMark
||
1474 nPart
== ControlPart::MenuItemRadioMark
)
1476 HTHEME hTheme
= getThemeHandle(mhWnd
, L
"Menu", mWinSalGraphicsImplBase
);
1477 tools::Rectangle
aBoxRect( rControlRegion
);
1478 tools::Rectangle
aRect( ImplGetThemeRect( hTheme
, hDC
,
1482 if (!aRect
.IsEmpty())
1485 SUCCEEDED(GetThemeMargins(hTheme
, hDC
, MENU_POPUPCHECK
, MC_CHECKMARKNORMAL
,
1486 TMT_CONTENTMARGINS
, nullptr, &mg
)))
1488 aRect
.AdjustLeft(-mg
.cxLeftWidth
);
1489 aRect
.AdjustRight(mg
.cxRightWidth
);
1490 aRect
.AdjustTop(-mg
.cyTopHeight
);
1491 aRect
.AdjustBottom(mg
.cyBottomHeight
);
1493 rNativeContentRegion
= rNativeBoundingRegion
= aRect
;
1500 if( nType
== ControlType::Slider
&& ( (nPart
== ControlPart::ThumbHorz
) || (nPart
== ControlPart::ThumbVert
) ) )
1502 HTHEME hTheme
= getThemeHandle(mhWnd
, L
"Trackbar", mWinSalGraphicsImplBase
);
1505 int iPart
= (nPart
== ControlPart::ThumbHorz
) ? TKP_THUMB
: TKP_THUMBVERT
;
1506 int iState
= (nPart
== ControlPart::ThumbHorz
) ? static_cast<int>(TUS_NORMAL
) : static_cast<int>(TUVS_NORMAL
);
1507 tools::Rectangle aThumbRect
= ImplGetThemeRect( hTheme
, hDC
, iPart
, iState
, tools::Rectangle() );
1508 if( nPart
== ControlPart::ThumbHorz
)
1510 tools::Long nW
= aThumbRect
.GetWidth();
1511 tools::Rectangle
aRect( rControlRegion
);
1512 aRect
.SetRight( aRect
.Left() + nW
- 1 );
1513 rNativeContentRegion
= aRect
;
1514 rNativeBoundingRegion
= rNativeContentRegion
;
1518 tools::Long nH
= aThumbRect
.GetHeight();
1519 tools::Rectangle
aRect( rControlRegion
);
1520 aRect
.SetBottom( aRect
.Top() + nH
- 1 );
1521 rNativeContentRegion
= aRect
;
1522 rNativeBoundingRegion
= rNativeContentRegion
;
1528 if ( ( nType
== ControlType::TabItem
) && ( nPart
== ControlPart::Entire
) )
1530 tools::Rectangle
aControlRect( rControlRegion
);
1531 rNativeContentRegion
= aControlRect
;
1533 aControlRect
.AdjustBottom(-1);
1535 if( rControlValue
.getType() == ControlType::TabItem
)
1537 const TabitemValue
& rValue
= static_cast<const TabitemValue
&>(rControlValue
);
1538 if (rValue
.isBothAligned())
1539 aControlRect
.AdjustRight(-1);
1541 if ( nState
& ControlState::SELECTED
)
1543 aControlRect
.AdjustLeft(-2);
1544 if (!rValue
.isBothAligned())
1546 if (rValue
.isLeftAligned() || rValue
.isNotAligned())
1547 aControlRect
.AdjustRight(2);
1548 if (rValue
.isRightAligned())
1549 aControlRect
.AdjustRight(1);
1551 aControlRect
.AdjustTop(-2);
1552 aControlRect
.AdjustBottom(2);
1555 rNativeBoundingRegion
= aControlRect
;
1559 ReleaseDC( mhWnd
, hDC
);
1563 void WinSalGraphics::updateSettingsNative( AllSettings
& rSettings
)
1565 if ( !IsThemeActive() )
1568 StyleSettings aStyleSettings
= rSettings
.GetStyleSettings();
1569 ImplSVData
* pSVData
= ImplGetSVData();
1571 // don't draw frame around each and every toolbar
1572 pSVData
->maNWFData
.mbDockingAreaAvoidTBFrames
= true;
1574 // FIXME get the color directly from the theme, not from the settings
1575 Color aMenuBarTextColor
= aStyleSettings
.GetPersonaMenuBarTextColor().value_or( aStyleSettings
.GetMenuTextColor() );
1576 // in aero menuitem highlight text is drawn in the same color as normal
1577 aStyleSettings
.SetMenuHighlightTextColor( aStyleSettings
.GetMenuTextColor() );
1578 aStyleSettings
.SetMenuBarRolloverTextColor( aMenuBarTextColor
);
1579 aStyleSettings
.SetMenuBarHighlightTextColor( aMenuBarTextColor
);
1580 pSVData
->maNWFData
.mnMenuFormatBorderX
= 2;
1581 pSVData
->maNWFData
.mnMenuFormatBorderY
= 2;
1582 pSVData
->maNWFData
.maMenuBarHighlightTextColor
= aMenuBarTextColor
;
1583 GetSalData()->mbThemeMenuSupport
= true;
1585 rSettings
.SetStyleSettings( aStyleSettings
);
1588 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */