]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/animate.cpp
Compile fix.
[wxWidgets.git] / src / gtk / animate.cpp
CommitLineData
72045d57
VZ
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/gtk/animate.cpp
3// Purpose: wxAnimation and wxAnimationCtrl
4// Author: Francesco Montorsi
5// Modified By:
6// Created: 24/09/2006
7// Id: $Id$
8// Copyright: (c) Francesco Montorsi
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12
13// ----------------------------------------------------------------------------
14// headers
15// ----------------------------------------------------------------------------
16
17// For compilers that support precompilation, includes "wx.h".
18#include "wx/wxprec.h"
19
20#if wxUSE_ANIMATIONCTRL
21
22#include "wx/animate.h"
23#include <gtk/gtk.h>
24#include <gtk/gtkimage.h>
25
26
27// ============================================================================
28// implementation
29// ============================================================================
30
31void gdk_pixbuf_area_updated(GdkPixbufLoader *loader,
32 gint x,
33 gint y,
34 gint width,
35 gint height,
36 wxAnimation *anim)
37{
38 if (anim && anim->GetPixbuf() == NULL)
39 {
40 // we need to set the pixbuf only if this is the first time this signal
41 // has been called!
42 anim->SetPixbuf(gdk_pixbuf_loader_get_animation(loader));
43 }
44}
45
46
47//-----------------------------------------------------------------------------
48// wxAnimation
49//-----------------------------------------------------------------------------
50
51IMPLEMENT_DYNAMIC_CLASS(wxAnimation, wxAnimationBase)
52
53bool wxAnimation::LoadFile(const wxString &name, wxAnimationType WXUNUSED(type))
54{
55 UnRef();
56 m_pixbuf = gdk_pixbuf_animation_new_from_file(name.c_str(), NULL);
57 return IsOk();
58}
59
60bool wxAnimation::Load(wxInputStream &stream, wxAnimationType type)
61{
62 UnRef();
63
64 char anim_type[12];
65 switch (type)
66 {
67 case wxANIMATION_TYPE_GIF:
68 strcpy(anim_type, "gif");
69 break;
70
71 case wxANIMATION_TYPE_ANI:
72 strcpy(anim_type, "ani");
73 break;
74
75 default:
76 break;
77 }
78
79 // create a GdkPixbufLoader
80 GError *error = NULL;
81 GdkPixbufLoader *loader;
82 if (type != wxANIMATION_TYPE_INVALID && type != wxANIMATION_TYPE_ANY)
83 loader = gdk_pixbuf_loader_new_with_type(anim_type, &error);
84 else
85 loader = gdk_pixbuf_loader_new();
86
87 if (!loader)
88 {
89 wxLogDebug(wxT("Could not create the loader for '%s' animation type"), anim_type);
90 return false;
91 }
92
93 // connect to loader signals
94 g_signal_connect(loader, "area-updated", G_CALLBACK(gdk_pixbuf_area_updated), this);
95
96 //m_bLoadComplete = false;
97 guchar buf[2048];
98 while (stream.IsOk())
99 {
100 // read a chunk of data
101 stream.Read(buf, 2048);
102
103 // fetch all data into the loader
104 if (!gdk_pixbuf_loader_write(loader, buf, stream.LastRead(), &error))
105 {
106 gdk_pixbuf_loader_close(loader, &error);
107 wxLogDebug(wxT("Could not write to the loader"));
108 return false;
109 }
110 }
111
112 // load complete
113 if (!gdk_pixbuf_loader_close(loader, &error))
114 {
115 wxLogDebug(wxT("Could not close the loader"));
116 return false;
117 }
118 //m_bLoadComplete = true;
119
120 // wait until we get the last area_updated signal
121 return true;
122}
123
124
125//-----------------------------------------------------------------------------
126// wxAnimationCtrl
127//-----------------------------------------------------------------------------
128
129IMPLEMENT_DYNAMIC_CLASS(wxAnimationCtrl, wxAnimationCtrlBase)
130BEGIN_EVENT_TABLE(wxAnimationCtrl, wxAnimationCtrlBase)
131 EVT_TIMER(wxID_ANY, wxAnimationCtrl::OnTimer)
132END_EVENT_TABLE()
133
134bool wxAnimationCtrl::Create( wxWindow *parent, wxWindowID id,
135 const wxAnimation& anim,
136 const wxPoint& pos,
137 const wxSize& size,
138 long style,
139 const wxString& name)
140{
141 m_needParent = true;
142 m_acceptsFocus = true;
143
144 if (!PreCreation( parent, pos, size ) ||
145 !wxControl::CreateBase(parent, id, pos, size, style & wxWINDOW_STYLE_MASK,
146 wxDefaultValidator, name))
147 {
148 wxFAIL_MSG( wxT("wxAnimationCtrl creation failed") );
149 return false;
150 }
151
152 SetWindowStyle(style);
153
154 m_widget = gtk_image_new();
155 gtk_widget_show( GTK_WIDGET(m_widget) );
156
157 m_parent->DoAddChild( this );
158
159 PostCreation(size);
160 SetBestSize(size);
161
162 m_anim = NULL;
163 m_iter = NULL;
164 m_bPlaying = false;
165 if (anim != wxNullAnimation)
166 SetAnimation(anim);
167
168 // init the timer used for animation
169 m_timer.SetOwner(this);
170
171 return true;
172}
173
174wxAnimationCtrl::~wxAnimationCtrl()
175{
176 ResetAnim();
177 ResetIter();
178}
179
180bool wxAnimationCtrl::LoadFile(const wxString &filename, wxAnimationType type)
181{
182 wxAnimation anim;
183 if (!anim.LoadFile(filename, type))
184 return false;
185
186 SetAnimation(anim);
187 return true;
188}
189
190void wxAnimationCtrl::SetAnimation(const wxAnimation &anim)
191{
192 if (IsPlaying())
193 Stop();
194
195 ResetAnim();
196 ResetIter();
197
198 // copy underlying GdkPixbuf object
199 m_anim = anim.GetPixbuf();
200
201 // m_anim may be null in case wxNullAnimation has been passed
202 if (m_anim)
203 {
204 // add a reference to the GdkPixbufAnimation
205 g_object_ref(m_anim);
206
207 if (!this->HasFlag(wxAC_NO_AUTORESIZE))
208 FitToAnimation();
209
210 // display first frame
211 gtk_image_set_from_pixbuf(GTK_IMAGE(m_widget),
212 gdk_pixbuf_animation_get_static_image(m_anim));
213 }
214 else
215 {
216 // we need to clear the control to the background colour
217 ClearToBackgroundColour();
218 }
219}
220
221void wxAnimationCtrl::FitToAnimation()
222{
223 if (!m_anim)
224 return;
225
226 int w = gdk_pixbuf_animation_get_width(m_anim),
227 h = gdk_pixbuf_animation_get_height(m_anim);
228
229 // update our size to fit animation
230 //if (w > 0 && h > 0)
231// gtk_widget_set_size_request(m_widget, w, h);
232 SetSize(w, h);
233}
234
235bool wxAnimationCtrl::Play()
236{
237 if (m_anim == NULL)
238 return false;
239
240 // init the iterator and start a one-shot timer
241 ResetIter();
242 m_iter = gdk_pixbuf_animation_get_iter (m_anim, NULL);
243 m_bPlaying = true;
244
245 // gdk_pixbuf_animation_iter_get_delay_time() may return -1 which means
246 // that the timer should not start
247 int n = gdk_pixbuf_animation_iter_get_delay_time(m_iter);
248 if (n >= 0)
249 m_timer.Start(n, true);
250
251 return true;
252}
253
254void wxAnimationCtrl::Stop()
255{
256 // leave current frame displayed until Play() is called again
257 if (IsPlaying())
258 m_timer.Stop();
259 m_bPlaying = false;
260}
261
262bool wxAnimationCtrl::IsPlaying() const
263{
264 // NB: we cannot just return m_timer.IsRunning() as this would not
265 // be safe as e.g. if we are displaying a frame forever,
266 // then we are "officially" still playing the animation, but
267 // the timer is not running anymore...
268 return m_bPlaying;
269}
270
271wxSize wxAnimationCtrl::DoGetBestSize() const
272{
273 if (m_anim && !this->HasFlag(wxAC_NO_AUTORESIZE))
274 {
275 return wxSize(gdk_pixbuf_animation_get_width(m_anim),
276 gdk_pixbuf_animation_get_height(m_anim));
277 }
278
279 return wxSize(100,100);
280}
281
282void wxAnimationCtrl::ClearToBackgroundColour()
283{
284 wxSize sz = GetClientSize();
285 GdkPixbuf *newpix = gdk_pixbuf_new(GDK_COLORSPACE_RGB, false, 8,
286 sz.GetWidth(), sz.GetHeight());
287 if (!newpix)
288 return;
289
290 wxColour clr = GetBackgroundColour();
291 guint32 col = (clr.Red() << 24) | (clr.Green() << 16) | (clr.Blue() << 8);
292 gdk_pixbuf_fill(newpix, col);
293
294 wxLogDebug(wxT("Clearing to background %s"), clr.GetAsString().c_str());
295
296 gtk_image_set_from_pixbuf(GTK_IMAGE(m_widget), newpix);
297 g_object_unref(newpix);
298}
299
300bool wxAnimationCtrl::SetBackgroundColour( const wxColour &colour )
301{
302 // wxWindowGTK::SetBackgroundColour works but since our m_widget is a GtkImage
303 // it won't show the background colour unlike the user would expect.
304 // Thus we clear the GtkImage contents to the background colour...
305 if (!wxControl::SetBackgroundColour(colour))
306 return false;
307 ClearToBackgroundColour();
308 return true;
309}
310
311
312//-----------------------------------------------------------------------------
313// wxAnimationCtrl - event handlers
314//-----------------------------------------------------------------------------
315
316void wxAnimationCtrl::OnTimer(wxTimerEvent &ev)
317{
318 wxASSERT(m_iter != NULL);
319
320 // gdk_pixbuf_animation_iter_advance() will automatically restart
321 // the animation, if necessary and we have no way to know !!
322 if (gdk_pixbuf_animation_iter_advance(m_iter, NULL))
323 {
324 // start a new one-shot timer
325 int n = gdk_pixbuf_animation_iter_get_delay_time(m_iter);
326 if (n >= 0)
327 m_timer.Start(n, true);
328
329 gtk_image_set_from_pixbuf(GTK_IMAGE(m_widget),
330 gdk_pixbuf_animation_iter_get_pixbuf(m_iter));
331 }
332 else
333 {
334 // no need to update the m_widget yet
335 m_timer.Start(10, true);
336 }
337}
338
339#endif // wxUSE_ANIMATIONCTRL