Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / vcl / win / gdi / salnativewidgets-luna.cxx
blob84a9bda35ec3d6325d6f06769f9fe15a0759828f
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 <boost/optional.hpp>
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 class VisualStylesAPI
69 private:
70 typedef HTHEME (WINAPI * OpenThemeData_Proc_T) ( HWND hwnd, LPCWSTR pszClassList );
71 typedef HRESULT (WINAPI * CloseThemeData_Proc_T) ( HTHEME hTheme );
72 typedef HRESULT (WINAPI * GetThemeBackgroundContentRect_Proc_T) ( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pBoundingRect, RECT *pContentRect );
73 typedef HRESULT (WINAPI * DrawThemeBackground_Proc_T) ( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, const RECT *pClipRect );
74 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 );
75 typedef HRESULT (WINAPI * GetThemePartSize_Proc_T) ( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, RECT *prc, THEMESIZE eSize, SIZE *psz );
76 typedef BOOL (WINAPI * IsThemeActive_Proc_T) ( void );
78 OpenThemeData_Proc_T lpfnOpenThemeData;
79 CloseThemeData_Proc_T lpfnCloseThemeData;
80 GetThemeBackgroundContentRect_Proc_T lpfnGetThemeBackgroundContentRect;
81 DrawThemeBackground_Proc_T lpfnDrawThemeBackground;
82 DrawThemeText_Proc_T lpfnDrawThemeText;
83 GetThemePartSize_Proc_T lpfnGetThemePartSize;
84 IsThemeActive_Proc_T lpfnIsThemeActive;
86 oslModule mhModule;
88 public:
89 VisualStylesAPI();
90 ~VisualStylesAPI();
92 HTHEME OpenThemeData( HWND hwnd, LPCWSTR pszClassList );
93 HRESULT CloseThemeData( HTHEME hTheme );
94 HRESULT GetThemeBackgroundContentRect( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pBoundingRect, RECT *pContentRect );
95 HRESULT DrawThemeBackground( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, const RECT *pClipRect );
96 HRESULT DrawThemeText( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCWSTR pszText, int iCharCount, DWORD dwTextFlags, DWORD dwTextFlags2, const RECT *pRect );
97 HRESULT GetThemePartSize( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, RECT *prc, THEMESIZE eSize, SIZE *psz );
98 BOOL IsThemeActive();
101 static VisualStylesAPI vsAPI;
103 VisualStylesAPI::VisualStylesAPI()
104 : lpfnOpenThemeData( nullptr ),
105 lpfnCloseThemeData( nullptr ),
106 lpfnGetThemeBackgroundContentRect( nullptr ),
107 lpfnDrawThemeBackground( nullptr ),
108 lpfnDrawThemeText( nullptr ),
109 lpfnGetThemePartSize( nullptr ),
110 lpfnIsThemeActive( nullptr )
112 OUString aLibraryName( "uxtheme.dll" );
113 mhModule = osl_loadModule( aLibraryName.pData, SAL_LOADMODULE_DEFAULT );
115 if ( mhModule )
117 lpfnOpenThemeData = reinterpret_cast<OpenThemeData_Proc_T>(osl_getAsciiFunctionSymbol( mhModule, "OpenThemeData" ));
118 lpfnCloseThemeData = reinterpret_cast<CloseThemeData_Proc_T>(osl_getAsciiFunctionSymbol( mhModule, "CloseThemeData" ));
119 lpfnGetThemeBackgroundContentRect = reinterpret_cast<GetThemeBackgroundContentRect_Proc_T>(osl_getAsciiFunctionSymbol( mhModule, "GetThemeBackgroundContentRect" ));
120 lpfnDrawThemeBackground = reinterpret_cast<DrawThemeBackground_Proc_T>(osl_getAsciiFunctionSymbol( mhModule, "DrawThemeBackground" ));
121 lpfnDrawThemeText = reinterpret_cast<DrawThemeText_Proc_T>(osl_getAsciiFunctionSymbol( mhModule, "DrawThemeText" ));
122 lpfnGetThemePartSize = reinterpret_cast<GetThemePartSize_Proc_T>(osl_getAsciiFunctionSymbol( mhModule, "GetThemePartSize" ));
123 lpfnIsThemeActive = reinterpret_cast<IsThemeActive_Proc_T>(osl_getAsciiFunctionSymbol( mhModule, "IsThemeActive" ));
127 VisualStylesAPI::~VisualStylesAPI()
129 if( mhModule )
130 osl_unloadModule( mhModule );
133 HTHEME VisualStylesAPI::OpenThemeData( HWND hwnd, LPCWSTR pszClassList )
135 if(lpfnOpenThemeData)
136 return (*lpfnOpenThemeData) (hwnd, pszClassList);
137 else
138 return nullptr;
141 HRESULT VisualStylesAPI::CloseThemeData( HTHEME hTheme )
143 if(lpfnCloseThemeData)
144 return (*lpfnCloseThemeData) (hTheme);
145 else
146 return S_FALSE;
149 HRESULT VisualStylesAPI::GetThemeBackgroundContentRect( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pBoundingRect, RECT *pContentRect )
151 if(lpfnGetThemeBackgroundContentRect)
152 return (*lpfnGetThemeBackgroundContentRect) ( hTheme, hdc, iPartId, iStateId, pBoundingRect, pContentRect );
153 else
154 return S_FALSE;
157 HRESULT VisualStylesAPI::DrawThemeBackground( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, const RECT *pClipRect )
159 if(lpfnDrawThemeBackground)
160 return (*lpfnDrawThemeBackground) (hTheme, hdc, iPartId, iStateId, pRect, pClipRect);
161 else
162 return S_FALSE;
165 HRESULT VisualStylesAPI::DrawThemeText( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCWSTR pszText, int iCharCount, DWORD dwTextFlags, DWORD dwTextFlags2, const RECT *pRect )
167 if(lpfnDrawThemeText)
168 return (*lpfnDrawThemeText) (hTheme, hdc, iPartId, iStateId, pszText, iCharCount, dwTextFlags, dwTextFlags2, pRect);
169 else
170 return S_FALSE;
173 HRESULT VisualStylesAPI::GetThemePartSize( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, RECT *prc, THEMESIZE eSize, SIZE *psz )
175 if(lpfnGetThemePartSize)
176 return (*lpfnGetThemePartSize) (hTheme, hdc, iPartId, iStateId, prc, eSize, psz);
177 else
178 return S_FALSE;
181 BOOL VisualStylesAPI::IsThemeActive()
183 if(lpfnIsThemeActive)
184 return (*lpfnIsThemeActive) ();
185 else
186 return FALSE;
189 /*********************************************************
190 * Initialize XP theming and local stuff
191 *********************************************************/
192 void SalData::initNWF()
194 ImplSVData* pSVData = ImplGetSVData();
196 // the menu bar and the top docking area should have a common background (gradient)
197 pSVData->maNWFData.mbMenuBarDockingAreaCommonBG = true;
200 // *********************************************************
201 // * Release theming handles
202 // ********************************************************
203 void SalData::deInitNWF()
205 for( auto& rEntry : aThemeMap )
206 vsAPI.CloseThemeData(rEntry.second);
207 aThemeMap.clear();
210 static HTHEME getThemeHandle( HWND hWnd, LPCWSTR name )
212 if( GetSalData()->mbThemeChanged )
214 // throw away invalid theme handles
215 SalData::deInitNWF();
216 GetSalData()->mbThemeChanged = false;
219 ThemeMap::iterator iter;
220 if( (iter = aThemeMap.find( name )) != aThemeMap.end() )
221 return iter->second;
222 // theme not found -> add it to map
223 HTHEME hTheme = vsAPI.OpenThemeData( hWnd, name );
224 if( hTheme != nullptr )
225 aThemeMap[name] = hTheme;
226 return hTheme;
229 bool WinSalGraphics::isNativeControlSupported( ControlType nType, ControlPart nPart )
231 HTHEME hTheme = nullptr;
233 switch( nType )
235 case ControlType::Pushbutton:
236 case ControlType::Radiobutton:
237 case ControlType::Checkbox:
238 if( nPart == ControlPart::Entire )
239 hTheme = getThemeHandle( mhWnd, L"Button");
240 break;
241 case ControlType::Scrollbar:
242 if( nPart == ControlPart::DrawBackgroundHorz || nPart == ControlPart::DrawBackgroundVert )
243 return FALSE; // no background painting needed
244 if( nPart == ControlPart::Entire )
245 hTheme = getThemeHandle( mhWnd, L"Scrollbar");
246 break;
247 case ControlType::Combobox:
248 if( nPart == ControlPart::HasBackgroundTexture )
249 return FALSE; // we do not paint the inner part (ie the selection background/focus indication)
250 if( nPart == ControlPart::Entire )
251 hTheme = getThemeHandle( mhWnd, L"Edit");
252 else if( nPart == ControlPart::ButtonDown )
253 hTheme = getThemeHandle( mhWnd, L"Combobox");
254 break;
255 case ControlType::Spinbox:
256 if( nPart == ControlPart::Entire )
257 hTheme = getThemeHandle( mhWnd, L"Edit");
258 else if( nPart == ControlPart::AllButtons ||
259 nPart == ControlPart::ButtonUp || nPart == ControlPart::ButtonDown ||
260 nPart == ControlPart::ButtonLeft|| nPart == ControlPart::ButtonRight )
261 hTheme = getThemeHandle( mhWnd, L"Spin");
262 break;
263 case ControlType::SpinButtons:
264 if( nPart == ControlPart::Entire || nPart == ControlPart::AllButtons )
265 hTheme = getThemeHandle( mhWnd, L"Spin");
266 break;
267 case ControlType::Editbox:
268 case ControlType::MultilineEditbox:
269 if( nPart == ControlPart::HasBackgroundTexture )
270 return FALSE; // we do not paint the inner part (ie the selection background/focus indication)
271 //return TRUE;
272 if( nPart == ControlPart::Entire )
273 hTheme = getThemeHandle( mhWnd, L"Edit");
274 break;
275 case ControlType::Listbox:
276 if( nPart == ControlPart::HasBackgroundTexture )
277 return FALSE; // we do not paint the inner part (ie the selection background/focus indication)
278 if( nPart == ControlPart::Entire || nPart == ControlPart::ListboxWindow )
279 hTheme = getThemeHandle( mhWnd, L"Listview");
280 else if( nPart == ControlPart::ButtonDown )
281 hTheme = getThemeHandle( mhWnd, L"Combobox");
282 break;
283 case ControlType::TabPane:
284 case ControlType::TabBody:
285 case ControlType::TabItem:
286 if( nPart == ControlPart::Entire )
287 hTheme = getThemeHandle( mhWnd, L"Tab");
288 break;
289 case ControlType::Toolbar:
290 if( nPart == ControlPart::Entire || nPart == ControlPart::Button )
291 hTheme = getThemeHandle( mhWnd, L"Toolbar");
292 else
293 // use rebar theme for grip and background
294 hTheme = getThemeHandle( mhWnd, L"Rebar");
295 break;
296 case ControlType::Menubar:
297 if( nPart == ControlPart::Entire )
298 hTheme = getThemeHandle( mhWnd, L"Rebar");
299 else if( GetSalData()->mbThemeMenuSupport )
301 if( nPart == ControlPart::MenuItem )
302 hTheme = getThemeHandle( mhWnd, L"Menu" );
304 break;
305 case ControlType::MenuPopup:
306 if( GetSalData()->mbThemeMenuSupport )
308 if( nPart == ControlPart::Entire ||
309 nPart == ControlPart::MenuItem ||
310 nPart == ControlPart::MenuItemCheckMark ||
311 nPart == ControlPart::MenuItemRadioMark ||
312 nPart == ControlPart::Separator )
313 hTheme = getThemeHandle( mhWnd, L"Menu" );
315 break;
316 case ControlType::Progress:
317 if( nPart == ControlPart::Entire )
318 hTheme = getThemeHandle( mhWnd, L"Progress");
319 break;
320 case ControlType::Slider:
321 if( nPart == ControlPart::TrackHorzArea || nPart == ControlPart::TrackVertArea )
322 hTheme = getThemeHandle( mhWnd, L"Trackbar" );
323 break;
324 case ControlType::ListNode:
325 if( nPart == ControlPart::Entire )
326 hTheme = getThemeHandle( mhWnd, L"TreeView" );
327 break;
328 default:
329 hTheme = nullptr;
330 break;
333 return (hTheme != nullptr);
336 bool WinSalGraphics::hitTestNativeControl( ControlType,
337 ControlPart,
338 const tools::Rectangle&,
339 const Point&,
340 bool& )
342 return FALSE;
345 static bool ImplDrawTheme( HTHEME hTheme, HDC hDC, int iPart, int iState, RECT rc, const OUString& aStr)
347 HRESULT hr = vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, nullptr);
349 if( aStr.getLength() )
351 RECT rcContent;
352 hr = vsAPI.GetThemeBackgroundContentRect( hTheme, hDC, iPart, iState, &rc, &rcContent);
353 hr = vsAPI.DrawThemeText( hTheme, hDC, iPart, iState,
354 o3tl::toW(aStr.getStr()), -1,
355 DT_CENTER | DT_VCENTER | DT_SINGLELINE,
356 0, &rcContent);
358 return (hr == S_OK);
361 static tools::Rectangle ImplGetThemeRect( HTHEME hTheme, HDC hDC, int iPart, int iState, const tools::Rectangle& /* aRect */, THEMESIZE eTS = TS_TRUE )
363 SIZE aSz;
364 HRESULT hr = vsAPI.GetThemePartSize( hTheme, hDC, iPart, iState, nullptr, eTS, &aSz ); // TS_TRUE returns optimal size
365 if( hr == S_OK )
366 return tools::Rectangle( 0, 0, aSz.cx, aSz.cy );
367 else
368 return tools::Rectangle();
371 // Helper functions
373 static void ImplConvertSpinbuttonValues( ControlPart nControlPart, const ControlState& rState, const tools::Rectangle& rRect,
374 int* pLunaPart, int *pLunaState, RECT *pRect )
376 if( nControlPart == ControlPart::ButtonDown )
378 *pLunaPart = SPNP_DOWN;
379 if( rState & ControlState::PRESSED )
380 *pLunaState = DNS_PRESSED;
381 else if( !(rState & ControlState::ENABLED) )
382 *pLunaState = DNS_DISABLED;
383 else if( rState & ControlState::ROLLOVER )
384 *pLunaState = DNS_HOT;
385 else
386 *pLunaState = DNS_NORMAL;
388 if( nControlPart == ControlPart::ButtonUp )
390 *pLunaPart = SPNP_UP;
391 if( rState & ControlState::PRESSED )
392 *pLunaState = UPS_PRESSED;
393 else if( !(rState & ControlState::ENABLED) )
394 *pLunaState = UPS_DISABLED;
395 else if( rState & ControlState::ROLLOVER )
396 *pLunaState = UPS_HOT;
397 else
398 *pLunaState = UPS_NORMAL;
400 if( nControlPart == ControlPart::ButtonRight )
402 *pLunaPart = SPNP_UPHORZ;
403 if( rState & ControlState::PRESSED )
404 *pLunaState = DNHZS_PRESSED;
405 else if( !(rState & ControlState::ENABLED) )
406 *pLunaState = DNHZS_DISABLED;
407 else if( rState & ControlState::ROLLOVER )
408 *pLunaState = DNHZS_HOT;
409 else
410 *pLunaState = DNHZS_NORMAL;
412 if( nControlPart == ControlPart::ButtonLeft )
414 *pLunaPart = SPNP_DOWNHORZ;
415 if( rState & ControlState::PRESSED )
416 *pLunaState = UPHZS_PRESSED;
417 else if( !(rState & ControlState::ENABLED) )
418 *pLunaState = UPHZS_DISABLED;
419 else if( rState & ControlState::ROLLOVER )
420 *pLunaState = UPHZS_HOT;
421 else
422 *pLunaState = UPHZS_NORMAL;
425 pRect->left = rRect.Left();
426 pRect->right = rRect.Right()+1;
427 pRect->top = rRect.Top();
428 pRect->bottom = rRect.Bottom()+1;
431 /// Draw an own toolbar style on Windows Vista or later, looks better there
432 static void impl_drawAeroToolbar( HDC hDC, RECT rc, bool bHorizontal )
434 if ( rc.top == 0 && bHorizontal )
436 const long GRADIENT_HEIGHT = 32;
438 long gradient_break = rc.top;
439 long gradient_bottom = rc.bottom - 1;
440 GRADIENT_RECT g_rect[1] = { { 0, 1 } };
442 // very slow gradient at the top (if we have space for that)
443 if ( gradient_bottom - rc.top > GRADIENT_HEIGHT )
445 gradient_break = gradient_bottom - GRADIENT_HEIGHT;
447 TRIVERTEX vert[2] = {
448 { rc.left, rc.top, 0xff00, 0xff00, 0xff00, 0xff00 },
449 { rc.right, gradient_break, 0xfa00, 0xfa00, 0xfa00, 0xff00 },
451 GdiGradientFill( hDC, vert, 2, g_rect, 1, GRADIENT_FILL_RECT_V );
454 // gradient at the bottom
455 TRIVERTEX vert[2] = {
456 { rc.left, gradient_break, 0xfa00, 0xfa00, 0xfa00, 0xff00 },
457 { rc.right, gradient_bottom, 0xf000, 0xf000, 0xf000, 0xff00 }
459 GdiGradientFill( hDC, vert, 2, g_rect, 1, GRADIENT_FILL_RECT_V );
461 // and a darker horizontal line under that
462 ScopedSelectedHPEN hPen(hDC, CreatePen(PS_SOLID, 1, RGB( 0xb0, 0xb0, 0xb0)));
464 MoveToEx( hDC, rc.left, gradient_bottom, nullptr );
465 LineTo( hDC, rc.right, gradient_bottom );
467 else
469 ScopedHBRUSH hbrush(CreateSolidBrush(RGB(0xf0, 0xf0, 0xf0)));
470 FillRect(hDC, &rc, hbrush.get());
472 // darker line to distinguish the toolbar and viewshell
473 // it is drawn only for the horizontal toolbars; it did not look well
474 // when done for the vertical ones too
475 if ( bHorizontal )
477 long from_x, from_y, to_x, to_y;
479 from_x = rc.left;
480 to_x = rc.right;
481 from_y = to_y = rc.top;
483 ScopedSelectedHPEN hPen(hDC, CreatePen(PS_SOLID, 1, RGB( 0xb0, 0xb0, 0xb0)));
485 MoveToEx( hDC, from_x, from_y, nullptr );
486 LineTo( hDC, to_x, to_y );
492 * Gives the actual rectangle used for rendering by ControlType::MenuPopup's
493 * ControlPart::MenuItemCheckMark or ControlPart::MenuItemRadioMark.
495 static tools::Rectangle GetMenuPopupMarkRegion(const ImplControlValue& rValue)
497 tools::Rectangle aRet;
499 auto pMVal = dynamic_cast<const MenupopupValue*>(&rValue);
500 if (!pMVal)
501 return aRet;
503 aRet.SetTop(pMVal->maItemRect.Top());
504 aRet.SetBottom(pMVal->maItemRect.Bottom() + 1); // see below in drawNativeControl
505 if (AllSettings::GetLayoutRTL())
507 aRet.SetRight(pMVal->maItemRect.Right() + 1);
508 aRet.SetLeft(aRet.Right() - (pMVal->getNumericVal() - pMVal->maItemRect.Left()));
510 else
512 aRet.SetRight(pMVal->getNumericVal());
513 aRet.SetLeft(pMVal->maItemRect.Left());
516 return aRet;
519 static bool ImplDrawNativeControl( HDC hDC, HTHEME hTheme, RECT rc,
520 ControlType nType,
521 ControlPart nPart,
522 ControlState nState,
523 const ImplControlValue& aValue,
524 OUString const & aCaption )
526 // a listbox dropdown is actually a combobox dropdown
527 if( nType == ControlType::Listbox )
528 if( nPart == ControlPart::ButtonDown )
529 nType = ControlType::Combobox;
531 // draw entire combobox as a large edit box
532 if( nType == ControlType::Combobox )
533 if( nPart == ControlPart::Entire )
534 nType = ControlType::Editbox;
536 // draw entire spinbox as a large edit box
537 if( nType == ControlType::Spinbox )
538 if( nPart == ControlPart::Entire )
539 nType = ControlType::Editbox;
541 int iPart(0), iState(0);
542 if( nType == ControlType::Scrollbar )
544 HRESULT hr;
545 if( nPart == ControlPart::ButtonUp )
547 iPart = SBP_ARROWBTN;
548 if( nState & ControlState::PRESSED )
549 iState = ABS_UPPRESSED;
550 else if( !(nState & ControlState::ENABLED) )
551 iState = ABS_UPDISABLED;
552 else if( nState & ControlState::ROLLOVER )
553 iState = ABS_UPHOT;
554 else
555 iState = ABS_UPNORMAL;
556 hr = vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, nullptr);
557 return (hr == S_OK);
559 if( nPart == ControlPart::ButtonDown )
561 iPart = SBP_ARROWBTN;
562 if( nState & ControlState::PRESSED )
563 iState = ABS_DOWNPRESSED;
564 else if( !(nState & ControlState::ENABLED) )
565 iState = ABS_DOWNDISABLED;
566 else if( nState & ControlState::ROLLOVER )
567 iState = ABS_DOWNHOT;
568 else
569 iState = ABS_DOWNNORMAL;
570 hr = vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, nullptr);
571 return (hr == S_OK);
573 if( nPart == ControlPart::ButtonLeft )
575 iPart = SBP_ARROWBTN;
576 if( nState & ControlState::PRESSED )
577 iState = ABS_LEFTPRESSED;
578 else if( !(nState & ControlState::ENABLED) )
579 iState = ABS_LEFTDISABLED;
580 else if( nState & ControlState::ROLLOVER )
581 iState = ABS_LEFTHOT;
582 else
583 iState = ABS_LEFTNORMAL;
584 hr = vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, nullptr);
585 return (hr == S_OK);
587 if( nPart == ControlPart::ButtonRight )
589 iPart = SBP_ARROWBTN;
590 if( nState & ControlState::PRESSED )
591 iState = ABS_RIGHTPRESSED;
592 else if( !(nState & ControlState::ENABLED) )
593 iState = ABS_RIGHTDISABLED;
594 else if( nState & ControlState::ROLLOVER )
595 iState = ABS_RIGHTHOT;
596 else
597 iState = ABS_RIGHTNORMAL;
598 hr = vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, nullptr);
599 return (hr == S_OK);
601 if( nPart == ControlPart::ThumbHorz || nPart == ControlPart::ThumbVert )
603 iPart = (nPart == ControlPart::ThumbHorz) ? SBP_THUMBBTNHORZ : SBP_THUMBBTNVERT;
604 if( nState & ControlState::PRESSED )
605 iState = SCRBS_PRESSED;
606 else if( !(nState & ControlState::ENABLED) )
607 iState = SCRBS_DISABLED;
608 else if( nState & ControlState::ROLLOVER )
609 iState = SCRBS_HOT;
610 else
611 iState = SCRBS_NORMAL;
613 SIZE sz;
614 vsAPI.GetThemePartSize(hTheme, hDC, iPart, iState, nullptr, TS_MIN, &sz);
615 vsAPI.GetThemePartSize(hTheme, hDC, iPart, iState, nullptr, TS_TRUE, &sz);
616 vsAPI.GetThemePartSize(hTheme, hDC, iPart, iState, nullptr, TS_DRAW, &sz);
618 hr = vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, nullptr);
619 // paint gripper on thumb if enough space
620 if( ( (nPart == ControlPart::ThumbVert) && (rc.bottom-rc.top > 12) ) ||
621 ( (nPart == ControlPart::ThumbHorz) && (rc.right-rc.left > 12) ) )
623 iPart = (nPart == ControlPart::ThumbHorz) ? SBP_GRIPPERHORZ : SBP_GRIPPERVERT;
624 iState = 0;
625 vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, nullptr);
627 return (hr == S_OK);
629 if( nPart == ControlPart::TrackHorzLeft || nPart == ControlPart::TrackHorzRight || nPart == ControlPart::TrackVertUpper || nPart == ControlPart::TrackVertLower )
631 switch( nPart )
633 case ControlPart::TrackHorzLeft: iPart = SBP_UPPERTRACKHORZ; break;
634 case ControlPart::TrackHorzRight: iPart = SBP_LOWERTRACKHORZ; break;
635 case ControlPart::TrackVertUpper: iPart = SBP_UPPERTRACKVERT; break;
636 case ControlPart::TrackVertLower: iPart = SBP_LOWERTRACKVERT; break;
637 default: break;
640 if( nState & ControlState::PRESSED )
641 iState = SCRBS_PRESSED;
642 else if( !(nState & ControlState::ENABLED) )
643 iState = SCRBS_DISABLED;
644 else if( nState & ControlState::ROLLOVER )
645 iState = SCRBS_HOT;
646 else
647 iState = SCRBS_NORMAL;
648 hr = vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, nullptr);
649 return (hr == S_OK);
652 if( nType == ControlType::SpinButtons && nPart == ControlPart::AllButtons )
654 if( aValue.getType() == ControlType::SpinButtons )
656 const SpinbuttonValue* pValue = (aValue.getType() == ControlType::SpinButtons) ? static_cast<const SpinbuttonValue*>(&aValue) : nullptr;
658 RECT rect;
659 ImplConvertSpinbuttonValues( pValue->mnUpperPart, pValue->mnUpperState, pValue->maUpperRect, &iPart, &iState, &rect );
660 bool bOk = ImplDrawTheme( hTheme, hDC, iPart, iState, rect, aCaption);
662 if( bOk )
664 ImplConvertSpinbuttonValues( pValue->mnLowerPart, pValue->mnLowerState, pValue->maLowerRect, &iPart, &iState, &rect );
665 bOk = ImplDrawTheme( hTheme, hDC, iPart, iState, rect, aCaption);
668 return bOk;
671 if( nType == ControlType::Spinbox )
673 if( nPart == ControlPart::AllButtons )
675 if( aValue.getType() == ControlType::SpinButtons )
677 const SpinbuttonValue *pValue = static_cast<const SpinbuttonValue*>(&aValue);
679 RECT rect;
680 ImplConvertSpinbuttonValues( pValue->mnUpperPart, pValue->mnUpperState, pValue->maUpperRect, &iPart, &iState, &rect );
681 bool bOk = ImplDrawTheme( hTheme, hDC, iPart, iState, rect, aCaption);
683 if( bOk )
685 ImplConvertSpinbuttonValues( pValue->mnLowerPart, pValue->mnLowerState, pValue->maLowerRect, &iPart, &iState, &rect );
686 bOk = ImplDrawTheme( hTheme, hDC, iPart, iState, rect, aCaption);
689 return bOk;
693 if( nPart == ControlPart::ButtonDown )
695 iPart = SPNP_DOWN;
696 if( nState & ControlState::PRESSED )
697 iState = DNS_PRESSED;
698 else if( !(nState & ControlState::ENABLED) )
699 iState = DNS_DISABLED;
700 else if( nState & ControlState::ROLLOVER )
701 iState = DNS_HOT;
702 else
703 iState = DNS_NORMAL;
705 if( nPart == ControlPart::ButtonUp )
707 iPart = SPNP_UP;
708 if( nState & ControlState::PRESSED )
709 iState = UPS_PRESSED;
710 else if( !(nState & ControlState::ENABLED) )
711 iState = UPS_DISABLED;
712 else if( nState & ControlState::ROLLOVER )
713 iState = UPS_HOT;
714 else
715 iState = UPS_NORMAL;
717 if( nPart == ControlPart::ButtonRight )
719 iPart = SPNP_DOWNHORZ;
720 if( nState & ControlState::PRESSED )
721 iState = DNHZS_PRESSED;
722 else if( !(nState & ControlState::ENABLED) )
723 iState = DNHZS_DISABLED;
724 else if( nState & ControlState::ROLLOVER )
725 iState = DNHZS_HOT;
726 else
727 iState = DNHZS_NORMAL;
729 if( nPart == ControlPart::ButtonLeft )
731 iPart = SPNP_UPHORZ;
732 if( nState & ControlState::PRESSED )
733 iState = UPHZS_PRESSED;
734 else if( !(nState & ControlState::ENABLED) )
735 iState = UPHZS_DISABLED;
736 else if( nState & ControlState::ROLLOVER )
737 iState = UPHZS_HOT;
738 else
739 iState = UPHZS_NORMAL;
741 if( nPart == ControlPart::ButtonLeft || nPart == ControlPart::ButtonRight || nPart == ControlPart::ButtonUp || nPart == ControlPart::ButtonDown )
742 return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
744 if( nType == ControlType::Combobox )
746 if( nPart == ControlPart::ButtonDown )
748 iPart = CP_DROPDOWNBUTTON;
749 if( nState & ControlState::PRESSED )
750 iState = CBXS_PRESSED;
751 else if( !(nState & ControlState::ENABLED) )
752 iState = CBXS_DISABLED;
753 else if( nState & ControlState::ROLLOVER )
754 iState = CBXS_HOT;
755 else
756 iState = CBXS_NORMAL;
757 return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
760 if( nType == ControlType::Pushbutton )
762 iPart = BP_PUSHBUTTON;
763 if( nState & ControlState::PRESSED )
764 iState = PBS_PRESSED;
765 else if( !(nState & ControlState::ENABLED) )
766 iState = PBS_DISABLED;
767 else if( nState & ControlState::ROLLOVER )
768 iState = PBS_HOT;
769 else if( nState & ControlState::DEFAULT )
770 iState = PBS_DEFAULTED;
771 //else if( nState & ControlState::FOCUSED )
772 // iState = PBS_DEFAULTED; // may need to draw focus rect
773 else
774 iState = PBS_NORMAL;
776 return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
779 if( nType == ControlType::Radiobutton )
781 iPart = BP_RADIOBUTTON;
782 bool bChecked = ( aValue.getTristateVal() == ButtonValue::On );
784 if( nState & ControlState::PRESSED )
785 iState = bChecked ? RBS_CHECKEDPRESSED : RBS_UNCHECKEDPRESSED;
786 else if( !(nState & ControlState::ENABLED) )
787 iState = bChecked ? RBS_CHECKEDDISABLED : RBS_UNCHECKEDDISABLED;
788 else if( nState & ControlState::ROLLOVER )
789 iState = bChecked ? RBS_CHECKEDHOT : RBS_UNCHECKEDHOT;
790 else
791 iState = bChecked ? RBS_CHECKEDNORMAL : RBS_UNCHECKEDNORMAL;
793 //if( nState & ControlState::FOCUSED )
794 // iState |= PBS_DEFAULTED; // may need to draw focus rect
796 return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
799 if( nType == ControlType::Checkbox )
801 iPart = BP_CHECKBOX;
802 ButtonValue v = aValue.getTristateVal();
804 if( nState & ControlState::PRESSED )
805 iState = (v == ButtonValue::On) ? CBS_CHECKEDPRESSED :
806 ( (v == ButtonValue::Off) ? CBS_UNCHECKEDPRESSED : CBS_MIXEDPRESSED );
807 else if( !(nState & ControlState::ENABLED) )
808 iState = (v == ButtonValue::On) ? CBS_CHECKEDDISABLED :
809 ( (v == ButtonValue::Off) ? CBS_UNCHECKEDDISABLED : CBS_MIXEDDISABLED );
810 else if( nState & ControlState::ROLLOVER )
811 iState = (v == ButtonValue::On) ? CBS_CHECKEDHOT :
812 ( (v == ButtonValue::Off) ? CBS_UNCHECKEDHOT : CBS_MIXEDHOT );
813 else
814 iState = (v == ButtonValue::On) ? CBS_CHECKEDNORMAL :
815 ( (v == ButtonValue::Off) ? CBS_UNCHECKEDNORMAL : CBS_MIXEDNORMAL );
817 //if( nState & ControlState::FOCUSED )
818 // iState |= PBS_DEFAULTED; // may need to draw focus rect
820 //SIZE sz;
821 //THEMESIZE eSize = TS_DRAW; // TS_MIN, TS_TRUE, TS_DRAW
822 //vsAPI.GetThemePartSize( hTheme, hDC, iPart, iState, &rc, eSize, &sz);
824 return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
827 if( ( nType == ControlType::Editbox ) || ( nType == ControlType::MultilineEditbox ) )
829 iPart = EP_EDITTEXT;
830 if( !(nState & ControlState::ENABLED) )
831 iState = ETS_DISABLED;
832 else if( nState & ControlState::FOCUSED )
833 iState = ETS_FOCUSED;
834 else if( nState & ControlState::ROLLOVER )
835 iState = ETS_HOT;
836 else
837 iState = ETS_NORMAL;
839 return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
842 if( nType == ControlType::Listbox )
844 if( nPart == ControlPart::Entire || nPart == ControlPart::ListboxWindow )
846 iPart = LVP_EMPTYTEXT; // ??? no idea which part to choose here
847 return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
851 if( nType == ControlType::TabPane )
853 iPart = TABP_PANE;
854 return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
857 if( nType == ControlType::TabBody )
859 iPart = TABP_BODY;
860 return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
863 if( nType == ControlType::TabItem )
865 iPart = TABP_TABITEMLEFTEDGE;
866 rc.bottom--;
868 OSL_ASSERT( aValue.getType() == ControlType::TabItem );
870 const TabitemValue& rValue = static_cast<const TabitemValue&>(aValue);
871 if (rValue.isBothAligned())
873 iPart = TABP_TABITEMLEFTEDGE;
874 rc.right--;
876 else if (rValue.isLeftAligned())
877 iPart = TABP_TABITEMLEFTEDGE;
878 else if (rValue.isRightAligned())
879 iPart = TABP_TABITEMRIGHTEDGE;
880 else iPart = TABP_TABITEM;
882 if( !(nState & ControlState::ENABLED) )
883 iState = TILES_DISABLED;
884 else if( nState & ControlState::SELECTED )
886 iState = TILES_SELECTED;
887 // increase the selected tab
888 rc.left-=2;
889 if (rValue.isBothAligned())
891 if (rValue.isLeftAligned() || rValue.isNotAligned())
892 rc.right+=2;
893 if (rValue.isRightAligned())
894 rc.right+=1;
896 rc.top-=2;
897 rc.bottom+=2;
899 else if( nState & ControlState::ROLLOVER )
900 iState = TILES_HOT;
901 else if( nState & ControlState::FOCUSED )
902 iState = TILES_FOCUSED; // may need to draw focus rect
903 else
904 iState = TILES_NORMAL;
905 return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
908 if( nType == ControlType::Toolbar )
910 if( nPart == ControlPart::Button )
912 iPart = TP_BUTTON;
913 bool bChecked = ( aValue.getTristateVal() == ButtonValue::On );
914 if( !(nState & ControlState::ENABLED) )
915 //iState = TS_DISABLED;
916 // disabled buttons are typically not painted at all but we need visual
917 // feedback when travelling by keyboard over disabled entries
918 iState = TS_HOT;
919 else if( nState & ControlState::PRESSED )
920 iState = TS_PRESSED;
921 else if( nState & ControlState::ROLLOVER )
922 iState = bChecked ? TS_HOTCHECKED : TS_HOT;
923 else
924 iState = bChecked ? TS_CHECKED : TS_NORMAL;
925 return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
927 else if( nPart == ControlPart::ThumbHorz || nPart == ControlPart::ThumbVert )
929 // the vertical gripper is not supported in most themes and it makes no
930 // sense to only support horizontal gripper
931 //iPart = (nPart == ControlPart::ThumbHorz) ? RP_GRIPPERVERT : RP_GRIPPER;
932 //return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
934 else if( nPart == ControlPart::DrawBackgroundHorz || nPart == ControlPart::DrawBackgroundVert )
936 if( aValue.getType() == ControlType::Toolbar )
938 const ToolbarValue *pValue = static_cast<const ToolbarValue*>(&aValue);
939 if( pValue->mbIsTopDockingArea )
940 rc.top = 0; // extend potential gradient to cover menu bar as well
943 // make it more compatible with Aero
944 if( ImplGetSVData()->maNWFData.mbDockingAreaAvoidTBFrames )
946 impl_drawAeroToolbar( hDC, rc, nPart == ControlPart::DrawBackgroundHorz );
947 return true;
950 return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
954 if( nType == ControlType::Menubar )
956 if( nPart == ControlPart::Entire )
958 if( aValue.getType() == ControlType::Menubar )
960 const MenubarValue *pValue = static_cast<const MenubarValue*>(&aValue);
961 rc.bottom += pValue->maTopDockingAreaHeight; // extend potential gradient to cover docking area as well
963 // make it more compatible with Aero
964 if( ImplGetSVData()->maNWFData.mbDockingAreaAvoidTBFrames )
966 impl_drawAeroToolbar( hDC, rc, true );
967 return true;
970 return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
972 else if( nPart == ControlPart::MenuItem )
974 if( nState & ControlState::ENABLED )
976 if( nState & ControlState::SELECTED )
977 iState = MBI_PUSHED;
978 else if( nState & ControlState::ROLLOVER )
979 iState = MBI_HOT;
980 else
981 iState = MBI_NORMAL;
983 else
985 if( nState & ControlState::SELECTED )
986 iState = MBI_DISABLEDPUSHED;
987 else if( nState & ControlState::ROLLOVER )
988 iState = MBI_DISABLEDHOT;
989 else
990 iState = MBI_DISABLED;
992 return ImplDrawTheme( hTheme, hDC, MENU_BARITEM, iState, rc, aCaption );
996 if( nType == ControlType::Progress )
998 if( nPart != ControlPart::Entire )
999 return FALSE;
1001 if( ! ImplDrawTheme( hTheme, hDC, PP_BAR, iState, rc, aCaption) )
1002 return false;
1003 RECT aProgressRect = rc;
1004 if( vsAPI.GetThemeBackgroundContentRect( hTheme, hDC, PP_BAR, iState, &rc, &aProgressRect) != S_OK )
1005 return false;
1007 long nProgressWidth = aValue.getNumericVal();
1008 nProgressWidth *= (aProgressRect.right - aProgressRect.left);
1009 nProgressWidth /= (rc.right - rc.left);
1010 if( AllSettings::GetLayoutRTL() )
1011 aProgressRect.left = aProgressRect.right - nProgressWidth;
1012 else
1013 aProgressRect.right = aProgressRect.left + nProgressWidth;
1015 return ImplDrawTheme( hTheme, hDC, PP_CHUNK, iState, aProgressRect, aCaption );
1018 if( nType == ControlType::Slider )
1020 iPart = (nPart == ControlPart::TrackHorzArea) ? TKP_TRACK : TKP_TRACKVERT;
1021 iState = (nPart == ControlPart::TrackHorzArea) ? static_cast<int>(TRS_NORMAL) : static_cast<int>(TRVS_NORMAL);
1023 tools::Rectangle aTrackRect = ImplGetThemeRect( hTheme, hDC, iPart, iState, tools::Rectangle() );
1024 RECT aTRect = rc;
1025 if( nPart == ControlPart::TrackHorzArea )
1027 long nH = aTrackRect.GetHeight();
1028 aTRect.top += (rc.bottom - rc.top - nH)/2;
1029 aTRect.bottom = aTRect.top + nH;
1031 else
1033 long nW = aTrackRect.GetWidth();
1034 aTRect.left += (rc.right - rc.left - nW)/2;
1035 aTRect.right = aTRect.left + nW;
1037 ImplDrawTheme( hTheme, hDC, iPart, iState, aTRect, aCaption );
1039 RECT aThumbRect;
1040 OSL_ASSERT( aValue.getType() == ControlType::Slider );
1041 const SliderValue* pVal = static_cast<const SliderValue*>(&aValue);
1042 aThumbRect.left = pVal->maThumbRect.Left();
1043 aThumbRect.top = pVal->maThumbRect.Top();
1044 aThumbRect.right = pVal->maThumbRect.Right();
1045 aThumbRect.bottom = pVal->maThumbRect.Bottom();
1046 iPart = (nPart == ControlPart::TrackHorzArea) ? TKP_THUMB : TKP_THUMBVERT;
1047 iState = (nState & ControlState::ENABLED) ? TUS_NORMAL : TUS_DISABLED;
1048 return ImplDrawTheme( hTheme, hDC, iPart, iState, aThumbRect, aCaption );
1051 if( nType == ControlType::ListNode )
1053 if( nPart != ControlPart::Entire )
1054 return FALSE;
1056 ButtonValue aButtonValue = aValue.getTristateVal();
1057 iPart = TVP_GLYPH;
1058 switch( aButtonValue )
1060 case ButtonValue::On:
1061 iState = GLPS_OPENED;
1062 break;
1063 case ButtonValue::Off:
1064 iState = GLPS_CLOSED;
1065 break;
1066 default:
1067 return FALSE;
1069 return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption );
1072 if( GetSalData()->mbThemeMenuSupport )
1074 if( nType == ControlType::MenuPopup )
1076 if( nPart == ControlPart::Entire )
1078 RECT aGutterRC = rc;
1079 if( AllSettings::GetLayoutRTL() )
1081 aGutterRC.right -= aValue.getNumericVal()+1;
1082 aGutterRC.left = aGutterRC.right-3;
1084 else
1086 aGutterRC.left += aValue.getNumericVal();
1087 aGutterRC.right = aGutterRC.left+3;
1089 return
1090 ImplDrawTheme( hTheme, hDC, MENU_POPUPBACKGROUND, 0, rc, aCaption ) &&
1091 ImplDrawTheme( hTheme, hDC, MENU_POPUPGUTTER, 0, aGutterRC, aCaption )
1094 else if( nPart == ControlPart::MenuItem )
1096 if( nState & ControlState::ENABLED )
1097 iState = (nState & ControlState::SELECTED) ? MPI_HOT : MPI_NORMAL;
1098 else
1099 iState = (nState & ControlState::SELECTED) ? MPI_DISABLEDHOT : MPI_DISABLED;
1100 return ImplDrawTheme( hTheme, hDC, MENU_POPUPITEM, iState, rc, aCaption );
1102 else if( nPart == ControlPart::MenuItemCheckMark || nPart == ControlPart::MenuItemRadioMark )
1104 if( nState & ControlState::PRESSED )
1106 RECT aBGRect = rc;
1107 if( aValue.getType() == ControlType::MenuPopup )
1109 tools::Rectangle aRectangle = GetMenuPopupMarkRegion(aValue);
1110 aBGRect.top = aRectangle.Top();
1111 aBGRect.left = aRectangle.Left();
1112 aBGRect.bottom = aRectangle.Bottom();
1113 aBGRect.right = aRectangle.Right();
1114 rc = aBGRect;
1116 iState = (nState & ControlState::ENABLED) ? MCB_NORMAL : MCB_DISABLED;
1117 ImplDrawTheme( hTheme, hDC, MENU_POPUPCHECKBACKGROUND, iState, aBGRect, aCaption );
1118 if( nPart == ControlPart::MenuItemCheckMark )
1119 iState = (nState & ControlState::ENABLED) ? MC_CHECKMARKNORMAL : MC_CHECKMARKDISABLED;
1120 else
1121 iState = (nState & ControlState::ENABLED) ? MC_BULLETNORMAL : MC_BULLETDISABLED;
1122 return ImplDrawTheme( hTheme, hDC, MENU_POPUPCHECK, iState, rc, aCaption );
1124 else
1125 return true; // unchecked: do nothing
1127 else if( nPart == ControlPart::Separator )
1129 // adjust for gutter position
1130 if( AllSettings::GetLayoutRTL() )
1131 rc.right -= aValue.getNumericVal()+1;
1132 else
1133 rc.left += aValue.getNumericVal()+1;
1134 tools::Rectangle aRect( ImplGetThemeRect( hTheme, hDC,
1135 MENU_POPUPSEPARATOR, 0, tools::Rectangle( rc.left, rc.top, rc.right, rc.bottom ) ) );
1136 // center the separator inside the passed rectangle
1137 long nDY = ((rc.bottom - rc.top + 1) - aRect.GetHeight()) / 2;
1138 rc.top += nDY;
1139 rc.bottom = rc.top+aRect.GetHeight()-1;
1140 return ImplDrawTheme( hTheme, hDC, MENU_POPUPSEPARATOR, 0, rc, aCaption );
1145 return false;
1148 bool WinSalGraphics::drawNativeControl( ControlType nType,
1149 ControlPart nPart,
1150 const tools::Rectangle& rControlRegion,
1151 ControlState nState,
1152 const ImplControlValue& aValue,
1153 const OUString& aCaption )
1155 bool bOk = false;
1156 HTHEME hTheme = nullptr;
1158 tools::Rectangle buttonRect = rControlRegion;
1159 tools::Rectangle cacheRect = rControlRegion;
1160 Size keySize = cacheRect.GetSize();
1162 WinOpenGLSalGraphicsImpl* pImpl = dynamic_cast<WinOpenGLSalGraphicsImpl*>(mpImpl.get());
1164 // tdf#95618 - A few controls render outside the region they're given.
1165 if (pImpl && nType == ControlType::TabItem)
1167 tools::Rectangle rNativeBoundingRegion;
1168 tools::Rectangle rNativeContentRegion;
1169 if (getNativeControlRegion(nType, nPart, rControlRegion, nState, aValue, aCaption,
1170 rNativeBoundingRegion, rNativeContentRegion))
1172 cacheRect = rNativeBoundingRegion;
1173 keySize = rNativeBoundingRegion.GetSize();
1177 if (pImpl && nType == ControlType::MenuPopup && (nPart == ControlPart::MenuItemCheckMark || nPart == ControlPart::MenuItemRadioMark))
1179 tools::Rectangle aRectangle = GetMenuPopupMarkRegion(aValue);
1180 if (!aRectangle.IsEmpty())
1182 cacheRect = GetMenuPopupMarkRegion(aValue);
1183 buttonRect = cacheRect;
1184 keySize = cacheRect.GetSize();
1189 ControlCacheKey aControlCacheKey(nType, nPart, nState, keySize);
1190 if (pImpl != nullptr && pImpl->TryRenderCachedNativeControl(aControlCacheKey, buttonRect.Left(), buttonRect.Top()))
1192 return true;
1195 switch( nType )
1197 case ControlType::Pushbutton:
1198 case ControlType::Radiobutton:
1199 case ControlType::Checkbox:
1200 hTheme = getThemeHandle( mhWnd, L"Button");
1201 break;
1202 case ControlType::Scrollbar:
1203 hTheme = getThemeHandle( mhWnd, L"Scrollbar");
1204 break;
1205 case ControlType::Combobox:
1206 if( nPart == ControlPart::Entire )
1207 hTheme = getThemeHandle( mhWnd, L"Edit");
1208 else if( nPart == ControlPart::ButtonDown )
1209 hTheme = getThemeHandle( mhWnd, L"Combobox");
1210 break;
1211 case ControlType::Spinbox:
1212 if( nPart == ControlPart::Entire )
1213 hTheme = getThemeHandle( mhWnd, L"Edit");
1214 else
1215 hTheme = getThemeHandle( mhWnd, L"Spin");
1216 break;
1217 case ControlType::SpinButtons:
1218 hTheme = getThemeHandle( mhWnd, L"Spin");
1219 break;
1220 case ControlType::Editbox:
1221 case ControlType::MultilineEditbox:
1222 hTheme = getThemeHandle( mhWnd, L"Edit");
1223 break;
1224 case ControlType::Listbox:
1225 if( nPart == ControlPart::Entire || nPart == ControlPart::ListboxWindow )
1226 hTheme = getThemeHandle( mhWnd, L"Listview");
1227 else if( nPart == ControlPart::ButtonDown )
1228 hTheme = getThemeHandle( mhWnd, L"Combobox");
1229 break;
1230 case ControlType::TabPane:
1231 case ControlType::TabBody:
1232 case ControlType::TabItem:
1233 hTheme = getThemeHandle( mhWnd, L"Tab");
1234 break;
1235 case ControlType::Toolbar:
1236 if( nPart == ControlPart::Entire || nPart == ControlPart::Button )
1237 hTheme = getThemeHandle( mhWnd, L"Toolbar");
1238 else
1239 // use rebar for grip and background
1240 hTheme = getThemeHandle( mhWnd, L"Rebar");
1241 break;
1242 case ControlType::Menubar:
1243 if( nPart == ControlPart::Entire )
1244 hTheme = getThemeHandle( mhWnd, L"Rebar");
1245 else if( GetSalData()->mbThemeMenuSupport )
1247 if( nPart == ControlPart::MenuItem )
1248 hTheme = getThemeHandle( mhWnd, L"Menu" );
1250 break;
1251 case ControlType::Progress:
1252 if( nPart == ControlPart::Entire )
1253 hTheme = getThemeHandle( mhWnd, L"Progress");
1254 break;
1255 case ControlType::ListNode:
1256 if( nPart == ControlPart::Entire )
1257 hTheme = getThemeHandle( mhWnd, L"TreeView");
1258 break;
1259 case ControlType::Slider:
1260 if( nPart == ControlPart::TrackHorzArea || nPart == ControlPart::TrackVertArea )
1261 hTheme = getThemeHandle( mhWnd, L"Trackbar" );
1262 break;
1263 case ControlType::MenuPopup:
1264 if( GetSalData()->mbThemeMenuSupport )
1266 if( nPart == ControlPart::Entire || nPart == ControlPart::MenuItem ||
1267 nPart == ControlPart::MenuItemCheckMark || nPart == ControlPart::MenuItemRadioMark ||
1268 nPart == ControlPart::Separator
1270 hTheme = getThemeHandle( mhWnd, L"Menu" );
1272 break;
1273 default:
1274 hTheme = nullptr;
1275 break;
1278 if( !hTheme )
1279 return false;
1281 RECT rc;
1282 rc.left = buttonRect.Left();
1283 rc.right = buttonRect.Right()+1;
1284 rc.top = buttonRect.Top();
1285 rc.bottom = buttonRect.Bottom()+1;
1287 OUString aCaptionStr(aCaption.replace('~', '&')); // translate mnemonics
1289 if (pImpl == nullptr)
1291 // set default text alignment
1292 int ta = SetTextAlign(getHDC(), TA_LEFT|TA_TOP|TA_NOUPDATECP);
1294 bOk = ImplDrawNativeControl(getHDC(), hTheme, rc, nType, nPart, nState, aValue, aCaptionStr);
1296 // restore alignment
1297 SetTextAlign(getHDC(), ta);
1299 else
1301 // We can do OpenGL
1302 OpenGLCompatibleDC aBlackDC(*this, cacheRect.Left(), cacheRect.Top(), cacheRect.GetWidth()+1, cacheRect.GetHeight()+1);
1303 SetTextAlign(aBlackDC.getCompatibleHDC(), TA_LEFT|TA_TOP|TA_NOUPDATECP);
1304 aBlackDC.fill(RGB(0, 0, 0));
1306 OpenGLCompatibleDC aWhiteDC(*this, cacheRect.Left(), cacheRect.Top(), cacheRect.GetWidth()+1, cacheRect.GetHeight()+1);
1307 SetTextAlign(aWhiteDC.getCompatibleHDC(), TA_LEFT|TA_TOP|TA_NOUPDATECP);
1308 aWhiteDC.fill(RGB(0xff, 0xff, 0xff));
1310 if (ImplDrawNativeControl(aBlackDC.getCompatibleHDC(), hTheme, rc, nType, nPart, nState, aValue, aCaptionStr) &&
1311 ImplDrawNativeControl(aWhiteDC.getCompatibleHDC(), hTheme, rc, nType, nPart, nState, aValue, aCaptionStr))
1313 bOk = pImpl->RenderAndCacheNativeControl(aWhiteDC, aBlackDC, cacheRect.Left(), cacheRect.Top(), aControlCacheKey);
1317 return bOk;
1320 bool WinSalGraphics::getNativeControlRegion( ControlType nType,
1321 ControlPart nPart,
1322 const tools::Rectangle& rControlRegion,
1323 ControlState nState,
1324 const ImplControlValue& rControlValue,
1325 const OUString&,
1326 tools::Rectangle &rNativeBoundingRegion,
1327 tools::Rectangle &rNativeContentRegion )
1329 bool bRet = FALSE;
1331 // FIXME: rNativeBoundingRegion has a different origin
1332 // depending on which part is used; horrors.
1334 HDC hDC = GetDC( mhWnd );
1335 if( nType == ControlType::Toolbar )
1337 if( nPart == ControlPart::ThumbHorz || nPart == ControlPart::ThumbVert )
1340 // the vertical gripper is not supported in most themes and it makes no
1341 // sense to only support horizontal gripper
1343 HTHEME hTheme = getThemeHandle( mhWnd, L"Rebar");
1344 if( hTheme )
1346 tools::Rectangle aRect( ImplGetThemeRect( hTheme, hDC, nPart == ControlPart::ThumbHorz ? RP_GRIPPERVERT : RP_GRIPPER,
1347 0, rControlRegion.GetBoundRect() ) );
1348 if( nPart == ControlPart::ThumbHorz && !aRect.IsEmpty() )
1350 tools::Rectangle aVertRect( 0, 0, aRect.getHeight(), aRect.getWidth() );
1351 rNativeContentRegion = aVertRect;
1353 else
1354 rNativeContentRegion = aRect;
1355 rNativeBoundingRegion = rNativeContentRegion;
1356 if( !rNativeContentRegion.IsEmpty() )
1357 bRet = TRUE;
1361 if( nPart == ControlPart::Button )
1363 HTHEME hTheme = getThemeHandle( mhWnd, L"Toolbar");
1364 if( hTheme )
1366 tools::Rectangle aRect( ImplGetThemeRect( hTheme, hDC, TP_SPLITBUTTONDROPDOWN,
1367 TS_HOT, rControlRegion ) );
1368 rNativeContentRegion = aRect;
1369 rNativeBoundingRegion = rNativeContentRegion;
1370 if( !rNativeContentRegion.IsEmpty() )
1371 bRet = TRUE;
1375 if( nType == ControlType::Progress && nPart == ControlPart::Entire )
1377 HTHEME hTheme = getThemeHandle( mhWnd, L"Progress");
1378 if( hTheme )
1380 tools::Rectangle aRect( ImplGetThemeRect( hTheme, hDC, PP_BAR,
1381 0, rControlRegion ) );
1382 rNativeContentRegion = aRect;
1383 rNativeBoundingRegion = rNativeContentRegion;
1384 if( !rNativeContentRegion.IsEmpty() )
1385 bRet = TRUE;
1388 if( (nType == ControlType::Listbox || nType == ControlType::Combobox ) && nPart == ControlPart::Entire )
1390 HTHEME hTheme = getThemeHandle( mhWnd, L"Combobox");
1391 if( hTheme )
1393 tools::Rectangle aBoxRect( rControlRegion );
1394 tools::Rectangle aRect( ImplGetThemeRect( hTheme, hDC, CP_DROPDOWNBUTTON,
1395 CBXS_NORMAL, aBoxRect ) );
1396 if( aRect.GetHeight() > aBoxRect.GetHeight() )
1397 aBoxRect.SetBottom( aBoxRect.Top() + aRect.GetHeight() );
1398 if( aRect.GetWidth() > aBoxRect.GetWidth() )
1399 aBoxRect.SetRight( aBoxRect.Left() + aRect.GetWidth() );
1400 rNativeContentRegion = aBoxRect;
1401 rNativeBoundingRegion = rNativeContentRegion;
1402 if( !aRect.IsEmpty() )
1403 bRet = TRUE;
1407 if( (nType == ControlType::Editbox || nType == ControlType::Spinbox) && nPart == ControlPart::Entire )
1409 HTHEME hTheme = getThemeHandle( mhWnd, L"Edit");
1410 if( hTheme )
1412 // get border size
1413 tools::Rectangle aBoxRect( rControlRegion );
1414 tools::Rectangle aRect( ImplGetThemeRect( hTheme, hDC, EP_BACKGROUNDWITHBORDER,
1415 EBWBS_HOT, aBoxRect ) );
1416 // ad app font height
1417 NONCLIENTMETRICSW aNonClientMetrics;
1418 aNonClientMetrics.cbSize = sizeof( aNonClientMetrics );
1419 if ( SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, sizeof( aNonClientMetrics ), &aNonClientMetrics, 0 ) )
1421 long nFontHeight = aNonClientMetrics.lfMessageFont.lfHeight;
1422 if( nFontHeight < 0 )
1423 nFontHeight = -nFontHeight;
1425 if( aRect.GetHeight() && nFontHeight )
1427 aRect.AdjustBottom(aRect.GetHeight());
1428 aRect.AdjustBottom(nFontHeight);
1429 if( aRect.GetHeight() > aBoxRect.GetHeight() )
1430 aBoxRect.SetBottom( aBoxRect.Top() + aRect.GetHeight() );
1431 if( aRect.GetWidth() > aBoxRect.GetWidth() )
1432 aBoxRect.SetRight( aBoxRect.Left() + aRect.GetWidth() );
1433 rNativeContentRegion = aBoxRect;
1434 rNativeBoundingRegion = rNativeContentRegion;
1435 bRet = TRUE;
1441 if( GetSalData()->mbThemeMenuSupport )
1443 if( nType == ControlType::MenuPopup )
1445 if( nPart == ControlPart::MenuItemCheckMark ||
1446 nPart == ControlPart::MenuItemRadioMark )
1448 HTHEME hTheme = getThemeHandle( mhWnd, L"Menu");
1449 tools::Rectangle aBoxRect( rControlRegion );
1450 tools::Rectangle aRect( ImplGetThemeRect( hTheme, hDC,
1451 MENU_POPUPCHECK,
1452 MC_CHECKMARKNORMAL,
1453 aBoxRect ) );
1454 if( aBoxRect.GetWidth() && aBoxRect.GetHeight() )
1456 rNativeContentRegion = aRect;
1457 rNativeBoundingRegion = rNativeContentRegion;
1458 bRet = TRUE;
1464 if( nType == ControlType::Slider && ( (nPart == ControlPart::ThumbHorz) || (nPart == ControlPart::ThumbVert) ) )
1466 HTHEME hTheme = getThemeHandle( mhWnd, L"Trackbar");
1467 if( hTheme )
1469 int iPart = (nPart == ControlPart::ThumbHorz) ? TKP_THUMB : TKP_THUMBVERT;
1470 int iState = (nPart == ControlPart::ThumbHorz) ? static_cast<int>(TUS_NORMAL) : static_cast<int>(TUVS_NORMAL);
1471 tools::Rectangle aThumbRect = ImplGetThemeRect( hTheme, hDC, iPart, iState, tools::Rectangle() );
1472 if( nPart == ControlPart::ThumbHorz )
1474 long nW = aThumbRect.GetWidth();
1475 tools::Rectangle aRect( rControlRegion );
1476 aRect.SetRight( aRect.Left() + nW - 1 );
1477 rNativeContentRegion = aRect;
1478 rNativeBoundingRegion = rNativeContentRegion;
1480 else
1482 long nH = aThumbRect.GetHeight();
1483 tools::Rectangle aRect( rControlRegion );
1484 aRect.SetBottom( aRect.Top() + nH - 1 );
1485 rNativeContentRegion = aRect;
1486 rNativeBoundingRegion = rNativeContentRegion;
1488 bRet = TRUE;
1492 if ( ( nType == ControlType::TabItem ) && ( nPart == ControlPart::Entire ) )
1494 tools::Rectangle aControlRect( rControlRegion );
1495 rNativeContentRegion = aControlRect;
1497 aControlRect.AdjustBottom(-1);
1499 if( rControlValue.getType() == ControlType::TabItem )
1501 const TabitemValue& rValue = static_cast<const TabitemValue&>(rControlValue);
1502 if (rValue.isBothAligned())
1503 aControlRect.AdjustRight(-1);
1505 if ( nState & ControlState::SELECTED )
1507 aControlRect.AdjustLeft(-2);
1508 if (!rValue.isBothAligned())
1510 if (rValue.isLeftAligned() || rValue.isNotAligned())
1511 aControlRect.AdjustRight(2);
1512 if (rValue.isRightAligned())
1513 aControlRect.AdjustRight(1);
1515 aControlRect.AdjustTop(-2);
1516 aControlRect.AdjustBottom(2);
1519 rNativeBoundingRegion = aControlRect;
1520 bRet = TRUE;
1523 ReleaseDC( mhWnd, hDC );
1524 return bRet;
1527 void WinSalGraphics::updateSettingsNative( AllSettings& rSettings )
1529 if ( !vsAPI.IsThemeActive() )
1530 return;
1532 StyleSettings aStyleSettings = rSettings.GetStyleSettings();
1533 ImplSVData* pSVData = ImplGetSVData();
1535 // don't draw frame around each and every toolbar
1536 pSVData->maNWFData.mbDockingAreaAvoidTBFrames = true;
1538 // FIXME get the color directly from the theme, not from the settings
1539 Color aMenuBarTextColor = aStyleSettings.GetPersonaMenuBarTextColor().get_value_or( aStyleSettings.GetMenuTextColor() );
1540 // in aero menuitem highlight text is drawn in the same color as normal
1541 aStyleSettings.SetMenuHighlightTextColor( aStyleSettings.GetMenuTextColor() );
1542 aStyleSettings.SetMenuBarRolloverTextColor( aMenuBarTextColor );
1543 aStyleSettings.SetMenuBarHighlightTextColor( aMenuBarTextColor );
1544 pSVData->maNWFData.mnMenuFormatBorderX = 2;
1545 pSVData->maNWFData.mnMenuFormatBorderY = 2;
1546 pSVData->maNWFData.maMenuBarHighlightTextColor = aMenuBarTextColor;
1547 GetSalData()->mbThemeMenuSupport = true;
1549 rSettings.SetStyleSettings( aStyleSettings );
1552 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */