]>
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 
   8 // Copyright:   (c) Francesco Montorsi 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // For compilers that support precompilation, includes "wx.h". 
  13 #include "wx/wxprec.h" 
  15 #if wxUSE_ANIMATIONCTRL && !defined(__WXUNIVERSAL__) 
  17 #include "wx/animate.h" 
  22     #include "wx/stream.h" 
  25 #include "wx/wfstream.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(name
.fn_str(), 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
); 
 236     gtk_widget_show(m_widget
); 
 238     m_parent
->DoAddChild( this ); 
 241     SetInitialSize(size
); 
 246     // init the timer used for animation 
 247     m_timer
.SetOwner(this); 
 252 wxAnimationCtrl::~wxAnimationCtrl() 
 258 bool wxAnimationCtrl::LoadFile(const wxString 
&filename
, wxAnimationType type
) 
 260     wxFileInputStream 
fis(filename
); 
 263     return Load(fis
, type
); 
 266 bool wxAnimationCtrl::Load(wxInputStream
& stream
, wxAnimationType type
) 
 269     if ( !anim
.Load(stream
, type
) || !anim
.IsOk() ) 
 276 void wxAnimationCtrl::SetAnimation(const wxAnimation 
&anim
) 
 284     // copy underlying GdkPixbuf object 
 285     m_anim 
= anim
.GetPixbuf(); 
 287     // m_anim may be null in case wxNullAnimation has been passed 
 290         // add a reference to the GdkPixbufAnimation 
 291         g_object_ref(m_anim
); 
 293         if (!this->HasFlag(wxAC_NO_AUTORESIZE
)) 
 297     DisplayStaticImage(); 
 300 void wxAnimationCtrl::FitToAnimation() 
 305     int w 
= gdk_pixbuf_animation_get_width(m_anim
), 
 306         h 
= gdk_pixbuf_animation_get_height(m_anim
); 
 308     // update our size to fit animation 
 312 void wxAnimationCtrl::ResetAnim() 
 315         g_object_unref(m_anim
); 
 319 void wxAnimationCtrl::ResetIter() 
 322         g_object_unref(m_iter
); 
 326 bool wxAnimationCtrl::Play() 
 331     // init the iterator and start a one-shot timer 
 333     m_iter 
= gdk_pixbuf_animation_get_iter (m_anim
, NULL
); 
 336     // gdk_pixbuf_animation_iter_get_delay_time() may return -1 which means 
 337     // that the timer should not start 
 338     int n 
= gdk_pixbuf_animation_iter_get_delay_time(m_iter
); 
 340         m_timer
.Start(n
, true); 
 345 void wxAnimationCtrl::Stop() 
 347     // leave current frame displayed until Play() is called again 
 353     DisplayStaticImage(); 
 356 void wxAnimationCtrl::DisplayStaticImage() 
 358     wxASSERT(!IsPlaying()); 
 360     // m_bmpStaticReal will be updated only if necessary... 
 363     if (m_bmpStaticReal
.IsOk()) 
 365         // show inactive bitmap 
 366         GdkBitmap 
*mask 
= NULL
; 
 367         if (m_bmpStaticReal
.GetMask()) 
 368             mask 
= m_bmpStaticReal
.GetMask()->GetBitmap(); 
 370         if (m_bmpStaticReal
.HasPixbuf()) 
 372             gtk_image_set_from_pixbuf(GTK_IMAGE(m_widget
), 
 373                                       m_bmpStaticReal
.GetPixbuf()); 
 377             gtk_image_set_from_pixmap(GTK_IMAGE(m_widget
), 
 378                                       m_bmpStaticReal
.GetPixmap(), mask
); 
 385             // even if not clearly documented, gdk_pixbuf_animation_get_static_image() 
 386             // always returns the first frame of the animation 
 387             gtk_image_set_from_pixbuf(GTK_IMAGE(m_widget
), 
 388                                         gdk_pixbuf_animation_get_static_image(m_anim
)); 
 392             ClearToBackgroundColour(); 
 397 bool wxAnimationCtrl::IsPlaying() const 
 399     // NB: we cannot just return m_timer.IsRunning() as this would not 
 400     //     be safe as e.g. if we are displaying a frame forever, 
 401     //     then we are "officially" still playing the animation, but 
 402     //     the timer is not running anymore... 
 406 wxSize 
wxAnimationCtrl::DoGetBestSize() const 
 408     if (m_anim 
&& !this->HasFlag(wxAC_NO_AUTORESIZE
)) 
 410         return wxSize(gdk_pixbuf_animation_get_width(m_anim
), 
 411                       gdk_pixbuf_animation_get_height(m_anim
)); 
 414     return wxSize(100,100); 
 417 void wxAnimationCtrl::ClearToBackgroundColour() 
 419     wxSize sz 
= GetClientSize(); 
 420     GdkPixbuf 
*newpix 
= gdk_pixbuf_new(GDK_COLORSPACE_RGB
, false, 8, 
 421                                        sz
.GetWidth(), sz
.GetHeight()); 
 425     wxColour clr 
= GetBackgroundColour(); 
 426     guint32 col 
= (clr
.Red() << 24) | (clr
.Green() << 16) | (clr
.Blue() << 8); 
 427     gdk_pixbuf_fill(newpix
, col
); 
 429     gtk_image_set_from_pixbuf(GTK_IMAGE(m_widget
), newpix
); 
 430     g_object_unref(newpix
); 
 433 bool wxAnimationCtrl::SetBackgroundColour( const wxColour 
&colour 
) 
 435     // wxWindowGTK::SetBackgroundColour works but since our m_widget is a GtkImage 
 436     // it won't show the background colour unlike the user would expect. 
 437     // Thus we clear the GtkImage contents to the background colour... 
 438     if (!wxControl::SetBackgroundColour(colour
)) 
 441     // if not playing the change must take place immediately but 
 442     // remember that the inactive bitmap has higher priority over the background 
 443     // colour; DisplayStaticImage() will handle that 
 445         DisplayStaticImage(); 
 451 //----------------------------------------------------------------------------- 
 452 // wxAnimationCtrl - event handlers 
 453 //----------------------------------------------------------------------------- 
 455 void wxAnimationCtrl::OnTimer(wxTimerEvent
& WXUNUSED(ev
)) 
 457     wxASSERT(m_iter 
!= NULL
); 
 459     // gdk_pixbuf_animation_iter_advance() will automatically restart 
 460     // the animation, if necessary and we have no way to know !! 
 461     if (gdk_pixbuf_animation_iter_advance(m_iter
, NULL
)) 
 463         // start a new one-shot timer 
 464         int n 
= gdk_pixbuf_animation_iter_get_delay_time(m_iter
); 
 466             m_timer
.Start(n
, true); 
 468         gtk_image_set_from_pixbuf(GTK_IMAGE(m_widget
), 
 469                                   gdk_pixbuf_animation_iter_get_pixbuf(m_iter
)); 
 473         // no need to update the m_widget yet 
 474         m_timer
.Start(10, true); 
 478 #endif      // wxUSE_ANIMATIONCTRL