1 ///////////////////////////////////////////////////////////////////////////////
3 // Purpose: Implementation of wxAnimation classes
4 // Author: Julian Smart and Guillermo Rodriguez Garcia
8 // Copyright: (c) Julian Smart and Guillermo Rodriguez Garcia
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "animate.h"
16 #include "wx/wxprec.h"
22 #include "wx/wfstream.h"
24 #include "wx/gifdecod.h"
25 #include "wx/animate/animate.h"
31 IMPLEMENT_CLASS(wxAnimationPlayer
, wxObject
)
33 wxAnimationPlayer::wxAnimationPlayer(wxAnimationBase
*animation
, bool destroyAnimation
)
35 m_animation
= animation
;
36 m_destroyAnimation
= destroyAnimation
;
38 m_window
= (wxWindow
*) NULL
;
39 m_position
= wxPoint(0, 0);
42 m_useBackgroundColour
= FALSE
;
43 m_customBackgroundColour
= wxColour(0, 0, 0);
44 m_useCustomBackgroundColour
= FALSE
;
45 m_useParentBackground
= FALSE
;
46 m_timer
.SetPlayer(this);
49 wxAnimationPlayer::~wxAnimationPlayer()
54 if (m_destroyAnimation
)
58 void wxAnimationPlayer::SetAnimation(wxAnimationBase
* animation
, bool destroyAnimation
)
61 if (m_destroyAnimation
)
63 m_animation
= animation
;
64 m_destroyAnimation
= destroyAnimation
;
68 bool wxAnimationPlayer::Play(wxWindow
& window
, const wxPoint
& pos
, bool looped
)
72 if (!m_animation
|| !m_animation
->IsValid())
75 wxSize sz
= GetLogicalScreenSize();
79 if (m_frames
.Number() == 0)
83 wxLogWarning("wxAnimationPlayer::Play: could not build the image cache.");
89 // Create the backing store
90 m_backingStore
.Create(sz
.x
, sz
.y
);
97 // Build animation (list of wxImages). If not called before Play
98 // is called, Play will call this automatically.
99 bool wxAnimationPlayer::Build()
104 int n
= GetFrameCount();
106 for (i
= 0; i
< n
; i
++)
108 wxBitmap
* bitmap
= NULL
;
109 wxImage
* image
= GetFrame(i
);
112 // If the frame has transparency,
113 // set the colour so converting to a bitmap
114 // will create a mask
115 wxColour transparentColour
;
116 if (GetTransparentColour(transparentColour
))
117 image
->SetMaskColour(transparentColour
.Red(), transparentColour
.Green(), transparentColour
.Blue());
119 bitmap
= new wxBitmap(* image
);
122 m_frames
.Append(bitmap
);
135 // Stop the animation
136 void wxAnimationPlayer::Stop()
142 // Draw the current view of the animation into this DC.
143 // Call this from your OnPaint, for example.
144 void wxAnimationPlayer::Draw(wxDC
& dc
)
146 dc
.DrawBitmap(m_backingStore
, m_position
.x
, m_position
.y
);
150 int wxAnimationPlayer::GetFrameCount() const
153 return m_animation
->GetFrameCount();
158 wxImage
* wxAnimationPlayer::GetFrame(int i
) const
161 return m_animation
->GetFrame(i
);
163 return (wxImage
*) NULL
;
166 wxAnimationDisposal
wxAnimationPlayer::GetDisposalMethod(int i
) const
169 return m_animation
->GetDisposalMethod(i
);
171 return wxANIM_UNSPECIFIED
;
174 wxRect
wxAnimationPlayer::GetFrameRect(int i
) const
177 return m_animation
->GetFrameRect(i
);
179 return wxRect(0, 0, 0, 0);
182 int wxAnimationPlayer::GetDelay(int i
) const
185 return m_animation
->GetDelay(i
);
190 wxSize
wxAnimationPlayer::GetLogicalScreenSize() const
193 return m_animation
->GetLogicalScreenSize();
198 bool wxAnimationPlayer::GetBackgroundColour(wxColour
& col
) const
201 return m_animation
->GetBackgroundColour(col
);
206 bool wxAnimationPlayer::GetTransparentColour(wxColour
& col
) const
209 return m_animation
->GetTransparentColour(col
);
215 bool wxAnimationPlayer::PlayFrame(int frame
, wxWindow
& window
, wxPoint
& pos
)
218 dc
.SelectObject(m_backingStore
);
220 // Draw the background: colour or area beneath animation
221 wxColour
col(255, 255, 255);
223 if (UsingBackgroundColour())
225 if (UsingCustomBackgroundColour())
226 col
= GetCustomBackgroundColour();
229 GetBackgroundColour(col
);
232 // Draw the background colour loaded from the animation
233 // (or set by the user)
234 DrawBackground(dc
, wxPoint(0, 0), col
);
238 // Draw background we saved
239 dc
.DrawBitmap(m_savedBackground
, 0, 0);
242 // Draw all intermediate frames that haven't been removed from the
245 for (i
= 0; i
< (frame
- 1); i
++)
247 if ((GetDisposalMethod(i
) == wxANIM_DONOTREMOVE
) || (GetDisposalMethod(i
) == wxANIM_UNSPECIFIED
))
249 DrawFrame(i
, dc
, wxPoint(0, 0));
252 DrawFrame(frame
, dc
, wxPoint(0, 0));
254 dc
.SelectObject(wxNullBitmap
);
256 // Draw from backing bitmap onto window
257 wxClientDC
clientDC(& window
);
263 bool wxAnimationPlayer::PlayFrame()
267 PlayFrame(GetCurrentFrame(), * GetWindow(), GetPosition());
269 // Set the timer for the next frame
270 m_timer
.Start(GetDelay(GetCurrentFrame()));
274 if (m_currentFrame
== GetFrameCount())
276 // Should a non-looped animation display the last frame?
289 // Clear the wxImage cache
290 void wxAnimationPlayer::ClearCache()
292 wxNode
* node
= m_frames
.First();
295 wxNode
* next
= node
->Next();
296 wxBitmap
* bitmap
= (wxBitmap
*) node
->Data();
303 // Draw the background colour
304 void wxAnimationPlayer::DrawBackground(wxDC
& dc
, const wxPoint
& pos
, const wxColour
& colour
)
306 wxASSERT_MSG( (m_animation
!= NULL
), "Animation not present in wxAnimationPlayer");
307 wxASSERT_MSG( (m_frames
.Number() != 0), "Animation cache not present in wxAnimationPlayer");
309 // Optimization: if the first frame fills the whole area, and is non-transparent,
310 // don't bother drawing the background
312 wxBitmap
* firstBitmap
= (wxBitmap
*) m_frames
.First()->Data() ;
313 wxSize screenSize
= GetLogicalScreenSize();
314 if (!firstBitmap
->GetMask() && (firstBitmap
->GetWidth() == screenSize
.x
) && (firstBitmap
->GetHeight() == screenSize
.y
))
319 wxBrush
brush(colour
, wxSOLID
);
320 wxPen
pen(colour
, 1, wxSOLID
);
323 dc
.SetLogicalFunction(wxCOPY
);
325 dc
.DrawRectangle(pos
.x
, pos
.y
, screenSize
.x
, screenSize
.y
);
328 // Save the pertinent area of the window so we can restore
329 // it if drawing transparently
330 void wxAnimationPlayer::SaveBackground(const wxRect
& rect
)
332 wxASSERT( GetWindow() );
337 m_savedBackground
.Create(rect
.width
, rect
.height
);
340 memDC
.SelectObject(m_savedBackground
);
342 if (m_useParentBackground
&& GetWindow()->GetParent())
344 wxWindow
* parent
= GetWindow()->GetParent();
345 wxClientDC
dc(parent
);
347 // Translate the point to coordinates in the
348 // parent's client area, going via screen coordinates
349 wxPoint
pt(rect
.x
, rect
.y
);
350 wxPoint screenPt
= GetWindow()->ClientToScreen(pt
);
351 wxPoint parentPt
= parent
->ScreenToClient(screenPt
);
353 memDC
.Blit(0, 0, rect
.width
, rect
.height
, & dc
, parentPt
.x
, parentPt
.y
);
357 wxClientDC
dc(GetWindow());
359 memDC
.Blit(0, 0, rect
.width
, rect
.height
, & dc
, rect
.x
, rect
.y
);
361 memDC
.SelectObject(wxNullBitmap
);
365 void wxAnimationPlayer::DrawFrame(int frame
, wxDC
& dc
, const wxPoint
& pos
)
367 wxASSERT_MSG( (m_animation
!= NULL
), "Animation not present in wxAnimationPlayer");
368 wxASSERT_MSG( (m_frames
.Number() != 0), "Animation cache not present in wxAnimationPlayer");
369 wxASSERT_MSG( (m_frames
.Nth(frame
) != (wxNode
*) NULL
), "Image not present in wxAnimationPlayer::DrawFrame");
371 wxBitmap
* bitmap
= (wxBitmap
*) m_frames
.Nth(frame
)->Data() ;
373 wxRect rect
= GetFrameRect(frame
);
375 dc
.DrawBitmap(* bitmap
, pos
.x
+ rect
.x
, pos
.y
+ rect
.y
, (bitmap
->GetMask() != NULL
));
378 void wxAnimationTimer::Notify()
380 m_player
->PlayFrame();
387 IMPLEMENT_ABSTRACT_CLASS(wxAnimationBase
, wxObject
)
393 IMPLEMENT_CLASS(wxGIFAnimation
, wxAnimationBase
)
395 wxGIFAnimation::wxGIFAnimation()
397 m_decoder
= (wxGIFDecoder
*) NULL
;
400 wxGIFAnimation::~wxGIFAnimation()
405 int wxGIFAnimation::GetFrameCount() const
407 wxASSERT_MSG( (m_decoder
!= (wxGIFDecoder
*) NULL
), "m_decoder must be non-NULL");
409 return m_decoder
->GetNumberOfFrames();
412 wxImage
* wxGIFAnimation::GetFrame(int i
) const
414 wxASSERT_MSG( (m_decoder
!= (wxGIFDecoder
*) NULL
), "m_decoder must be non-NULL");
416 m_decoder
->GoFrame(i
);
418 wxImage
* image
= new wxImage
;
419 m_decoder
->ConvertToImage(image
);
423 wxAnimationDisposal
wxGIFAnimation::GetDisposalMethod(int i
) const
425 wxASSERT_MSG( (m_decoder
!= (wxGIFDecoder
*) NULL
), "m_decoder must be non-NULL");
427 m_decoder
->GoFrame(i
);
429 int disposalMethod
= m_decoder
->GetDisposalMethod();
430 return (wxAnimationDisposal
) disposalMethod
;
433 wxRect
wxGIFAnimation::GetFrameRect(int i
) const
435 wxASSERT_MSG( (m_decoder
!= (wxGIFDecoder
*) NULL
), "m_decoder must be non-NULL");
437 m_decoder
->GoFrame(i
);
439 wxRect
rect(m_decoder
->GetLeft(), m_decoder
->GetTop(), m_decoder
->GetWidth(), m_decoder
->GetHeight());
443 int wxGIFAnimation::GetDelay(int i
) const
445 wxASSERT_MSG( (m_decoder
!= (wxGIFDecoder
*) NULL
), "m_decoder must be non-NULL");
447 m_decoder
->GoFrame(i
);
448 return m_decoder
->GetDelay();
451 wxSize
wxGIFAnimation::GetLogicalScreenSize() const
453 wxASSERT_MSG( (m_decoder
!= (wxGIFDecoder
*) NULL
), "m_decoder must be non-NULL");
455 return wxSize(m_decoder
->GetLogicalScreenWidth(), m_decoder
->GetLogicalScreenHeight());
458 bool wxGIFAnimation::GetBackgroundColour(wxColour
& col
) const
460 wxASSERT_MSG( (m_decoder
!= (wxGIFDecoder
*) NULL
), "m_decoder must be non-NULL");
462 int i
= m_decoder
->GetBackgroundColour();
467 unsigned char* pal
= m_decoder
->GetPalette();
471 col
= wxColour(pal
[3*i
+ 0], pal
[3*i
+ 1], pal
[3*i
+ 2]);
479 bool wxGIFAnimation::GetTransparentColour(wxColour
& col
) const
481 wxASSERT_MSG( (m_decoder
!= (wxGIFDecoder
*) NULL
), "m_decoder must be non-NULL");
483 int i
= m_decoder
->GetTransparentColour();
488 unsigned char* pal
= m_decoder
->GetPalette();
492 col
= wxColour(pal
[3*i
+ 0], pal
[3*i
+ 1], pal
[3*i
+ 2]);
500 bool wxGIFAnimation::IsValid() const
502 return ((m_decoder
!= NULL
) && (m_decoder
->IsAnimation()));
505 bool wxGIFAnimation::LoadFile(const wxString
& filename
)
511 if (wxFileExists(filename
))
513 wxFileInputStream
stream(filename
);
514 m_decoder
= new wxGIFDecoder(& stream
, TRUE
);
516 if (m_decoder
->ReadGIF() != wxGIF_OK
)
523 if (!m_decoder
->IsAnimation())
538 * wxAnimationCtrlBase
539 * Abstract base class for format-specific animation controls.
540 * This class implements most of the functionality; all a derived
541 * class has to do is create the appropriate animation class on demand.
544 IMPLEMENT_ABSTRACT_CLASS(wxAnimationCtrlBase
, wxControl
)
546 BEGIN_EVENT_TABLE(wxAnimationCtrlBase
, wxControl
)
547 EVT_PAINT(wxAnimationCtrlBase::OnPaint
)
550 bool wxAnimationCtrlBase::Create(wxWindow
*parent
, wxWindowID id
,
551 const wxString
& filename
, const wxPoint
& pos
,
552 const wxSize
& size
, long style
, const wxString
& name
)
555 m_filename
= filename
;
557 if (!wxControl::Create(parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
560 SetBackgroundColour(parent
->GetBackgroundColour());
562 m_animationPlayer
.SetCustomBackgroundColour(GetBackgroundColour());
564 // Want to give the impression of transparency by painting
565 // the parent background
567 // m_animationPlayer.UseParentBackground(TRUE);
568 m_animationPlayer
.SetWindow(this);
569 m_animationPlayer
.SetPosition(wxPoint(0, 0));
570 m_animationPlayer
.SetDestroyAnimation(FALSE
);
575 wxAnimationCtrlBase::~wxAnimationCtrlBase()
577 if (m_animationPlayer
.IsPlaying())
578 m_animationPlayer
.Stop();
579 m_animationPlayer
.SetAnimation(NULL
, FALSE
);
583 bool wxAnimationCtrlBase::LoadFile(const wxString
& filename
)
585 if (m_animationPlayer
.IsPlaying())
586 m_animationPlayer
.Stop();
588 wxString
filename1(filename
);
590 if (filename1
.IsEmpty())
591 filename1
= m_filename
;
593 if (filename1
.IsEmpty())
602 m_animation
= DoCreateAnimation(filename1
);
606 if (!m_animation
->LoadFile(filename
) || !m_animation
->IsValid())
612 m_animationPlayer
.SetAnimation(m_animation
, FALSE
);
614 if (GetWindowStyle() & wxAN_FIT_ANIMATION
)
620 bool wxAnimationCtrlBase::Play(bool looped
)
622 return m_animationPlayer
.Play(*this, wxPoint(0, 0), looped
);
625 wxSize
wxAnimationCtrlBase::DoGetBestSize() const
627 if (m_animationPlayer
.HasAnimation() && (GetWindowStyle() & wxAN_FIT_ANIMATION
))
629 return m_animationPlayer
.GetLogicalScreenSize();
637 void wxAnimationCtrlBase::FitToAnimation()
639 if (!m_animationPlayer
.HasAnimation())
642 wxSize sz
= m_animationPlayer
.GetLogicalScreenSize();
646 void wxAnimationCtrlBase::OnPaint(wxPaintEvent
& event
)
650 if (GetPlayer().IsPlaying())
652 GetPlayer().Draw(dc
);
658 * Provides a GIF animation class when required.
661 IMPLEMENT_ABSTRACT_CLASS(wxGIFAnimationCtrl
, wxAnimationCtrlBase
)
663 wxAnimationBase
* wxGIFAnimationCtrl::DoCreateAnimation(const wxString
& WXUNUSED(filename
))
665 return new wxGIFAnimation
;