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
- 1); 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 m_timer
.Start(GetDelay(GetCurrentFrame()));
277 if (m_currentFrame
== GetFrameCount())
279 // Should a non-looped animation display the last frame?
292 // Clear the wxImage cache
293 void wxAnimationPlayer::ClearCache()
295 wxList::compatibility_iterator node
= m_frames
.GetFirst();
298 wxList::compatibility_iterator next
= node
->GetNext();
299 wxBitmap
* bitmap
= (wxBitmap
*) node
->GetData();
301 m_frames
.Erase(node
);
306 // Draw the background colour
307 void wxAnimationPlayer::DrawBackground(wxDC
& dc
, const wxPoint
& pos
, const wxColour
& colour
)
309 wxASSERT_MSG( (m_animation
!= NULL
), _T("Animation not present in wxAnimationPlayer"));
310 wxASSERT_MSG( (m_frames
.GetCount() != 0), _T("Animation cache not present in wxAnimationPlayer"));
312 // Optimization: if the first frame fills the whole area, and is non-transparent,
313 // don't bother drawing the background
315 wxBitmap
* firstBitmap
= (wxBitmap
*) m_frames
.GetFirst()->GetData() ;
316 wxSize screenSize
= GetLogicalScreenSize();
317 if (!firstBitmap
->GetMask() && (firstBitmap
->GetWidth() == screenSize
.x
) && (firstBitmap
->GetHeight() == screenSize
.y
))
322 wxBrush
brush(colour
, wxSOLID
);
323 wxPen
pen(colour
, 1, wxSOLID
);
326 dc
.SetLogicalFunction(wxCOPY
);
328 dc
.DrawRectangle(pos
.x
, pos
.y
, screenSize
.x
, screenSize
.y
);
331 // Save the pertinent area of the window so we can restore
332 // it if drawing transparently
333 void wxAnimationPlayer::SaveBackground(const wxRect
& rect
)
335 wxASSERT( GetWindow() );
340 m_savedBackground
.Create(rect
.width
, rect
.height
);
343 memDC
.SelectObject(m_savedBackground
);
345 if (m_useParentBackground
&& GetWindow()->GetParent())
347 wxWindow
* parent
= GetWindow()->GetParent();
348 wxClientDC
dc(parent
);
350 // Translate the point to coordinates in the
351 // parent's client area, going via screen coordinates
352 wxPoint
pt(rect
.x
, rect
.y
);
353 wxPoint screenPt
= GetWindow()->ClientToScreen(pt
);
354 wxPoint parentPt
= parent
->ScreenToClient(screenPt
);
356 memDC
.Blit(0, 0, rect
.width
, rect
.height
, & dc
, parentPt
.x
, parentPt
.y
);
360 wxClientDC
dc(GetWindow());
362 memDC
.Blit(0, 0, rect
.width
, rect
.height
, & dc
, rect
.x
, rect
.y
);
364 memDC
.SelectObject(wxNullBitmap
);
368 void wxAnimationPlayer::DrawFrame(int frame
, wxDC
& dc
, const wxPoint
& pos
)
370 wxASSERT_MSG( (m_animation
!= NULL
), _T("Animation not present in wxAnimationPlayer"));
371 wxASSERT_MSG( (m_frames
.GetCount() != 0), _T("Animation cache not present in wxAnimationPlayer"));
372 wxASSERT_MSG( !!m_frames
.Item(frame
), _T("Image not present in wxAnimationPlayer::DrawFrame"));
374 wxBitmap
* bitmap
= (wxBitmap
*) m_frames
.Item(frame
)->GetData() ;
376 wxRect rect
= GetFrameRect(frame
);
378 dc
.DrawBitmap(* bitmap
, pos
.x
+ rect
.x
, pos
.y
+ rect
.y
, (bitmap
->GetMask() != NULL
));
381 void wxAnimationTimer::Notify()
383 m_player
->PlayFrame();
390 IMPLEMENT_ABSTRACT_CLASS(wxAnimationBase
, wxObject
)
396 IMPLEMENT_CLASS(wxGIFAnimation
, wxAnimationBase
)
398 wxGIFAnimation::wxGIFAnimation()
400 m_decoder
= (wxGIFDecoder
*) NULL
;
403 wxGIFAnimation::~wxGIFAnimation()
408 int wxGIFAnimation::GetFrameCount() const
410 wxASSERT_MSG( (m_decoder
!= (wxGIFDecoder
*) NULL
), _T("m_decoder must be non-NULL"));
412 return m_decoder
->GetNumberOfFrames();
415 wxImage
* wxGIFAnimation::GetFrame(int i
) const
417 wxASSERT_MSG( (m_decoder
!= (wxGIFDecoder
*) NULL
), _T("m_decoder must be non-NULL"));
419 m_decoder
->GoFrame(i
);
421 wxImage
* image
= new wxImage
;
422 m_decoder
->ConvertToImage(image
);
426 wxAnimationDisposal
wxGIFAnimation::GetDisposalMethod(int i
) const
428 wxASSERT_MSG( (m_decoder
!= (wxGIFDecoder
*) NULL
), _T("m_decoder must be non-NULL"));
430 m_decoder
->GoFrame(i
);
432 int disposalMethod
= m_decoder
->GetDisposalMethod();
433 return (wxAnimationDisposal
) disposalMethod
;
436 wxRect
wxGIFAnimation::GetFrameRect(int i
) const
438 wxASSERT_MSG( (m_decoder
!= (wxGIFDecoder
*) NULL
), _T("m_decoder must be non-NULL"));
440 m_decoder
->GoFrame(i
);
442 wxRect
rect(m_decoder
->GetLeft(), m_decoder
->GetTop(), m_decoder
->GetWidth(), m_decoder
->GetHeight());
446 int wxGIFAnimation::GetDelay(int i
) const
448 wxASSERT_MSG( (m_decoder
!= (wxGIFDecoder
*) NULL
), _T("m_decoder must be non-NULL"));
450 m_decoder
->GoFrame(i
);
451 return m_decoder
->GetDelay();
454 wxSize
wxGIFAnimation::GetLogicalScreenSize() const
456 wxASSERT_MSG( (m_decoder
!= (wxGIFDecoder
*) NULL
), _T("m_decoder must be non-NULL"));
458 return wxSize(m_decoder
->GetLogicalScreenWidth(), m_decoder
->GetLogicalScreenHeight());
461 bool wxGIFAnimation::GetBackgroundColour(wxColour
& col
) const
463 wxASSERT_MSG( (m_decoder
!= (wxGIFDecoder
*) NULL
), _T("m_decoder must be non-NULL"));
465 int i
= m_decoder
->GetBackgroundColour();
470 unsigned char* pal
= m_decoder
->GetPalette();
474 col
= wxColour(pal
[3*i
+ 0], pal
[3*i
+ 1], pal
[3*i
+ 2]);
482 bool wxGIFAnimation::GetTransparentColour(wxColour
& col
) const
484 wxASSERT_MSG( (m_decoder
!= (wxGIFDecoder
*) NULL
), _T("m_decoder must be non-NULL"));
486 int i
= m_decoder
->GetTransparentColour();
491 unsigned char* pal
= m_decoder
->GetPalette();
495 col
= wxColour(pal
[3*i
+ 0], pal
[3*i
+ 1], pal
[3*i
+ 2]);
503 bool wxGIFAnimation::IsValid() const
505 return ((m_decoder
!= NULL
) && (m_decoder
->IsAnimation()));
508 bool wxGIFAnimation::LoadFile(const wxString
& filename
)
514 if (wxFileExists(filename
))
516 wxFileInputStream
stream(filename
);
517 m_decoder
= new wxGIFDecoder(& stream
, TRUE
);
519 if (m_decoder
->ReadGIF() != wxGIF_OK
)
526 if (!m_decoder
->IsAnimation())
541 * wxAnimationCtrlBase
542 * Abstract base class for format-specific animation controls.
543 * This class implements most of the functionality; all a derived
544 * class has to do is create the appropriate animation class on demand.
547 IMPLEMENT_ABSTRACT_CLASS(wxAnimationCtrlBase
, wxControl
)
549 BEGIN_EVENT_TABLE(wxAnimationCtrlBase
, wxControl
)
550 EVT_PAINT(wxAnimationCtrlBase::OnPaint
)
553 bool wxAnimationCtrlBase::Create(wxWindow
*parent
, wxWindowID id
,
554 const wxString
& filename
, const wxPoint
& pos
,
555 const wxSize
& size
, long style
, const wxString
& name
)
558 m_filename
= filename
;
560 if (!wxControl::Create(parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
563 SetBackgroundColour(parent
->GetBackgroundColour());
565 m_animationPlayer
.SetCustomBackgroundColour(GetBackgroundColour());
567 // Want to give the impression of transparency by painting
568 // the parent background
570 // m_animationPlayer.UseParentBackground(TRUE);
571 m_animationPlayer
.SetWindow(this);
572 m_animationPlayer
.SetPosition(wxPoint(0, 0));
573 m_animationPlayer
.SetDestroyAnimation(FALSE
);
578 wxAnimationCtrlBase::~wxAnimationCtrlBase()
580 if (m_animationPlayer
.IsPlaying())
581 m_animationPlayer
.Stop();
582 m_animationPlayer
.SetAnimation(NULL
, FALSE
);
586 bool wxAnimationCtrlBase::LoadFile(const wxString
& filename
)
588 if (m_animationPlayer
.IsPlaying())
589 m_animationPlayer
.Stop();
591 wxString
filename1(filename
);
593 if (filename1
.IsEmpty())
594 filename1
= m_filename
;
596 if (filename1
.IsEmpty())
605 m_animation
= DoCreateAnimation(filename1
);
609 if (!m_animation
->LoadFile(filename
) || !m_animation
->IsValid())
615 m_animationPlayer
.SetAnimation(m_animation
, FALSE
);
617 if (GetWindowStyle() & wxAN_FIT_ANIMATION
)
623 bool wxAnimationCtrlBase::Play(bool looped
)
625 return m_animationPlayer
.Play(*this, wxPoint(0, 0), looped
);
628 wxSize
wxAnimationCtrlBase::DoGetBestSize() const
630 if (m_animationPlayer
.HasAnimation() && (GetWindowStyle() & wxAN_FIT_ANIMATION
))
632 return m_animationPlayer
.GetLogicalScreenSize();
640 void wxAnimationCtrlBase::FitToAnimation()
642 if (!m_animationPlayer
.HasAnimation())
645 wxSize sz
= m_animationPlayer
.GetLogicalScreenSize();
649 void wxAnimationCtrlBase::OnPaint(wxPaintEvent
& WXUNUSED(event
))
653 if (GetPlayer().IsPlaying())
655 GetPlayer().Draw(dc
);
661 * Provides a GIF animation class when required.
664 IMPLEMENT_ABSTRACT_CLASS(wxGIFAnimationCtrl
, wxAnimationCtrlBase
)
666 wxAnimationBase
* wxGIFAnimationCtrl::DoCreateAnimation(const wxString
& WXUNUSED(filename
))
668 return new wxGIFAnimation
;