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"
26 #include "wx/dcmemory.h"
27 #include "wx/animate/animate.h"
29 #include "wx/dcclient.h"
35 IMPLEMENT_CLASS(wxAnimationPlayer
, wxObject
)
37 wxAnimationPlayer::wxAnimationPlayer(wxAnimationBase
*animation
, bool destroyAnimation
)
39 m_animation
= animation
;
40 m_destroyAnimation
= destroyAnimation
;
42 m_window
= (wxWindow
*) NULL
;
43 m_position
= wxPoint(0, 0);
46 m_useBackgroundColour
= FALSE
;
47 m_customBackgroundColour
= wxColour(0, 0, 0);
48 m_useCustomBackgroundColour
= FALSE
;
49 m_useParentBackground
= FALSE
;
50 m_timer
.SetPlayer(this);
53 wxAnimationPlayer::~wxAnimationPlayer()
58 if (m_destroyAnimation
)
62 void wxAnimationPlayer::SetAnimation(wxAnimationBase
* animation
, bool destroyAnimation
)
65 if (m_destroyAnimation
)
67 m_animation
= animation
;
68 m_destroyAnimation
= destroyAnimation
;
72 bool wxAnimationPlayer::Play(wxWindow
& window
, const wxPoint
& pos
, bool WXUNUSED(looped
))
76 if (!m_animation
|| !m_animation
->IsValid())
79 wxSize sz
= GetLogicalScreenSize();
83 if (m_frames
.GetCount() == 0)
87 wxLogWarning(_T("wxAnimationPlayer::Play: could not build the image cache."));
93 // Create the backing store
94 m_backingStore
.Create(sz
.x
, sz
.y
);
101 // Build animation (list of wxImages). If not called before Play
102 // is called, Play will call this automatically.
103 bool wxAnimationPlayer::Build()
108 int n
= GetFrameCount();
110 for (i
= 0; i
< n
; i
++)
112 wxImage
* image
= GetFrame(i
);
115 // If the frame has transparency,
116 // set the colour so converting to a bitmap
117 // will create a mask
118 wxColour transparentColour
;
119 if (GetTransparentColour(transparentColour
))
120 image
->SetMaskColour(transparentColour
.Red(), transparentColour
.Green(), transparentColour
.Blue());
122 wxBitmap
* bitmap
= new wxBitmap(* image
);
125 m_frames
.Append(bitmap
);
138 // Stop the animation
139 void wxAnimationPlayer::Stop()
145 // Draw the current view of the animation into this DC.
146 // Call this from your OnPaint, for example.
147 void wxAnimationPlayer::Draw(wxDC
& dc
)
149 dc
.DrawBitmap(m_backingStore
, m_position
.x
, m_position
.y
);
153 int wxAnimationPlayer::GetFrameCount() const
156 return m_animation
->GetFrameCount();
161 wxImage
* wxAnimationPlayer::GetFrame(int i
) const
164 return m_animation
->GetFrame(i
);
166 return (wxImage
*) NULL
;
169 wxAnimationDisposal
wxAnimationPlayer::GetDisposalMethod(int i
) const
172 return m_animation
->GetDisposalMethod(i
);
174 return wxANIM_UNSPECIFIED
;
177 wxRect
wxAnimationPlayer::GetFrameRect(int i
) const
180 return m_animation
->GetFrameRect(i
);
182 return wxRect(0, 0, 0, 0);
185 int wxAnimationPlayer::GetDelay(int i
) const
188 return m_animation
->GetDelay(i
);
193 wxSize
wxAnimationPlayer::GetLogicalScreenSize() const
196 return m_animation
->GetLogicalScreenSize();
201 bool wxAnimationPlayer::GetBackgroundColour(wxColour
& col
) const
204 return m_animation
->GetBackgroundColour(col
);
209 bool wxAnimationPlayer::GetTransparentColour(wxColour
& col
) const
212 return m_animation
->GetTransparentColour(col
);
218 bool wxAnimationPlayer::PlayFrame(int frame
, wxWindow
& window
, const wxPoint
& WXUNUSED(pos
))
221 dc
.SelectObject(m_backingStore
);
223 // Draw the background: colour or area beneath animation
224 wxColour
col(255, 255, 255);
226 if (UsingBackgroundColour())
228 if (UsingCustomBackgroundColour())
229 col
= GetCustomBackgroundColour();
232 GetBackgroundColour(col
);
235 // Draw the background colour loaded from the animation
236 // (or set by the user)
237 DrawBackground(dc
, wxPoint(0, 0), col
);
241 // Draw background we saved
242 dc
.DrawBitmap(m_savedBackground
, 0, 0);
245 // Draw all intermediate frames that haven't been removed from the
248 for (i
= 0; i
< frame
; i
++)
250 if ((GetDisposalMethod(i
) == wxANIM_DONOTREMOVE
) || (GetDisposalMethod(i
) == wxANIM_UNSPECIFIED
))
252 DrawFrame(i
, dc
, wxPoint(0, 0));
255 DrawFrame(frame
, dc
, wxPoint(0, 0));
257 dc
.SelectObject(wxNullBitmap
);
259 // Draw from backing bitmap onto window
260 wxClientDC
clientDC(& window
);
266 bool wxAnimationPlayer::PlayFrame()
270 PlayFrame(GetCurrentFrame(), * GetWindow(), GetPosition());
272 // Set the timer for the next frame
273 int delay
= GetDelay(GetCurrentFrame());
275 delay
= 1; // 0 is invalid timeout for wxTimer.
277 m_timer
.Start(delay
);
281 if (m_currentFrame
== GetFrameCount())
283 // Should a non-looped animation display the last frame?
296 // Clear the wxImage cache
297 void wxAnimationPlayer::ClearCache()
299 wxList::compatibility_iterator node
= m_frames
.GetFirst();
302 wxList::compatibility_iterator next
= node
->GetNext();
303 wxBitmap
* bitmap
= (wxBitmap
*) node
->GetData();
305 m_frames
.Erase(node
);
310 // Draw the background colour
311 void wxAnimationPlayer::DrawBackground(wxDC
& dc
, const wxPoint
& pos
, const wxColour
& colour
)
313 wxASSERT_MSG( (m_animation
!= NULL
), _T("Animation not present in wxAnimationPlayer"));
314 wxASSERT_MSG( (m_frames
.GetCount() != 0), _T("Animation cache not present in wxAnimationPlayer"));
316 // Optimization: if the first frame fills the whole area, and is non-transparent,
317 // don't bother drawing the background
319 wxBitmap
* firstBitmap
= (wxBitmap
*) m_frames
.GetFirst()->GetData() ;
320 wxSize screenSize
= GetLogicalScreenSize();
321 if (!firstBitmap
->GetMask() && (firstBitmap
->GetWidth() == screenSize
.x
) && (firstBitmap
->GetHeight() == screenSize
.y
))
326 wxBrush
brush(colour
, wxSOLID
);
327 wxPen
pen(colour
, 1, wxSOLID
);
330 dc
.SetLogicalFunction(wxCOPY
);
332 dc
.DrawRectangle(pos
.x
, pos
.y
, screenSize
.x
, screenSize
.y
);
335 // Save the pertinent area of the window so we can restore
336 // it if drawing transparently
337 void wxAnimationPlayer::SaveBackground(const wxRect
& rect
)
339 wxASSERT( GetWindow() );
344 m_savedBackground
.Create(rect
.width
, rect
.height
);
347 memDC
.SelectObject(m_savedBackground
);
349 if (m_useParentBackground
&& GetWindow()->GetParent())
351 wxWindow
* parent
= GetWindow()->GetParent();
352 wxClientDC
dc(parent
);
354 // Translate the point to coordinates in the
355 // parent's client area, going via screen coordinates
356 wxPoint
pt(rect
.x
, rect
.y
);
357 wxPoint screenPt
= GetWindow()->ClientToScreen(pt
);
358 wxPoint parentPt
= parent
->ScreenToClient(screenPt
);
360 memDC
.Blit(0, 0, rect
.width
, rect
.height
, & dc
, parentPt
.x
, parentPt
.y
);
364 wxClientDC
dc(GetWindow());
366 memDC
.Blit(0, 0, rect
.width
, rect
.height
, & dc
, rect
.x
, rect
.y
);
368 memDC
.SelectObject(wxNullBitmap
);
372 void wxAnimationPlayer::DrawFrame(int frame
, wxDC
& dc
, const wxPoint
& pos
)
374 wxASSERT_MSG( (m_animation
!= NULL
), _T("Animation not present in wxAnimationPlayer"));
375 wxASSERT_MSG( (m_frames
.GetCount() != 0), _T("Animation cache not present in wxAnimationPlayer"));
376 wxASSERT_MSG( !!m_frames
.Item(frame
), _T("Image not present in wxAnimationPlayer::DrawFrame"));
378 wxBitmap
* bitmap
= (wxBitmap
*) m_frames
.Item(frame
)->GetData() ;
380 wxRect rect
= GetFrameRect(frame
);
382 dc
.DrawBitmap(* bitmap
, pos
.x
+ rect
.x
, pos
.y
+ rect
.y
, (bitmap
->GetMask() != NULL
));
385 void wxAnimationTimer::Notify()
387 m_player
->PlayFrame();
394 IMPLEMENT_ABSTRACT_CLASS(wxAnimationBase
, wxObject
)
400 IMPLEMENT_CLASS(wxGIFAnimation
, wxAnimationBase
)
402 wxGIFAnimation::wxGIFAnimation()
404 m_decoder
= (wxGIFDecoder
*) NULL
;
407 wxGIFAnimation::~wxGIFAnimation()
412 int wxGIFAnimation::GetFrameCount() const
414 wxASSERT_MSG( (m_decoder
!= (wxGIFDecoder
*) NULL
), _T("m_decoder must be non-NULL"));
416 return m_decoder
->GetNumberOfFrames();
419 wxImage
* wxGIFAnimation::GetFrame(int i
) const
421 wxASSERT_MSG( (m_decoder
!= (wxGIFDecoder
*) NULL
), _T("m_decoder must be non-NULL"));
423 m_decoder
->GoFrame(i
+ 1);
425 wxImage
* image
= new wxImage
;
426 m_decoder
->ConvertToImage(image
);
430 wxAnimationDisposal
wxGIFAnimation::GetDisposalMethod(int i
) const
432 wxASSERT_MSG( (m_decoder
!= (wxGIFDecoder
*) NULL
), _T("m_decoder must be non-NULL"));
434 m_decoder
->GoFrame(i
+ 1);
436 int disposalMethod
= m_decoder
->GetDisposalMethod();
437 return (wxAnimationDisposal
) disposalMethod
;
440 wxRect
wxGIFAnimation::GetFrameRect(int i
) const
442 wxASSERT_MSG( (m_decoder
!= (wxGIFDecoder
*) NULL
), _T("m_decoder must be non-NULL"));
444 m_decoder
->GoFrame(i
+ 1);
446 wxRect
rect(m_decoder
->GetLeft(), m_decoder
->GetTop(), m_decoder
->GetWidth(), m_decoder
->GetHeight());
450 int wxGIFAnimation::GetDelay(int i
) const
452 wxASSERT_MSG( (m_decoder
!= (wxGIFDecoder
*) NULL
), _T("m_decoder must be non-NULL"));
454 m_decoder
->GoFrame(i
+ 1);
455 return m_decoder
->GetDelay();
458 wxSize
wxGIFAnimation::GetLogicalScreenSize() const
460 wxASSERT_MSG( (m_decoder
!= (wxGIFDecoder
*) NULL
), _T("m_decoder must be non-NULL"));
462 return wxSize(m_decoder
->GetLogicalScreenWidth(), m_decoder
->GetLogicalScreenHeight());
465 bool wxGIFAnimation::GetBackgroundColour(wxColour
& col
) const
467 wxASSERT_MSG( (m_decoder
!= (wxGIFDecoder
*) NULL
), _T("m_decoder must be non-NULL"));
469 int i
= m_decoder
->GetBackgroundColour();
474 unsigned char* pal
= m_decoder
->GetPalette();
478 col
= wxColour(pal
[3*i
+ 0], pal
[3*i
+ 1], pal
[3*i
+ 2]);
486 bool wxGIFAnimation::GetTransparentColour(wxColour
& col
) const
488 wxASSERT_MSG( (m_decoder
!= (wxGIFDecoder
*) NULL
), _T("m_decoder must be non-NULL"));
490 int i
= m_decoder
->GetTransparentColour();
495 unsigned char* pal
= m_decoder
->GetPalette();
499 col
= wxColour(pal
[3*i
+ 0], pal
[3*i
+ 1], pal
[3*i
+ 2]);
507 bool wxGIFAnimation::IsValid() const
509 return ((m_decoder
!= NULL
) && (m_decoder
->IsAnimation()));
512 bool wxGIFAnimation::LoadFile(const wxString
& filename
)
518 if (wxFileExists(filename
))
520 wxFileInputStream
stream(filename
);
521 m_decoder
= new wxGIFDecoder(& stream
, TRUE
);
523 if (m_decoder
->ReadGIF() != wxGIF_OK
)
530 if (!m_decoder
->IsAnimation())
545 * wxAnimationCtrlBase
546 * Abstract base class for format-specific animation controls.
547 * This class implements most of the functionality; all a derived
548 * class has to do is create the appropriate animation class on demand.
551 IMPLEMENT_ABSTRACT_CLASS(wxAnimationCtrlBase
, wxControl
)
553 BEGIN_EVENT_TABLE(wxAnimationCtrlBase
, wxControl
)
554 EVT_PAINT(wxAnimationCtrlBase::OnPaint
)
557 bool wxAnimationCtrlBase::Create(wxWindow
*parent
, wxWindowID id
,
558 const wxString
& filename
, const wxPoint
& pos
,
559 const wxSize
& size
, long style
, const wxString
& name
)
562 m_filename
= filename
;
564 if (!wxControl::Create(parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
567 SetBackgroundColour(parent
->GetBackgroundColour());
569 m_animationPlayer
.SetCustomBackgroundColour(GetBackgroundColour());
571 // Want to give the impression of transparency by painting
572 // the parent background
574 // m_animationPlayer.UseParentBackground(TRUE);
575 m_animationPlayer
.SetWindow(this);
576 m_animationPlayer
.SetPosition(wxPoint(0, 0));
577 m_animationPlayer
.SetDestroyAnimation(FALSE
);
584 wxAnimationCtrlBase::~wxAnimationCtrlBase()
586 if (m_animationPlayer
.IsPlaying())
587 m_animationPlayer
.Stop();
588 m_animationPlayer
.SetAnimation(NULL
, FALSE
);
592 bool wxAnimationCtrlBase::LoadFile(const wxString
& filename
)
594 if (m_animationPlayer
.IsPlaying())
595 m_animationPlayer
.Stop();
597 wxString
filename1(filename
);
599 if (filename1
.IsEmpty())
600 filename1
= m_filename
;
602 if (filename1
.IsEmpty())
611 m_animation
= DoCreateAnimation(filename1
);
615 if (!m_animation
->LoadFile(filename
) || !m_animation
->IsValid())
621 m_animationPlayer
.SetAnimation(m_animation
, FALSE
);
623 if (GetWindowStyle() & wxAN_FIT_ANIMATION
)
629 bool wxAnimationCtrlBase::Play(bool looped
)
631 return m_animationPlayer
.Play(*this, wxPoint(0, 0), looped
);
634 wxSize
wxAnimationCtrlBase::DoGetBestSize() const
636 if (m_animationPlayer
.HasAnimation() && (GetWindowStyle() & wxAN_FIT_ANIMATION
))
638 return m_animationPlayer
.GetLogicalScreenSize();
646 void wxAnimationCtrlBase::FitToAnimation()
648 if (!m_animationPlayer
.HasAnimation())
651 wxSize sz
= m_animationPlayer
.GetLogicalScreenSize();
655 void wxAnimationCtrlBase::OnPaint(wxPaintEvent
& WXUNUSED(event
))
659 if (GetPlayer().IsPlaying())
661 GetPlayer().Draw(dc
);
667 * Provides a GIF animation class when required.
670 IMPLEMENT_ABSTRACT_CLASS(wxGIFAnimationCtrl
, wxAnimationCtrlBase
)
672 wxAnimationBase
* wxGIFAnimationCtrl::DoCreateAnimation(const wxString
& WXUNUSED(filename
))
674 return new wxGIFAnimation
;