1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_vcl.hxx"
26 
27 #define _SV_SALNATIVEWIDGETS_CXX
28 
29 #include "rtl/ustring.h"
30 
31 #include "osl/module.h"
32 
33 #include "vcl/svapp.hxx"
34 
35 #include "win/svsys.h"
36 #include "win/salgdi.h"
37 #include "win/saldata.hxx"
38 
39 #include "uxtheme.h"
40 #include "vssym32.h"
41 
42 #include <map>
43 #include <string>
44 
45 using namespace rtl;
46 using namespace std;
47 
48 typedef map< wstring, HTHEME > ThemeMap;
49 static ThemeMap aThemeMap;
50 
51 
52 /****************************************************
53  wrap visual styles API to avoid linking against it
54  it is not available on all Windows platforms
55 *****************************************************/
56 
57 class VisualStylesAPI
58 {
59 private:
60     typedef HTHEME  (WINAPI * OpenThemeData_Proc_T) ( HWND hwnd, LPCWSTR pszClassList );
61     typedef HRESULT (WINAPI * CloseThemeData_Proc_T) ( HTHEME hTheme );
62     typedef HRESULT (WINAPI * GetThemeBackgroundContentRect_Proc_T) ( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pBoundingRect, RECT *pContentRect );
63     typedef HRESULT (WINAPI * DrawThemeBackground_Proc_T) ( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, const RECT *pClipRect );
64     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 );
65     typedef HRESULT (WINAPI * GetThemePartSize_Proc_T) ( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, RECT *prc, THEMESIZE eSize, SIZE *psz );
66 
67     OpenThemeData_Proc_T                    lpfnOpenThemeData;
68     CloseThemeData_Proc_T                   lpfnCloseThemeData;
69     GetThemeBackgroundContentRect_Proc_T    lpfnGetThemeBackgroundContentRect;
70     DrawThemeBackground_Proc_T              lpfnDrawThemeBackground;
71     DrawThemeText_Proc_T                    lpfnDrawThemeText;
72     GetThemePartSize_Proc_T                 lpfnGetThemePartSize;
73 
74     oslModule mhModule;
75 
76 public:
77     VisualStylesAPI();
78     ~VisualStylesAPI();
IsAvailable()79     sal_Bool IsAvailable()  { return (mhModule != NULL); }
80 
81     HTHEME OpenThemeData( HWND hwnd, LPCWSTR pszClassList );
82     HRESULT CloseThemeData( HTHEME hTheme );
83     HRESULT GetThemeBackgroundContentRect( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pBoundingRect, RECT *pContentRect );
84     HRESULT DrawThemeBackground( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, const RECT *pClipRect );
85     HRESULT DrawThemeText( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCWSTR pszText, int iCharCount, DWORD dwTextFlags, DWORD dwTextFlags2, const RECT *pRect );
86     HRESULT GetThemePartSize( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, RECT *prc, THEMESIZE eSize, SIZE *psz );
87 };
88 
89 static VisualStylesAPI vsAPI;
90 
VisualStylesAPI()91 VisualStylesAPI::VisualStylesAPI()
92 {
93     mhModule = osl_loadAsciiModule( "uxtheme.dll", SAL_LOADMODULE_DEFAULT );
94 
95     if ( mhModule )
96     {
97         lpfnOpenThemeData = (OpenThemeData_Proc_T)osl_getAsciiFunctionSymbol( mhModule, "OpenThemeData" );
98         lpfnCloseThemeData = (CloseThemeData_Proc_T)osl_getAsciiFunctionSymbol( mhModule, "CloseThemeData" );
99         lpfnGetThemeBackgroundContentRect = (GetThemeBackgroundContentRect_Proc_T)osl_getAsciiFunctionSymbol( mhModule, "GetThemeBackgroundContentRect" );
100         lpfnDrawThemeBackground = (DrawThemeBackground_Proc_T)osl_getAsciiFunctionSymbol( mhModule, "DrawThemeBackground" );
101         lpfnDrawThemeText = (DrawThemeText_Proc_T)osl_getAsciiFunctionSymbol( mhModule, "DrawThemeText" );
102         lpfnGetThemePartSize = (GetThemePartSize_Proc_T)osl_getAsciiFunctionSymbol( mhModule, "GetThemePartSize" );
103     }
104     else
105     {
106         lpfnOpenThemeData = NULL;
107         lpfnCloseThemeData = NULL;
108         lpfnGetThemeBackgroundContentRect = NULL;
109         lpfnDrawThemeBackground = NULL;
110         lpfnDrawThemeText = NULL;
111         lpfnGetThemePartSize = NULL;
112     }
113 }
~VisualStylesAPI()114 VisualStylesAPI::~VisualStylesAPI()
115 {
116     if( mhModule )
117         osl_unloadModule( mhModule );
118 }
OpenThemeData(HWND hwnd,LPCWSTR pszClassList)119 HTHEME VisualStylesAPI::OpenThemeData( HWND hwnd, LPCWSTR pszClassList )
120 {
121     if(lpfnOpenThemeData)
122         return (*lpfnOpenThemeData) (hwnd, pszClassList);
123     else
124         return NULL;
125 }
126 
CloseThemeData(HTHEME hTheme)127 HRESULT VisualStylesAPI::CloseThemeData( HTHEME hTheme )
128 {
129     if(lpfnCloseThemeData)
130         return (*lpfnCloseThemeData) (hTheme);
131     else
132         return S_FALSE;
133 }
GetThemeBackgroundContentRect(HTHEME hTheme,HDC hdc,int iPartId,int iStateId,const RECT * pBoundingRect,RECT * pContentRect)134 HRESULT VisualStylesAPI::GetThemeBackgroundContentRect( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pBoundingRect, RECT *pContentRect )
135 {
136     if(lpfnGetThemeBackgroundContentRect)
137         return (*lpfnGetThemeBackgroundContentRect) ( hTheme, hdc, iPartId, iStateId, pBoundingRect, pContentRect );
138     else
139         return S_FALSE;
140 }
DrawThemeBackground(HTHEME hTheme,HDC hdc,int iPartId,int iStateId,const RECT * pRect,const RECT * pClipRect)141 HRESULT VisualStylesAPI::DrawThemeBackground( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, const RECT *pClipRect )
142 {
143     if(lpfnDrawThemeBackground)
144         return (*lpfnDrawThemeBackground) (hTheme, hdc, iPartId, iStateId, pRect, pClipRect);
145     else
146         return S_FALSE;
147 }
DrawThemeText(HTHEME hTheme,HDC hdc,int iPartId,int iStateId,LPCWSTR pszText,int iCharCount,DWORD dwTextFlags,DWORD dwTextFlags2,const RECT * pRect)148 HRESULT VisualStylesAPI::DrawThemeText( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCWSTR pszText, int iCharCount, DWORD dwTextFlags, DWORD dwTextFlags2, const RECT *pRect )
149 {
150     if(lpfnDrawThemeText)
151         return (*lpfnDrawThemeText) (hTheme, hdc, iPartId, iStateId, pszText, iCharCount, dwTextFlags, dwTextFlags2, pRect);
152     else
153         return S_FALSE;
154 }
GetThemePartSize(HTHEME hTheme,HDC hdc,int iPartId,int iStateId,RECT * prc,THEMESIZE eSize,SIZE * psz)155 HRESULT VisualStylesAPI::GetThemePartSize( HTHEME hTheme, HDC hdc, int iPartId, int iStateId, RECT *prc, THEMESIZE eSize, SIZE *psz )
156 {
157     if(lpfnGetThemePartSize)
158         return (*lpfnGetThemePartSize) (hTheme, hdc, iPartId, iStateId, prc, eSize, psz);
159     else
160         return S_FALSE;
161 }
162 
163 
164 /*********************************************************
165  * Initialize XP theming and local stuff
166  *********************************************************/
initNWF(void)167 void SalData::initNWF( void )
168 {
169     ImplSVData* pSVData = ImplGetSVData();
170 
171     // the menu bar and the top docking area should have a common background (gradient)
172     pSVData->maNWFData.mbMenuBarDockingAreaCommonBG = true;
173 }
174 
175 
176 // *********************************************************
177 // * Release theming handles
178 // ********************************************************
deInitNWF(void)179 void SalData::deInitNWF( void )
180 {
181     ThemeMap::iterator iter = aThemeMap.begin();
182     while( iter != aThemeMap.end() )
183     {
184         vsAPI.CloseThemeData(iter->second);
185         iter++;
186     }
187     aThemeMap.clear();
188     if( maDwmLib )
189         osl_unloadModule( maDwmLib );
190 }
191 
getThemeHandle(HWND hWnd,LPCWSTR name)192 static HTHEME getThemeHandle( HWND hWnd, LPCWSTR name )
193 {
194     if( GetSalData()->mbThemeChanged )
195     {
196         // throw away invalid theme handles
197         GetSalData()->deInitNWF();
198         GetSalData()->mbThemeChanged = FALSE;
199     }
200 
201     ThemeMap::iterator iter;
202     if( (iter = aThemeMap.find( name )) != aThemeMap.end() )
203         return iter->second;
204     // theme not found -> add it to map
205     HTHEME hTheme = vsAPI.OpenThemeData( hWnd, name );
206     if( hTheme != NULL )
207         aThemeMap[name] = hTheme;
208     return hTheme;
209 }
210 
211 /*
212  * IsNativeControlSupported()
213  *
214  *  Returns TRUE if the platform supports native
215  *  drawing of the control defined by nPart
216  */
IsNativeControlSupported(ControlType nType,ControlPart nPart)217 sal_Bool WinSalGraphics::IsNativeControlSupported( ControlType nType, ControlPart nPart )
218 {
219     HTHEME hTheme = NULL;
220 
221     switch( nType )
222     {
223         case CTRL_PUSHBUTTON:
224         case CTRL_RADIOBUTTON:
225         case CTRL_CHECKBOX:
226             if( nPart == PART_ENTIRE_CONTROL )
227                 hTheme = getThemeHandle( mhWnd, L"Button");
228             break;
229         case CTRL_SCROLLBAR:
230             if( nPart == PART_DRAW_BACKGROUND_HORZ || nPart == PART_DRAW_BACKGROUND_VERT )
231                 return FALSE;   // no background painting needed
232             if( nPart == PART_ENTIRE_CONTROL )
233                 hTheme = getThemeHandle( mhWnd, L"Scrollbar");
234             break;
235         case CTRL_COMBOBOX:
236             if( nPart == HAS_BACKGROUND_TEXTURE )
237                 return FALSE;   // we do not paint the inner part (ie the selection background/focus indication)
238             if( nPart == PART_ENTIRE_CONTROL )
239                 hTheme = getThemeHandle( mhWnd, L"Edit");
240             else if( nPart == PART_BUTTON_DOWN )
241                 hTheme = getThemeHandle( mhWnd, L"Combobox");
242             break;
243         case CTRL_SPINBOX:
244             if( nPart == PART_ENTIRE_CONTROL )
245                 hTheme = getThemeHandle( mhWnd, L"Edit");
246             else if( nPart == PART_ALL_BUTTONS ||
247                 nPart == PART_BUTTON_UP || nPart == PART_BUTTON_DOWN ||
248                 nPart == PART_BUTTON_LEFT|| nPart == PART_BUTTON_RIGHT )
249                 hTheme = getThemeHandle( mhWnd, L"Spin");
250             break;
251         case CTRL_SPINBUTTONS:
252             if( nPart == PART_ENTIRE_CONTROL || nPart == PART_ALL_BUTTONS )
253                 hTheme = getThemeHandle( mhWnd, L"Spin");
254             break;
255         case CTRL_EDITBOX:
256         case CTRL_MULTILINE_EDITBOX:
257             if( nPart == HAS_BACKGROUND_TEXTURE )
258                 return FALSE;   // we do not paint the inner part (ie the selection background/focus indication)
259                 //return TRUE;
260             if( nPart == PART_ENTIRE_CONTROL )
261                 hTheme = getThemeHandle( mhWnd, L"Edit");
262             break;
263         case CTRL_LISTBOX:
264             if( nPart == HAS_BACKGROUND_TEXTURE )
265                 return FALSE;   // we do not paint the inner part (ie the selection background/focus indication)
266             if( nPart == PART_ENTIRE_CONTROL || nPart == PART_WINDOW )
267                 hTheme = getThemeHandle( mhWnd, L"Listview");
268             else if( nPart == PART_BUTTON_DOWN )
269                 hTheme = getThemeHandle( mhWnd, L"Combobox");
270             break;
271         case CTRL_TAB_PANE:
272         case CTRL_TAB_BODY:
273         case CTRL_TAB_ITEM:
274         case CTRL_FIXEDBORDER:
275             if( nPart == PART_ENTIRE_CONTROL )
276                 hTheme = getThemeHandle( mhWnd, L"Tab");
277             break;
278         case CTRL_TOOLBAR:
279             if( nPart == PART_ENTIRE_CONTROL || nPart == PART_BUTTON )
280                 hTheme = getThemeHandle( mhWnd, L"Toolbar");
281             else
282                 // use rebar theme for grip and background
283                 hTheme = getThemeHandle( mhWnd, L"Rebar");
284             break;
285         case CTRL_MENUBAR:
286             if( nPart == PART_ENTIRE_CONTROL )
287                 hTheme = getThemeHandle( mhWnd, L"Rebar");
288             else if( GetSalData()->mbThemeMenuSupport )
289             {
290                 if( nPart == PART_MENU_ITEM )
291                     hTheme = getThemeHandle( mhWnd, L"Menu" );
292             }
293             break;
294         case CTRL_MENU_POPUP:
295             if( GetSalData()->mbThemeMenuSupport )
296             {
297                 if( nPart == PART_ENTIRE_CONTROL ||
298                     nPart == PART_MENU_ITEM ||
299                     nPart == PART_MENU_ITEM_CHECK_MARK ||
300                     nPart == PART_MENU_ITEM_RADIO_MARK ||
301                     nPart == PART_MENU_SEPARATOR )
302                     hTheme = getThemeHandle( mhWnd, L"Menu" );
303             }
304             break;
305         case CTRL_PROGRESS:
306             if( nPart == PART_ENTIRE_CONTROL )
307                 hTheme = getThemeHandle( mhWnd, L"Progress");
308             break;
309         case CTRL_SLIDER:
310             if( nPart == PART_TRACK_HORZ_AREA || nPart == PART_TRACK_VERT_AREA )
311                 hTheme = getThemeHandle( mhWnd, L"Trackbar" );
312             break;
313         case CTRL_LISTNODE:
314             if( nPart == PART_ENTIRE_CONTROL )
315                 hTheme = getThemeHandle( mhWnd, L"TreeView" );
316             break;
317         default:
318             hTheme = NULL;
319             break;
320     }
321 
322     return (hTheme != NULL);
323 }
324 
325 
326 /*
327  * HitTestNativeControl()
328  *
329  *  If the return value is TRUE, bIsInside contains information whether
330  *  aPos was or was not inside the native widget specified by the
331  *  nType/nPart combination.
332  */
hitTestNativeControl(ControlType,ControlPart,const Rectangle &,const Point &,sal_Bool &)333 sal_Bool WinSalGraphics::hitTestNativeControl( ControlType,
334 							  ControlPart,
335 							  const Rectangle&,
336 							  const Point&,
337 							  sal_Bool& )
338 {
339     return FALSE;
340 }
341 
ImplDrawTheme(HTHEME hTheme,HDC hDC,int iPart,int iState,RECT rc,const OUString & aStr)342 sal_Bool ImplDrawTheme( HTHEME hTheme, HDC hDC, int iPart, int iState, RECT rc, const OUString& aStr)
343 {
344     HRESULT hr = vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, 0);
345 
346     if( aStr.getLength() )
347     {
348         RECT rcContent;
349         hr = vsAPI.GetThemeBackgroundContentRect( hTheme, hDC, iPart, iState, &rc, &rcContent);
350         hr = vsAPI.DrawThemeText( hTheme, hDC, iPart, iState,
351             reinterpret_cast<LPCWSTR>(aStr.getStr()), -1,
352             DT_CENTER | DT_VCENTER | DT_SINGLELINE,
353             0, &rcContent);
354     }
355     return (hr == S_OK);
356 }
357 
358 
ImplGetThemeRect(HTHEME hTheme,HDC hDC,int iPart,int iState,const Rectangle & aRect,THEMESIZE eTS=TS_TRUE)359 Rectangle ImplGetThemeRect( HTHEME hTheme, HDC hDC, int iPart, int iState, const Rectangle& aRect, THEMESIZE eTS = TS_TRUE )
360 {
361     SIZE aSz;
362     RECT rc;
363     rc.left = aRect.nLeft;
364     rc.right = aRect.nRight;
365     rc.top = aRect.nTop;
366     rc.bottom = aRect.nBottom;
367     HRESULT hr = vsAPI.GetThemePartSize( hTheme, hDC, iPart, iState, NULL, eTS, &aSz ); // TS_TRUE returns optimal size
368     if( hr == S_OK )
369         return Rectangle( 0, 0, aSz.cx, aSz.cy );
370     else
371         return Rectangle();
372 }
373 
374 // Helper functions
375 // ----
376 
ImplConvertSpinbuttonValues(int nControlPart,const ControlState & rState,const Rectangle & rRect,int * pLunaPart,int * pLunaState,RECT * pRect)377 void ImplConvertSpinbuttonValues( int nControlPart, const ControlState& rState, const Rectangle& rRect,
378                                  int* pLunaPart, int *pLunaState, RECT *pRect )
379 {
380     if( nControlPart == PART_BUTTON_DOWN )
381     {
382         *pLunaPart = SPNP_DOWN;
383         if( rState & CTRL_STATE_PRESSED )
384             *pLunaState = DNS_PRESSED;
385         else if( !(rState & CTRL_STATE_ENABLED) )
386             *pLunaState = DNS_DISABLED;
387         else if( rState & CTRL_STATE_ROLLOVER )
388             *pLunaState = DNS_HOT;
389         else
390             *pLunaState = DNS_NORMAL;
391     }
392     if( nControlPart == PART_BUTTON_UP )
393     {
394         *pLunaPart = SPNP_UP;
395         if( rState & CTRL_STATE_PRESSED )
396             *pLunaState = UPS_PRESSED;
397         else if( !(rState & CTRL_STATE_ENABLED) )
398             *pLunaState = UPS_DISABLED;
399         else if( rState & CTRL_STATE_ROLLOVER )
400             *pLunaState = UPS_HOT;
401         else
402             *pLunaState = UPS_NORMAL;
403     }
404     if( nControlPart == PART_BUTTON_RIGHT )
405     {
406         *pLunaPart = SPNP_UPHORZ;
407         if( rState & CTRL_STATE_PRESSED )
408             *pLunaState = DNHZS_PRESSED;
409         else if( !(rState & CTRL_STATE_ENABLED) )
410             *pLunaState = DNHZS_DISABLED;
411         else if( rState & CTRL_STATE_ROLLOVER )
412             *pLunaState = DNHZS_HOT;
413         else
414             *pLunaState = DNHZS_NORMAL;
415     }
416     if( nControlPart == PART_BUTTON_LEFT )
417     {
418         *pLunaPart = SPNP_DOWNHORZ;
419         if( rState & CTRL_STATE_PRESSED )
420             *pLunaState = UPHZS_PRESSED;
421         else if( !(rState & CTRL_STATE_ENABLED) )
422             *pLunaState = UPHZS_DISABLED;
423         else if( rState & CTRL_STATE_ROLLOVER )
424             *pLunaState = UPHZS_HOT;
425         else
426             *pLunaState = UPHZS_NORMAL;
427     }
428 
429     pRect->left   = rRect.Left();
430     pRect->right  = rRect.Right()+1;
431     pRect->top    = rRect.Top();
432     pRect->bottom = rRect.Bottom()+1;
433 }
434 
435 // ----
436 
ImplDrawNativeControl(HDC hDC,HTHEME hTheme,RECT rc,ControlType nType,ControlPart nPart,ControlState nState,const ImplControlValue & aValue,OUString aCaption)437 sal_Bool ImplDrawNativeControl(	HDC hDC, HTHEME hTheme, RECT rc,
438                             ControlType nType,
439 							ControlPart nPart,
440 							ControlState nState,
441 							const ImplControlValue& aValue,
442 							OUString aCaption )
443 {
444     // a listbox dropdown is actually a combobox dropdown
445     if( nType == CTRL_LISTBOX )
446         if( nPart == PART_BUTTON_DOWN )
447             nType = CTRL_COMBOBOX;
448 
449     // draw entire combobox as a large edit box
450     if( nType == CTRL_COMBOBOX )
451         if( nPart == PART_ENTIRE_CONTROL )
452             nType = CTRL_EDITBOX;
453 
454     // draw entire spinbox as a large edit box
455     if( nType == CTRL_SPINBOX )
456         if( nPart == PART_ENTIRE_CONTROL )
457             nType = CTRL_EDITBOX;
458 
459     int iPart(0), iState(0);
460     if( nType == CTRL_SCROLLBAR )
461     {
462         HRESULT hr;
463         if( nPart == PART_BUTTON_UP )
464         {
465             iPart = SBP_ARROWBTN;
466             if( nState & CTRL_STATE_PRESSED )
467                 iState = ABS_UPPRESSED;
468             else if( !(nState & CTRL_STATE_ENABLED) )
469                 iState = ABS_UPDISABLED;
470             else if( nState & CTRL_STATE_ROLLOVER )
471                 iState = ABS_UPHOT;
472             else
473                 iState = ABS_UPNORMAL;
474             hr = vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, 0);
475             return (hr == S_OK);
476         }
477         if( nPart == PART_BUTTON_DOWN )
478         {
479             iPart = SBP_ARROWBTN;
480             if( nState & CTRL_STATE_PRESSED )
481                 iState = ABS_DOWNPRESSED;
482             else if( !(nState & CTRL_STATE_ENABLED) )
483                 iState = ABS_DOWNDISABLED;
484             else if( nState & CTRL_STATE_ROLLOVER )
485                 iState = ABS_DOWNHOT;
486             else
487                 iState = ABS_DOWNNORMAL;
488             hr = vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, 0);
489             return (hr == S_OK);
490         }
491         if( nPart == PART_BUTTON_LEFT )
492         {
493             iPart = SBP_ARROWBTN;
494             if( nState & CTRL_STATE_PRESSED )
495                 iState = ABS_LEFTPRESSED;
496             else if( !(nState & CTRL_STATE_ENABLED) )
497                 iState = ABS_LEFTDISABLED;
498             else if( nState & CTRL_STATE_ROLLOVER )
499                 iState = ABS_LEFTHOT;
500             else
501                 iState = ABS_LEFTNORMAL;
502             hr = vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, 0);
503             return (hr == S_OK);
504         }
505         if( nPart == PART_BUTTON_RIGHT )
506         {
507             iPart = SBP_ARROWBTN;
508             if( nState & CTRL_STATE_PRESSED )
509                 iState = ABS_RIGHTPRESSED;
510             else if( !(nState & CTRL_STATE_ENABLED) )
511                 iState = ABS_RIGHTDISABLED;
512             else if( nState & CTRL_STATE_ROLLOVER )
513                 iState = ABS_RIGHTHOT;
514             else
515                 iState = ABS_RIGHTNORMAL;
516             hr = vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, 0);
517             return (hr == S_OK);
518         }
519         if( nPart == PART_THUMB_HORZ || nPart == PART_THUMB_VERT )
520         {
521             iPart = (nPart == PART_THUMB_HORZ) ? SBP_THUMBBTNHORZ : SBP_THUMBBTNVERT;
522             if( nState & CTRL_STATE_PRESSED )
523                 iState = SCRBS_PRESSED;
524             else if( !(nState & CTRL_STATE_ENABLED) )
525                 iState = SCRBS_DISABLED;
526             else if( nState & CTRL_STATE_ROLLOVER )
527                 iState = SCRBS_HOT;
528             else
529                 iState = SCRBS_NORMAL;
530 
531             SIZE sz;
532             vsAPI.GetThemePartSize(hTheme, hDC, iPart, iState, NULL, TS_MIN, &sz);
533             vsAPI.GetThemePartSize(hTheme, hDC, iPart, iState, NULL, TS_TRUE, &sz);
534             vsAPI.GetThemePartSize(hTheme, hDC, iPart, iState, NULL, TS_DRAW, &sz);
535 
536             hr = vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, 0);
537             // paint gripper on thumb if enough space
538             if( ( (nPart == PART_THUMB_VERT) && (rc.bottom-rc.top > 12) ) ||
539                 ( (nPart == PART_THUMB_HORZ) && (rc.right-rc.left > 12) ) )
540             {
541                 iPart = (nPart == PART_THUMB_HORZ) ? SBP_GRIPPERHORZ : SBP_GRIPPERVERT;
542                 iState = 0;
543                 vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, 0);
544             }
545             return (hr == S_OK);
546         }
547         if( nPart == PART_TRACK_HORZ_LEFT || nPart == PART_TRACK_HORZ_RIGHT || nPart == PART_TRACK_VERT_UPPER || nPart == PART_TRACK_VERT_LOWER )
548         {
549             switch( nPart )
550             {
551                 case PART_TRACK_HORZ_LEFT:  iPart = SBP_UPPERTRACKHORZ; break;
552                 case PART_TRACK_HORZ_RIGHT: iPart = SBP_LOWERTRACKHORZ; break;
553                 case PART_TRACK_VERT_UPPER: iPart = SBP_UPPERTRACKVERT; break;
554                 case PART_TRACK_VERT_LOWER: iPart = SBP_LOWERTRACKVERT; break;
555             }
556 
557             if( nState & CTRL_STATE_PRESSED )
558                 iState = SCRBS_PRESSED;
559             else if( !(nState & CTRL_STATE_ENABLED) )
560                 iState = SCRBS_DISABLED;
561             else if( nState & CTRL_STATE_ROLLOVER )
562                 iState = SCRBS_HOT;
563             else
564                 iState = SCRBS_NORMAL;
565             hr = vsAPI.DrawThemeBackground( hTheme, hDC, iPart, iState, &rc, 0);
566             return (hr == S_OK);
567         }
568     }
569     if( nType == CTRL_SPINBUTTONS && nPart == PART_ALL_BUTTONS )
570     {
571         if( aValue.getType() == CTRL_SPINBUTTONS )
572         {
573             const SpinbuttonValue* pValue = (aValue.getType() == CTRL_SPINBUTTONS) ? static_cast<const SpinbuttonValue*>(&aValue) : NULL;
574             sal_Bool bOk = sal_False;
575 
576             RECT rect;
577             ImplConvertSpinbuttonValues( pValue->mnUpperPart, pValue->mnUpperState, pValue->maUpperRect, &iPart, &iState, &rect );
578             bOk = ImplDrawTheme( hTheme, hDC, iPart, iState, rect, aCaption);
579 
580             if( bOk )
581             {
582                 ImplConvertSpinbuttonValues( pValue->mnLowerPart, pValue->mnLowerState, pValue->maLowerRect, &iPart, &iState, &rect );
583                 bOk = ImplDrawTheme( hTheme, hDC, iPart, iState, rect, aCaption);
584             }
585 
586             return bOk;
587         }
588     }
589     if( nType == CTRL_SPINBOX )
590     {
591         // decrease spinbutton rects a little
592         //rc.right--;
593         //rc.bottom--;
594         if( nPart == PART_ALL_BUTTONS )
595         {
596             if( aValue.getType() == CTRL_SPINBUTTONS )
597             {
598                 const SpinbuttonValue *pValue = static_cast<const SpinbuttonValue*>(&aValue);
599                 sal_Bool bOk = sal_False;
600 
601                 RECT rect;
602                 ImplConvertSpinbuttonValues( pValue->mnUpperPart, pValue->mnUpperState, pValue->maUpperRect, &iPart, &iState, &rect );
603                 bOk = ImplDrawTheme( hTheme, hDC, iPart, iState, rect, aCaption);
604 
605                 if( bOk )
606                 {
607                     ImplConvertSpinbuttonValues( pValue->mnLowerPart, pValue->mnLowerState, pValue->maLowerRect, &iPart, &iState, &rect );
608                     bOk = ImplDrawTheme( hTheme, hDC, iPart, iState, rect, aCaption);
609                 }
610 
611                 return bOk;
612             }
613         }
614 
615         if( nPart == PART_BUTTON_DOWN )
616         {
617             iPart = SPNP_DOWN;
618             if( nState & CTRL_STATE_PRESSED )
619                 iState = DNS_PRESSED;
620             else if( !(nState & CTRL_STATE_ENABLED) )
621                 iState = DNS_DISABLED;
622             else if( nState & CTRL_STATE_ROLLOVER )
623                 iState = DNS_HOT;
624             else
625                 iState = DNS_NORMAL;
626         }
627         if( nPart == PART_BUTTON_UP )
628         {
629             iPart = SPNP_UP;
630             if( nState & CTRL_STATE_PRESSED )
631                 iState = UPS_PRESSED;
632             else if( !(nState & CTRL_STATE_ENABLED) )
633                 iState = UPS_DISABLED;
634             else if( nState & CTRL_STATE_ROLLOVER )
635                 iState = UPS_HOT;
636             else
637                 iState = UPS_NORMAL;
638         }
639         if( nPart == PART_BUTTON_RIGHT )
640         {
641             iPart = SPNP_DOWNHORZ;
642             if( nState & CTRL_STATE_PRESSED )
643                 iState = DNHZS_PRESSED;
644             else if( !(nState & CTRL_STATE_ENABLED) )
645                 iState = DNHZS_DISABLED;
646             else if( nState & CTRL_STATE_ROLLOVER )
647                 iState = DNHZS_HOT;
648             else
649                 iState = DNHZS_NORMAL;
650         }
651         if( nPart == PART_BUTTON_LEFT )
652         {
653             iPart = SPNP_UPHORZ;
654             if( nState & CTRL_STATE_PRESSED )
655                 iState = UPHZS_PRESSED;
656             else if( !(nState & CTRL_STATE_ENABLED) )
657                 iState = UPHZS_DISABLED;
658             else if( nState & CTRL_STATE_ROLLOVER )
659                 iState = UPHZS_HOT;
660             else
661                 iState = UPHZS_NORMAL;
662         }
663         if( nPart == PART_BUTTON_LEFT || nPart == PART_BUTTON_RIGHT || nPart == PART_BUTTON_UP || nPart == PART_BUTTON_DOWN )
664             return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
665     }
666     if( nType == CTRL_COMBOBOX )
667     {
668         if( nPart == PART_BUTTON_DOWN )
669         {
670             iPart = CP_DROPDOWNBUTTON;
671             if( nState & CTRL_STATE_PRESSED )
672                 iState = CBXS_PRESSED;
673             else if( !(nState & CTRL_STATE_ENABLED) )
674                 iState = CBXS_DISABLED;
675             else if( nState & CTRL_STATE_ROLLOVER )
676                 iState = CBXS_HOT;
677             else
678                 iState = CBXS_NORMAL;
679             return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
680         }
681     }
682     if( nType == CTRL_PUSHBUTTON )
683     {
684         iPart = BP_PUSHBUTTON;
685         if( nState & CTRL_STATE_PRESSED )
686             iState = PBS_PRESSED;
687         else if( !(nState & CTRL_STATE_ENABLED) )
688             iState = PBS_DISABLED;
689         else if( nState & CTRL_STATE_ROLLOVER )
690             iState = PBS_HOT;
691         else if( nState & CTRL_STATE_DEFAULT )
692             iState = PBS_DEFAULTED;
693         //else if( nState & CTRL_STATE_FOCUSED )
694         //    iState = PBS_DEFAULTED;    // may need to draw focus rect
695         else
696             iState = PBS_NORMAL;
697 
698         return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
699     }
700 
701     if( nType == CTRL_RADIOBUTTON )
702     {
703         iPart = BP_RADIOBUTTON;
704         sal_Bool bChecked = ( aValue.getTristateVal() == BUTTONVALUE_ON );
705 
706         if( nState & CTRL_STATE_PRESSED )
707             iState = bChecked ? RBS_CHECKEDPRESSED : RBS_UNCHECKEDPRESSED;
708         else if( !(nState & CTRL_STATE_ENABLED) )
709             iState = bChecked ? RBS_CHECKEDDISABLED : RBS_UNCHECKEDDISABLED;
710         else if( nState & CTRL_STATE_ROLLOVER )
711             iState = bChecked ? RBS_CHECKEDHOT : RBS_UNCHECKEDHOT;
712         else
713             iState = bChecked ? RBS_CHECKEDNORMAL : RBS_UNCHECKEDNORMAL;
714 
715         //if( nState & CTRL_STATE_FOCUSED )
716         //    iState |= PBS_DEFAULTED;    // may need to draw focus rect
717 
718         return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
719     }
720 
721     if( nType == CTRL_CHECKBOX )
722     {
723         iPart = BP_CHECKBOX;
724         ButtonValue v = aValue.getTristateVal();
725 
726         if( nState & CTRL_STATE_PRESSED )
727             iState = (v == BUTTONVALUE_ON)  ? CBS_CHECKEDPRESSED :
728                     ( (v == BUTTONVALUE_OFF) ? CBS_UNCHECKEDPRESSED : CBS_MIXEDPRESSED );
729         else if( !(nState & CTRL_STATE_ENABLED) )
730             iState = (v == BUTTONVALUE_ON)  ? CBS_CHECKEDDISABLED :
731                     ( (v == BUTTONVALUE_OFF) ? CBS_UNCHECKEDDISABLED : CBS_MIXEDDISABLED );
732         else if( nState & CTRL_STATE_ROLLOVER )
733             iState = (v == BUTTONVALUE_ON)  ? CBS_CHECKEDHOT :
734                     ( (v == BUTTONVALUE_OFF) ? CBS_UNCHECKEDHOT : CBS_MIXEDHOT );
735         else
736             iState = (v == BUTTONVALUE_ON)  ? CBS_CHECKEDNORMAL :
737                     ( (v == BUTTONVALUE_OFF) ? CBS_UNCHECKEDNORMAL : CBS_MIXEDNORMAL );
738 
739         //if( nState & CTRL_STATE_FOCUSED )
740         //    iState |= PBS_DEFAULTED;    // may need to draw focus rect
741 
742         //SIZE sz;
743         //THEMESIZE eSize = TS_DRAW; // TS_MIN, TS_TRUE, TS_DRAW
744         //vsAPI.GetThemePartSize( hTheme, hDC, iPart, iState, &rc, eSize, &sz);
745 
746         return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
747     }
748 
749     if( ( nType == CTRL_EDITBOX ) || ( nType == CTRL_MULTILINE_EDITBOX ) )
750     {
751         iPart = EP_EDITTEXT;
752         if( !(nState & CTRL_STATE_ENABLED) )
753             iState = ETS_DISABLED;
754         else if( nState & CTRL_STATE_FOCUSED )
755             iState = ETS_FOCUSED;
756         else if( nState & CTRL_STATE_ROLLOVER )
757             iState = ETS_HOT;
758         else
759             iState = ETS_NORMAL;
760 
761         return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
762     }
763 
764     if( nType == CTRL_LISTBOX )
765     {
766         if( nPart == PART_ENTIRE_CONTROL || nPart == PART_WINDOW )
767         {
768             iPart = LVP_EMPTYTEXT; // ??? no idea which part to choose here
769             return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
770         }
771     }
772 
773     if( nType == CTRL_TAB_PANE )
774     {
775         iPart = TABP_PANE;
776         return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
777     }
778 
779     if( nType == CTRL_FIXEDBORDER )
780     {
781         /*
782         iPart = BP_GROUPBOX;
783         if( !(nState & CTRL_STATE_ENABLED) )
784             iState = GBS_DISABLED;
785         else
786             iState = GBS_NORMAL;
787             */
788         // The fixed border is only used around the tools->options tabpage where
789         // TABP_PANE fits best
790         iPart = TABP_PANE;
791         return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
792     }
793 
794     if( nType == CTRL_TAB_BODY )
795     {
796         iPart = TABP_BODY;
797         return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
798     }
799 
800     if( nType == CTRL_TAB_ITEM )
801     {
802         iPart = TABP_TABITEMLEFTEDGE;
803         rc.bottom--;
804 
805         OSL_ASSERT( aValue.getType() == CTRL_TAB_ITEM );
806 
807         const TabitemValue *pValue = static_cast<const TabitemValue*>(&aValue);
808         if( pValue->isBothAligned() )
809         {
810             iPart = TABP_TABITEMLEFTEDGE;
811             rc.right--;
812         }
813         else if( pValue->isLeftAligned() )
814             iPart = TABP_TABITEMLEFTEDGE;
815         else if( pValue->isRightAligned() )
816             iPart = TABP_TABITEMRIGHTEDGE;
817         else iPart = TABP_TABITEM;
818 
819         if( !(nState & CTRL_STATE_ENABLED) )
820             iState = TILES_DISABLED;
821         else if( nState & CTRL_STATE_SELECTED )
822         {
823             iState = TILES_SELECTED;
824             // increase the selected tab
825             rc.left-=2;
826             if( pValue && !pValue->isBothAligned() )
827             {
828                 if( pValue->isLeftAligned() || pValue->isNotAligned() )
829                     rc.right+=2;
830                 if( pValue->isRightAligned() )
831                     rc.right+=1;
832             }
833             rc.top-=2;
834             rc.bottom+=2;
835         }
836         else if( nState & CTRL_STATE_ROLLOVER )
837             iState = TILES_HOT;
838         else if( nState & CTRL_STATE_FOCUSED )
839             iState = TILES_FOCUSED;    // may need to draw focus rect
840         else
841             iState = TILES_NORMAL;
842         return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
843     }
844 
845     if( nType == CTRL_TOOLBAR )
846     {
847         if( nPart == PART_BUTTON )
848         {
849             iPart = TP_BUTTON;
850             sal_Bool bChecked = ( aValue.getTristateVal() == BUTTONVALUE_ON );
851             if( !(nState & CTRL_STATE_ENABLED) )
852                 //iState = TS_DISABLED;
853                 // disabled buttons are typically not painted at all but we need visual
854                 // feedback when travelling by keyboard over disabled entries
855                 iState = TS_HOT;
856             else if( nState & CTRL_STATE_PRESSED )
857                 iState = TS_PRESSED;
858             else if( nState & CTRL_STATE_ROLLOVER )
859                 iState = bChecked ? TS_HOTCHECKED : TS_HOT;
860             else
861                 iState = bChecked ? TS_CHECKED : TS_NORMAL;
862             return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
863         }
864         else if( nPart == PART_THUMB_HORZ || nPart == PART_THUMB_VERT )
865         {
866             // the vertical gripper is not supported in most themes and it makes no
867             // sense to only support horizontal gripper
868             //iPart = (nPart == PART_THUMB_HORZ) ? RP_GRIPPERVERT : RP_GRIPPER;
869             //return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
870         }
871         else if( nPart == PART_DRAW_BACKGROUND_HORZ || nPart == PART_DRAW_BACKGROUND_VERT )
872         {
873             if( aValue.getType() == CTRL_TOOLBAR )
874             {
875                 const ToolbarValue *pValue = static_cast<const ToolbarValue*>(&aValue);
876                 if( pValue->mbIsTopDockingArea )
877                     rc.top = 0; // extend potential gradient to cover menu bar as well
878             }
879             return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
880         }
881     }
882 
883     if( nType == CTRL_MENUBAR )
884     {
885         if( nPart == PART_ENTIRE_CONTROL )
886         {
887             if( aValue.getType() == CTRL_MENUBAR )
888             {
889                 const MenubarValue *pValue = static_cast<const MenubarValue*>(&aValue);
890                 rc.bottom += pValue->maTopDockingAreaHeight;    // extend potential gradient to cover docking area as well
891             }
892             return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption);
893         }
894         else if( nPart == PART_MENU_ITEM )
895         {
896             if( (nState & CTRL_STATE_ENABLED) )
897                 iState = (nState & CTRL_STATE_SELECTED) ? MBI_HOT : MBI_NORMAL;
898             else
899                 iState = (nState & CTRL_STATE_SELECTED) ? MBI_DISABLEDHOT : MBI_DISABLED;
900             return ImplDrawTheme( hTheme, hDC, MENU_BARITEM, iState, rc, aCaption );
901         }
902     }
903 
904     if( nType == CTRL_PROGRESS )
905     {
906         if( nPart != PART_ENTIRE_CONTROL )
907             return FALSE;
908 
909         if( ! ImplDrawTheme( hTheme, hDC, PP_BAR, iState, rc, aCaption) )
910             return false;
911         RECT aProgressRect = rc;
912         if( vsAPI.GetThemeBackgroundContentRect( hTheme, hDC, PP_BAR, iState, &rc, &aProgressRect) != S_OK )
913             return false;
914 
915         long nProgressWidth = aValue.getNumericVal();
916         nProgressWidth *= (aProgressRect.right - aProgressRect.left);
917         nProgressWidth /= (rc.right - rc.left);
918         if( Application::GetSettings().GetLayoutRTL() )
919             aProgressRect.left = aProgressRect.right - nProgressWidth;
920         else
921             aProgressRect.right = aProgressRect.left + nProgressWidth;
922 
923         return ImplDrawTheme( hTheme, hDC, PP_CHUNK, iState, aProgressRect, aCaption );
924     }
925 
926     if( nType == CTRL_SLIDER )
927     {
928         iPart = (nPart == PART_TRACK_HORZ_AREA) ? TKP_TRACK : TKP_TRACKVERT;
929         iState = (nPart == PART_TRACK_HORZ_AREA) ? TRS_NORMAL : TRVS_NORMAL;
930 
931         Rectangle aTrackRect = ImplGetThemeRect( hTheme, hDC, iPart, iState, Rectangle() );
932         RECT aTRect = rc;
933         if( nPart == PART_TRACK_HORZ_AREA )
934         {
935             long nH = aTrackRect.GetHeight();
936             aTRect.top += (rc.bottom - rc.top - nH)/2;
937             aTRect.bottom = aTRect.top + nH;
938         }
939         else
940         {
941             long nW = aTrackRect.GetWidth();
942             aTRect.left += (rc.right - rc.left - nW)/2;
943             aTRect.right = aTRect.left + nW;
944         }
945         ImplDrawTheme( hTheme, hDC, iPart, iState, aTRect, aCaption );
946 
947         RECT aThumbRect;
948         OSL_ASSERT( aValue.getType() == CTRL_SLIDER );
949         const SliderValue* pVal = static_cast<const SliderValue*>(&aValue);
950         aThumbRect.left   = pVal->maThumbRect.Left();
951         aThumbRect.top    = pVal->maThumbRect.Top();
952         aThumbRect.right  = pVal->maThumbRect.Right();
953         aThumbRect.bottom = pVal->maThumbRect.Bottom();
954         iPart = (nPart == PART_TRACK_HORZ_AREA) ? TKP_THUMB : TKP_THUMBVERT;
955         iState = (nState & CTRL_STATE_ENABLED) ? TUS_NORMAL : TUS_DISABLED;
956         return ImplDrawTheme( hTheme, hDC, iPart, iState, aThumbRect, aCaption );
957     }
958 
959     if( nType == CTRL_LISTNODE )
960     {
961         if( nPart != PART_ENTIRE_CONTROL )
962             return FALSE;
963 
964         ButtonValue aButtonValue = aValue.getTristateVal();
965         iPart = TVP_GLYPH;
966         switch( aButtonValue )
967         {
968         case BUTTONVALUE_ON:
969             iState = GLPS_OPENED;
970             break;
971         case BUTTONVALUE_OFF:
972             iState = GLPS_CLOSED;
973             break;
974         default:
975             return FALSE;
976         }
977         return ImplDrawTheme( hTheme, hDC, iPart, iState, rc, aCaption );
978     }
979 
980     if( GetSalData()->mbThemeMenuSupport )
981     {
982         if( nType == CTRL_MENU_POPUP )
983         {
984             if( nPart == PART_ENTIRE_CONTROL )
985             {
986                 RECT aGutterRC = rc;
987                 aGutterRC.left += aValue.getNumericVal();
988                 aGutterRC.right = aGutterRC.left+3;
989                 return
990                 ImplDrawTheme( hTheme, hDC, MENU_POPUPBACKGROUND, 0, rc, aCaption ) &&
991                 ImplDrawTheme( hTheme, hDC, MENU_POPUPGUTTER, 0, aGutterRC, aCaption )
992                 ;
993             }
994             else if( nPart == PART_MENU_ITEM )
995             {
996                 if( (nState & CTRL_STATE_ENABLED) )
997                     iState = (nState & CTRL_STATE_SELECTED) ? MPI_HOT : MPI_NORMAL;
998                 else
999                     iState = (nState & CTRL_STATE_SELECTED) ? MPI_DISABLEDHOT : MPI_DISABLED;
1000                 return ImplDrawTheme( hTheme, hDC, MENU_POPUPITEM, iState, rc, aCaption );
1001             }
1002             else if( nPart == PART_MENU_ITEM_CHECK_MARK || nPart == PART_MENU_ITEM_RADIO_MARK )
1003             {
1004                 if( (nState & CTRL_STATE_PRESSED) )
1005                 {
1006                     RECT aBGRect = rc;
1007                     if( aValue.getType() == CTRL_MENU_POPUP )
1008                     {
1009                         const MenupopupValue& rMVal( static_cast<const MenupopupValue&>(aValue) );
1010                         aBGRect.left   = rMVal.maItemRect.Left();
1011                         aBGRect.top    = rMVal.maItemRect.Top();
1012                         aBGRect.bottom = rMVal.maItemRect.Bottom()+1; // see below in drawNativeControl
1013                         aBGRect.right  = rMVal.getNumericVal();
1014 
1015                         // FIXME: magic
1016                         aBGRect.left += 1; aBGRect.top += 1; aBGRect.bottom +=1;
1017                     }
1018                     iState = (nState & CTRL_STATE_ENABLED) ? MCB_NORMAL : MCB_DISABLED;
1019                     ImplDrawTheme( hTheme, hDC, MENU_POPUPCHECKBACKGROUND, iState, aBGRect, aCaption );
1020                     if( nPart == PART_MENU_ITEM_CHECK_MARK )
1021                         iState = (nState & CTRL_STATE_ENABLED) ? MC_CHECKMARKNORMAL : MC_CHECKMARKDISABLED;
1022                     else
1023                         iState = (nState & CTRL_STATE_ENABLED) ? MC_BULLETNORMAL : MC_BULLETDISABLED;
1024                     return ImplDrawTheme( hTheme, hDC, MENU_POPUPCHECK, iState, rc, aCaption );
1025                 }
1026                 else
1027                     return true; // unchecked: do nothing
1028             }
1029             else if( nPart == PART_MENU_SEPARATOR )
1030             {
1031                 rc.left += aValue.getNumericVal(); // adjust for gutter position
1032                 Rectangle aRect( ImplGetThemeRect( hTheme, hDC,
1033                     MENU_POPUPSEPARATOR, 0, Rectangle( rc.left, rc.top, rc.right, rc.bottom ) ) );
1034 				// center the separator inside the passed rectangle
1035 				long nDY = ((rc.bottom - rc.top + 1) - aRect.GetHeight()) / 2;
1036 				rc.top += nDY;
1037 				rc.bottom = rc.top+aRect.GetHeight()-1;
1038                 return ImplDrawTheme( hTheme, hDC, MENU_POPUPSEPARATOR, 0, rc, aCaption );
1039             }
1040         }
1041     }
1042 
1043     return false;
1044 }
1045 
1046 /*
1047  * DrawNativeControl()
1048  *
1049  *  Draws the requested control described by nPart/nState.
1050  *
1051  *  rControlRegion:	The bounding region of the complete control in VCL frame coordinates.
1052  *  aValue:  		An optional value (tristate/numerical/string)
1053  *  aCaption:  	A caption or title string (like button text etc)
1054  */
drawNativeControl(ControlType nType,ControlPart nPart,const Rectangle & rControlRegion,ControlState nState,const ImplControlValue & aValue,const OUString & aCaption)1055 sal_Bool WinSalGraphics::drawNativeControl(	ControlType nType,
1056 							ControlPart nPart,
1057 							const Rectangle& rControlRegion,
1058 							ControlState nState,
1059 							const ImplControlValue& aValue,
1060 							const OUString& aCaption )
1061 {
1062     sal_Bool bOk = false;
1063     HTHEME hTheme = NULL;
1064 
1065     switch( nType )
1066     {
1067         case CTRL_PUSHBUTTON:
1068         case CTRL_RADIOBUTTON:
1069         case CTRL_CHECKBOX:
1070             hTheme = getThemeHandle( mhWnd, L"Button");
1071             break;
1072         case CTRL_SCROLLBAR:
1073             hTheme = getThemeHandle( mhWnd, L"Scrollbar");
1074             break;
1075         case CTRL_COMBOBOX:
1076             if( nPart == PART_ENTIRE_CONTROL )
1077                 hTheme = getThemeHandle( mhWnd, L"Edit");
1078             else if( nPart == PART_BUTTON_DOWN )
1079                 hTheme = getThemeHandle( mhWnd, L"Combobox");
1080             break;
1081         case CTRL_SPINBOX:
1082             if( nPart == PART_ENTIRE_CONTROL )
1083                 hTheme = getThemeHandle( mhWnd, L"Edit");
1084             else
1085                 hTheme = getThemeHandle( mhWnd, L"Spin");
1086             break;
1087         case CTRL_SPINBUTTONS:
1088             hTheme = getThemeHandle( mhWnd, L"Spin");
1089             break;
1090         case CTRL_EDITBOX:
1091         case CTRL_MULTILINE_EDITBOX:
1092             hTheme = getThemeHandle( mhWnd, L"Edit");
1093             break;
1094         case CTRL_LISTBOX:
1095             if( nPart == PART_ENTIRE_CONTROL || nPart == PART_WINDOW )
1096                 hTheme = getThemeHandle( mhWnd, L"Listview");
1097             else if( nPart == PART_BUTTON_DOWN )
1098                 hTheme = getThemeHandle( mhWnd, L"Combobox");
1099             break;
1100         case CTRL_TAB_PANE:
1101         case CTRL_TAB_BODY:
1102         case CTRL_TAB_ITEM:
1103         case CTRL_FIXEDBORDER:
1104             hTheme = getThemeHandle( mhWnd, L"Tab");
1105             break;
1106         case CTRL_TOOLBAR:
1107             if( nPart == PART_ENTIRE_CONTROL || nPart == PART_BUTTON )
1108                 hTheme = getThemeHandle( mhWnd, L"Toolbar");
1109             else
1110                 // use rebar for grip and background
1111                 hTheme = getThemeHandle( mhWnd, L"Rebar");
1112             break;
1113         case CTRL_MENUBAR:
1114             if( nPart == PART_ENTIRE_CONTROL )
1115                 hTheme = getThemeHandle( mhWnd, L"Rebar");
1116             else if( GetSalData()->mbThemeMenuSupport )
1117             {
1118                 if( nPart == PART_MENU_ITEM )
1119                     hTheme = getThemeHandle( mhWnd, L"Menu" );
1120             }
1121             break;
1122         case CTRL_PROGRESS:
1123             if( nPart == PART_ENTIRE_CONTROL )
1124                 hTheme = getThemeHandle( mhWnd, L"Progress");
1125             break;
1126         case CTRL_LISTNODE:
1127             if( nPart == PART_ENTIRE_CONTROL )
1128                 hTheme = getThemeHandle( mhWnd, L"TreeView");
1129             break;
1130         case CTRL_SLIDER:
1131             if( nPart == PART_TRACK_HORZ_AREA || nPart == PART_TRACK_VERT_AREA )
1132                 hTheme = getThemeHandle( mhWnd, L"Trackbar" );
1133             break;
1134         case CTRL_MENU_POPUP:
1135             if( GetSalData()->mbThemeMenuSupport )
1136             {
1137                 if( nPart == PART_ENTIRE_CONTROL || nPart == PART_MENU_ITEM ||
1138                     nPart == PART_MENU_ITEM_CHECK_MARK || nPart == PART_MENU_ITEM_RADIO_MARK ||
1139                     nPart == PART_MENU_SEPARATOR
1140                     )
1141                     hTheme = getThemeHandle( mhWnd, L"Menu" );
1142             }
1143             break;
1144         default:
1145             hTheme = NULL;
1146             break;
1147     }
1148 
1149     if( !hTheme )
1150         return false;
1151 
1152 	Rectangle buttonRect = rControlRegion;
1153     RECT rc;
1154     rc.left   = buttonRect.Left();
1155     rc.right  = buttonRect.Right()+1;
1156     rc.top    = buttonRect.Top();
1157     rc.bottom = buttonRect.Bottom()+1;
1158 
1159     // set default text alignment
1160     int ta = SetTextAlign( getHDC(), TA_LEFT|TA_TOP|TA_NOUPDATECP );
1161 
1162     OUString aCaptionStr( aCaption.replace('~', '&') ); // translate mnemonics
1163     bOk = ImplDrawNativeControl(getHDC(), hTheme, rc,
1164                             nType, nPart, nState, aValue,
1165 							aCaptionStr );
1166 
1167     // restore alignment
1168     SetTextAlign( getHDC(), ta );
1169 
1170 
1171     //GdiFlush();
1172 
1173 	return bOk;
1174 }
1175 
1176 
1177 /*
1178  * DrawNativeControlText()
1179  *
1180  *  OPTIONAL.  Draws the requested text for the control described by nPart/nState.
1181  *     Used if text not drawn by DrawNativeControl().
1182  *
1183  *  rControlRegion:	The bounding region of the complete control in VCL frame coordinates.
1184  *  aValue:  		An optional value (tristate/numerical/string)
1185  *  aCaption:  	A caption or title string (like button text etc)
1186  */
drawNativeControlText(ControlType,ControlPart,const Rectangle &,ControlState,const ImplControlValue &,const OUString &)1187 sal_Bool WinSalGraphics::drawNativeControlText(	ControlType,
1188 								ControlPart,
1189 								const Rectangle&,
1190 								ControlState,
1191 								const ImplControlValue&,
1192 								const OUString& )
1193 {
1194 	return( false );
1195 }
1196 
1197 
1198 /*
1199  * GetNativeControlRegion()
1200  *
1201  *  If the return value is TRUE, rNativeBoundingRegion
1202  *  contains the true bounding region covered by the control
1203  *  including any adornment, while rNativeContentRegion contains the area
1204  *  within the control that can be safely drawn into without drawing over
1205  *  the borders of the control.
1206  *
1207  *  rControlRegion:	The bounding region of the control in VCL frame coordinates.
1208  *  aValue:		An optional value (tristate/numerical/string)
1209  *  aCaption:		A caption or title string (like button text etc)
1210  */
getNativeControlRegion(ControlType nType,ControlPart nPart,const Rectangle & rControlRegion,ControlState nState,const ImplControlValue & rControlValue,const OUString &,Rectangle & rNativeBoundingRegion,Rectangle & rNativeContentRegion)1211 sal_Bool WinSalGraphics::getNativeControlRegion(  ControlType nType,
1212 								ControlPart nPart,
1213 								const Rectangle& rControlRegion,
1214 								ControlState nState,
1215 								const ImplControlValue& rControlValue,
1216 								const OUString&,
1217 								Rectangle &rNativeBoundingRegion,
1218 								Rectangle &rNativeContentRegion )
1219 {
1220     sal_Bool bRet = FALSE;
1221 
1222     HDC hDC = GetDC( mhWnd );
1223     if( nType == CTRL_TOOLBAR )
1224     {
1225         if( nPart == PART_THUMB_HORZ || nPart == PART_THUMB_VERT )
1226         {
1227             /*
1228             // the vertical gripper is not supported in most themes and it makes no
1229             // sense to only support horizontal gripper
1230 
1231             HTHEME hTheme = getThemeHandle( mhWnd, L"Rebar");
1232             if( hTheme )
1233             {
1234                 Rectangle aRect( ImplGetThemeRect( hTheme, hDC, nPart == PART_THUMB_HORZ ? RP_GRIPPERVERT : RP_GRIPPER,
1235                     0, rControlRegion.GetBoundRect() ) );
1236                 if( nPart == PART_THUMB_HORZ && !aRect.IsEmpty() )
1237                 {
1238                     Rectangle aVertRect( 0, 0, aRect.getHeight(), aRect.getWidth() );
1239                     rNativeContentRegion = aVertRect;
1240                 }
1241                 else
1242                     rNativeContentRegion = aRect;
1243                 rNativeBoundingRegion = rNativeContentRegion;
1244                 if( !rNativeContentRegion.IsEmpty() )
1245                     bRet = TRUE;
1246             }
1247             */
1248         }
1249         if( nPart == PART_BUTTON )
1250         {
1251             HTHEME hTheme = getThemeHandle( mhWnd, L"Toolbar");
1252             if( hTheme )
1253             {
1254                 Rectangle aRect( ImplGetThemeRect( hTheme, hDC, TP_SPLITBUTTONDROPDOWN,
1255                     TS_HOT, rControlRegion ) );
1256                 rNativeContentRegion = aRect;
1257                 rNativeBoundingRegion = rNativeContentRegion;
1258                 if( !rNativeContentRegion.IsEmpty() )
1259                     bRet = TRUE;
1260             }
1261         }
1262     }
1263     if( nType == CTRL_PROGRESS && nPart == PART_ENTIRE_CONTROL )
1264     {
1265         HTHEME hTheme = getThemeHandle( mhWnd, L"Progress");
1266         if( hTheme )
1267         {
1268             Rectangle aRect( ImplGetThemeRect( hTheme, hDC, PP_BAR,
1269                 0, rControlRegion ) );
1270             rNativeContentRegion = aRect;
1271             rNativeBoundingRegion = rNativeContentRegion;
1272             if( !rNativeContentRegion.IsEmpty() )
1273                 bRet = TRUE;
1274         }
1275     }
1276     if( (nType == CTRL_LISTBOX || nType == CTRL_COMBOBOX ) && nPart == PART_ENTIRE_CONTROL )
1277     {
1278         HTHEME hTheme = getThemeHandle( mhWnd, L"Combobox");
1279         if( hTheme )
1280         {
1281             Rectangle aBoxRect( rControlRegion );
1282             Rectangle aRect( ImplGetThemeRect( hTheme, hDC, CP_DROPDOWNBUTTON,
1283                                                CBXS_NORMAL, aBoxRect ) );
1284             if( aRect.GetHeight() > aBoxRect.GetHeight() )
1285                 aBoxRect.Bottom() = aBoxRect.Top() + aRect.GetHeight();
1286             if( aRect.GetWidth() > aBoxRect.GetWidth() )
1287                 aBoxRect.Right() = aBoxRect.Left() + aRect.GetWidth();
1288             rNativeContentRegion = aBoxRect;
1289             rNativeBoundingRegion = rNativeContentRegion;
1290             if( !aRect.IsEmpty() )
1291                 bRet = TRUE;
1292         }
1293     }
1294 
1295     if( (nType == CTRL_EDITBOX || nType == CTRL_SPINBOX) && nPart == PART_ENTIRE_CONTROL )
1296     {
1297         HTHEME hTheme = getThemeHandle( mhWnd, L"Edit");
1298         if( hTheme )
1299         {
1300             // get border size
1301             Rectangle aBoxRect( rControlRegion );
1302             Rectangle aRect( ImplGetThemeRect( hTheme, hDC, EP_BACKGROUNDWITHBORDER,
1303                                                EBWBS_HOT, aBoxRect ) );
1304             // ad app font height
1305             NONCLIENTMETRICSW aNonClientMetrics;
1306             aNonClientMetrics.cbSize = sizeof( aNonClientMetrics );
1307             if ( SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, sizeof( aNonClientMetrics ), &aNonClientMetrics, 0 ) )
1308             {
1309                 long nFontHeight = aNonClientMetrics.lfMessageFont.lfHeight;
1310                 if( nFontHeight < 0 )
1311                     nFontHeight = -nFontHeight;
1312 
1313                 if( aRect.GetHeight() && nFontHeight )
1314                 {
1315                     aRect.Bottom() += aRect.GetHeight();
1316                     aRect.Bottom() += nFontHeight;
1317                     if( aRect.GetHeight() > aBoxRect.GetHeight() )
1318                         aBoxRect.Bottom() = aBoxRect.Top() + aRect.GetHeight();
1319                     if( aRect.GetWidth() > aBoxRect.GetWidth() )
1320                         aBoxRect.Right() = aBoxRect.Left() + aRect.GetWidth();
1321                     rNativeContentRegion = aBoxRect;
1322                     rNativeBoundingRegion = rNativeContentRegion;
1323                         bRet = TRUE;
1324                 }
1325             }
1326         }
1327     }
1328 
1329     if( GetSalData()->mbThemeMenuSupport )
1330     {
1331         if( nType == CTRL_MENU_POPUP )
1332         {
1333             if( nPart == PART_MENU_ITEM_CHECK_MARK ||
1334                 nPart == PART_MENU_ITEM_RADIO_MARK )
1335             {
1336                 HTHEME hTheme = getThemeHandle( mhWnd, L"Menu");
1337                 Rectangle aBoxRect( rControlRegion );
1338                 Rectangle aRect( ImplGetThemeRect( hTheme, hDC,
1339                     MENU_POPUPCHECK,
1340                     MC_CHECKMARKNORMAL,
1341                     aBoxRect ) );
1342                 if( aBoxRect.GetWidth() && aBoxRect.GetHeight() )
1343                 {
1344                     rNativeContentRegion = aRect;
1345                     rNativeBoundingRegion = rNativeContentRegion;
1346                     bRet = TRUE;
1347                 }
1348             }
1349         }
1350     }
1351 
1352     if( nType == CTRL_SLIDER && ( (nPart == PART_THUMB_HORZ) || (nPart == PART_THUMB_VERT) ) )
1353     {
1354         HTHEME hTheme = getThemeHandle( mhWnd, L"Trackbar");
1355         if( hTheme )
1356         {
1357             int iPart = (nPart == PART_THUMB_HORZ) ? TKP_THUMB : TKP_THUMBVERT;
1358             int iState = (nPart == PART_THUMB_HORZ) ? TUS_NORMAL : TUVS_NORMAL;
1359             Rectangle aThumbRect = ImplGetThemeRect( hTheme, hDC, iPart, iState, Rectangle() );
1360             if( nPart == PART_THUMB_HORZ )
1361             {
1362                 long nW = aThumbRect.GetWidth();
1363                 Rectangle aRect( rControlRegion );
1364                 aRect.Right() = aRect.Left() + nW - 1;
1365                 rNativeContentRegion = aRect;
1366                 rNativeBoundingRegion = rNativeContentRegion;
1367             }
1368             else
1369             {
1370                 long nH = aThumbRect.GetHeight();
1371                 Rectangle aRect( rControlRegion );
1372                 aRect.Bottom() = aRect.Top() + nH - 1;
1373                 rNativeContentRegion = aRect;
1374                 rNativeBoundingRegion = rNativeContentRegion;
1375             }
1376             bRet = TRUE;
1377         }
1378     }
1379 
1380     if ( ( nType == CTRL_TAB_ITEM ) && ( nPart == PART_ENTIRE_CONTROL ) )
1381     {
1382         Rectangle aControlRect( rControlRegion );
1383         rNativeContentRegion = aControlRect;
1384 
1385         --aControlRect.Bottom();
1386 
1387         if( rControlValue.getType() == CTRL_TAB_ITEM )
1388         {
1389             const TabitemValue *pValue = static_cast<const TabitemValue*>(&rControlValue);
1390             if ( pValue->isBothAligned() )
1391                 --aControlRect.Right();
1392 
1393             if ( nState & CTRL_STATE_SELECTED )
1394             {
1395                 aControlRect.Left() -= 2;
1396                 if ( pValue && !pValue->isBothAligned() )
1397                 {
1398                     if ( pValue->isLeftAligned() || pValue->isNotAligned() )
1399                         aControlRect.Right() += 2;
1400                     if ( pValue->isRightAligned() )
1401                         aControlRect.Right() += 1;
1402                 }
1403                 aControlRect.Top() -= 2;
1404                 aControlRect.Bottom() += 2;
1405             }
1406         }
1407         rNativeBoundingRegion = aControlRect;
1408         bRet = TRUE;
1409     }
1410 
1411     ReleaseDC( mhWnd, hDC );
1412 	return( bRet );
1413 }
1414 
1415