]>
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"
28 // ============================================================================
30 // ============================================================================
32 void gdk_pixbuf_area_updated(GdkPixbufLoader
*loader
,
39 if (anim
&& anim
->GetPixbuf() == NULL
)
41 // we need to set the pixbuf only if this is the first time this signal
43 anim
->SetPixbuf(gdk_pixbuf_loader_get_animation(loader
));
48 //-----------------------------------------------------------------------------
50 //-----------------------------------------------------------------------------
52 IMPLEMENT_DYNAMIC_CLASS(wxAnimation
, wxAnimationBase
)
54 wxAnimation::wxAnimation(const wxAnimation
& that
)
57 m_pixbuf
= that
.m_pixbuf
;
59 g_object_ref(m_pixbuf
);
62 wxAnimation
& wxAnimation::operator=(const wxAnimation
& that
)
66 base_type::operator=(that
);
68 m_pixbuf
= that
.m_pixbuf
;
70 g_object_ref(m_pixbuf
);
75 bool wxAnimation::LoadFile(const wxString
&name
, wxAnimationType
WXUNUSED(type
))
78 m_pixbuf
= gdk_pixbuf_animation_new_from_file(
79 wxConvFileName
->cWX2MB(name
), NULL
);
83 bool wxAnimation::Load(wxInputStream
&stream
, wxAnimationType type
)
90 case wxANIMATION_TYPE_GIF
:
91 strcpy(anim_type
, "gif");
94 case wxANIMATION_TYPE_ANI
:
95 strcpy(anim_type
, "ani");
103 // create a GdkPixbufLoader
104 GError
*error
= NULL
;
105 GdkPixbufLoader
*loader
;
106 if (type
!= wxANIMATION_TYPE_INVALID
&& type
!= wxANIMATION_TYPE_ANY
)
107 loader
= gdk_pixbuf_loader_new_with_type(anim_type
, &error
);
109 loader
= gdk_pixbuf_loader_new();
113 wxLogDebug(wxT("Could not create the loader for '%s' animation type"), anim_type
);
117 // connect to loader signals
118 g_signal_connect(loader
, "area-updated", G_CALLBACK(gdk_pixbuf_area_updated
), this);
121 while (stream
.IsOk())
123 // read a chunk of data
124 stream
.Read(buf
, sizeof(buf
));
126 // fetch all data into the loader
127 if (!gdk_pixbuf_loader_write(loader
, buf
, stream
.LastRead(), &error
))
129 gdk_pixbuf_loader_close(loader
, &error
);
130 wxLogDebug(wxT("Could not write to the loader"));
136 if (!gdk_pixbuf_loader_close(loader
, &error
))
138 wxLogDebug(wxT("Could not close the loader"));
142 // wait until we get the last area_updated signal
146 wxImage
wxAnimation::GetFrame(size_t i
) const
151 wxSize
wxAnimation::GetSize() const
153 return wxSize(gdk_pixbuf_animation_get_width(m_pixbuf
),
154 gdk_pixbuf_animation_get_height(m_pixbuf
));
157 void wxAnimation::UnRef()
160 g_object_unref(m_pixbuf
);
164 void wxAnimation::SetPixbuf(GdkPixbufAnimation
* p
)
169 g_object_ref(m_pixbuf
);
172 //-----------------------------------------------------------------------------
174 //-----------------------------------------------------------------------------
176 IMPLEMENT_DYNAMIC_CLASS(wxAnimationCtrl
, wxAnimationCtrlBase
)
177 BEGIN_EVENT_TABLE(wxAnimationCtrl
, wxAnimationCtrlBase
)
178 EVT_TIMER(wxID_ANY
, wxAnimationCtrl::OnTimer
)
181 void wxAnimationCtrl::Init()
188 bool wxAnimationCtrl::Create( wxWindow
*parent
, wxWindowID id
,
189 const wxAnimation
& anim
,
193 const wxString
& name
)
196 m_acceptsFocus
= true;
198 if (!PreCreation( parent
, pos
, size
) ||
199 !base_type::CreateBase(parent
, id
, pos
, size
, style
& wxWINDOW_STYLE_MASK
,
200 wxDefaultValidator
, name
))
202 wxFAIL_MSG( wxT("wxAnimationCtrl creation failed") );
206 SetWindowStyle(style
);
208 m_widget
= gtk_image_new();
209 gtk_widget_show( GTK_WIDGET(m_widget
) );
211 m_parent
->DoAddChild( this );
216 if (anim
!= wxNullAnimation
)
219 // init the timer used for animation
220 m_timer
.SetOwner(this);
225 wxAnimationCtrl::~wxAnimationCtrl()
231 bool wxAnimationCtrl::LoadFile(const wxString
&filename
, wxAnimationType type
)
234 if (!anim
.LoadFile(filename
, type
))
241 void wxAnimationCtrl::SetAnimation(const wxAnimation
&anim
)
249 // copy underlying GdkPixbuf object
250 m_anim
= anim
.GetPixbuf();
252 // m_anim may be null in case wxNullAnimation has been passed
255 // add a reference to the GdkPixbufAnimation
256 g_object_ref(m_anim
);
258 if (!this->HasFlag(wxAC_NO_AUTORESIZE
))
262 DisplayStaticImage();
265 void wxAnimationCtrl::FitToAnimation()
270 int w
= gdk_pixbuf_animation_get_width(m_anim
),
271 h
= gdk_pixbuf_animation_get_height(m_anim
);
273 // update our size to fit animation
277 void wxAnimationCtrl::ResetAnim()
280 g_object_unref(m_anim
);
284 void wxAnimationCtrl::ResetIter()
287 g_object_unref(m_iter
);
291 bool wxAnimationCtrl::Play()
296 // init the iterator and start a one-shot timer
298 m_iter
= gdk_pixbuf_animation_get_iter (m_anim
, NULL
);
301 // gdk_pixbuf_animation_iter_get_delay_time() may return -1 which means
302 // that the timer should not start
303 int n
= gdk_pixbuf_animation_iter_get_delay_time(m_iter
);
305 m_timer
.Start(n
, true);
310 void wxAnimationCtrl::Stop()
312 // leave current frame displayed until Play() is called again
318 DisplayStaticImage();
321 void wxAnimationCtrl::SetInactiveBitmap(const wxBitmap
&bmp
)
323 wxAnimationCtrlBase::SetInactiveBitmap(bmp
);
325 // update the pixbuf associated with m_widget now...
327 DisplayStaticImage();
330 void wxAnimationCtrl::DisplayStaticImage()
332 wxASSERT(!IsPlaying());
334 if (m_bmpStatic
.IsOk())
336 // show inactive bitmap
337 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
338 if (m_bmpStatic
.GetMask())
339 mask
= m_bmpStatic
.GetMask()->GetBitmap();
341 if (m_bmpStatic
.HasPixbuf())
343 gtk_image_set_from_pixbuf(GTK_IMAGE(m_widget
),
344 m_bmpStatic
.GetPixbuf());
348 gtk_image_set_from_pixmap(GTK_IMAGE(m_widget
),
349 m_bmpStatic
.GetPixmap(), mask
);
356 // even if not clearly documented, gdk_pixbuf_animation_get_static_image()
357 // always returns the first frame of the animation
358 gtk_image_set_from_pixbuf(GTK_IMAGE(m_widget
),
359 gdk_pixbuf_animation_get_static_image(m_anim
));
363 ClearToBackgroundColour();
368 bool wxAnimationCtrl::IsPlaying() const
370 // NB: we cannot just return m_timer.IsRunning() as this would not
371 // be safe as e.g. if we are displaying a frame forever,
372 // then we are "officially" still playing the animation, but
373 // the timer is not running anymore...
377 wxSize
wxAnimationCtrl::DoGetBestSize() const
379 if (m_anim
&& !this->HasFlag(wxAC_NO_AUTORESIZE
))
381 return wxSize(gdk_pixbuf_animation_get_width(m_anim
),
382 gdk_pixbuf_animation_get_height(m_anim
));
385 return wxSize(100,100);
388 void wxAnimationCtrl::ClearToBackgroundColour()
390 wxSize sz
= GetClientSize();
391 GdkPixbuf
*newpix
= gdk_pixbuf_new(GDK_COLORSPACE_RGB
, false, 8,
392 sz
.GetWidth(), sz
.GetHeight());
396 wxColour clr
= GetBackgroundColour();
397 guint32 col
= (clr
.Red() << 24) | (clr
.Green() << 16) | (clr
.Blue() << 8);
398 gdk_pixbuf_fill(newpix
, col
);
400 gtk_image_set_from_pixbuf(GTK_IMAGE(m_widget
), newpix
);
401 g_object_unref(newpix
);
404 bool wxAnimationCtrl::SetBackgroundColour( const wxColour
&colour
)
406 // wxWindowGTK::SetBackgroundColour works but since our m_widget is a GtkImage
407 // it won't show the background colour unlike the user would expect.
408 // Thus we clear the GtkImage contents to the background colour...
409 if (!wxControl::SetBackgroundColour(colour
))
411 ClearToBackgroundColour();
416 //-----------------------------------------------------------------------------
417 // wxAnimationCtrl - event handlers
418 //-----------------------------------------------------------------------------
420 void wxAnimationCtrl::OnTimer(wxTimerEvent
&ev
)
422 wxASSERT(m_iter
!= NULL
);
424 // gdk_pixbuf_animation_iter_advance() will automatically restart
425 // the animation, if necessary and we have no way to know !!
426 if (gdk_pixbuf_animation_iter_advance(m_iter
, NULL
))
428 // start a new one-shot timer
429 int n
= gdk_pixbuf_animation_iter_get_delay_time(m_iter
);
431 m_timer
.Start(n
, true);
433 gtk_image_set_from_pixbuf(GTK_IMAGE(m_widget
),
434 gdk_pixbuf_animation_iter_get_pixbuf(m_iter
));
438 // no need to update the m_widget yet
439 m_timer
.Start(10, true);
443 #endif // wxUSE_ANIMATIONCTRL