]> git.saurik.com Git - wxWidgets.git/commitdiff
Fix setting frame icon when using non-standard icon sizes in wxMSW.
authorVadim Zeitlin <vadim@wxwidgets.org>
Tue, 24 Jan 2012 22:17:47 +0000 (22:17 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Tue, 24 Jan 2012 22:17:47 +0000 (22:17 +0000)
Set the closest (and larger, if possible) icon if the icon of exactly the
system icon size is not available. This fixes setting the icons when using
custom DPI settings under MSW as the standard icon size may be different from
the standard 32*32 in this case.

This also improves wxIconBundle::GetIcon() to make its behaviour when the icon
with exactly the given size is not found more flexible as a side effect.

Closes #13891.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@70455 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

docs/changes.txt
include/wx/iconbndl.h
interface/wx/iconbndl.h
src/common/iconbndl.cpp
src/msw/toplevel.cpp

index f058577236ef36b659ab1580d6836f118f35a70b..c723c17e1d2b2b432522f13613b48f64ed9ab02f 100644 (file)
@@ -471,6 +471,7 @@ All (GUI):
 - Fix multiple item selection in generic wxTreeCtrl (Igor Korot).
 - Implement wxMenuBar::IsEnabledTop() for all major ports (Igor Korot).
 - Implement best size calculation for report mode wxListCtrl.
+- Fix setting of the frame icon when using non-standard icon sizes (vid).
 
 GTK:
 
index e80edb4d9ff31c4e9a68a0107b210fc958b71b57..0955e716546bee1d6b3409fbf83c7ad4a0a5764c 100644 (file)
@@ -28,6 +28,23 @@ WX_DECLARE_EXPORTED_OBJARRAY(wxIcon, wxIconArray);
 class WXDLLIMPEXP_CORE wxIconBundle : public wxGDIObject
 {
 public:
+    // Flags that determine what happens if GetIcon() doesn't find the icon of
+    // exactly the requested size.
+    enum
+    {
+        // Return invalid icon if exact size is not found.
+        FALLBACK_NONE = 0,
+
+        // Return the icon of the system icon size if exact size is not found.
+        // May be combined with other non-NONE enum elements to determine what
+        // happens if the system icon size is not found neither.
+        FALLBACK_SYSTEM = 1,
+
+        // Return the icon of closest larger size or, if there is no icon of
+        // larger size in the bundle, the closest icon of smaller size.
+        FALLBACK_NEAREST_LARGER = 2
+    };
+
     // default constructor
     wxIconBundle();
 
@@ -60,13 +77,13 @@ public:
     void AddIcon(const wxIcon& icon);
 
     // returns the icon with the given size; if no such icon exists,
-    // returns the icon with size wxSYS_ICON_[XY]; if no such icon exists,
-    // returns the first icon in the bundle
-    wxIcon GetIcon(const wxSize& size) const;
+    // behavior is specified by the flags.
+    wxIcon GetIcon(const wxSize& size, int flags = FALLBACK_SYSTEM) const;
 
     // equivalent to GetIcon(wxSize(size, size))
-    wxIcon GetIcon(wxCoord size = wxDefaultCoord) const
-        { return GetIcon(wxSize(size, size)); }
+    wxIcon GetIcon(wxCoord size = wxDefaultCoord,
+                   int flags = FALLBACK_SYSTEM) const
+        { return GetIcon(wxSize(size, size), flags); }
 
     // returns the icon exactly of the specified size or wxNullIcon if no icon
     // of exactly given size are available
index 28c54ee38cfdb6723ccff11794534c0f834dfdd0..c33009d0effd7724010c84f16a381f771e0f6754 100644 (file)
 class wxIconBundle : public wxGDIObject
 {
 public:
+    /**
+        The elements of this enum determine what happens if GetIcon() doesn't
+        find the icon of exactly the requested size.
+
+        @since 2.9.4
+     */
+    enum
+    {
+        /// Return invalid icon if exact size is not found.
+        FALLBACK_NONE = 0,
+
+        /// Return the icon of the system icon size if exact size is not found.
+        /// May be combined with other non-NONE enum elements to determine what
+        /// happens if the system icon size is not found neither.
+        FALLBACK_SYSTEM = 1,
+
+        /// Return the icon of closest larger size or, if there is no icon of
+        /// larger size in the bundle, the closest icon of smaller size.
+        FALLBACK_NEAREST_LARGER = 2
+    };
+
+
     /**
         Default ctor.
     */
@@ -85,19 +107,31 @@ public:
     void AddIcon(const wxIcon& icon);
 
     /**
-        Returns the icon with the given size; if no such icon exists, returns
-        the icon with size @c wxSYS_ICON_X and @c wxSYS_ICON_Y; if no such icon
-        exists, returns the first icon in the bundle.
+        Returns the icon with the given size.
+
+        If @a size is ::wxDefaultSize, it is interpreted as the standard system
+        icon size, i.e. the size returned by wxSystemSettings::GetMetric() for
+        @c wxSYS_ICON_X and @c wxSYS_ICON_Y.
+
+        If the bundle contains an icon with exactly the requested size, it's
+        always returned. Otherwise, the behaviour depends on the flags. If only
+        ::FALLBACK_NONE is given, the function returns an invalid icon. If
+        ::FALLBACK_SYSTEM is given, it tries to find the icon of standard
+        system size, regardless of the size passed as parameter. Otherwise, or
+        if the icon system size is not found neither, but
+        ::FALLBACK_NEAREST_LARGER flag is specified, the function returns the
+        smallest icon of the size larger than the requested one or, if this
+        fails too, just the icon closest to the specified size.
 
-        If size = wxDefaultSize, returns the icon with size @c wxSYS_ICON_X and
-        @c wxSYS_ICON_Y.
+        The @a flags parameter is available only since wxWidgets 2.9.4.
     */
-    wxIcon GetIcon(const wxSize& size) const;
+    wxIcon GetIcon(const wxSize& size, int flags = FALLBACK_SYSTEM) const;
 
     /**
         Same as @code GetIcon( wxSize( size, size ) ) @endcode.
     */
-    wxIcon GetIcon(wxCoord size = wxDefaultCoord) const;
+    wxIcon GetIcon(wxCoord size = wxDefaultCoord,
+                   int flags = FALLBACK_SYSTEM) const;
 
     /**
         Returns the icon with exactly the given size or ::wxNullIcon if this
index 186d4df0cccc3ac64838e6d3e70e35e74fdee9ae..d589943453e98af4d6057971c3f09bee82d56d69 100644 (file)
@@ -193,49 +193,91 @@ void wxIconBundle::AddIcon(wxInputStream& stream, wxBitmapType type)
 
 #endif // wxUSE_STREAMS && wxUSE_IMAGE
 
-wxIcon wxIconBundle::GetIcon(const wxSize& size) const
+wxIcon wxIconBundle::GetIcon(const wxSize& size, int flags) const
 {
-    const size_t count = GetIconCount();
+    wxASSERT( size == wxDefaultSize || (size.x >= 0 && size.y > 0) );
+
+    // We need the standard system icon size when using FALLBACK_SYSTEM.
+    wxCoord sysX = 0,
+            sysY = 0;
+    if ( flags & FALLBACK_SYSTEM )
+    {
+        sysX = wxSystemSettings::GetMetric(wxSYS_ICON_X);
+        sysY = wxSystemSettings::GetMetric(wxSYS_ICON_Y);
+    }
 
-    // optimize for the common case of icon bundles containing one icon only
+    // If size == wxDefaultSize, we use system default icon size by convention.
+    wxCoord sizeX = size.x;
+    wxCoord sizeY = size.y;
+    if ( size == wxDefaultSize )
+    {
+        wxASSERT_MSG( flags == FALLBACK_SYSTEM,
+                      wxS("Must have valid size if not using FALLBACK_SYSTEM") );
+
+        sizeX = sysX;
+        sizeY = sysY;
+    }
+
+    // Iterate over all icons searching for the exact match or the closest icon
+    // for FALLBACK_NEAREST_LARGER.
     wxIcon iconBest;
-    switch ( count )
+    int bestDiff = 0;
+    bool bestIsLarger = false;
+    bool bestIsSystem = false;
+
+    const size_t count = GetIconCount();
+
+    const wxIconArray& iconArray = M_ICONBUNDLEDATA->m_icons;
+    for ( size_t i = 0; i < count; i++ )
     {
-        case 0:
-            // nothing to do, iconBest is already invalid
-            break;
+        const wxIcon& icon = iconArray[i];
+        if ( !icon.IsOk() )
+            continue;
+        wxCoord sx = icon.GetWidth(),
+                sy = icon.GetHeight();
 
-        case 1:
-            iconBest = M_ICONBUNDLEDATA->m_icons[0];
+        // Exact match ends search immediately in any case.
+        if ( sx == sizeX && sy == sizeY )
+        {
+            iconBest = icon;
             break;
+        }
 
-        default:
-            // there is more than one icon, find the best match:
-            wxCoord sysX = wxSystemSettings::GetMetric( wxSYS_ICON_X ),
-                    sysY = wxSystemSettings::GetMetric( wxSYS_ICON_Y );
+        if ( flags & FALLBACK_SYSTEM )
+        {
+            if ( sx == sysX && sy == sysY )
+            {
+                iconBest = icon;
+                bestIsSystem = true;
+                continue;
+            }
+        }
 
-            const wxIconArray& iconArray = M_ICONBUNDLEDATA->m_icons;
-            for ( size_t i = 0; i < count; i++ )
+        if ( !bestIsSystem && (flags & FALLBACK_NEAREST_LARGER) )
+        {
+            bool iconLarger = (sx >= sizeX) && (sy >= sizeY);
+            int iconDiff = abs(sx - sizeX) + abs(sy - sizeY);
+
+            // Use current icon as candidate for the best icon, if either:
+            // - we have no candidate yet
+            // - we have no candidate larger than desired size and current icon is
+            // - current icon is closer to desired size than candidate
+            if ( !iconBest.IsOk() ||
+                    (!bestIsLarger && iconLarger) ||
+                        (iconLarger && (iconDiff < bestDiff)) )
             {
-                const wxIcon& icon = iconArray[i];
-                wxCoord sx = icon.GetWidth(),
-                        sy = icon.GetHeight();
-
-                // if we got an icon of exactly the requested size, we're done
-                if ( sx == size.x && sy == size.y )
-                {
-                    iconBest = icon;
-                    break;
-                }
-
-                // the best icon is by default (arbitrarily) the first one but
-                // if we find a system-sized icon, take it instead
-                if ((sx == sysX && sy == sysY) || !iconBest.IsOk())
-                    iconBest = icon;
+                iconBest = icon;
+                bestIsLarger = iconLarger;
+                bestDiff = iconDiff;
+                continue;
             }
+        }
     }
 
 #if defined( __WXMAC__ ) && wxOSX_USE_CARBON
+    if (!iconBest.IsOk())
+        return wxNullIcon;
+
     return wxIcon(iconBest.GetHICON(), size);
 #else
     return iconBest;
@@ -244,14 +286,7 @@ wxIcon wxIconBundle::GetIcon(const wxSize& size) const
 
 wxIcon wxIconBundle::GetIconOfExactSize(const wxSize& size) const
 {
-    wxIcon icon = GetIcon(size);
-    if ( icon.IsOk() &&
-            (icon.GetWidth() != size.x || icon.GetHeight() != size.y) )
-    {
-        icon = wxNullIcon;
-    }
-
-    return icon;
+    return GetIcon(size, FALLBACK_NONE);
 }
 
 void wxIconBundle::AddIcon(const wxIcon& icon)
index 8219f12a43b782c8a12b20f92be3ab0e47abdb78..7adf8c69259ef4b7c22d2bca98aae2ef7285fe43 100644 (file)
@@ -1100,18 +1100,7 @@ bool wxTopLevelWindowMSW::DoSelectAndSetIcon(const wxIconBundle& icons,
 {
     const wxSize size(::GetSystemMetrics(smX), ::GetSystemMetrics(smY));
 
-    // Try the exact size first.
-    wxIcon icon = icons.GetIconOfExactSize(size);
-
-    if ( !icon.IsOk() )
-    {
-        // If we didn't find any, set at least some icon: it will look scaled
-        // and ugly but in practice it's impossible to prevent this because not
-        // everyone can provide the icons in all sizes used by all versions of
-        // Windows in all DPIs (this would include creating them in at least
-        // 14, 16, 22, 32, 48, 64 and 128 pixel sizes).
-        icon = icons.GetIcon(size);
-    }
+    wxIcon icon = icons.GetIcon(size, wxIconBundle::FALLBACK_NEAREST_LARGER);
 
     if ( !icon.IsOk() )
         return false;