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 ///////////////////////////////////////////////////////////////////////////////
12 #include "wx/wxprec.h"
18 #include "wx/wfstream.h"
20 #include "wx/gifdecod.h"
22 #include "wx/dcmemory.h"
23 #include "wx/animate/animate.h"
25 #include "wx/dcclient.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 WXUNUSED(looped
))
72 if (!m_animation
|| !m_animation
->IsValid())
75 wxSize sz
= GetLogicalScreenSize();
79 if (m_frames
.GetCount() == 0)
83 wxLogWarning(_T("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 wxImage
* image
= GetFrame(i
);
111 // If the frame has transparency,
112 // set the colour so converting to a bitmap
113 // will create a mask
114 wxColour transparentColour
;
115 if (GetTransparentColour(transparentColour
))
116 image
->SetMaskColour(transparentColour
.Red(), transparentColour
.Green(), transparentColour
.Blue());
118 wxBitmap
* bitmap
= new wxBitmap(* image
);
121 m_frames
.Append(bitmap
);
134 // Stop the animation
135 void wxAnimationPlayer::Stop()
141 // Draw the current view of the animation into this DC.
142 // Call this from your OnPaint, for example.
143 void wxAnimationPlayer::Draw(wxDC
& dc
)
145 dc
.DrawBitmap(m_backingStore
, m_position
.x
, m_position
.y
);
149 int wxAnimationPlayer::GetFrameCount() const
152 return m_animation
->GetFrameCount();
157 wxImage
* wxAnimationPlayer::GetFrame(int i
) const
160 return m_animation
->GetFrame(i
);
162 return (wxImage
*) NULL
;
165 wxAnimationDisposal
wxAnimationPlayer::GetDisposalMethod(int i
) const
168 return m_animation
->GetDisposalMethod(i
);
170 return wxANIM_UNSPECIFIED
;
173 wxRect
wxAnimationPlayer::GetFrameRect(int i
) const
176 return m_animation
->GetFrameRect(i
);
178 return wxRect(0, 0, 0, 0);
181 int wxAnimationPlayer::GetDelay(int i
) const
184 return m_animation
->GetDelay(i
);
189 wxSize
wxAnimationPlayer::GetLogicalScreenSize() const
192 return m_animation
->GetLogicalScreenSize();
197 bool wxAnimationPlayer::GetBackgroundColour(wxColour
& col
) const
200 return m_animation
->GetBackgroundColour(col
);
205 bool wxAnimationPlayer::GetTransparentColour(wxColour
& col
) const
208 return m_animation
->GetTransparentColour(col
);
214 bool wxAnimationPlayer::PlayFrame(int frame
, wxWindow
& window
, const wxPoint
& WXUNUSED(pos
))
217 dc
.SelectObject(m_backingStore
);
219 // Draw the background: colour or area beneath animation
220 wxColour
col(255, 255, 255);
222 if (UsingBackgroundColour())
224 if (UsingCustomBackgroundColour())
225 col
= GetCustomBackgroundColour();
228 GetBackgroundColour(col
);
231 // Draw the background colour loaded from the animation
232 // (or set by the user)
233 DrawBackground(dc
, wxPoint(0, 0), col
);
237 // Draw background we saved
238 dc
.DrawBitmap(m_savedBackground
, 0, 0);
241 // Draw all intermediate frames that haven't been removed from the
244 for (i
= 0; i
< frame
; i
++)
246 if ((GetDisposalMethod(i
) == wxANIM_DONOTREMOVE
) || (GetDisposalMethod(i
) == wxANIM_UNSPECIFIED
))
248 DrawFrame(i
, dc
, wxPoint(0, 0));
251 DrawFrame(frame
, dc
, wxPoint(0, 0));
253 dc
.SelectObject(wxNullBitmap
);
255 // Draw from backing bitmap onto window
256 wxClientDC
clientDC(& window
);
262 bool wxAnimationPlayer::PlayFrame()
266 PlayFrame(GetCurrentFrame(), * GetWindow(), GetPosition());
268 // Set the timer for the next frame
269 int delay
= GetDelay(GetCurrentFrame());
271 delay
= 1; // 0 is invalid timeout for wxTimer.
273 m_timer
.Start(delay
);
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
+ 1);
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
+ 1);
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
+ 1);
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
+ 1);
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
);
580 wxAnimationCtrlBase::~wxAnimationCtrlBase()
582 if (m_animationPlayer
.IsPlaying())
583 m_animationPlayer
.Stop();
584 m_animationPlayer
.SetAnimation(NULL
, FALSE
);
588 bool wxAnimationCtrlBase::LoadFile(const wxString
& filename
)
590 if (m_animationPlayer
.IsPlaying())
591 m_animationPlayer
.Stop();
593 wxString
filename1(filename
);
595 if (filename1
.IsEmpty())
596 filename1
= m_filename
;
598 if (filename1
.IsEmpty())
607 m_animation
= DoCreateAnimation(filename1
);
611 if (!m_animation
->LoadFile(filename
) || !m_animation
->IsValid())
617 m_animationPlayer
.SetAnimation(m_animation
, FALSE
);
619 if (GetWindowStyle() & wxAN_FIT_ANIMATION
)
625 bool wxAnimationCtrlBase::Play(bool looped
)
627 return m_animationPlayer
.Play(*this, wxPoint(0, 0), looped
);
630 wxSize
wxAnimationCtrlBase::DoGetBestSize() const
632 if (m_animationPlayer
.HasAnimation() && (GetWindowStyle() & wxAN_FIT_ANIMATION
))
634 return m_animationPlayer
.GetLogicalScreenSize();
642 void wxAnimationCtrlBase::FitToAnimation()
644 if (!m_animationPlayer
.HasAnimation())
647 wxSize sz
= m_animationPlayer
.GetLogicalScreenSize();
651 void wxAnimationCtrlBase::OnPaint(wxPaintEvent
& WXUNUSED(event
))
655 if (GetPlayer().IsPlaying())
657 GetPlayer().Draw(dc
);
663 * Provides a GIF animation class when required.
666 IMPLEMENT_ABSTRACT_CLASS(wxGIFAnimationCtrl
, wxAnimationCtrlBase
)
668 wxAnimationBase
* wxGIFAnimationCtrl::DoCreateAnimation(const wxString
& WXUNUSED(filename
))
670 return new wxGIFAnimation
;