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