X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/fba93835f51b6c922bf3cc447367ed97ccd3d600..55410bb4f67febe1ca20654f078ea4fb9a6223ae:/src/gtk/animate.cpp diff --git a/src/gtk/animate.cpp b/src/gtk/animate.cpp index 27e535f8ef..1975fcf5d0 100644 --- a/src/gtk/animate.cpp +++ b/src/gtk/animate.cpp @@ -9,20 +9,22 @@ // 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" -#include "wx/log.h" + +#ifndef WX_PRECOMP + #include "wx/image.h" + #include "wx/log.h" + #include "wx/stream.h" +#endif + +#include "wx/wfstream.h" + #include -#include // ============================================================================ @@ -30,10 +32,10 @@ // ============================================================================ 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) @@ -51,11 +53,38 @@ void gdk_pixbuf_area_updated(GdkPixbufLoader *loader, 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( - wxConvFileName->cWX2MB(name), NULL); + m_pixbuf = gdk_pixbuf_animation_new_from_file(name.fn_str(), NULL); return IsOk(); } @@ -75,6 +104,7 @@ bool wxAnimation::Load(wxInputStream &stream, wxAnimationType type) break; default: + anim_type[0] = '\0'; break; } @@ -86,43 +116,87 @@ bool wxAnimation::Load(wxInputStream &stream, wxAnimationType type) 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 @@ -133,6 +207,13 @@ BEGIN_EVENT_TABLE(wxAnimationCtrl, wxAnimationCtrlBase) 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, @@ -140,11 +221,8 @@ bool wxAnimationCtrl::Create( wxWindow *parent, wxWindowID id, 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") ); @@ -154,17 +232,15 @@ bool wxAnimationCtrl::Create( wxWindow *parent, wxWindowID id, SetWindowStyle(style); m_widget = gtk_image_new(); - gtk_widget_show( GTK_WIDGET(m_widget) ); + g_object_ref(m_widget); + gtk_widget_show(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 @@ -180,9 +256,17 @@ wxAnimationCtrl::~wxAnimationCtrl() } 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); @@ -208,16 +292,9 @@ void wxAnimationCtrl::SetAnimation(const wxAnimation &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() @@ -229,9 +306,21 @@ 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() @@ -259,6 +348,50 @@ void wxAnimationCtrl::Stop() 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 + GdkBitmap *mask = NULL; + if (m_bmpStaticReal.GetMask()) + mask = m_bmpStaticReal.GetMask()->GetBitmap(); + + if (m_bmpStaticReal.HasPixbuf()) + { + gtk_image_set_from_pixbuf(GTK_IMAGE(m_widget), + m_bmpStaticReal.GetPixbuf()); + } + else + { + gtk_image_set_from_pixmap(GTK_IMAGE(m_widget), + m_bmpStaticReal.GetPixmap(), mask); + } + } + 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 @@ -293,8 +426,6 @@ void wxAnimationCtrl::ClearToBackgroundColour() 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); } @@ -306,7 +437,13 @@ bool wxAnimationCtrl::SetBackgroundColour( const wxColour &colour ) // 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; } @@ -315,7 +452,7 @@ bool wxAnimationCtrl::SetBackgroundColour( const wxColour &colour ) // wxAnimationCtrl - event handlers //----------------------------------------------------------------------------- -void wxAnimationCtrl::OnTimer(wxTimerEvent &ev) +void wxAnimationCtrl::OnTimer(wxTimerEvent& WXUNUSED(ev)) { wxASSERT(m_iter != NULL);