]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/artmsw.cpp
Ensure there is valid context for DrawRectangle
[wxWidgets.git] / src / msw / artmsw.cpp
index 695fad7d2834e0e9df2bc7b3beae44ef3a997e83..c4f01f86fddea67e3ead12c4d10e3072bbeb9eb5 100644 (file)
 #endif
 
 #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
@@ -35,31 +144,114 @@ protected:
                                   const wxSize& size);
 };
 
-static wxBitmap CreateFromStdIcon(const char *iconName)
+static wxBitmap CreateFromStdIcon(const char *iconName,
+                                  const wxArtClient& client)
 {
     wxIcon icon(iconName);
     wxBitmap bmp;
     bmp.CopyFromIcon(icon);
+
+#if wxUSE_IMAGE
+    // The standard native message box icons are in message box size (32x32).
+    // If they are requested in any size other than the default or message
+    // box size, they must be rescaled first.
+    if ( client != wxART_MESSAGE_BOX && client != wxART_OTHER )
+    {
+        const wxSize size = wxArtProvider::GetNativeSizeHint(client);
+        if ( size != wxDefaultSize )
+        {
+            wxImage img = bmp.ConvertToImage();
+            img.Rescale(size.x, size.y);
+            bmp = wxBitmap(img);
+        }
+    }
+#endif // wxUSE_IMAGE
+
     return bmp;
 }
 
 wxBitmap wxWindowsArtProvider::CreateBitmap(const wxArtID& id,
-                                            const wxArtClient& WXUNUSED(client),
-                                            const wxSize& WXUNUSED(size))
+                                            const wxArtClient& client,
+                                            const wxSize& size)
 {
-    // handle message box icons specially (wxIcon ctor treat these names
-    // as special cases via wxICOResourceHandler::LoadIcon):
-    if ( id == wxART_ERROR )
-        return CreateFromStdIcon("wxICON_ERROR");
-    else if ( id == wxART_INFORMATION )
-        return CreateFromStdIcon("wxICON_INFORMATION");
-    else if ( id == wxART_WARNING )
-        return CreateFromStdIcon("wxICON_WARNING");
-    else if ( id == wxART_QUESTION )
-        return CreateFromStdIcon("wxICON_QUESTION");
+    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<SHSTOCKICONINFO> 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;
 }
 
 // ----------------------------------------------------------------------------
@@ -68,7 +260,7 @@ wxBitmap wxWindowsArtProvider::CreateBitmap(const wxArtID& id,
 
 /*static*/ void wxArtProvider::InitNativeProvider()
 {
-    Push(new wxWindowsArtProvider);
+    PushBack(new wxWindowsArtProvider);
 }
 
 // ----------------------------------------------------------------------------
@@ -101,6 +293,10 @@ wxSize wxArtProvider::GetNativeSizeHint(const wxArtClient& client)
     {
         return wxSize(16, 16);
     }
+    else if (client == wxART_LIST)
+    {
+        return wxSize(16, 16);
+    }
 
     return wxDefaultSize;
 }