Fix tab navigation bug with radio boxes without enabled items.
[wxWidgets.git] / src / msw / artmsw.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/artmsw.cpp
3 // Purpose: stock wxArtProvider instance with native MSW stock icons
4 // Author: Vaclav Slavik
5 // Modified by:
6 // Created: 2008-10-15
7 // RCS-ID: $Id$
8 // Copyright: (c) Vaclav Slavik, 2008
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ---------------------------------------------------------------------------
13 // headers
14 // ---------------------------------------------------------------------------
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #if defined(__BORLANDC__)
20 #pragma hdrstop
21 #endif
22
23 #include "wx/artprov.h"
24 #include "wx/image.h"
25 #include "wx/dynlib.h"
26 #include "wx/volume.h"
27 #include "wx/msw/private.h"
28 #include "wx/msw/wrapwin.h"
29
30 #ifdef SHGSI_ICON
31 #define wxHAS_SHGetStockIconInfo
32 #endif
33
34 namespace
35 {
36
37 #ifdef wxHAS_SHGetStockIconInfo
38
39 SHSTOCKICONID MSWGetStockIconIdForArtProviderId(const wxArtID& art_id)
40 {
41 // try to find an equivalent MSW stock icon id for wxArtID
42 if ( art_id == wxART_ERROR) return SIID_ERROR;
43 else if ( art_id == wxART_QUESTION ) return SIID_HELP;
44 else if ( art_id == wxART_WARNING ) return SIID_WARNING;
45 else if ( art_id == wxART_INFORMATION ) return SIID_INFO;
46 else if ( art_id == wxART_HELP ) return SIID_HELP;
47 else if ( art_id == wxART_FOLDER ) return SIID_FOLDER;
48 else if ( art_id == wxART_FOLDER_OPEN ) return SIID_FOLDEROPEN;
49 else if ( art_id == wxART_DELETE ) return SIID_DELETE;
50 else if ( art_id == wxART_FIND ) return SIID_FIND;
51 else if ( art_id == wxART_HARDDISK ) return SIID_DRIVEFIXED;
52 else if ( art_id == wxART_FLOPPY ) return SIID_DRIVE35;
53 else if ( art_id == wxART_CDROM ) return SIID_DRIVECD;
54 else if ( art_id == wxART_REMOVABLE ) return SIID_DRIVEREMOVE;
55
56 return SIID_INVALID;
57 };
58
59
60 // try to load SHGetStockIconInfo dynamically, so this code runs
61 // even on pre-Vista Windows versions
62 HRESULT
63 MSW_SHGetStockIconInfo(SHSTOCKICONID siid,
64 UINT uFlags,
65 SHSTOCKICONINFO *psii)
66 {
67 typedef HRESULT (WINAPI *PSHGETSTOCKICONINFO)(SHSTOCKICONID, UINT, SHSTOCKICONINFO *);
68 static PSHGETSTOCKICONINFO pSHGetStockIconInfo = (PSHGETSTOCKICONINFO)-1;
69
70 if ( pSHGetStockIconInfo == (PSHGETSTOCKICONINFO)-1 )
71 {
72 wxDynamicLibrary shell32(wxT("shell32.dll"));
73
74 pSHGetStockIconInfo = (PSHGETSTOCKICONINFO)shell32.RawGetSymbol( wxT("SHGetStockIconInfo") );
75 }
76
77 if ( !pSHGetStockIconInfo )
78 return E_FAIL;
79
80 return pSHGetStockIconInfo(siid, uFlags, psii);
81 }
82
83 #endif // #ifdef wxHAS_SHGetStockIconInfo
84
85 wxBitmap
86 MSWGetBitmapForPath(const wxString& path, const wxSize& size, DWORD uFlags = 0)
87 {
88 SHFILEINFO fi;
89 wxZeroMemory(fi);
90
91 uFlags |= SHGFI_USEFILEATTRIBUTES | SHGFI_ICON;
92 if ( size != wxDefaultSize )
93 {
94 if ( size.x <= 16 )
95 uFlags |= SHGFI_SMALLICON;
96 else if ( size.x >= 64 )
97 uFlags |= SHGFI_LARGEICON;
98 }
99
100 if ( !SHGetFileInfo(path.t_str(), FILE_ATTRIBUTE_DIRECTORY,
101 &fi, sizeof(SHFILEINFO), uFlags) )
102 return wxNullBitmap;
103
104 wxIcon icon;
105 icon.CreateFromHICON((WXHICON)fi.hIcon);
106
107 wxBitmap bitmap(icon);
108 ::DestroyIcon(fi.hIcon);
109
110 return bitmap;
111 }
112
113 #if wxUSE_FSVOLUME
114
115 wxBitmap
116 GetDriveBitmapForVolumeType(const wxFSVolumeKind& volKind, const wxSize& size)
117 {
118 // get all volumes and try to find one with a matching type
119 wxArrayString volumes = wxFSVolume::GetVolumes();
120 for ( size_t i = 0; i < volumes.Count(); i++ )
121 {
122 wxFSVolume vol( volumes[i] );
123 if ( vol.GetKind() == volKind )
124 {
125 return MSWGetBitmapForPath(volumes[i], size);
126 }
127 }
128
129 return wxNullBitmap;
130 }
131
132 #endif // wxUSE_FSVOLUME
133
134 } // anonymous namespace
135
136 // ----------------------------------------------------------------------------
137 // wxWindowsArtProvider
138 // ----------------------------------------------------------------------------
139
140 class wxWindowsArtProvider : public wxArtProvider
141 {
142 protected:
143 virtual wxBitmap CreateBitmap(const wxArtID& id, const wxArtClient& client,
144 const wxSize& size);
145 };
146
147 static wxBitmap CreateFromStdIcon(const char *iconName,
148 const wxArtClient& client)
149 {
150 wxIcon icon(iconName);
151 wxBitmap bmp;
152 bmp.CopyFromIcon(icon);
153
154 #if wxUSE_IMAGE
155 // The standard native message box icons are in message box size (32x32).
156 // If they are requested in any size other than the default or message
157 // box size, they must be rescaled first.
158 if ( client != wxART_MESSAGE_BOX && client != wxART_OTHER )
159 {
160 const wxSize size = wxArtProvider::GetNativeSizeHint(client);
161 if ( size != wxDefaultSize )
162 {
163 wxImage img = bmp.ConvertToImage();
164 img.Rescale(size.x, size.y);
165 bmp = wxBitmap(img);
166 }
167 }
168 #endif // wxUSE_IMAGE
169
170 return bmp;
171 }
172
173 wxBitmap wxWindowsArtProvider::CreateBitmap(const wxArtID& id,
174 const wxArtClient& client,
175 const wxSize& size)
176 {
177 wxBitmap bitmap;
178
179 #ifdef wxHAS_SHGetStockIconInfo
180 // first try to use SHGetStockIconInfo, available only on Vista and higher
181 SHSTOCKICONID stockIconId = MSWGetStockIconIdForArtProviderId( id );
182 if ( stockIconId != SIID_INVALID )
183 {
184 WinStruct<SHSTOCKICONINFO> sii;
185
186 UINT uFlags = SHGSI_ICON;
187 if ( size != wxDefaultSize )
188 {
189 if ( size.x <= 16 )
190 uFlags |= SHGSI_SMALLICON;
191 else if ( size.x >= 64 )
192 uFlags |= SHGSI_LARGEICON;
193 }
194
195 HRESULT res = MSW_SHGetStockIconInfo(stockIconId, uFlags, &sii);
196 if ( res == S_OK )
197 {
198 wxIcon icon;
199 icon.CreateFromHICON( (WXHICON)sii.hIcon );
200
201 wxBitmap bitmap( icon );
202 ::DestroyIcon(sii.hIcon);
203
204 if ( bitmap.IsOk() )
205 return bitmap;
206 }
207 }
208 #endif // wxHAS_SHGetStockIconInfo
209
210
211 #if wxUSE_FSVOLUME
212 // now try SHGetFileInfo
213 wxFSVolumeKind volKind = wxFS_VOL_OTHER;
214 if ( id == wxART_HARDDISK )
215 volKind = wxFS_VOL_DISK;
216 else if ( id == wxART_FLOPPY )
217 volKind = wxFS_VOL_FLOPPY;
218 else if ( id == wxART_CDROM )
219 volKind = wxFS_VOL_CDROM;
220
221 if ( volKind != wxFS_VOL_OTHER )
222 {
223 bitmap = GetDriveBitmapForVolumeType(volKind, size);
224 if ( bitmap.IsOk() )
225 return bitmap;
226 }
227 #endif // wxUSE_FSVOLUME
228
229 // notice that the directory used here doesn't need to exist
230 if ( id == wxART_FOLDER )
231 bitmap = MSWGetBitmapForPath("C:\\wxdummydir\\", size );
232 else if ( id == wxART_FOLDER_OPEN )
233 bitmap = MSWGetBitmapForPath("C:\\wxdummydir\\", size, SHGFI_OPENICON );
234
235 if ( !bitmap.IsOk() )
236 {
237 // handle message box icons specially (wxIcon ctor treat these names
238 // as special cases via wxICOResourceHandler::LoadIcon):
239 const char *name = NULL;
240 if ( id == wxART_ERROR )
241 name = "wxICON_ERROR";
242 else if ( id == wxART_INFORMATION )
243 name = "wxICON_INFORMATION";
244 else if ( id == wxART_WARNING )
245 name = "wxICON_WARNING";
246 else if ( id == wxART_QUESTION )
247 name = "wxICON_QUESTION";
248
249 if ( name )
250 return CreateFromStdIcon(name, client);
251 }
252
253 // for anything else, fall back to generic provider:
254 return bitmap;
255 }
256
257 // ----------------------------------------------------------------------------
258 // wxArtProvider::InitNativeProvider()
259 // ----------------------------------------------------------------------------
260
261 /*static*/ void wxArtProvider::InitNativeProvider()
262 {
263 PushBack(new wxWindowsArtProvider);
264 }
265
266 // ----------------------------------------------------------------------------
267 // wxArtProvider::GetNativeSizeHint()
268 // ----------------------------------------------------------------------------
269
270 /*static*/
271 wxSize wxArtProvider::GetNativeSizeHint(const wxArtClient& client)
272 {
273 if ( client == wxART_TOOLBAR )
274 {
275 return wxSize(24, 24);
276 }
277 else if ( client == wxART_MENU )
278 {
279 return wxSize(16, 16);
280 }
281 else if ( client == wxART_FRAME_ICON )
282 {
283 return wxSize(::GetSystemMetrics(SM_CXSMICON),
284 ::GetSystemMetrics(SM_CYSMICON));
285 }
286 else if ( client == wxART_CMN_DIALOG ||
287 client == wxART_MESSAGE_BOX )
288 {
289 return wxSize(::GetSystemMetrics(SM_CXICON),
290 ::GetSystemMetrics(SM_CYICON));
291 }
292 else if (client == wxART_BUTTON)
293 {
294 return wxSize(16, 16);
295 }
296 else if (client == wxART_LIST)
297 {
298 return wxSize(16, 16);
299 }
300
301 return wxDefaultSize;
302 }