1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/iconbndl.cpp
3 // Purpose: wxIconBundle
4 // Author: Mattia Barbon, Vadim Zeitlin
6 // Copyright: (c) Mattia barbon
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
17 #include "wx/iconbndl.h"
20 #include "wx/settings.h"
23 #include "wx/bitmap.h"
25 #include "wx/stream.h"
28 #include "wx/wfstream.h"
30 #include "wx/arrimpl.cpp"
31 WX_DEFINE_OBJARRAY(wxIconArray
)
33 IMPLEMENT_DYNAMIC_CLASS(wxIconBundle
, wxGDIObject
)
35 #define M_ICONBUNDLEDATA static_cast<wxIconBundleRefData*>(m_refData)
37 // ----------------------------------------------------------------------------
38 // wxIconBundleRefData
39 // ----------------------------------------------------------------------------
41 class WXDLLEXPORT wxIconBundleRefData
: public wxGDIRefData
44 wxIconBundleRefData() { }
46 // We need the copy ctor for CloneGDIRefData() but notice that we use the
47 // base class default ctor in it and not the copy one which it doesn't have.
48 wxIconBundleRefData(const wxIconBundleRefData
& other
)
50 m_icons(other
.m_icons
)
54 // default assignment operator and dtor are ok
56 virtual bool IsOk() const { return !m_icons
.empty(); }
61 // ============================================================================
62 // wxIconBundle implementation
63 // ============================================================================
65 wxIconBundle::wxIconBundle()
69 #if wxUSE_STREAMS && wxUSE_IMAGE
71 #if wxUSE_FFILE || wxUSE_FILE
72 wxIconBundle::wxIconBundle(const wxString
& file
, wxBitmapType type
)
77 #endif // wxUSE_FFILE || wxUSE_FILE
79 wxIconBundle::wxIconBundle(wxInputStream
& stream
, wxBitmapType type
)
82 AddIcon(stream
, type
);
84 #endif // wxUSE_STREAMS && wxUSE_IMAGE
86 wxIconBundle::wxIconBundle(const wxIcon
& icon
)
92 wxGDIRefData
*wxIconBundle::CreateGDIRefData() const
94 return new wxIconBundleRefData
;
97 wxGDIRefData
*wxIconBundle::CloneGDIRefData(const wxGDIRefData
*data
) const
99 return new wxIconBundleRefData(*static_cast<const wxIconBundleRefData
*>(data
));
102 void wxIconBundle::DeleteIcons()
107 #if wxUSE_STREAMS && wxUSE_IMAGE
112 // Adds icon from 'input' to the bundle. Shows 'errorMessage' on failure
113 // (it must contain "%d", because it is used to report # of image in the file
114 // that failed to load):
115 void DoAddIcon(wxIconBundle
& bundle
,
116 wxInputStream
& input
,
118 const wxString
& errorMessage
)
122 const wxFileOffset posOrig
= input
.TellI();
124 const size_t count
= wxImage::GetImageCount(input
, type
);
125 for ( size_t i
= 0; i
< count
; ++i
)
129 // the call to LoadFile() for the first sub-image updated the
130 // stream position but we need to start reading the subsequent
131 // sub-image at the image beginning too
132 input
.SeekI(posOrig
);
135 if ( !image
.LoadFile(input
, type
, i
) )
137 wxLogError(errorMessage
, i
);
141 if ( type
== wxBITMAP_TYPE_ANY
)
143 // store the type so that we don't need to try all handlers again
144 // for the subsequent images, they should all be of the same type
145 type
= image
.GetType();
149 tmp
.CopyFromBitmap(wxBitmap(image
));
154 } // anonymous namespace
156 #if wxUSE_FFILE || wxUSE_FILE
158 void wxIconBundle::AddIcon(const wxString
& file
, wxBitmapType type
)
161 // Deal with standard icons
162 if ( type
== wxBITMAP_TYPE_ICON_RESOURCE
)
164 wxIcon
tmp(file
, type
);
174 wxFFileInputStream
stream(file
);
176 wxFileInputStream
stream(file
);
182 wxString::Format(_("Failed to load image %%d from file '%s'."), file
)
186 #endif // wxUSE_FFILE || wxUSE_FILE
188 void wxIconBundle::AddIcon(wxInputStream
& stream
, wxBitmapType type
)
190 DoAddIcon(*this, stream
, type
, _("Failed to load image %d from stream."));
193 #endif // wxUSE_STREAMS && wxUSE_IMAGE
195 wxIcon
wxIconBundle::GetIcon(const wxSize
& size
, int flags
) const
197 wxASSERT( size
== wxDefaultSize
|| (size
.x
>= 0 && size
.y
> 0) );
199 // We need the standard system icon size when using FALLBACK_SYSTEM.
202 if ( flags
& FALLBACK_SYSTEM
)
204 sysX
= wxSystemSettings::GetMetric(wxSYS_ICON_X
);
205 sysY
= wxSystemSettings::GetMetric(wxSYS_ICON_Y
);
208 // If size == wxDefaultSize, we use system default icon size by convention.
209 wxCoord sizeX
= size
.x
;
210 wxCoord sizeY
= size
.y
;
211 if ( size
== wxDefaultSize
)
213 wxASSERT_MSG( flags
== FALLBACK_SYSTEM
,
214 wxS("Must have valid size if not using FALLBACK_SYSTEM") );
220 // Iterate over all icons searching for the exact match or the closest icon
221 // for FALLBACK_NEAREST_LARGER.
224 bool bestIsLarger
= false;
225 bool bestIsSystem
= false;
227 const size_t count
= GetIconCount();
229 const wxIconArray
& iconArray
= M_ICONBUNDLEDATA
->m_icons
;
230 for ( size_t i
= 0; i
< count
; i
++ )
232 const wxIcon
& icon
= iconArray
[i
];
235 wxCoord sx
= icon
.GetWidth(),
236 sy
= icon
.GetHeight();
238 // Exact match ends search immediately in any case.
239 if ( sx
== sizeX
&& sy
== sizeY
)
245 if ( flags
& FALLBACK_SYSTEM
)
247 if ( sx
== sysX
&& sy
== sysY
)
255 if ( !bestIsSystem
&& (flags
& FALLBACK_NEAREST_LARGER
) )
257 bool iconLarger
= (sx
>= sizeX
) && (sy
>= sizeY
);
258 int iconDiff
= abs(sx
- sizeX
) + abs(sy
- sizeY
);
260 // Use current icon as candidate for the best icon, if either:
261 // - we have no candidate yet
262 // - we have no candidate larger than desired size and current icon is
263 // - current icon is closer to desired size than candidate
264 if ( !iconBest
.IsOk() ||
265 (!bestIsLarger
&& iconLarger
) ||
266 (iconLarger
&& (iconDiff
< bestDiff
)) )
269 bestIsLarger
= iconLarger
;
276 #if defined( __WXMAC__ ) && wxOSX_USE_CARBON
277 if (!iconBest
.IsOk())
280 return wxIcon(iconBest
.GetHICON(), size
);
286 wxIcon
wxIconBundle::GetIconOfExactSize(const wxSize
& size
) const
288 return GetIcon(size
, FALLBACK_NONE
);
291 void wxIconBundle::AddIcon(const wxIcon
& icon
)
293 wxCHECK_RET( icon
.IsOk(), wxT("invalid icon") );
297 wxIconArray
& iconArray
= M_ICONBUNDLEDATA
->m_icons
;
299 // replace existing icon with the same size if we already have it
300 const size_t count
= iconArray
.size();
301 for ( size_t i
= 0; i
< count
; ++i
)
303 wxIcon
& tmp
= iconArray
[i
];
305 tmp
.GetWidth() == icon
.GetWidth() &&
306 tmp
.GetHeight() == icon
.GetHeight() )
313 // if we don't, add an icon with new size
317 size_t wxIconBundle::GetIconCount() const
319 return IsOk() ? M_ICONBUNDLEDATA
->m_icons
.size() : 0;
322 wxIcon
wxIconBundle::GetIconByIndex(size_t n
) const
324 wxCHECK_MSG( n
< GetIconCount(), wxNullIcon
, wxT("invalid index") );
326 return M_ICONBUNDLEDATA
->m_icons
[n
];