don't crash when IsEmpty() is called on invalid bundle; don't assert if GetIcon(...
[wxWidgets.git] / src / common / iconbndl.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/iconbndl.cpp
3 // Purpose: wxIconBundle
4 // Author: Mattia Barbon, Vadim Zeitlin
5 // Created: 23.03.2002
6 // RCS-ID: $Id$
7 // Copyright: (c) Mattia barbon
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21
22 #ifdef __BORLANDC__
23 #pragma hdrstop
24 #endif
25
26 #include "wx/iconbndl.h"
27
28 #ifndef WX_PRECOMP
29 #include "wx/settings.h"
30 #include "wx/icon.h"
31 #include "wx/log.h"
32 #include "wx/intl.h"
33 #include "wx/bitmap.h"
34 #include "wx/image.h"
35 #endif
36
37 #include "wx/arrimpl.cpp"
38
39 WX_DEFINE_OBJARRAY(wxIconArray)
40
41 IMPLEMENT_DYNAMIC_CLASS(wxIconBundle, wxGDIObject)
42
43 #define M_ICONBUNDLEDATA ((wxIconBundleRefData *)m_refData)
44
45 // ----------------------------------------------------------------------------
46 // wxIconBundleRefData
47 // ----------------------------------------------------------------------------
48
49 class WXDLLEXPORT wxIconBundleRefData : public wxGDIRefData
50 {
51 public:
52 // default and copy ctors and assignment operators are ok
53
54 protected:
55 wxIconArray m_icons;
56
57 friend class WXDLLEXPORT wxIconBundle;
58 };
59
60 // ============================================================================
61 // wxIconBundle implementation
62 // ============================================================================
63
64 wxIconBundle::wxIconBundle()
65 : wxGDIObject()
66 {
67 m_refData = new wxIconBundleRefData;
68 }
69
70 wxIconBundle::wxIconBundle(const wxString& file, long type)
71 : wxGDIObject()
72 {
73 m_refData = new wxIconBundleRefData;
74 AddIcon(file, type);
75 }
76
77 wxIconBundle::wxIconBundle(const wxIconBundle& icon)
78 : wxGDIObject()
79 {
80 Ref(icon);
81 }
82
83 wxIconBundle::wxIconBundle(const wxIcon& icon)
84 : wxGDIObject()
85 {
86 m_refData = new wxIconBundleRefData;
87 AddIcon(icon);
88 }
89
90 wxObjectRefData *wxIconBundle::CreateRefData() const
91 {
92 return new wxIconBundleRefData;
93 }
94
95 wxObjectRefData *wxIconBundle::CloneRefData(const wxObjectRefData *data) const
96 {
97 return new wxIconBundleRefData(*wx_static_cast(const wxIconBundleRefData *, data));
98 }
99
100 void wxIconBundle::DeleteIcons()
101 {
102 wxIconBundleRefData* ref = new wxIconBundleRefData();
103 UnRef();
104 m_refData = ref;
105 }
106
107 bool wxIconBundle::IsOk() const
108 {
109 return M_ICONBUNDLEDATA && !M_ICONBUNDLEDATA->m_icons.IsEmpty();
110 }
111
112 void wxIconBundle::AddIcon(const wxString& file, long type)
113 {
114 #ifdef __WXMAC__
115 // Deal with standard icons
116 if ( type == wxBITMAP_TYPE_ICON_RESOURCE )
117 {
118 wxIcon tmp(file, type);
119 if (tmp.Ok())
120 {
121 AddIcon(tmp);
122 return;
123 }
124 }
125 #endif // __WXMAC__
126
127 #if wxUSE_IMAGE && (!defined(__WXMSW__) || wxUSE_WXDIB)
128 wxImage image;
129
130 const size_t count = wxImage::GetImageCount( file, type );
131 for ( size_t i = 0; i < count; ++i )
132 {
133 if ( !image.LoadFile( file, type, i ) )
134 {
135 wxLogError( _("Failed to load image %d from file '%s'."),
136 i, file.c_str() );
137 continue;
138 }
139
140 wxIcon tmp;
141 tmp.CopyFromBitmap(wxBitmap(image));
142 AddIcon(tmp);
143 }
144 #else // !wxUSE_IMAGE
145 wxUnusedVar(file);
146 wxUnusedVar(type);
147 #endif // wxUSE_IMAGE/!wxUSE_IMAGE
148 }
149
150 wxIcon wxIconBundle::GetIcon(const wxSize& size) const
151 {
152 const size_t count = GetIconCount();
153
154 // optimize for the common case of icon bundles containing one icon only
155 wxIcon iconBest;
156 switch ( count )
157 {
158 case 0:
159 // nothing to do, iconBest is already invalid
160 break;
161
162 case 1:
163 iconBest = M_ICONBUNDLEDATA->m_icons[0];
164 break;
165
166 default:
167 // there is more than one icon, find the best match:
168 wxCoord sysX = wxSystemSettings::GetMetric( wxSYS_ICON_X ),
169 sysY = wxSystemSettings::GetMetric( wxSYS_ICON_Y );
170
171 const wxIconArray& iconArray = M_ICONBUNDLEDATA->m_icons;
172 for ( size_t i = 0; i < count; i++ )
173 {
174 const wxIcon& icon = iconArray[i];
175 wxCoord sx = icon.GetWidth(),
176 sy = icon.GetHeight();
177
178 // if we got an icon of exactly the requested size, we're done
179 if ( sx == size.x && sy == size.y )
180 {
181 iconBest = icon;
182 break;
183 }
184
185 // the best icon is by default (arbitrarily) the first one but
186 // if we find a system-sized icon, take it instead
187 if ( sx == sysX && sy == sysY || !iconBest.IsOk() )
188 iconBest = icon;
189 }
190 }
191
192 #ifdef __WXMAC__
193 return wxIcon(iconBest.GetHICON(), size);
194 #else
195 return iconBest;
196 #endif
197 }
198
199 void wxIconBundle::AddIcon(const wxIcon& icon)
200 {
201 wxCHECK_RET( icon.IsOk(), _T("invalid icon") );
202
203 AllocExclusive();
204
205 wxIconArray& iconArray = M_ICONBUNDLEDATA->m_icons;
206
207 // replace existing icon with the same size if we already have it
208 const size_t count = iconArray.size();
209 for ( size_t i = 0; i < count; ++i )
210 {
211 wxIcon& tmp = iconArray[i];
212 if ( tmp.Ok() &&
213 tmp.GetWidth() == icon.GetWidth() &&
214 tmp.GetHeight() == icon.GetHeight() )
215 {
216 tmp = icon;
217 return;
218 }
219 }
220
221 // if we don't, add an icon with new size
222 iconArray.Add(icon);
223 }
224
225 size_t wxIconBundle::GetIconCount() const
226 {
227 return IsOk() ? M_ICONBUNDLEDATA->m_icons.size() : 0;
228 }
229
230 wxIcon wxIconBundle::GetIconByIndex(size_t n) const
231 {
232 wxCHECK_MSG( n < GetIconCount(), wxNullIcon, _T("invalid index") );
233
234 return M_ICONBUNDLEDATA->m_icons[n];
235 }
236