]>
git.saurik.com Git - wxWidgets.git/blob - src/gtk/animate.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/animate.cpp
3 // Purpose: wxAnimation and wxAnimationCtrl
4 // Author: Francesco Montorsi
7 // Copyright: (c) Francesco Montorsi
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
14 #if wxUSE_ANIMATIONCTRL && !defined(__WXUNIVERSAL__)
16 #include "wx/animate.h"
21 #include "wx/stream.h"
24 #include "wx/wfstream.h"
25 #include "wx/gtk/private.h"
30 // ============================================================================
32 // ============================================================================
34 void gdk_pixbuf_area_updated(GdkPixbufLoader
*loader
,
38 gint
WXUNUSED(height
),
41 if (anim
&& anim
->GetPixbuf() == NULL
)
43 // we need to set the pixbuf only if this is the first time this signal
45 anim
->SetPixbuf(gdk_pixbuf_loader_get_animation(loader
));
50 //-----------------------------------------------------------------------------
52 //-----------------------------------------------------------------------------
54 IMPLEMENT_DYNAMIC_CLASS(wxAnimation
, wxAnimationBase
)
56 wxAnimation::wxAnimation(const wxAnimation
& that
)
59 m_pixbuf
= that
.m_pixbuf
;
61 g_object_ref(m_pixbuf
);
64 wxAnimation::wxAnimation(GdkPixbufAnimation
*p
)
68 g_object_ref(m_pixbuf
);
71 wxAnimation
& wxAnimation::operator=(const wxAnimation
& that
)
75 base_type::operator=(that
);
77 m_pixbuf
= that
.m_pixbuf
;
79 g_object_ref(m_pixbuf
);
84 bool wxAnimation::LoadFile(const wxString
&name
, wxAnimationType
WXUNUSED(type
))
87 m_pixbuf
= gdk_pixbuf_animation_new_from_file(wxGTK_CONV_FN(name
), NULL
);
91 bool wxAnimation::Load(wxInputStream
&stream
, wxAnimationType type
)
98 case wxANIMATION_TYPE_GIF
:
99 strcpy(anim_type
, "gif");
102 case wxANIMATION_TYPE_ANI
:
103 strcpy(anim_type
, "ani");
111 // create a GdkPixbufLoader
112 GError
*error
= NULL
;
113 GdkPixbufLoader
*loader
;
114 if (type
!= wxANIMATION_TYPE_INVALID
&& type
!= wxANIMATION_TYPE_ANY
)
115 loader
= gdk_pixbuf_loader_new_with_type(anim_type
, &error
);
117 loader
= gdk_pixbuf_loader_new();
120 error
!= NULL
) // even if the loader was allocated, an error could have happened
122 wxLogDebug(wxT("Could not create the loader for '%s' animation type: %s"),
123 anim_type
, error
->message
);
127 // connect to loader signals
128 g_signal_connect(loader
, "area-updated", G_CALLBACK(gdk_pixbuf_area_updated
), this);
131 bool data_written
= false;
132 while (stream
.IsOk())
134 // read a chunk of data
135 if (!stream
.Read(buf
, sizeof(buf
)) &&
136 stream
.GetLastError() != wxSTREAM_EOF
) // EOF is OK for now
138 // gdk_pixbuf_loader_close wants the GError == NULL
139 gdk_pixbuf_loader_close(loader
, NULL
);
143 // fetch all data into the loader
144 if (!gdk_pixbuf_loader_write(loader
, buf
, stream
.LastRead(), &error
))
146 wxLogDebug(wxT("Could not write to the loader: %s"), error
->message
);
148 // gdk_pixbuf_loader_close wants the GError == NULL
149 gdk_pixbuf_loader_close(loader
, NULL
);
158 wxLogDebug("Could not read data from the stream...");
162 // load complete: gdk_pixbuf_loader_close will now check if the data we
163 // wrote inside the pixbuf loader does make sense and will give an error
164 // if it doesn't (because of a truncated file, corrupted data or whatelse)
165 if (!gdk_pixbuf_loader_close(loader
, &error
))
167 wxLogDebug(wxT("Could not close the loader: %s"), error
->message
);
171 // wait until we get the last area_updated signal
175 wxImage
wxAnimation::GetFrame(unsigned int WXUNUSED(frame
)) const
180 wxSize
wxAnimation::GetSize() const
182 return wxSize(gdk_pixbuf_animation_get_width(m_pixbuf
),
183 gdk_pixbuf_animation_get_height(m_pixbuf
));
186 void wxAnimation::UnRef()
189 g_object_unref(m_pixbuf
);
193 void wxAnimation::SetPixbuf(GdkPixbufAnimation
* p
)
198 g_object_ref(m_pixbuf
);
201 //-----------------------------------------------------------------------------
203 //-----------------------------------------------------------------------------
205 IMPLEMENT_DYNAMIC_CLASS(wxAnimationCtrl
, wxAnimationCtrlBase
)
206 BEGIN_EVENT_TABLE(wxAnimationCtrl
, wxAnimationCtrlBase
)
207 EVT_TIMER(wxID_ANY
, wxAnimationCtrl::OnTimer
)
210 void wxAnimationCtrl::Init()
217 bool wxAnimationCtrl::Create( wxWindow
*parent
, wxWindowID id
,
218 const wxAnimation
& anim
,
222 const wxString
& name
)
224 if (!PreCreation( parent
, pos
, size
) ||
225 !base_type::CreateBase(parent
, id
, pos
, size
, style
& wxWINDOW_STYLE_MASK
,
226 wxDefaultValidator
, name
))
228 wxFAIL_MSG( wxT("wxAnimationCtrl creation failed") );
232 SetWindowStyle(style
);
234 m_widget
= gtk_image_new();
235 g_object_ref(m_widget
);
237 m_parent
->DoAddChild( this );
240 SetInitialSize(size
);
245 // init the timer used for animation
246 m_timer
.SetOwner(this);
251 wxAnimationCtrl::~wxAnimationCtrl()
257 bool wxAnimationCtrl::LoadFile(const wxString
&filename
, wxAnimationType type
)
259 wxFileInputStream
fis(filename
);
262 return Load(fis
, type
);
265 bool wxAnimationCtrl::Load(wxInputStream
& stream
, wxAnimationType type
)
268 if ( !anim
.Load(stream
, type
) || !anim
.IsOk() )
275 void wxAnimationCtrl::SetAnimation(const wxAnimation
&anim
)
283 // copy underlying GdkPixbuf object
284 m_anim
= anim
.GetPixbuf();
286 // m_anim may be null in case wxNullAnimation has been passed
289 // add a reference to the GdkPixbufAnimation
290 g_object_ref(m_anim
);
292 if (!this->HasFlag(wxAC_NO_AUTORESIZE
))
296 DisplayStaticImage();
299 void wxAnimationCtrl::FitToAnimation()
304 int w
= gdk_pixbuf_animation_get_width(m_anim
),
305 h
= gdk_pixbuf_animation_get_height(m_anim
);
307 // update our size to fit animation
311 void wxAnimationCtrl::ResetAnim()
314 g_object_unref(m_anim
);
318 void wxAnimationCtrl::ResetIter()
321 g_object_unref(m_iter
);
325 bool wxAnimationCtrl::Play()
330 // init the iterator and start a one-shot timer
332 m_iter
= gdk_pixbuf_animation_get_iter (m_anim
, NULL
);
335 // gdk_pixbuf_animation_iter_get_delay_time() may return -1 which means
336 // that the timer should not start
337 int n
= gdk_pixbuf_animation_iter_get_delay_time(m_iter
);
339 m_timer
.Start(n
, true);
344 void wxAnimationCtrl::Stop()
346 // leave current frame displayed until Play() is called again
352 DisplayStaticImage();
355 void wxAnimationCtrl::DisplayStaticImage()
357 wxASSERT(!IsPlaying());
359 // m_bmpStaticReal will be updated only if necessary...
362 if (m_bmpStaticReal
.IsOk())
364 // show inactive bitmap
365 gtk_image_set_from_pixbuf(GTK_IMAGE(m_widget
),
366 m_bmpStaticReal
.GetPixbuf());
372 // even if not clearly documented, gdk_pixbuf_animation_get_static_image()
373 // always returns the first frame of the animation
374 gtk_image_set_from_pixbuf(GTK_IMAGE(m_widget
),
375 gdk_pixbuf_animation_get_static_image(m_anim
));
379 ClearToBackgroundColour();
384 bool wxAnimationCtrl::IsPlaying() const
386 // NB: we cannot just return m_timer.IsRunning() as this would not
387 // be safe as e.g. if we are displaying a frame forever,
388 // then we are "officially" still playing the animation, but
389 // the timer is not running anymore...
393 wxSize
wxAnimationCtrl::DoGetBestSize() const
395 if (m_anim
&& !this->HasFlag(wxAC_NO_AUTORESIZE
))
397 return wxSize(gdk_pixbuf_animation_get_width(m_anim
),
398 gdk_pixbuf_animation_get_height(m_anim
));
401 return wxSize(100,100);
404 void wxAnimationCtrl::ClearToBackgroundColour()
406 wxSize sz
= GetClientSize();
407 GdkPixbuf
*newpix
= gdk_pixbuf_new(GDK_COLORSPACE_RGB
, false, 8,
408 sz
.GetWidth(), sz
.GetHeight());
412 wxColour clr
= GetBackgroundColour();
413 guint32 col
= (clr
.Red() << 24) | (clr
.Green() << 16) | (clr
.Blue() << 8);
414 gdk_pixbuf_fill(newpix
, col
);
416 gtk_image_set_from_pixbuf(GTK_IMAGE(m_widget
), newpix
);
417 g_object_unref(newpix
);
420 bool wxAnimationCtrl::SetBackgroundColour( const wxColour
&colour
)
422 // wxWindowGTK::SetBackgroundColour works but since our m_widget is a GtkImage
423 // it won't show the background colour unlike the user would expect.
424 // Thus we clear the GtkImage contents to the background colour...
425 if (!wxControl::SetBackgroundColour(colour
))
428 // if not playing the change must take place immediately but
429 // remember that the inactive bitmap has higher priority over the background
430 // colour; DisplayStaticImage() will handle that
432 DisplayStaticImage();
438 //-----------------------------------------------------------------------------
439 // wxAnimationCtrl - event handlers
440 //-----------------------------------------------------------------------------
442 void wxAnimationCtrl::OnTimer(wxTimerEvent
& WXUNUSED(ev
))
444 wxASSERT(m_iter
!= NULL
);
446 // gdk_pixbuf_animation_iter_advance() will automatically restart
447 // the animation, if necessary and we have no way to know !!
448 if (gdk_pixbuf_animation_iter_advance(m_iter
, NULL
))
450 // start a new one-shot timer
451 int n
= gdk_pixbuf_animation_iter_get_delay_time(m_iter
);
453 m_timer
.Start(n
, true);
455 gtk_image_set_from_pixbuf(GTK_IMAGE(m_widget
),
456 gdk_pixbuf_animation_iter_get_pixbuf(m_iter
));
460 // no need to update the m_widget yet
461 m_timer
.Start(10, true);
465 #endif // wxUSE_ANIMATIONCTRL