From: Vadim Zeitlin Date: Sat, 2 Mar 2013 12:11:47 +0000 (+0000) Subject: Use more native icons in wxMSW wxArtProvider. X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/f29b59b7811cbd130e1deb620ed05c1a5354b3d6 Use more native icons in wxMSW wxArtProvider. Use SHGetStockIconInfo() and SHGetFileInfo() to look up some icons. Closes #15068. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@73593 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/docs/changes.txt b/docs/changes.txt index 6371eedc05..52b72d39e9 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -652,6 +652,7 @@ wxMSW: - Add wxIcon::CreateFromHICON() (troelsk). - Improve wxCURSOR_RIGHT_ARROW appearance (DoltAlya). - Generate menu highlight events for popup menus in wxDialog (Sam Partington). +- Return more native shell icons from wxArtProvider (Markus Juergens). wxOSX/Cocoa: diff --git a/src/msw/artmsw.cpp b/src/msw/artmsw.cpp index 22314f1e25..c4f01f86fd 100644 --- a/src/msw/artmsw.cpp +++ b/src/msw/artmsw.cpp @@ -22,8 +22,116 @@ #include "wx/artprov.h" #include "wx/image.h" +#include "wx/dynlib.h" +#include "wx/volume.h" +#include "wx/msw/private.h" #include "wx/msw/wrapwin.h" +#ifdef SHGSI_ICON + #define wxHAS_SHGetStockIconInfo +#endif + +namespace +{ + +#ifdef wxHAS_SHGetStockIconInfo + +SHSTOCKICONID MSWGetStockIconIdForArtProviderId(const wxArtID& art_id) +{ + // try to find an equivalent MSW stock icon id for wxArtID + if ( art_id == wxART_ERROR) return SIID_ERROR; + else if ( art_id == wxART_QUESTION ) return SIID_HELP; + else if ( art_id == wxART_WARNING ) return SIID_WARNING; + else if ( art_id == wxART_INFORMATION ) return SIID_INFO; + else if ( art_id == wxART_HELP ) return SIID_HELP; + else if ( art_id == wxART_FOLDER ) return SIID_FOLDER; + else if ( art_id == wxART_FOLDER_OPEN ) return SIID_FOLDEROPEN; + else if ( art_id == wxART_DELETE ) return SIID_DELETE; + else if ( art_id == wxART_FIND ) return SIID_FIND; + else if ( art_id == wxART_HARDDISK ) return SIID_DRIVEFIXED; + else if ( art_id == wxART_FLOPPY ) return SIID_DRIVE35; + else if ( art_id == wxART_CDROM ) return SIID_DRIVECD; + else if ( art_id == wxART_REMOVABLE ) return SIID_DRIVEREMOVE; + + return SIID_INVALID; +}; + + +// try to load SHGetStockIconInfo dynamically, so this code runs +// even on pre-Vista Windows versions +HRESULT +MSW_SHGetStockIconInfo(SHSTOCKICONID siid, + UINT uFlags, + SHSTOCKICONINFO *psii) +{ + typedef HRESULT (WINAPI *PSHGETSTOCKICONINFO)(SHSTOCKICONID, UINT, SHSTOCKICONINFO *); + static PSHGETSTOCKICONINFO pSHGetStockIconInfo = (PSHGETSTOCKICONINFO)-1; + + if ( pSHGetStockIconInfo == (PSHGETSTOCKICONINFO)-1 ) + { + wxDynamicLibrary shell32(wxT("shell32.dll")); + + pSHGetStockIconInfo = (PSHGETSTOCKICONINFO)shell32.RawGetSymbol( wxT("SHGetStockIconInfo") ); + } + + if ( !pSHGetStockIconInfo ) + return E_FAIL; + + return pSHGetStockIconInfo(siid, uFlags, psii); +} + +#endif // #ifdef wxHAS_SHGetStockIconInfo + +wxBitmap +MSWGetBitmapForPath(const wxString& path, const wxSize& size, DWORD uFlags = 0) +{ + SHFILEINFO fi; + wxZeroMemory(fi); + + uFlags |= SHGFI_USEFILEATTRIBUTES | SHGFI_ICON; + if ( size != wxDefaultSize ) + { + if ( size.x <= 16 ) + uFlags |= SHGFI_SMALLICON; + else if ( size.x >= 64 ) + uFlags |= SHGFI_LARGEICON; + } + + if ( !SHGetFileInfo(path.t_str(), FILE_ATTRIBUTE_DIRECTORY, + &fi, sizeof(SHFILEINFO), uFlags) ) + return wxNullBitmap; + + wxIcon icon; + icon.CreateFromHICON((WXHICON)fi.hIcon); + + wxBitmap bitmap(icon); + ::DestroyIcon(fi.hIcon); + + return bitmap; +} + +#if wxUSE_FSVOLUME + +wxBitmap +GetDriveBitmapForVolumeType(const wxFSVolumeKind& volKind, const wxSize& size) +{ + // get all volumes and try to find one with a matching type + wxArrayString volumes = wxFSVolume::GetVolumes(); + for ( size_t i = 0; i < volumes.Count(); i++ ) + { + wxFSVolume vol( volumes[i] ); + if ( vol.GetKind() == volKind ) + { + return MSWGetBitmapForPath(volumes[i], size); + } + } + + return wxNullBitmap; +} + +#endif // wxUSE_FSVOLUME + +} // anonymous namespace // ---------------------------------------------------------------------------- // wxWindowsArtProvider @@ -64,25 +172,86 @@ static wxBitmap CreateFromStdIcon(const char *iconName, wxBitmap wxWindowsArtProvider::CreateBitmap(const wxArtID& id, const wxArtClient& client, - const wxSize& WXUNUSED(size)) + const wxSize& size) { - // handle message box icons specially (wxIcon ctor treat these names - // as special cases via wxICOResourceHandler::LoadIcon): - const char *name = NULL; - if ( id == wxART_ERROR ) - name = "wxICON_ERROR"; - else if ( id == wxART_INFORMATION ) - name = "wxICON_INFORMATION"; - else if ( id == wxART_WARNING ) - name = "wxICON_WARNING"; - else if ( id == wxART_QUESTION ) - name = "wxICON_QUESTION"; - - if ( name ) - return CreateFromStdIcon(name, client); + wxBitmap bitmap; + +#ifdef wxHAS_SHGetStockIconInfo + // first try to use SHGetStockIconInfo, available only on Vista and higher + SHSTOCKICONID stockIconId = MSWGetStockIconIdForArtProviderId( id ); + if ( stockIconId != SIID_INVALID ) + { + WinStruct sii; + + UINT uFlags = SHGSI_ICON; + if ( size != wxDefaultSize ) + { + if ( size.x <= 16 ) + uFlags |= SHGSI_SMALLICON; + else if ( size.x >= 64 ) + uFlags |= SHGSI_LARGEICON; + } + + HRESULT res = MSW_SHGetStockIconInfo(stockIconId, uFlags, &sii); + if ( res == S_OK ) + { + wxIcon icon; + icon.CreateFromHICON( (WXHICON)sii.hIcon ); + + wxBitmap bitmap( icon ); + ::DestroyIcon(sii.hIcon); + + if ( bitmap.IsOk() ) + return bitmap; + } + } +#endif // wxHAS_SHGetStockIconInfo + + +#if wxUSE_FSVOLUME + // now try SHGetFileInfo + wxFSVolumeKind volKind = wxFS_VOL_OTHER; + if ( id == wxART_HARDDISK ) + volKind = wxFS_VOL_DISK; + else if ( id == wxART_FLOPPY ) + volKind = wxFS_VOL_FLOPPY; + else if ( id == wxART_CDROM ) + volKind = wxFS_VOL_CDROM; + + if ( volKind != wxFS_VOL_OTHER ) + { + bitmap = GetDriveBitmapForVolumeType(volKind, size); + if ( bitmap.IsOk() ) + return bitmap; + } +#endif // wxUSE_FSVOLUME + + // notice that the directory used here doesn't need to exist + if ( id == wxART_FOLDER ) + bitmap = MSWGetBitmapForPath("C:\\wxdummydir\\", size ); + else if ( id == wxART_FOLDER_OPEN ) + bitmap = MSWGetBitmapForPath("C:\\wxdummydir\\", size, SHGFI_OPENICON ); + + if ( !bitmap.IsOk() ) + { + // handle message box icons specially (wxIcon ctor treat these names + // as special cases via wxICOResourceHandler::LoadIcon): + const char *name = NULL; + if ( id == wxART_ERROR ) + name = "wxICON_ERROR"; + else if ( id == wxART_INFORMATION ) + name = "wxICON_INFORMATION"; + else if ( id == wxART_WARNING ) + name = "wxICON_WARNING"; + else if ( id == wxART_QUESTION ) + name = "wxICON_QUESTION"; + + if ( name ) + return CreateFromStdIcon(name, client); + } // for anything else, fall back to generic provider: - return wxNullBitmap; + return bitmap; } // ----------------------------------------------------------------------------