1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/common/animatecmn.cpp
3 // Purpose:     wxAnimation and wxAnimationCtrl
4 // Author:      Francesco Montorsi
5 // Modified By:
6 // Created:     24/09/2006
7 // Copyright:   (c) Francesco Montorsi
8 // Licence:     wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10 
11 
12 // ----------------------------------------------------------------------------
13 // headers
14 // ----------------------------------------------------------------------------
15 
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18 
19 
20 #if wxUSE_ANIMATIONCTRL
21 
22 #include "wx/animate.h"
23 #include "wx/bitmap.h"
24 #include "wx/log.h"
25 #include "wx/brush.h"
26 #include "wx/image.h"
27 #include "wx/dcmemory.h"
28 #include "wx/module.h"
29 
30 #include "wx/gifdecod.h"
31 #include "wx/anidecod.h"
32 
33 #include "wx/private/animate.h"
34 
35 // global objects
36 const char wxAnimationCtrlNameStr[] = "animationctrl";
37 wxAnimation wxNullAnimation;
38 
39 wxIMPLEMENT_DYNAMIC_CLASS(wxAnimation, wxObject);
40 
41 #if !defined(wxHAS_NATIVE_ANIMATIONCTRL)
42     // In this case the "native" ctrl is the generic ctrl. See wx/animate.h
43     // Notice that it's important to use wxGenericAnimationCtrl here because
44     // wxAnimation::IsCompatibleWith() relies on control deriving from
45     // wxGenericAnimationCtrl when using generic wxAnimation implementation.
46     wxIMPLEMENT_CLASS(wxAnimationCtrl, wxGenericAnimationCtrl);
47 #endif
48 
49 #include "wx/listimpl.cpp"
50 WX_DEFINE_LIST(wxAnimationDecoderList)
51 
52 wxAnimationDecoderList wxAnimation::sm_handlers;
53 
54 // ----------------------------------------------------------------------------
55 // wxAnimation
56 // ----------------------------------------------------------------------------
57 
wxAnimation()58 wxAnimation::wxAnimation()
59 {
60     m_refData = wxAnimationImpl::CreateDefault();
61 }
62 
wxAnimation(wxAnimationImpl * impl)63 wxAnimation::wxAnimation(wxAnimationImpl* impl)
64 {
65     m_refData = impl;
66 }
67 
wxAnimation(const wxString & name,wxAnimationType type)68 wxAnimation::wxAnimation(const wxString &name, wxAnimationType type)
69 {
70     m_refData = wxAnimationImpl::CreateDefault();
71     LoadFile(name, type);
72 }
73 
GetImpl() const74 wxAnimationImpl* wxAnimation::GetImpl() const
75 {
76     return static_cast<wxAnimationImpl*>(m_refData);
77 }
78 
IsOk() const79 bool wxAnimation::IsOk() const
80 {
81     return GetImpl() && GetImpl()->IsOk();
82 }
83 
IsCompatibleWith(wxClassInfo * ci) const84 bool wxAnimation::IsCompatibleWith(wxClassInfo* ci) const
85 {
86     wxCHECK_MSG( IsOk(), false, wxT("invalid animation") );
87 
88     return GetImpl()->IsCompatibleWith(ci);
89 }
90 
GetDelay(unsigned int frame) const91 int wxAnimation::GetDelay(unsigned int frame) const
92 {
93     wxCHECK_MSG( IsOk(), -1, wxT("invalid animation") );
94     return GetImpl()->GetDelay(frame);
95 }
96 
GetFrameCount() const97 unsigned int wxAnimation::GetFrameCount() const
98 {
99     wxCHECK_MSG( IsOk(), 0, wxT("invalid animation") );
100     return GetImpl()->GetFrameCount();
101 }
102 
GetFrame(unsigned int frame) const103 wxImage wxAnimation::GetFrame(unsigned int frame) const
104 {
105     wxCHECK_MSG( IsOk(), wxNullImage, wxT("invalid animation") );
106     return GetImpl()->GetFrame(frame);
107 }
108 
GetSize() const109 wxSize wxAnimation::GetSize() const
110 {
111     wxCHECK_MSG( IsOk(), wxDefaultSize, wxT("invalid animation") );
112     return GetImpl()->GetSize();
113 }
114 
LoadFile(const wxString & name,wxAnimationType type)115 bool wxAnimation::LoadFile(const wxString& name, wxAnimationType type)
116 {
117     // the animation impl may not be fully ready until after it has loaded the
118     // file, so just check GetImpl in the Load methods
119     wxCHECK_MSG( GetImpl(), false, wxT("invalid animation") );
120     return GetImpl()->LoadFile(name, type);
121 }
122 
Load(wxInputStream & stream,wxAnimationType type)123 bool wxAnimation::Load(wxInputStream& stream, wxAnimationType type)
124 {
125     wxCHECK_MSG( GetImpl(), false, wxT("invalid animation") );
126     return GetImpl()->Load(stream, type);
127 }
128 
129 
130 // ----------------------------------------------------------------------------
131 // wxAnimationCtrlBase
132 // ----------------------------------------------------------------------------
133 
UpdateStaticImage()134 void wxAnimationCtrlBase::UpdateStaticImage()
135 {
136     if (!m_bmpStaticReal.IsOk() || !m_bmpStatic.IsOk())
137         return;
138 
139     // if given bitmap is not of the right size, recreate m_bmpStaticReal accordingly
140     const wxSize &sz = GetClientSize();
141     if (sz.GetWidth() != m_bmpStaticReal.GetWidth() ||
142         sz.GetHeight() != m_bmpStaticReal.GetHeight())
143     {
144         if (!m_bmpStaticReal.IsOk() ||
145             m_bmpStaticReal.GetWidth() != sz.GetWidth() ||
146             m_bmpStaticReal.GetHeight() != sz.GetHeight())
147         {
148             // need to (re)create m_bmpStaticReal
149             if (!m_bmpStaticReal.Create(sz.GetWidth(), sz.GetHeight(),
150                                         m_bmpStatic.GetDepth()))
151             {
152                 wxLogDebug(wxT("Cannot create the static bitmap"));
153                 m_bmpStatic = wxNullBitmap;
154                 return;
155             }
156         }
157 
158         if (m_bmpStatic.GetWidth() <= sz.GetWidth() &&
159             m_bmpStatic.GetHeight() <= sz.GetHeight())
160         {
161             // clear the background of m_bmpStaticReal
162             wxBrush brush(GetBackgroundColour());
163             wxMemoryDC dc;
164             dc.SelectObject(m_bmpStaticReal);
165             dc.SetBackground(brush);
166             dc.Clear();
167 
168             // center the user-provided bitmap in m_bmpStaticReal
169             dc.DrawBitmap(m_bmpStatic,
170                         (sz.GetWidth()-m_bmpStatic.GetWidth())/2,
171                         (sz.GetHeight()-m_bmpStatic.GetHeight())/2,
172                         true /* use mask */ );
173         }
174         else
175         {
176             // the user-provided bitmap is bigger than our control, strech it
177             wxImage temp(m_bmpStatic.ConvertToImage());
178             temp.Rescale(sz.GetWidth(), sz.GetHeight(), wxIMAGE_QUALITY_HIGH);
179             m_bmpStaticReal = wxBitmap(temp);
180         }
181     }
182 }
183 
SetInactiveBitmap(const wxBitmap & bmp)184 void wxAnimationCtrlBase::SetInactiveBitmap(const wxBitmap &bmp)
185 {
186     m_bmpStatic = bmp;
187     m_bmpStaticReal = bmp;
188 
189     // if not playing, update the control now
190     // NOTE: DisplayStaticImage() will call UpdateStaticImage automatically
191     if ( !IsPlaying() )
192         DisplayStaticImage();
193 }
194 
195 // ----------------------------------------------------------------------------
196 // animation decoders
197 // ----------------------------------------------------------------------------
198 
AddHandler(wxAnimationDecoder * handler)199 void wxAnimation::AddHandler( wxAnimationDecoder *handler )
200 {
201     // Check for an existing handler of the type being added.
202     if (FindHandler( handler->GetType() ) == 0)
203     {
204         sm_handlers.Append( handler );
205     }
206     else
207     {
208         // This is not documented behaviour, merely the simplest 'fix'
209         // for preventing duplicate additions.  If someone ever has
210         // a good reason to add and remove duplicate handlers (and they
211         // may) we should probably refcount the duplicates.
212 
213         wxLogDebug( wxT("Adding duplicate animation handler for '%d' type"),
214                     handler->GetType() );
215         delete handler;
216     }
217 }
218 
InsertHandler(wxAnimationDecoder * handler)219 void wxAnimation::InsertHandler( wxAnimationDecoder *handler )
220 {
221     // Check for an existing handler of the type being added.
222     if (FindHandler( handler->GetType() ) == 0)
223     {
224         sm_handlers.Insert( handler );
225     }
226     else
227     {
228         // see AddHandler for additional comments.
229         wxLogDebug( wxT("Inserting duplicate animation handler for '%d' type"),
230                     handler->GetType() );
231         delete handler;
232     }
233 }
234 
FindHandler(wxAnimationType animType)235 const wxAnimationDecoder *wxAnimation::FindHandler( wxAnimationType animType )
236 {
237     wxAnimationDecoderList::compatibility_iterator node = sm_handlers.GetFirst();
238     while (node)
239     {
240         const wxAnimationDecoder *handler = (const wxAnimationDecoder *)node->GetData();
241         if (handler->GetType() == animType) return handler;
242         node = node->GetNext();
243     }
244     return 0;
245 }
246 
InitStandardHandlers()247 void wxAnimation::InitStandardHandlers()
248 {
249 #if wxUSE_GIF
250     AddHandler(new wxGIFDecoder);
251 #endif // wxUSE_GIF
252 #if wxUSE_ICO_CUR
253     AddHandler(new wxANIDecoder);
254 #endif // wxUSE_ICO_CUR
255 }
256 
CleanUpHandlers()257 void wxAnimation::CleanUpHandlers()
258 {
259     wxAnimationDecoderList::compatibility_iterator node = sm_handlers.GetFirst();
260     while (node)
261     {
262         wxAnimationDecoder *handler = (wxAnimationDecoder *)node->GetData();
263         wxAnimationDecoderList::compatibility_iterator next = node->GetNext();
264         delete handler;
265         node = next;
266     }
267 
268     sm_handlers.Clear();
269 }
270 
271 
272 // A module to allow wxAnimation initialization/cleanup
273 // without calling these functions from app.cpp or from
274 // the user's application.
275 
276 class wxAnimationModule: public wxModule
277 {
278     wxDECLARE_DYNAMIC_CLASS(wxAnimationModule);
279 public:
wxAnimationModule()280     wxAnimationModule() {}
OnInit()281     bool OnInit() wxOVERRIDE { wxAnimation::InitStandardHandlers(); return true; }
OnExit()282     void OnExit() wxOVERRIDE { wxAnimation::CleanUpHandlers(); }
283 };
284 
285 wxIMPLEMENT_DYNAMIC_CLASS(wxAnimationModule, wxModule);
286 
287 #endif      // wxUSE_ANIMATIONCTRL
288