// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
-
-// ----------------------------------------------------------------------------
-// headers
-// ----------------------------------------------------------------------------
-
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
-#if wxUSE_ANIMATIONCTRL
+#if wxUSE_ANIMATIONCTRL && !defined(__WXUNIVERSAL__)
#include "wx/animate.h"
+
+#ifndef WX_PRECOMP
+ #include "wx/image.h"
+ #include "wx/log.h"
+ #include "wx/stream.h"
+#endif
+
+#include "wx/wfstream.h"
+#include "wx/gtk/private.h"
+
#include <gtk/gtk.h>
-#include <gtk/gtkimage.h>
// ============================================================================
// ============================================================================
void gdk_pixbuf_area_updated(GdkPixbufLoader *loader,
- gint x,
- gint y,
- gint width,
- gint height,
+ gint WXUNUSED(x),
+ gint WXUNUSED(y),
+ gint WXUNUSED(width),
+ gint WXUNUSED(height),
wxAnimation *anim)
{
if (anim && anim->GetPixbuf() == NULL)
IMPLEMENT_DYNAMIC_CLASS(wxAnimation, wxAnimationBase)
+wxAnimation::wxAnimation(const wxAnimation& that)
+ : base_type(that)
+{
+ m_pixbuf = that.m_pixbuf;
+ if (m_pixbuf)
+ g_object_ref(m_pixbuf);
+}
+
+wxAnimation::wxAnimation(GdkPixbufAnimation *p)
+{
+ m_pixbuf = p;
+ if ( m_pixbuf )
+ g_object_ref(m_pixbuf);
+}
+
+wxAnimation& wxAnimation::operator=(const wxAnimation& that)
+{
+ if (this != &that)
+ {
+ base_type::operator=(that);
+ UnRef();
+ m_pixbuf = that.m_pixbuf;
+ if (m_pixbuf)
+ g_object_ref(m_pixbuf);
+ }
+ return *this;
+}
+
bool wxAnimation::LoadFile(const wxString &name, wxAnimationType WXUNUSED(type))
{
UnRef();
- m_pixbuf = gdk_pixbuf_animation_new_from_file(name.c_str(), NULL);
+ m_pixbuf = gdk_pixbuf_animation_new_from_file(wxGTK_CONV_FN(name), NULL);
return IsOk();
}
break;
default:
+ anim_type[0] = '\0';
break;
}
else
loader = gdk_pixbuf_loader_new();
- if (!loader)
+ if (!loader ||
+ error != NULL) // even if the loader was allocated, an error could have happened
{
- wxLogDebug(wxT("Could not create the loader for '%s' animation type"), anim_type);
+ wxLogDebug(wxT("Could not create the loader for '%s' animation type: %s"),
+ anim_type, error->message);
return false;
}
// connect to loader signals
g_signal_connect(loader, "area-updated", G_CALLBACK(gdk_pixbuf_area_updated), this);
- //m_bLoadComplete = false;
guchar buf[2048];
+ bool data_written = false;
while (stream.IsOk())
{
// read a chunk of data
- stream.Read(buf, 2048);
+ if (!stream.Read(buf, sizeof(buf)) &&
+ stream.GetLastError() != wxSTREAM_EOF) // EOF is OK for now
+ {
+ // gdk_pixbuf_loader_close wants the GError == NULL
+ gdk_pixbuf_loader_close(loader, NULL);
+ return false;
+ }
// fetch all data into the loader
if (!gdk_pixbuf_loader_write(loader, buf, stream.LastRead(), &error))
{
- gdk_pixbuf_loader_close(loader, &error);
- wxLogDebug(wxT("Could not write to the loader"));
+ wxLogDebug(wxT("Could not write to the loader: %s"), error->message);
+
+ // gdk_pixbuf_loader_close wants the GError == NULL
+ gdk_pixbuf_loader_close(loader, NULL);
return false;
}
+
+ data_written = true;
+ }
+
+ if (!data_written)
+ {
+ wxLogDebug("Could not read data from the stream...");
+ return false;
}
- // load complete
+ // load complete: gdk_pixbuf_loader_close will now check if the data we
+ // wrote inside the pixbuf loader does make sense and will give an error
+ // if it doesn't (because of a truncated file, corrupted data or whatelse)
if (!gdk_pixbuf_loader_close(loader, &error))
{
- wxLogDebug(wxT("Could not close the loader"));
+ wxLogDebug(wxT("Could not close the loader: %s"), error->message);
return false;
}
- //m_bLoadComplete = true;
// wait until we get the last area_updated signal
- return true;
+ return data_written;
+}
+
+wxImage wxAnimation::GetFrame(unsigned int WXUNUSED(frame)) const
+{
+ return wxNullImage;
+}
+
+wxSize wxAnimation::GetSize() const
+{
+ return wxSize(gdk_pixbuf_animation_get_width(m_pixbuf),
+ gdk_pixbuf_animation_get_height(m_pixbuf));
+}
+
+void wxAnimation::UnRef()
+{
+ if (m_pixbuf)
+ g_object_unref(m_pixbuf);
+ m_pixbuf = NULL;
}
+void wxAnimation::SetPixbuf(GdkPixbufAnimation* p)
+{
+ UnRef();
+ m_pixbuf = p;
+ if (m_pixbuf)
+ g_object_ref(m_pixbuf);
+}
//-----------------------------------------------------------------------------
// wxAnimationCtrl
EVT_TIMER(wxID_ANY, wxAnimationCtrl::OnTimer)
END_EVENT_TABLE()
+void wxAnimationCtrl::Init()
+{
+ m_anim = NULL;
+ m_iter = NULL;
+ m_bPlaying = false;
+}
+
bool wxAnimationCtrl::Create( wxWindow *parent, wxWindowID id,
const wxAnimation& anim,
const wxPoint& pos,
long style,
const wxString& name)
{
- m_needParent = true;
- m_acceptsFocus = true;
-
if (!PreCreation( parent, pos, size ) ||
- !wxControl::CreateBase(parent, id, pos, size, style & wxWINDOW_STYLE_MASK,
+ !base_type::CreateBase(parent, id, pos, size, style & wxWINDOW_STYLE_MASK,
wxDefaultValidator, name))
{
wxFAIL_MSG( wxT("wxAnimationCtrl creation failed") );
SetWindowStyle(style);
m_widget = gtk_image_new();
- gtk_widget_show( GTK_WIDGET(m_widget) );
+ g_object_ref(m_widget);
m_parent->DoAddChild( this );
PostCreation(size);
- SetBestSize(size);
+ SetInitialSize(size);
- m_anim = NULL;
- m_iter = NULL;
- m_bPlaying = false;
- if (anim != wxNullAnimation)
+ if (anim.IsOk())
SetAnimation(anim);
// init the timer used for animation
}
bool wxAnimationCtrl::LoadFile(const wxString &filename, wxAnimationType type)
+{
+ wxFileInputStream fis(filename);
+ if (!fis.IsOk())
+ return false;
+ return Load(fis, type);
+}
+
+bool wxAnimationCtrl::Load(wxInputStream& stream, wxAnimationType type)
{
wxAnimation anim;
- if (!anim.LoadFile(filename, type))
+ if ( !anim.Load(stream, type) || !anim.IsOk() )
return false;
SetAnimation(anim);
if (!this->HasFlag(wxAC_NO_AUTORESIZE))
FitToAnimation();
-
- // display first frame
- gtk_image_set_from_pixbuf(GTK_IMAGE(m_widget),
- gdk_pixbuf_animation_get_static_image(m_anim));
- }
- else
- {
- // we need to clear the control to the background colour
- ClearToBackgroundColour();
}
+
+ DisplayStaticImage();
}
void wxAnimationCtrl::FitToAnimation()
h = gdk_pixbuf_animation_get_height(m_anim);
// update our size to fit animation
- //if (w > 0 && h > 0)
-// gtk_widget_set_size_request(m_widget, w, h);
- SetSize(w, h);
+ SetSize(w, h);
+}
+
+void wxAnimationCtrl::ResetAnim()
+{
+ if (m_anim)
+ g_object_unref(m_anim);
+ m_anim = NULL;
+}
+
+void wxAnimationCtrl::ResetIter()
+{
+ if (m_iter)
+ g_object_unref(m_iter);
+ m_iter = NULL;
}
bool wxAnimationCtrl::Play()
if (IsPlaying())
m_timer.Stop();
m_bPlaying = false;
+
+ ResetIter();
+ DisplayStaticImage();
+}
+
+void wxAnimationCtrl::DisplayStaticImage()
+{
+ wxASSERT(!IsPlaying());
+
+ // m_bmpStaticReal will be updated only if necessary...
+ UpdateStaticImage();
+
+ if (m_bmpStaticReal.IsOk())
+ {
+ // show inactive bitmap
+ gtk_image_set_from_pixbuf(GTK_IMAGE(m_widget),
+ m_bmpStaticReal.GetPixbuf());
+ }
+ else
+ {
+ if (m_anim)
+ {
+ // even if not clearly documented, gdk_pixbuf_animation_get_static_image()
+ // always returns the first frame of the animation
+ gtk_image_set_from_pixbuf(GTK_IMAGE(m_widget),
+ gdk_pixbuf_animation_get_static_image(m_anim));
+ }
+ else
+ {
+ ClearToBackgroundColour();
+ }
+ }
}
bool wxAnimationCtrl::IsPlaying() const
guint32 col = (clr.Red() << 24) | (clr.Green() << 16) | (clr.Blue() << 8);
gdk_pixbuf_fill(newpix, col);
- wxLogDebug(wxT("Clearing to background %s"), clr.GetAsString().c_str());
-
gtk_image_set_from_pixbuf(GTK_IMAGE(m_widget), newpix);
g_object_unref(newpix);
}
// Thus we clear the GtkImage contents to the background colour...
if (!wxControl::SetBackgroundColour(colour))
return false;
- ClearToBackgroundColour();
+
+ // if not playing the change must take place immediately but
+ // remember that the inactive bitmap has higher priority over the background
+ // colour; DisplayStaticImage() will handle that
+ if ( !IsPlaying() )
+ DisplayStaticImage();
+
return true;
}
// wxAnimationCtrl - event handlers
//-----------------------------------------------------------------------------
-void wxAnimationCtrl::OnTimer(wxTimerEvent &ev)
+void wxAnimationCtrl::OnTimer(wxTimerEvent& WXUNUSED(ev))
{
wxASSERT(m_iter != NULL);