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