Version 7.1.7.1, tag libreoffice-7.1.7.1
[LibreOffice.git] / vcl / win / gdi / salnativewidgets-luna.cxx
blob68a18b020733e4a93053f3f27b4082e32d21842b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
20 // General info:
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)
28 // Theme subclasses:
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 <opengl/win/gdiimpl.hxx>
41 #include <vcl/svapp.hxx>
42 #include <vcl/settings.hxx>
44 #include <win/svsys.h>
45 #include <win/salgdi.h>
46 #include <win/saldata.hxx>
47 #include <win/scoped_gdi.hxx>
49 #include <uxtheme.h>
50 #include <vssym32.h>
52 #include <map>
53 #include <string>
54 #include <optional>
55 #include <ControlCacheKey.hxx>
57 using namespace std;
59 typedef map< wstring, HTHEME > ThemeMap;
60 static ThemeMap aThemeMap;
62 /****************************************************
63 wrap visual styles API to avoid linking against it
64 it is not available on all Windows platforms
65 *****************************************************/
67 namespace {
69 class VisualStylesAPI
71 private:
72 typedef HTHEME (WINAPI * OpenThemeData_Proc_T) ( HWND hwnd, LPCWSTR pszClassList );
73 typedef HRESULT (WINAPI * CloseThemeData_Proc_T) ( HTHEME hTheme );
74 typedef HRESULT (WINAPI * GetThemeBackgroundContentRect_Proc_T) ( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pBoundingRect, RECT *pContentRect );
75 typedef HRESULT (WINAPI * DrawThemeBackground_Proc_T) ( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, const RECT *pClipRect );
76 typedef HRESULT (WINAPI * DrawThemeText_Proc_T) ( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCWSTR pszText, int iCharCount, DWORD dwTextFlags, DWORD dwTextFlags2, const RECT *pRect );
77 typedef HRESULT (WINAPI * GetThemePartSize_Proc_T) ( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, RECT *prc, THEMESIZE eSize, SIZE *psz );
78 typedef BOOL (WINAPI * IsThemeActive_Proc_T) ( void );
80 OpenThemeData_Proc_T lpfnOpenThemeData;
81 CloseThemeData_Proc_T lpfnCloseThemeData;
82 GetThemeBackgroundContentRect_Proc_T lpfnGetThemeBackgroundContentRect;
83 DrawThemeBackground_Proc_T lpfnDrawThemeBackground;
84 DrawThemeText_Proc_T lpfnDrawThemeText;
85 GetThemePartSize_Proc_T lpfnGetThemePartSize;
86 IsThemeActive_Proc_T lpfnIsThemeActive;
88 oslModule mhModule;
90 public:
91 VisualStylesAPI();
92 ~VisualStylesAPI();
94 HTHEME OpenThemeData( HWND hwnd, LPCWSTR pszClassList );
95 HRESULT CloseThemeData( HTHEME hTheme );
96 HRESULT GetThemeBackgroundContentRect( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pBoundingRect, RECT *pContentRect );
97 HRESULT DrawThemeBackground( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, const RECT *pClipRect );
98 HRESULT DrawThemeText( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCWSTR pszText, int iCharCount, DWORD dwTextFlags, DWORD dwTextFlags2, const RECT *pRect );
99 HRESULT GetThemePartSize( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, RECT *prc, THEMESIZE eSize, SIZE *psz );
100 bool IsThemeActive();
105 static VisualStylesAPI vsAPI;
107 VisualStylesAPI::VisualStylesAPI()
108 : lpfnOpenThemeData( nullptr ),
109 lpfnCloseThemeData( nullptr ),
110 lpfnGetThemeBackgroundContentRect( nullptr ),
111 lpfnDrawThemeBackground( nullptr ),
112 lpfnDrawThemeText( nullptr ),
113 lpfnGetThemePartSize( nullptr ),
114 lpfnIsThemeActive( nullptr )
116 OUString aLibraryName( "uxtheme.dll" );
117 mhModule = osl_loadModule( aLibraryName.pData, SAL_LOADMODULE_DEFAULT );
119 if ( mhModule )
121 lpfnOpenThemeData = reinterpret_cast<OpenThemeData_Proc_T>(osl_getAsciiFunctionSymbol( mhModule, "OpenThemeData" ));
122 lpfnCloseThemeData = reinterpret_cast<CloseThemeData_Proc_T>(osl_getAsciiFunctionSymbol( mhModule, "CloseThemeData" ));
123 lpfnGetThemeBackgroundContentRect = reinterpret_cast<GetThemeBackgroundContentRect_Proc_T>(osl_getAsciiFunctionSymbol( mhModule, "GetThemeBackgroundContentRect" ));
124 lpfnDrawThemeBackground = reinterpret_cast<DrawThemeBackground_Proc_T>(osl_getAsciiFunctionSymbol( mhModule, "DrawThemeBackground" ));
125 lpfnDrawThemeText = reinterpret_cast<DrawThemeText_Proc_T>(osl_getAsciiFunctionSymbol( mhModule, "DrawThemeText" ));
126 lpfnGetThemePartSize = reinterpret_cast<GetThemePartSize_Proc_T>(osl_getAsciiFunctionSymbol( mhModule, "GetThemePartSize" ));
127 lpfnIsThemeActive = reinterpret_cast<IsThemeActive_Proc_T>(osl_getAsciiFunctionSymbol( mhModule, "IsThemeActive" ));
131 VisualStylesAPI::~VisualStylesAPI()
133 if( mhModule )
134 osl_unloadModule( mhModule );
137 HTHEME VisualStylesAPI::OpenThemeData( HWND hwnd, LPCWSTR pszClassList )
139 if(lpfnOpenThemeData)
140 return (*lpfnOpenThemeData) (hwnd, pszClassList);
141 else
142 return nullptr;
145 HRESULT VisualStylesAPI::CloseThemeData( HTHEME hTheme )
147 if(lpfnCloseThemeData)
148 return (*lpfnCloseThemeData) (hTheme);
149 else
150 return S_FALSE;
153 HRESULT VisualStylesAPI::GetThemeBackgroundContentRect( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pBoundingRect, RECT *pContentRect )
155 if(lpfnGetThemeBackgroundContentRect)
156 return (*lpfnGetThemeBackgroundContentRect) ( hTheme, hdc, iPartId, iStateId, pBoundingRect, pContentRect );
157 else
158 return S_FALSE;
161 HRESULT VisualStylesAPI::DrawThemeBackground( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, const RECT *pClipRect )
163 if(lpfnDrawThemeBackground)
164 return (*lpfnDrawThemeBackground) (hTheme, hdc, iPartId, iStateId, pRect, pClipRect);
165 else
166 return S_FALSE;
169 HRESULT VisualStylesAPI::DrawThemeText( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCWSTR pszText, int iCharCount, DWORD dwTextFlags, DWORD dwTextFlags2, const RECT *pRect )
171 if(lpfnDrawThemeText)
172 return (*lpfnDrawThemeText) (hTheme, hdc, iPartId, iStateId, pszText, iCharCount, dwTextFlags, dwTextFlags2, pRect);
173 else
174 return S_FALSE;
177 HRESULT VisualStylesAPI::GetThemePartSize( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, RECT *prc, THEMESIZE eSize, SIZE *psz )
179 if(lpfnGetThemePartSize)
180 return (*lpfnGetThemePartSize) (hTheme, hdc, iPartId, iStateId, prc, eSize, psz);
181 else
182 return S_FALSE;
185 bool VisualStylesAPI::IsThemeActive()
187 if(lpfnIsThemeActive)
188 return (*lpfnIsThemeActive) ();
189 else
190 return false;
193 /*********************************************************
194 * Initialize XP theming and local stuff
195 *********************************************************/
196 void SalData::initNWF()
198 ImplSVData* pSVData = ImplGetSVData();
200 // the menu bar and the top docking area should have a common background (gradient)
201 pSVData->maNWFData.mbMenuBarDockingAreaCommonBG = true;
204 // *********************************************************
205 // * Release theming handles
206 // ********************************************************
207 void SalData::deInitNWF()
209 for( auto& rEntry : aThemeMap )
210 vsAPI.CloseThemeData(rEntry.second);
211 aThemeMap.clear();
214 static HTHEME getThemeHandle( HWND hWnd, LPCWSTR name )
216 if( GetSalData()->mbThemeChanged )
218 // throw away invalid theme handles
219 SalData::deInitNWF();
220 GetSalData()->mbThemeChanged = false;
223 ThemeMap::iterator iter;
224 if( (iter = aThemeMap.find( name )) != aThemeMap.end() )
225 return iter->second;
226 // theme not found -> add it to map
227 HTHEME hTheme = vsAPI.OpenThemeData( hWnd, name );
228 if( hTheme != nullptr )
229 aThemeMap[name] = hTheme;
230 return hTheme;
233 bool WinSalGraphics::isNativeControlSupported( ControlType nType, ControlPart nPart )
235 HTHEME hTheme = nullptr;
237 switch( nType )
239 case ControlType::Pushbutton:
240 case ControlType::Radiobutton:
241 case ControlType::Checkbox:
242 if( nPart == ControlPart::Entire )
243 hTheme = getThemeHandle( mhWnd, L"Button");
244 break;
245 case ControlType::Scrollbar:
246 if( nPart == ControlPart::DrawBackgroundHorz || nPart == ControlPart::DrawBackgroundVert )
247 return false; // no background painting needed
248 if( nPart == ControlPart::Entire )
249 hTheme = getThemeHandle( mhWnd, L"Scrollbar");
250 break;
251 case ControlType::Combobox:
252 if( nPart == ControlPart::HasBackgroundTexture )
253 return false; // we do not paint the inner part (ie the selection background/focus indication)
254 if( nPart == ControlPart::Entire )
255 hTheme = getThemeHandle( mhWnd, L"Edit");
256 else if( nPart == ControlPart::ButtonDown )
257 hTheme = getThemeHandle( mhWnd, L"Combobox");
258 break;
259 case ControlType::Spinbox:
260 if( nPart == ControlPart::Entire )
261 hTheme = getThemeHandle( mhWnd, L"Edit");
262 else if( nPart == ControlPart::AllButtons ||
263 nPart == ControlPart::ButtonUp || nPart == ControlPart::ButtonDown ||
264 nPart == ControlPart::ButtonLeft|| nPart == ControlPart::ButtonRight )
265 hTheme = getThemeHandle( mhWnd, L"Spin");
266 break;
267 case ControlType::SpinButtons:
268 if( nPart == ControlPart::Entire || nPart == ControlPart::AllButtons )
269 hTheme = getThemeHandle( mhWnd, L"Spin");
270 break;
271 case ControlType::Editbox:
272 case ControlType::MultilineEditbox:
273 if( nPart == ControlPart::HasBackgroundTexture )
274 return false; // we do not paint the inner part (ie the selection background/focus indication)
275 //return TRUE;
276 if( nPart == ControlPart::Entire )
277 hTheme = getThemeHandle( mhWnd, L"Edit");
278 break;
279 case ControlType::Listbox:
280 if( nPart == ControlPart::HasBackgroundTexture )
281 return false; // we do not paint the inner part (ie the selection background/focus indication)
282 if( nPart == ControlPart::Entire || nPart == ControlPart::ListboxWindow )
283 hTheme = getThemeHandle( mhWnd, L"Listview");
284 else if( nPart == ControlPart::ButtonDown )
285 hTheme = getThemeHandle( mhWnd, L"Combobox");
286 break;
287 case ControlType::TabPane:
288 case ControlType::TabBody:
289 case ControlType::TabItem:
290 if( nPart == ControlPart::Entire )
291 hTheme = getThemeHandle( mhWnd, L"Tab");
292 break;
293 case ControlType::Toolbar:
294 if( nPart == ControlPart::Entire || nPart == ControlPart::Button )
295 hTheme = getThemeHandle( mhWnd, L"Toolbar");
296 else
297 // use rebar theme for grip and background
298 hTheme = getThemeHandle( mhWnd, L"Rebar");
299 break;
300 case ControlType::Menubar:
301 if( nPart == ControlPart::Entire )
302 hTheme = getThemeHandle( mhWnd, L"Rebar");
303 else if( GetSalData()->mbThemeMenuSupport )
305 if( nPart == ControlPart::MenuItem )
306 hTheme = getThemeHandle( mhWnd, L"Menu" );
308 break;
309 case ControlType::MenuPopup:
310 if( GetSalData()->mbThemeMenuSupport )
312 if( nPart == ControlPart::Entire ||
313 nPart == ControlPart::MenuItem ||
314 nPart == ControlPart::MenuItemCheckMark ||
315 nPart == ControlPart::MenuItemRadioMark ||
316 nPart == ControlPart::Separator )
317 hTheme = getThemeHandle( mhWnd, L"Menu" );
319 break;
320 case ControlType::Progress:
321 if( nPart == ControlPart::Entire )
322 hTheme = getThemeHandle( mhWnd, L"Progress");
323 break;
324 case ControlType::Slider:
325 if( nPart == ControlPart::TrackHorzArea || nPart == ControlPart::TrackVertArea )
326 hTheme = getThemeHandle( mhWnd, L"Trackbar" );
327 break;
328 case ControlType::ListNode:
329 if( nPart == ControlPart::Entire )
330 hTheme = getThemeHandle( mhWnd, L"TreeView" );
331 break;
332 default:
333 hTheme = nullptr;
334 break;
337 return (hTheme != nullptr);
340 bool WinSalGraphics::hitTestNativeControl( ControlType,
341 ControlPart,
342 const tools::Rectangle&,
343 const Point&,
344 bool& )
346 return false;
349 static bool ImplDrawTheme( HTHEME hTheme, HDC hDC, int iPart, int iState, RECT rc, const OUString& aStr)
351 HRESULT hr = vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, nullptr);
353 if( aStr.getLength() )
355 RECT rcContent;
356 hr = vsAPI.GetThemeBackgroundContentRect( hTheme, hDC, iPart, iState, &rc, &rcContent);
357 hr = vsAPI.DrawThemeText( hTheme, hDC, iPart, iState,
358 o3tl::toW(aStr.getStr()), -1,
359 DT_CENTER | DT_VCENTER | DT_SINGLELINE,
360 0, &rcContent);
362 return (hr == S_OK);
365 static tools::Rectangle ImplGetThemeRect( HTHEME hTheme, HDC hDC, int iPart, int iState, const tools::Rectangle& /* aRect */, THEMESIZE eTS = TS_TRUE )
367 SIZE aSz;
368 HRESULT hr = vsAPI.GetThemePartSize( hTheme, hDC, iPart, iState, nullptr, eTS, &aSz ); // TS_TRUE returns optimal size
369 if( hr == S_OK )
370 return tools::Rectangle( 0, 0, aSz.cx, aSz.cy );
371 else
372 return tools::Rectangle();
375 // Helper functions
377 static void ImplConvertSpinbuttonValues( ControlPart nControlPart, const ControlState& rState, const tools::Rectangle& rRect,
378 int* pLunaPart, int *pLunaState, RECT *pRect )
380 if( nControlPart == ControlPart::ButtonDown )
382 *pLunaPart = SPNP_DOWN;
383 if( rState & ControlState::PRESSED )
384 *pLunaState = DNS_PRESSED;
385 else if( !(rState & ControlState::ENABLED) )
386 *pLunaState = DNS_DISABLED;
387 else if( rState & ControlState::ROLLOVER )
388 *pLunaState = DNS_HOT;
389 else
390 *pLunaState = DNS_NORMAL;
392 if( nControlPart == ControlPart::ButtonUp )
394 *pLunaPart = SPNP_UP;
395 if( rState & ControlState::PRESSED )
396 *pLunaState = UPS_PRESSED;
397 else if( !(rState & ControlState::ENABLED) )
398 *pLunaState = UPS_DISABLED;
399 else if( rState & ControlState::ROLLOVER )
400 *pLunaState = UPS_HOT;
401 else
402 *pLunaState = UPS_NORMAL;
404 if( nControlPart == ControlPart::ButtonRight )
406 *pLunaPart = SPNP_UPHORZ;
407 if( rState & ControlState::PRESSED )
408 *pLunaState = DNHZS_PRESSED;
409 else if( !(rState & ControlState::ENABLED) )
410 *pLunaState = DNHZS_DISABLED;
411 else if( rState & ControlState::ROLLOVER )
412 *pLunaState = DNHZS_HOT;
413 else
414 *pLunaState = DNHZS_NORMAL;
416 if( nControlPart == ControlPart::ButtonLeft )
418 *pLunaPart = SPNP_DOWNHORZ;
419 if( rState & ControlState::PRESSED )
420 *pLunaState = UPHZS_PRESSED;
421 else if( !(rState & ControlState::ENABLED) )
422 *pLunaState = UPHZS_DISABLED;
423 else if( rState & ControlState::ROLLOVER )
424 *pLunaState = UPHZS_HOT;
425 else
426 *pLunaState = UPHZS_NORMAL;
429 pRect->left = rRect.Left();
430 pRect->right = rRect.Right()+1;
431 pRect->top = rRect.Top();
432 pRect->bottom = rRect.Bottom()+1;
435 /// Draw an own toolbar style on Windows Vista or later, looks better there
436 static void impl_drawAeroToolbar( HDC hDC, RECT rc, bool bHorizontal )
438 if ( rc.top == 0 && bHorizontal )
440 const long GRADIENT_HEIGHT = 32;
442 long gradient_break = rc.top;
443 long gradient_bottom = rc.bottom - 1;
444 GRADIENT_RECT g_rect[1] = { { 0, 1 } };
446 // very slow gradient at the top (if we have space for that)
447 if ( gradient_bottom - rc.top > GRADIENT_HEIGHT )
449 gradient_break = gradient_bottom - GRADIENT_HEIGHT;
451 TRIVERTEX vert[2] = {
452 { rc.left, rc.top, 0xff00, 0xff00, 0xff00, 0xff00 },
453 { rc.right, gradient_break, 0xfa00, 0xfa00, 0xfa00, 0xff00 },
455 GdiGradientFill( hDC, vert, 2, g_rect, 1, GRADIENT_FILL_RECT_V );
458 // gradient at the bottom
459 TRIVERTEX vert[2] = {
460 { rc.left, gradient_break, 0xfa00, 0xfa00, 0xfa00, 0xff00 },
461 { rc.right, gradient_bottom, 0xf000, 0xf000, 0xf000, 0xff00 }
463 GdiGradientFill( hDC, vert, 2, g_rect, 1, GRADIENT_FILL_RECT_V );
465 // and a darker horizontal line under that
466 ScopedSelectedHPEN hPen(hDC, CreatePen(PS_SOLID, 1, RGB( 0xb0, 0xb0, 0xb0)));
468 MoveToEx( hDC, rc.left, gradient_bottom, nullptr );
469 LineTo( hDC, rc.right, gradient_bottom );
471 else
473 ScopedHBRUSH hbrush(CreateSolidBrush(RGB(0xf0, 0xf0, 0xf0)));
474 FillRect(hDC, &rc, hbrush.get());
476 // darker line to distinguish the toolbar and viewshell
477 // it is drawn only for the horizontal toolbars; it did not look well
478 // when done for the vertical ones too
479 if ( bHorizontal )
481 long from_x, from_y, to_x, to_y;
483 from_x = rc.left;
484 to_x = rc.right;
485 from_y = to_y = rc.top;
487 ScopedSelectedHPEN hPen(hDC, CreatePen(PS_SOLID, 1, RGB( 0xb0, 0xb0, 0xb0)));
489 MoveToEx( hDC, from_x, from_y, nullptr );
490 LineTo( hDC, to_x, to_y );
496 * Gives the actual rectangle used for rendering by ControlType::MenuPopup's
497 * ControlPart::MenuItemCheckMark or ControlPart::MenuItemRadioMark.
499 static tools::Rectangle GetMenuPopupMarkRegion(const ImplControlValue& rValue)
501 tools::Rectangle aRet;
503 auto pMVal = dynamic_cast<const MenupopupValue*>(&rValue);
504 if (!pMVal)
505 return aRet;
507 aRet.SetTop(pMVal->maItemRect.Top());
508 aRet.SetBottom(pMVal->maItemRect.Bottom() + 1); // see below in drawNativeControl
509 if (AllSettings::GetLayoutRTL())
511 aRet.SetRight(pMVal->maItemRect.Right() + 1);
512 aRet.SetLeft(aRet.Right() - (pMVal->getNumericVal() - pMVal->maItemRect.Left()));
514 else
516 aRet.SetRight(pMVal->getNumericVal());
517 aRet.SetLeft(pMVal->maItemRect.Left());
520 return aRet;
523 static bool ImplDrawNativeControl( HDC hDC, HTHEME hTheme, RECT rc,
524 ControlType nType,
525 ControlPart nPart,
526 ControlState nState,
527 const ImplControlValue& aValue,
528 OUString const & aCaption )
530 // a listbox dropdown is actually a combobox dropdown
531 if( nType == ControlType::Listbox )
532 if( nPart == ControlPart::ButtonDown )
533 nType = ControlType::Combobox;
535 // draw entire combobox as a large edit box
536 if( nType == ControlType::Combobox )
537 if( nPart == ControlPart::Entire )
538 nType = ControlType::Editbox;
540 // draw entire spinbox as a large edit box
541 if( nType == ControlType::Spinbox )
542 if( nPart == ControlPart::Entire )
543 nType = ControlType::Editbox;
545 int iPart(0), iState(0);
546 if( nType == ControlType::Scrollbar )
548 HRESULT hr;
549 if( nPart == ControlPart::ButtonUp )
551 iPart = SBP_ARROWBTN;
552 if( nState & ControlState::PRESSED )
553 iState = ABS_UPPRESSED;
554 else if( !(nState & ControlState::ENABLED) )
555 iState = ABS_UPDISABLED;
556 else if( nState & ControlState::ROLLOVER )
557 iState = ABS_UPHOT;
558 else
559 iState = ABS_UPNORMAL;
560 hr = vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, nullptr);
561 return (hr == S_OK);
563 if( nPart == ControlPart::ButtonDown )
565 iPart = SBP_ARROWBTN;
566 if( nState & ControlState::PRESSED )
567 iState = ABS_DOWNPRESSED;
568 else if( !(nState & ControlState::ENABLED) )
569 iState = ABS_DOWNDISABLED;
570 else if( nState & ControlState::ROLLOVER )
571 iState = ABS_DOWNHOT;
572 else
573 iState = ABS_DOWNNORMAL;
574 hr = vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, nullptr);
575 return (hr == S_OK);
577 if( nPart == ControlPart::ButtonLeft )
579 iPart = SBP_ARROWBTN;
580 if( nState & ControlState::PRESSED )
581 iState = ABS_LEFTPRESSED;
582 else if( !(nState & ControlState::ENABLED) )
583 iState = ABS_LEFTDISABLED;
584 else if( nState & ControlState::ROLLOVER )
585 iState = ABS_LEFTHOT;
586 else
587 iState = ABS_LEFTNORMAL;
588 hr = vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, nullptr);
589 return (hr == S_OK);
591 if( nPart == ControlPart::ButtonRight )
593 iPart = SBP_ARROWBTN;
594 if( nState & ControlState::PRESSED )
595 iState = ABS_RIGHTPRESSED;
596 else if( !(nState & ControlState::ENABLED) )
597 iState = ABS_RIGHTDISABLED;
598 else if( nState & ControlState::ROLLOVER )
599 iState = ABS_RIGHTHOT;
600 else
601 iState = ABS_RIGHTNORMAL;
602 hr = vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, nullptr);
603 return (hr == S_OK);
605 if( nPart == ControlPart::ThumbHorz || nPart == ControlPart::ThumbVert )
607 iPart = (nPart == ControlPart::ThumbHorz) ? SBP_THUMBBTNHORZ : SBP_THUMBBTNVERT;
608 if( nState & ControlState::PRESSED )
609 iState = SCRBS_PRESSED;
610 else if( !(nState & ControlState::ENABLED) )
611 iState = SCRBS_DISABLED;
612 else if( nState & ControlState::ROLLOVER )
613 iState = SCRBS_HOT;
614 else
615 iState = SCRBS_NORMAL;
617 SIZE sz;
618 vsAPI.GetThemePartSize(hTheme, hDC, iPart, iState, nullptr, TS_MIN, &sz);
619 vsAPI.GetThemePartSize(hTheme, hDC, iPart, iState, nullptr, TS_TRUE, &sz);
620 vsAPI.GetThemePartSize(hTheme, hDC, iPart, iState, nullptr, TS_DRAW, &sz);
622 hr = vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, nullptr);
623 // paint gripper on thumb if enough space
624 if( ( (nPart == ControlPart::ThumbVert) && (rc.bottom-rc.top > 12) ) ||
625 ( (nPart == ControlPart::ThumbHorz) && (rc.right-rc.left > 12) ) )
627 iPart = (nPart == ControlPart::ThumbHorz) ? SBP_GRIPPERHORZ : SBP_GRIPPERVERT;
628 iState = 0;
629 vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, nullptr);
631 return (hr == S_OK);
633 if( nPart == ControlPart::TrackHorzLeft || nPart == ControlPart::TrackHorzRight || nPart == ControlPart::TrackVertUpper || nPart == ControlPart::TrackVertLower )
635 switch( nPart )
637 case ControlPart::TrackHorzLeft: iPart = SBP_UPPERTRACKHORZ; break;
638 case ControlPart::TrackHorzRight: iPart = SBP_LOWERTRACKHORZ; break;
639 case ControlPart::TrackVertUpper: iPart = SBP_UPPERTRACKVERT; break;
640 case ControlPart::TrackVertLower: iPart = SBP_LOWERTRACKVERT; break;
641 default: break;
644 if( nState & ControlState::PRESSED )
645 iState = SCRBS_PRESSED;
646 else if( !(nState & ControlState::ENABLED) )
647 iState = SCRBS_DISABLED;
648 else if( nState & ControlState::ROLLOVER )
649 iState = SCRBS_HOT;
650 else
651 iState = SCRBS_NORMAL;
652 hr = vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, nullptr);
653 return (hr == S_OK);
656 if( nType == ControlType::SpinButtons && nPart == ControlPart::AllButtons )
658 if( aValue.getType() == ControlType::SpinButtons )
660 const SpinbuttonValue* pValue = (aValue.getType() == ControlType::SpinButtons) ? static_cast<const SpinbuttonValue*>(&aValue) : nullptr;
662 RECT rect;
663 ImplConvertSpinbuttonValues( pValue->mnUpperPart, pValue->mnUpperState, pValue->maUpperRect, &iPart, &iState, &rect );
664 bool bOk = ImplDrawTheme( hTheme, hDC, iPart, iState, rect, aCaption);
666 if( bOk )
668 ImplConvertSpinbuttonValues( pValue->mnLowerPart, pValue->mnLowerState, pValue->maLowerRect, &iPart, &iState, &rect );
669 bOk = ImplDrawTheme( hTheme, hDC, iPart, iState, rect, aCaption);
672 return bOk;
675 if( nType == ControlType::Spinbox )
677 if( nPart == ControlPart::AllButtons )
679 if( aValue.getType() == ControlType::SpinButtons )
681 const SpinbuttonValue *pValue = static_cast<const SpinbuttonValue*>(&aValue);
683 RECT rect;
684 ImplConvertSpinbuttonValues( pValue->mnUpperPart, pValue->mnUpperState, pValue->maUpperRect, &iPart, &iState, &rect );
685 bool bOk = ImplDrawTheme( hTheme, hDC, iPart, iState, rect, aCaption);
687 if( bOk )
689 ImplConvertSpinbuttonValues( pValue->mnLowerPart, pValue->mnLowerState, pValue->maLowerRect, &iPart, &iState, &rect );
690 bOk = ImplDrawTheme( hTheme, hDC, iPart, iState, rect, aCaption);
693 return bOk;
697 if( nPart == ControlPart::ButtonDown )
699 iPart = SPNP_DOWN;
700 if( nState & ControlState::PRESSED )
701 iState = DNS_PRESSED;
702 else if( !(nState & ControlState::ENABLED) )
703 iState = DNS_DISABLED;
704 else if( nState & ControlState::ROLLOVER )
705 iState = DNS_HOT;
706 else
707 iState = DNS_NORMAL;
709 if( nPart == ControlPart::ButtonUp )
711 iPart = SPNP_UP;
712 if( nState & ControlState::PRESSED )
713 iState = UPS_PRESSED;
714 else if( !(nState & ControlState::ENABLED) )
715 iState = UPS_DISABLED;
716 else if( nState & ControlState::ROLLOVER )
717 iState = UPS_HOT;
718 else
719 iState = UPS_NORMAL;
721 if( nPart == ControlPart::ButtonRight )
723 iPart = SPNP_DOWNHORZ;
724 if( nState & ControlState::PRESSED )
725 iState = DNHZS_PRESSED;
726 else if( !(nState & ControlState::ENABLED) )
727 iState = DNHZS_DISABLED;
728 else if( nState & ControlState::ROLLOVER )
729 iState = DNHZS_HOT;
730 else
731 iState = DNHZS_NORMAL;
733 if( nPart == ControlPart::ButtonLeft )
735 iPart = SPNP_UPHORZ;
736 if( nState & ControlState::PRESSED )
737 iState = UPHZS_PRESSED;
738 else if( !(nState & ControlState::ENABLED) )
739 iState = UPHZS_DISABLED;
740 else if( nState & ControlState::ROLLOVER )
741 iState = UPHZS_HOT;
742 else
743 iState = UPHZS_NORMAL;
745 if( nPart == ControlPart::ButtonLeft || nPart == ControlPart::ButtonRight || nPart == ControlPart::ButtonUp || nPart == ControlPart::ButtonDown )
746 return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
748 if( nType == ControlType::Combobox )
750 if( nPart == ControlPart::ButtonDown )
752 iPart = CP_DROPDOWNBUTTON;
753 if( nState & ControlState::PRESSED )
754 iState = CBXS_PRESSED;
755 else if( !(nState & ControlState::ENABLED) )
756 iState = CBXS_DISABLED;
757 else if( nState & ControlState::ROLLOVER )
758 iState = CBXS_HOT;
759 else
760 iState = CBXS_NORMAL;
761 return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
764 if( nType == ControlType::Pushbutton )
766 iPart = BP_PUSHBUTTON;
767 if( nState & ControlState::PRESSED )
768 iState = PBS_PRESSED;
769 else if( !(nState & ControlState::ENABLED) )
770 iState = PBS_DISABLED;
771 else if( nState & ControlState::ROLLOVER )
772 iState = PBS_HOT;
773 else if( nState & ControlState::DEFAULT )
774 iState = PBS_DEFAULTED;
775 //else if( nState & ControlState::FOCUSED )
776 // iState = PBS_DEFAULTED; // may need to draw focus rect
777 else
778 iState = PBS_NORMAL;
780 return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
783 if( nType == ControlType::Radiobutton )
785 iPart = BP_RADIOBUTTON;
786 bool bChecked = ( aValue.getTristateVal() == ButtonValue::On );
788 if( nState & ControlState::PRESSED )
789 iState = bChecked ? RBS_CHECKEDPRESSED : RBS_UNCHECKEDPRESSED;
790 else if( !(nState & ControlState::ENABLED) )
791 iState = bChecked ? RBS_CHECKEDDISABLED : RBS_UNCHECKEDDISABLED;
792 else if( nState & ControlState::ROLLOVER )
793 iState = bChecked ? RBS_CHECKEDHOT : RBS_UNCHECKEDHOT;
794 else
795 iState = bChecked ? RBS_CHECKEDNORMAL : RBS_UNCHECKEDNORMAL;
797 //if( nState & ControlState::FOCUSED )
798 // iState |= PBS_DEFAULTED; // may need to draw focus rect
800 return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
803 if( nType == ControlType::Checkbox )
805 iPart = BP_CHECKBOX;
806 ButtonValue v = aValue.getTristateVal();
808 if( nState & ControlState::PRESSED )
809 iState = (v == ButtonValue::On) ? CBS_CHECKEDPRESSED :
810 ( (v == ButtonValue::Off) ? CBS_UNCHECKEDPRESSED : CBS_MIXEDPRESSED );
811 else if( !(nState & ControlState::ENABLED) )
812 iState = (v == ButtonValue::On) ? CBS_CHECKEDDISABLED :
813 ( (v == ButtonValue::Off) ? CBS_UNCHECKEDDISABLED : CBS_MIXEDDISABLED );
814 else if( nState & ControlState::ROLLOVER )
815 iState = (v == ButtonValue::On) ? CBS_CHECKEDHOT :
816 ( (v == ButtonValue::Off) ? CBS_UNCHECKEDHOT : CBS_MIXEDHOT );
817 else
818 iState = (v == ButtonValue::On) ? CBS_CHECKEDNORMAL :
819 ( (v == ButtonValue::Off) ? CBS_UNCHECKEDNORMAL : CBS_MIXEDNORMAL );
821 //if( nState & ControlState::FOCUSED )
822 // iState |= PBS_DEFAULTED; // may need to draw focus rect
824 //SIZE sz;
825 //THEMESIZE eSize = TS_DRAW; // TS_MIN, TS_TRUE, TS_DRAW
826 //vsAPI.GetThemePartSize( hTheme, hDC, iPart, iState, &rc, eSize, &sz);
828 return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
831 if( ( nType == ControlType::Editbox ) || ( nType == ControlType::MultilineEditbox ) )
833 iPart = EP_EDITTEXT;
834 if( !(nState & ControlState::ENABLED) )
835 iState = ETS_DISABLED;
836 else if( nState & ControlState::FOCUSED )
837 iState = ETS_FOCUSED;
838 else if( nState & ControlState::ROLLOVER )
839 iState = ETS_HOT;
840 else
841 iState = ETS_NORMAL;
843 return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
846 if( nType == ControlType::Listbox )
848 if( nPart == ControlPart::Entire || nPart == ControlPart::ListboxWindow )
850 iPart = LVP_EMPTYTEXT; // ??? no idea which part to choose here
851 return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
855 if( nType == ControlType::TabPane )
857 iPart = TABP_PANE;
858 return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
861 if( nType == ControlType::TabBody )
863 iPart = TABP_BODY;
864 return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
867 if( nType == ControlType::TabItem )
869 iPart = TABP_TABITEMLEFTEDGE;
870 rc.bottom--;
872 OSL_ASSERT( aValue.getType() == ControlType::TabItem );
874 const TabitemValue& rValue = static_cast<const TabitemValue&>(aValue);
875 if (rValue.isBothAligned())
877 iPart = TABP_TABITEMLEFTEDGE;
878 rc.right--;
880 else if (rValue.isLeftAligned())
881 iPart = TABP_TABITEMLEFTEDGE;
882 else if (rValue.isRightAligned())
883 iPart = TABP_TABITEMRIGHTEDGE;
884 else iPart = TABP_TABITEM;
886 if( !(nState & ControlState::ENABLED) )
887 iState = TILES_DISABLED;
888 else if( nState & ControlState::SELECTED )
890 iState = TILES_SELECTED;
891 // increase the selected tab
892 rc.left-=2;
893 if (rValue.isBothAligned())
895 if (rValue.isLeftAligned() || rValue.isNotAligned())
896 rc.right+=2;
897 if (rValue.isRightAligned())
898 rc.right+=1;
900 rc.top-=2;
901 rc.bottom+=2;
903 else if( nState & ControlState::ROLLOVER )
904 iState = TILES_HOT;
905 else if( nState & ControlState::FOCUSED )
906 iState = TILES_FOCUSED; // may need to draw focus rect
907 else
908 iState = TILES_NORMAL;
909 return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
912 if( nType == ControlType::Toolbar )
914 if( nPart == ControlPart::Button )
916 iPart = TP_BUTTON;
917 bool bChecked = ( aValue.getTristateVal() == ButtonValue::On );
918 if( !(nState & ControlState::ENABLED) )
919 //iState = TS_DISABLED;
920 // disabled buttons are typically not painted at all but we need visual
921 // feedback when travelling by keyboard over disabled entries
922 iState = TS_HOT;
923 else if( nState & ControlState::PRESSED )
924 iState = TS_PRESSED;
925 else if( nState & ControlState::ROLLOVER )
926 iState = bChecked ? TS_HOTCHECKED : TS_HOT;
927 else
928 iState = bChecked ? TS_CHECKED : TS_NORMAL;
929 return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
931 else if( nPart == ControlPart::ThumbHorz || nPart == ControlPart::ThumbVert )
933 // the vertical gripper is not supported in most themes and it makes no
934 // sense to only support horizontal gripper
935 //iPart = (nPart == ControlPart::ThumbHorz) ? RP_GRIPPERVERT : RP_GRIPPER;
936 //return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
938 else if( nPart == ControlPart::DrawBackgroundHorz || nPart == ControlPart::DrawBackgroundVert )
940 if( aValue.getType() == ControlType::Toolbar )
942 const ToolbarValue *pValue = static_cast<const ToolbarValue*>(&aValue);
943 if( pValue->mbIsTopDockingArea )
944 rc.top = 0; // extend potential gradient to cover menu bar as well
947 // make it more compatible with Aero
948 if( ImplGetSVData()->maNWFData.mbDockingAreaAvoidTBFrames )
950 impl_drawAeroToolbar( hDC, rc, nPart == ControlPart::DrawBackgroundHorz );
951 return true;
954 return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
958 if( nType == ControlType::Menubar )
960 if( nPart == ControlPart::Entire )
962 if( aValue.getType() == ControlType::Menubar )
964 const MenubarValue *pValue = static_cast<const MenubarValue*>(&aValue);
965 rc.bottom += pValue->maTopDockingAreaHeight; // extend potential gradient to cover docking area as well
967 // make it more compatible with Aero
968 if( ImplGetSVData()->maNWFData.mbDockingAreaAvoidTBFrames )
970 impl_drawAeroToolbar( hDC, rc, true );
971 return true;
974 return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
976 else if( nPart == ControlPart::MenuItem )
978 if( nState & ControlState::ENABLED )
980 if( nState & ControlState::SELECTED )
981 iState = MBI_PUSHED;
982 else if( nState & ControlState::ROLLOVER )
983 iState = MBI_HOT;
984 else
985 iState = MBI_NORMAL;
987 else
989 if( nState & ControlState::SELECTED )
990 iState = MBI_DISABLEDPUSHED;
991 else if( nState & ControlState::ROLLOVER )
992 iState = MBI_DISABLEDHOT;
993 else
994 iState = MBI_DISABLED;
996 return ImplDrawTheme( hTheme, hDC, MENU_BARITEM, iState, rc, aCaption );
1000 if( nType == ControlType::Progress )
1002 if( nPart != ControlPart::Entire )
1003 return false;
1005 if( ! ImplDrawTheme( hTheme, hDC, PP_BAR, iState, rc, aCaption) )
1006 return false;
1007 RECT aProgressRect = rc;
1008 if( vsAPI.GetThemeBackgroundContentRect( hTheme, hDC, PP_BAR, iState, &rc, &aProgressRect) != S_OK )
1009 return false;
1011 long nProgressWidth = aValue.getNumericVal();
1012 nProgressWidth *= (aProgressRect.right - aProgressRect.left);
1013 nProgressWidth /= (rc.right - rc.left);
1014 if( AllSettings::GetLayoutRTL() )
1015 aProgressRect.left = aProgressRect.right - nProgressWidth;
1016 else
1017 aProgressRect.right = aProgressRect.left + nProgressWidth;
1019 return ImplDrawTheme( hTheme, hDC, PP_CHUNK, iState, aProgressRect, aCaption );
1022 if( nType == ControlType::Slider )
1024 iPart = (nPart == ControlPart::TrackHorzArea) ? TKP_TRACK : TKP_TRACKVERT;
1025 iState = (nPart == ControlPart::TrackHorzArea) ? static_cast<int>(TRS_NORMAL) : static_cast<int>(TRVS_NORMAL);
1027 tools::Rectangle aTrackRect = ImplGetThemeRect( hTheme, hDC, iPart, iState, tools::Rectangle() );
1028 RECT aTRect = rc;
1029 if( nPart == ControlPart::TrackHorzArea )
1031 long nH = aTrackRect.GetHeight();
1032 aTRect.top += (rc.bottom - rc.top - nH)/2;
1033 aTRect.bottom = aTRect.top + nH;
1035 else
1037 long nW = aTrackRect.GetWidth();
1038 aTRect.left += (rc.right - rc.left - nW)/2;
1039 aTRect.right = aTRect.left + nW;
1041 ImplDrawTheme( hTheme, hDC, iPart, iState, aTRect, aCaption );
1043 RECT aThumbRect;
1044 OSL_ASSERT( aValue.getType() == ControlType::Slider );
1045 const SliderValue* pVal = static_cast<const SliderValue*>(&aValue);
1046 aThumbRect.left = pVal->maThumbRect.Left();
1047 aThumbRect.top = pVal->maThumbRect.Top();
1048 aThumbRect.right = pVal->maThumbRect.Right();
1049 aThumbRect.bottom = pVal->maThumbRect.Bottom();
1050 iPart = (nPart == ControlPart::TrackHorzArea) ? TKP_THUMB : TKP_THUMBVERT;
1051 iState = (nState & ControlState::ENABLED) ? TUS_NORMAL : TUS_DISABLED;
1052 return ImplDrawTheme( hTheme, hDC, iPart, iState, aThumbRect, aCaption );
1055 if( nType == ControlType::ListNode )
1057 if( nPart != ControlPart::Entire )
1058 return false;
1060 ButtonValue aButtonValue = aValue.getTristateVal();
1061 iPart = TVP_GLYPH;
1062 switch( aButtonValue )
1064 case ButtonValue::On:
1065 iState = GLPS_OPENED;
1066 break;
1067 case ButtonValue::Off:
1068 iState = GLPS_CLOSED;
1069 break;
1070 default:
1071 return false;
1073 return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption );
1076 if( GetSalData()->mbThemeMenuSupport )
1078 if( nType == ControlType::MenuPopup )
1080 if( nPart == ControlPart::Entire )
1082 RECT aGutterRC = rc;
1083 if( AllSettings::GetLayoutRTL() )
1085 aGutterRC.right -= aValue.getNumericVal()+1;
1086 aGutterRC.left = aGutterRC.right-3;
1088 else
1090 aGutterRC.left += aValue.getNumericVal();
1091 aGutterRC.right = aGutterRC.left+3;
1093 return
1094 ImplDrawTheme( hTheme, hDC, MENU_POPUPBACKGROUND, 0, rc, aCaption ) &&
1095 ImplDrawTheme( hTheme, hDC, MENU_POPUPGUTTER, 0, aGutterRC, aCaption )
1098 else if( nPart == ControlPart::MenuItem )
1100 if( nState & ControlState::ENABLED )
1101 iState = (nState & ControlState::SELECTED) ? MPI_HOT : MPI_NORMAL;
1102 else
1103 iState = (nState & ControlState::SELECTED) ? MPI_DISABLEDHOT : MPI_DISABLED;
1104 return ImplDrawTheme( hTheme, hDC, MENU_POPUPITEM, iState, rc, aCaption );
1106 else if( nPart == ControlPart::MenuItemCheckMark || nPart == ControlPart::MenuItemRadioMark )
1108 if( nState & ControlState::PRESSED )
1110 RECT aBGRect = rc;
1111 if( aValue.getType() == ControlType::MenuPopup )
1113 tools::Rectangle aRectangle = GetMenuPopupMarkRegion(aValue);
1114 aBGRect.top = aRectangle.Top();
1115 aBGRect.left = aRectangle.Left();
1116 aBGRect.bottom = aRectangle.Bottom();
1117 aBGRect.right = aRectangle.Right();
1118 rc = aBGRect;
1120 iState = (nState & ControlState::ENABLED) ? MCB_NORMAL : MCB_DISABLED;
1121 ImplDrawTheme( hTheme, hDC, MENU_POPUPCHECKBACKGROUND, iState, aBGRect, aCaption );
1122 if( nPart == ControlPart::MenuItemCheckMark )
1123 iState = (nState & ControlState::ENABLED) ? MC_CHECKMARKNORMAL : MC_CHECKMARKDISABLED;
1124 else
1125 iState = (nState & ControlState::ENABLED) ? MC_BULLETNORMAL : MC_BULLETDISABLED;
1126 return ImplDrawTheme( hTheme, hDC, MENU_POPUPCHECK, iState, rc, aCaption );
1128 else
1129 return true; // unchecked: do nothing
1131 else if( nPart == ControlPart::Separator )
1133 // adjust for gutter position
1134 if( AllSettings::GetLayoutRTL() )
1135 rc.right -= aValue.getNumericVal()+1;
1136 else
1137 rc.left += aValue.getNumericVal()+1;
1138 tools::Rectangle aRect( ImplGetThemeRect( hTheme, hDC,
1139 MENU_POPUPSEPARATOR, 0, tools::Rectangle( rc.left, rc.top, rc.right, rc.bottom ) ) );
1140 // center the separator inside the passed rectangle
1141 long nDY = ((rc.bottom - rc.top + 1) - aRect.GetHeight()) / 2;
1142 rc.top += nDY;
1143 rc.bottom = rc.top+aRect.GetHeight()-1;
1144 return ImplDrawTheme( hTheme, hDC, MENU_POPUPSEPARATOR, 0, rc, aCaption );
1149 return false;
1152 bool WinSalGraphics::drawNativeControl( ControlType nType,
1153 ControlPart nPart,
1154 const tools::Rectangle& rControlRegion,
1155 ControlState nState,
1156 const ImplControlValue& aValue,
1157 const OUString& aCaption,
1158 const Color& /*rBackgroundColor*/ )
1160 bool bOk = false;
1161 HTHEME hTheme = nullptr;
1163 tools::Rectangle buttonRect = rControlRegion;
1164 tools::Rectangle cacheRect = rControlRegion;
1165 Size keySize = cacheRect.GetSize();
1167 WinSalGraphicsImplBase* pImpl = dynamic_cast<WinSalGraphicsImplBase*>(mpImpl.get());
1168 if( !pImpl->UseRenderNativeControl())
1169 pImpl = nullptr;
1171 // tdf#95618 - A few controls render outside the region they're given.
1172 if (pImpl && nType == ControlType::TabItem)
1174 tools::Rectangle rNativeBoundingRegion;
1175 tools::Rectangle rNativeContentRegion;
1176 if (getNativeControlRegion(nType, nPart, rControlRegion, nState, aValue, aCaption,
1177 rNativeBoundingRegion, rNativeContentRegion))
1179 cacheRect = rNativeBoundingRegion;
1180 keySize = rNativeBoundingRegion.GetSize();
1184 if (pImpl && nType == ControlType::MenuPopup && (nPart == ControlPart::MenuItemCheckMark || nPart == ControlPart::MenuItemRadioMark))
1186 tools::Rectangle aRectangle = GetMenuPopupMarkRegion(aValue);
1187 if (!aRectangle.IsEmpty())
1189 cacheRect = GetMenuPopupMarkRegion(aValue);
1190 buttonRect = cacheRect;
1191 keySize = cacheRect.GetSize();
1196 ControlCacheKey aControlCacheKey(nType, nPart, nState, keySize);
1197 if (pImpl != nullptr && pImpl->TryRenderCachedNativeControl(aControlCacheKey, buttonRect.Left(), buttonRect.Top()))
1199 return true;
1202 switch( nType )
1204 case ControlType::Pushbutton:
1205 case ControlType::Radiobutton:
1206 case ControlType::Checkbox:
1207 hTheme = getThemeHandle( mhWnd, L"Button");
1208 break;
1209 case ControlType::Scrollbar:
1210 hTheme = getThemeHandle( mhWnd, L"Scrollbar");
1211 break;
1212 case ControlType::Combobox:
1213 if( nPart == ControlPart::Entire )
1214 hTheme = getThemeHandle( mhWnd, L"Edit");
1215 else if( nPart == ControlPart::ButtonDown )
1216 hTheme = getThemeHandle( mhWnd, L"Combobox");
1217 break;
1218 case ControlType::Spinbox:
1219 if( nPart == ControlPart::Entire )
1220 hTheme = getThemeHandle( mhWnd, L"Edit");
1221 else
1222 hTheme = getThemeHandle( mhWnd, L"Spin");
1223 break;
1224 case ControlType::SpinButtons:
1225 hTheme = getThemeHandle( mhWnd, L"Spin");
1226 break;
1227 case ControlType::Editbox:
1228 case ControlType::MultilineEditbox:
1229 hTheme = getThemeHandle( mhWnd, L"Edit");
1230 break;
1231 case ControlType::Listbox:
1232 if( nPart == ControlPart::Entire || nPart == ControlPart::ListboxWindow )
1233 hTheme = getThemeHandle( mhWnd, L"Listview");
1234 else if( nPart == ControlPart::ButtonDown )
1235 hTheme = getThemeHandle( mhWnd, L"Combobox");
1236 break;
1237 case ControlType::TabPane:
1238 case ControlType::TabBody:
1239 case ControlType::TabItem:
1240 hTheme = getThemeHandle( mhWnd, L"Tab");
1241 break;
1242 case ControlType::Toolbar:
1243 if( nPart == ControlPart::Entire || nPart == ControlPart::Button )
1244 hTheme = getThemeHandle( mhWnd, L"Toolbar");
1245 else
1246 // use rebar for grip and background
1247 hTheme = getThemeHandle( mhWnd, L"Rebar");
1248 break;
1249 case ControlType::Menubar:
1250 if( nPart == ControlPart::Entire )
1251 hTheme = getThemeHandle( mhWnd, L"Rebar");
1252 else if( GetSalData()->mbThemeMenuSupport )
1254 if( nPart == ControlPart::MenuItem )
1255 hTheme = getThemeHandle( mhWnd, L"Menu" );
1257 break;
1258 case ControlType::Progress:
1259 if( nPart == ControlPart::Entire )
1260 hTheme = getThemeHandle( mhWnd, L"Progress");
1261 break;
1262 case ControlType::ListNode:
1263 if( nPart == ControlPart::Entire )
1264 hTheme = getThemeHandle( mhWnd, L"TreeView");
1265 break;
1266 case ControlType::Slider:
1267 if( nPart == ControlPart::TrackHorzArea || nPart == ControlPart::TrackVertArea )
1268 hTheme = getThemeHandle( mhWnd, L"Trackbar" );
1269 break;
1270 case ControlType::MenuPopup:
1271 if( GetSalData()->mbThemeMenuSupport )
1273 if( nPart == ControlPart::Entire || nPart == ControlPart::MenuItem ||
1274 nPart == ControlPart::MenuItemCheckMark || nPart == ControlPart::MenuItemRadioMark ||
1275 nPart == ControlPart::Separator
1277 hTheme = getThemeHandle( mhWnd, L"Menu" );
1279 break;
1280 default:
1281 hTheme = nullptr;
1282 break;
1285 if( !hTheme )
1286 return false;
1288 RECT rc;
1289 rc.left = buttonRect.Left();
1290 rc.right = buttonRect.Right()+1;
1291 rc.top = buttonRect.Top();
1292 rc.bottom = buttonRect.Bottom()+1;
1294 OUString aCaptionStr(aCaption.replace('~', '&')); // translate mnemonics
1296 if (pImpl == nullptr)
1298 // set default text alignment
1299 int ta = SetTextAlign(getHDC(), TA_LEFT|TA_TOP|TA_NOUPDATECP);
1301 bOk = ImplDrawNativeControl(getHDC(), hTheme, rc, nType, nPart, nState, aValue, aCaptionStr);
1303 // restore alignment
1304 SetTextAlign(getHDC(), ta);
1306 else
1308 // We can do OpenGL/Skia
1309 std::unique_ptr<CompatibleDC> aBlackDC(CompatibleDC::create(*this, cacheRect.Left(), cacheRect.Top(), cacheRect.GetWidth()+1, cacheRect.GetHeight()+1));
1310 SetTextAlign(aBlackDC->getCompatibleHDC(), TA_LEFT|TA_TOP|TA_NOUPDATECP);
1311 aBlackDC->fill(RGB(0, 0, 0));
1313 std::unique_ptr<CompatibleDC> aWhiteDC(CompatibleDC::create(*this, cacheRect.Left(), cacheRect.Top(), cacheRect.GetWidth()+1, cacheRect.GetHeight()+1));
1314 SetTextAlign(aWhiteDC->getCompatibleHDC(), TA_LEFT|TA_TOP|TA_NOUPDATECP);
1315 aWhiteDC->fill(RGB(0xff, 0xff, 0xff));
1317 if (ImplDrawNativeControl(aBlackDC->getCompatibleHDC(), hTheme, rc, nType, nPart, nState, aValue, aCaptionStr) &&
1318 ImplDrawNativeControl(aWhiteDC->getCompatibleHDC(), hTheme, rc, nType, nPart, nState, aValue, aCaptionStr))
1320 bOk = pImpl->RenderAndCacheNativeControl(*aWhiteDC, *aBlackDC, cacheRect.Left(), cacheRect.Top(), aControlCacheKey);
1324 return bOk;
1327 bool WinSalGraphics::getNativeControlRegion( ControlType nType,
1328 ControlPart nPart,
1329 const tools::Rectangle& rControlRegion,
1330 ControlState nState,
1331 const ImplControlValue& rControlValue,
1332 const OUString&,
1333 tools::Rectangle &rNativeBoundingRegion,
1334 tools::Rectangle &rNativeContentRegion )
1336 bool bRet = false;
1338 // FIXME: rNativeBoundingRegion has a different origin
1339 // depending on which part is used; horrors.
1341 HDC hDC = GetDC( mhWnd );
1342 if( nType == ControlType::Toolbar )
1344 if( nPart == ControlPart::ThumbHorz || nPart == ControlPart::ThumbVert )
1347 // the vertical gripper is not supported in most themes and it makes no
1348 // sense to only support horizontal gripper
1350 HTHEME hTheme = getThemeHandle( mhWnd, L"Rebar");
1351 if( hTheme )
1353 tools::Rectangle aRect( ImplGetThemeRect( hTheme, hDC, nPart == ControlPart::ThumbHorz ? RP_GRIPPERVERT : RP_GRIPPER,
1354 0, rControlRegion.GetBoundRect() ) );
1355 if( nPart == ControlPart::ThumbHorz && !aRect.IsEmpty() )
1357 tools::Rectangle aVertRect( 0, 0, aRect.getHeight(), aRect.getWidth() );
1358 rNativeContentRegion = aVertRect;
1360 else
1361 rNativeContentRegion = aRect;
1362 rNativeBoundingRegion = rNativeContentRegion;
1363 if( !rNativeContentRegion.IsEmpty() )
1364 bRet = TRUE;
1368 if( nPart == ControlPart::Button )
1370 HTHEME hTheme = getThemeHandle( mhWnd, L"Toolbar");
1371 if( hTheme )
1373 tools::Rectangle aRect( ImplGetThemeRect( hTheme, hDC, TP_SPLITBUTTONDROPDOWN,
1374 TS_HOT, rControlRegion ) );
1375 rNativeContentRegion = aRect;
1376 rNativeBoundingRegion = rNativeContentRegion;
1377 if( !rNativeContentRegion.IsEmpty() )
1378 bRet = true;
1382 if( nType == ControlType::Progress && nPart == ControlPart::Entire )
1384 HTHEME hTheme = getThemeHandle( mhWnd, L"Progress");
1385 if( hTheme )
1387 tools::Rectangle aRect( ImplGetThemeRect( hTheme, hDC, PP_BAR,
1388 0, rControlRegion ) );
1389 rNativeContentRegion = aRect;
1390 rNativeBoundingRegion = rNativeContentRegion;
1391 if( !rNativeContentRegion.IsEmpty() )
1392 bRet = true;
1395 if( (nType == ControlType::Listbox || nType == ControlType::Combobox ) && nPart == ControlPart::Entire )
1397 HTHEME hTheme = getThemeHandle( mhWnd, L"Combobox");
1398 if( hTheme )
1400 tools::Rectangle aBoxRect( rControlRegion );
1401 tools::Rectangle aRect( ImplGetThemeRect( hTheme, hDC, CP_DROPDOWNBUTTON,
1402 CBXS_NORMAL, aBoxRect ) );
1403 if( aRect.GetHeight() > aBoxRect.GetHeight() )
1404 aBoxRect.SetBottom( aBoxRect.Top() + aRect.GetHeight() );
1405 if( aRect.GetWidth() > aBoxRect.GetWidth() )
1406 aBoxRect.SetRight( aBoxRect.Left() + aRect.GetWidth() );
1407 rNativeContentRegion = aBoxRect;
1408 rNativeBoundingRegion = rNativeContentRegion;
1409 if( !aRect.IsEmpty() )
1410 bRet = true;
1414 if( (nType == ControlType::Editbox || nType == ControlType::Spinbox) && nPart == ControlPart::Entire )
1416 HTHEME hTheme = getThemeHandle( mhWnd, L"Edit");
1417 if( hTheme )
1419 // get border size
1420 tools::Rectangle aBoxRect( rControlRegion );
1421 tools::Rectangle aRect( ImplGetThemeRect( hTheme, hDC, EP_BACKGROUNDWITHBORDER,
1422 EBWBS_HOT, aBoxRect ) );
1423 // ad app font height
1424 NONCLIENTMETRICSW aNonClientMetrics;
1425 aNonClientMetrics.cbSize = sizeof( aNonClientMetrics );
1426 if ( SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, sizeof( aNonClientMetrics ), &aNonClientMetrics, 0 ) )
1428 long nFontHeight = aNonClientMetrics.lfMessageFont.lfHeight;
1429 if( nFontHeight < 0 )
1430 nFontHeight = -nFontHeight;
1432 if( aRect.GetHeight() && nFontHeight )
1434 aRect.AdjustBottom(aRect.GetHeight());
1435 aRect.AdjustBottom(nFontHeight);
1436 if( aRect.GetHeight() > aBoxRect.GetHeight() )
1437 aBoxRect.SetBottom( aBoxRect.Top() + aRect.GetHeight() );
1438 if( aRect.GetWidth() > aBoxRect.GetWidth() )
1439 aBoxRect.SetRight( aBoxRect.Left() + aRect.GetWidth() );
1440 rNativeContentRegion = aBoxRect;
1441 rNativeBoundingRegion = rNativeContentRegion;
1442 bRet = true;
1448 if( GetSalData()->mbThemeMenuSupport )
1450 if( nType == ControlType::MenuPopup )
1452 if( nPart == ControlPart::MenuItemCheckMark ||
1453 nPart == ControlPart::MenuItemRadioMark )
1455 HTHEME hTheme = getThemeHandle( mhWnd, L"Menu");
1456 tools::Rectangle aBoxRect( rControlRegion );
1457 tools::Rectangle aRect( ImplGetThemeRect( hTheme, hDC,
1458 MENU_POPUPCHECK,
1459 MC_CHECKMARKNORMAL,
1460 aBoxRect ) );
1461 if( aBoxRect.GetWidth() && aBoxRect.GetHeight() )
1463 rNativeContentRegion = aRect;
1464 rNativeBoundingRegion = rNativeContentRegion;
1465 bRet = true;
1471 if( nType == ControlType::Slider && ( (nPart == ControlPart::ThumbHorz) || (nPart == ControlPart::ThumbVert) ) )
1473 HTHEME hTheme = getThemeHandle( mhWnd, L"Trackbar");
1474 if( hTheme )
1476 int iPart = (nPart == ControlPart::ThumbHorz) ? TKP_THUMB : TKP_THUMBVERT;
1477 int iState = (nPart == ControlPart::ThumbHorz) ? static_cast<int>(TUS_NORMAL) : static_cast<int>(TUVS_NORMAL);
1478 tools::Rectangle aThumbRect = ImplGetThemeRect( hTheme, hDC, iPart, iState, tools::Rectangle() );
1479 if( nPart == ControlPart::ThumbHorz )
1481 long nW = aThumbRect.GetWidth();
1482 tools::Rectangle aRect( rControlRegion );
1483 aRect.SetRight( aRect.Left() + nW - 1 );
1484 rNativeContentRegion = aRect;
1485 rNativeBoundingRegion = rNativeContentRegion;
1487 else
1489 long nH = aThumbRect.GetHeight();
1490 tools::Rectangle aRect( rControlRegion );
1491 aRect.SetBottom( aRect.Top() + nH - 1 );
1492 rNativeContentRegion = aRect;
1493 rNativeBoundingRegion = rNativeContentRegion;
1495 bRet = true;
1499 if ( ( nType == ControlType::TabItem ) && ( nPart == ControlPart::Entire ) )
1501 tools::Rectangle aControlRect( rControlRegion );
1502 rNativeContentRegion = aControlRect;
1504 aControlRect.AdjustBottom(-1);
1506 if( rControlValue.getType() == ControlType::TabItem )
1508 const TabitemValue& rValue = static_cast<const TabitemValue&>(rControlValue);
1509 if (rValue.isBothAligned())
1510 aControlRect.AdjustRight(-1);
1512 if ( nState & ControlState::SELECTED )
1514 aControlRect.AdjustLeft(-2);
1515 if (!rValue.isBothAligned())
1517 if (rValue.isLeftAligned() || rValue.isNotAligned())
1518 aControlRect.AdjustRight(2);
1519 if (rValue.isRightAligned())
1520 aControlRect.AdjustRight(1);
1522 aControlRect.AdjustTop(-2);
1523 aControlRect.AdjustBottom(2);
1526 rNativeBoundingRegion = aControlRect;
1527 bRet = true;
1530 ReleaseDC( mhWnd, hDC );
1531 return bRet;
1534 void WinSalGraphics::updateSettingsNative( AllSettings& rSettings )
1536 if ( !vsAPI.IsThemeActive() )
1537 return;
1539 StyleSettings aStyleSettings = rSettings.GetStyleSettings();
1540 ImplSVData* pSVData = ImplGetSVData();
1542 // don't draw frame around each and every toolbar
1543 pSVData->maNWFData.mbDockingAreaAvoidTBFrames = true;
1545 // FIXME get the color directly from the theme, not from the settings
1546 Color aMenuBarTextColor = aStyleSettings.GetPersonaMenuBarTextColor().value_or( aStyleSettings.GetMenuTextColor() );
1547 // in aero menuitem highlight text is drawn in the same color as normal
1548 aStyleSettings.SetMenuHighlightTextColor( aStyleSettings.GetMenuTextColor() );
1549 aStyleSettings.SetMenuBarRolloverTextColor( aMenuBarTextColor );
1550 aStyleSettings.SetMenuBarHighlightTextColor( aMenuBarTextColor );
1551 pSVData->maNWFData.mnMenuFormatBorderX = 2;
1552 pSVData->maNWFData.mnMenuFormatBorderY = 2;
1553 pSVData->maNWFData.maMenuBarHighlightTextColor = aMenuBarTextColor;
1554 GetSalData()->mbThemeMenuSupport = true;
1556 rSettings.SetStyleSettings( aStyleSettings );
1559 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */