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"
28 #include "wx/dcclient.h"
29 #include "wx/dcmemory.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 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 wxBitmap
* bitmap
= NULL
;
113 wxImage
* image
= GetFrame(i
);
116 // If the frame has transparency,
117 // set the colour so converting to a bitmap
118 // will create a mask
119 wxColour transparentColour
;
120 if (GetTransparentColour(transparentColour
))
121 image
->SetMaskColour(transparentColour
.Red(), transparentColour
.Green(), transparentColour
.Blue());
123 bitmap
= new wxBitmap(* image
);
126 m_frames
.Append(bitmap
);
139 // Stop the animation
140 void wxAnimationPlayer::Stop()
146 // Draw the current view of the animation into this DC.
147 // Call this from your OnPaint, for example.
148 void wxAnimationPlayer::Draw(wxDC
& dc
)
150 dc
.DrawBitmap(m_backingStore
, m_position
.x
, m_position
.y
);
154 int wxAnimationPlayer::GetFrameCount() const
157 return m_animation
->GetFrameCount();
162 wxImage
* wxAnimationPlayer::GetFrame(int i
) const
165 return m_animation
->GetFrame(i
);
167 return (wxImage
*) NULL
;
170 wxAnimationDisposal
wxAnimationPlayer::GetDisposalMethod(int i
) const
173 return m_animation
->GetDisposalMethod(i
);
175 return wxANIM_UNSPECIFIED
;
178 wxRect
wxAnimationPlayer::GetFrameRect(int i
) const
181 return m_animation
->GetFrameRect(i
);
183 return wxRect(0, 0, 0, 0);
186 int wxAnimationPlayer::GetDelay(int i
) const
189 return m_animation
->GetDelay(i
);
194 wxSize
wxAnimationPlayer::GetLogicalScreenSize() const
197 return m_animation
->GetLogicalScreenSize();
202 bool wxAnimationPlayer::GetBackgroundColour(wxColour
& col
) const
205 return m_animation
->GetBackgroundColour(col
);
210 bool wxAnimationPlayer::GetTransparentColour(wxColour
& col
) const
213 return m_animation
->GetTransparentColour(col
);
219 bool wxAnimationPlayer::PlayFrame(int frame
, wxWindow
& window
, const wxPoint
& pos
)
222 dc
.SelectObject(m_backingStore
);
224 // Draw the background: colour or area beneath animation
225 wxColour
col(255, 255, 255);
227 if (UsingBackgroundColour())
229 if (UsingCustomBackgroundColour())
230 col
= GetCustomBackgroundColour();
233 GetBackgroundColour(col
);
236 // Draw the background colour loaded from the animation
237 // (or set by the user)
238 DrawBackground(dc
, wxPoint(0, 0), col
);
242 // Draw background we saved
243 dc
.DrawBitmap(m_savedBackground
, 0, 0);
246 // Draw all intermediate frames that haven't been removed from the
249 for (i
= 0; i
< (frame
- 1); i
++)
251 if ((GetDisposalMethod(i
) == wxANIM_DONOTREMOVE
) || (GetDisposalMethod(i
) == wxANIM_UNSPECIFIED
))
253 DrawFrame(i
, dc
, wxPoint(0, 0));
256 DrawFrame(frame
, dc
, wxPoint(0, 0));
258 dc
.SelectObject(wxNullBitmap
);
260 // Draw from backing bitmap onto window
261 wxClientDC
clientDC(& window
);
267 bool wxAnimationPlayer::PlayFrame()
271 PlayFrame(GetCurrentFrame(), * GetWindow(), GetPosition());
273 // Set the timer for the next frame
274 m_timer
.Start(GetDelay(GetCurrentFrame()));
278 if (m_currentFrame
== GetFrameCount())
280 // Should a non-looped animation display the last frame?
293 // Clear the wxImage cache
294 void wxAnimationPlayer::ClearCache()
296 wxNode
* node
= m_frames
.GetFirst();
299 wxNode
* next
= node
->GetNext();
300 wxBitmap
* bitmap
= (wxBitmap
*) node
->GetData();
307 // Draw the background colour
308 void wxAnimationPlayer::DrawBackground(wxDC
& dc
, const wxPoint
& pos
, const wxColour
& colour
)
310 wxASSERT_MSG( (m_animation
!= NULL
), _T("Animation not present in wxAnimationPlayer"));
311 wxASSERT_MSG( (m_frames
.GetCount() != 0), _T("Animation cache not present in wxAnimationPlayer"));
313 // Optimization: if the first frame fills the whole area, and is non-transparent,
314 // don't bother drawing the background
316 wxBitmap
* firstBitmap
= (wxBitmap
*) m_frames
.GetFirst()->GetData() ;
317 wxSize screenSize
= GetLogicalScreenSize();
318 if (!firstBitmap
->GetMask() && (firstBitmap
->GetWidth() == screenSize
.x
) && (firstBitmap
->GetHeight() == screenSize
.y
))
323 wxBrush
brush(colour
, wxSOLID
);
324 wxPen
pen(colour
, 1, wxSOLID
);
327 dc
.SetLogicalFunction(wxCOPY
);
329 dc
.DrawRectangle(pos
.x
, pos
.y
, screenSize
.x
, screenSize
.y
);
332 // Save the pertinent area of the window so we can restore
333 // it if drawing transparently
334 void wxAnimationPlayer::SaveBackground(const wxRect
& rect
)
336 wxASSERT( GetWindow() );
341 m_savedBackground
.Create(rect
.width
, rect
.height
);
344 memDC
.SelectObject(m_savedBackground
);
346 if (m_useParentBackground
&& GetWindow()->GetParent())
348 wxWindow
* parent
= GetWindow()->GetParent();
349 wxClientDC
dc(parent
);
351 // Translate the point to coordinates in the
352 // parent's client area, going via screen coordinates
353 wxPoint
pt(rect
.x
, rect
.y
);
354 wxPoint screenPt
= GetWindow()->ClientToScreen(pt
);
355 wxPoint parentPt
= parent
->ScreenToClient(screenPt
);
357 memDC
.Blit(0, 0, rect
.width
, rect
.height
, & dc
, parentPt
.x
, parentPt
.y
);
361 wxClientDC
dc(GetWindow());
363 memDC
.Blit(0, 0, rect
.width
, rect
.height
, & dc
, rect
.x
, rect
.y
);
365 memDC
.SelectObject(wxNullBitmap
);
369 void wxAnimationPlayer::DrawFrame(int frame
, wxDC
& dc
, const wxPoint
& pos
)
371 wxASSERT_MSG( (m_animation
!= NULL
), _T("Animation not present in wxAnimationPlayer"));
372 wxASSERT_MSG( (m_frames
.GetCount() != 0), _T("Animation cache not present in wxAnimationPlayer"));
373 wxASSERT_MSG( (m_frames
.Item(frame
) != (wxNode
*) NULL
), _T("Image not present in wxAnimationPlayer::DrawFrame"));
375 wxBitmap
* bitmap
= (wxBitmap
*) m_frames
.Item(frame
)->GetData() ;
377 wxRect rect
= GetFrameRect(frame
);
379 dc
.DrawBitmap(* bitmap
, pos
.x
+ rect
.x
, pos
.y
+ rect
.y
, (bitmap
->GetMask() != NULL
));
382 void wxAnimationTimer::Notify()
384 m_player
->PlayFrame();
391 IMPLEMENT_ABSTRACT_CLASS(wxAnimationBase
, wxObject
)
397 IMPLEMENT_CLASS(wxGIFAnimation
, wxAnimationBase
)
399 wxGIFAnimation::wxGIFAnimation()
401 m_decoder
= (wxGIFDecoder
*) NULL
;
404 wxGIFAnimation::~wxGIFAnimation()
409 int wxGIFAnimation::GetFrameCount() const
411 wxASSERT_MSG( (m_decoder
!= (wxGIFDecoder
*) NULL
), _T("m_decoder must be non-NULL"));
413 return m_decoder
->GetNumberOfFrames();
416 wxImage
* wxGIFAnimation::GetFrame(int i
) const
418 wxASSERT_MSG( (m_decoder
!= (wxGIFDecoder
*) NULL
), _T("m_decoder must be non-NULL"));
420 m_decoder
->GoFrame(i
);
422 wxImage
* image
= new wxImage
;
423 m_decoder
->ConvertToImage(image
);
427 wxAnimationDisposal
wxGIFAnimation::GetDisposalMethod(int i
) const
429 wxASSERT_MSG( (m_decoder
!= (wxGIFDecoder
*) NULL
), _T("m_decoder must be non-NULL"));
431 m_decoder
->GoFrame(i
);
433 int disposalMethod
= m_decoder
->GetDisposalMethod();
434 return (wxAnimationDisposal
) disposalMethod
;
437 wxRect
wxGIFAnimation::GetFrameRect(int i
) const
439 wxASSERT_MSG( (m_decoder
!= (wxGIFDecoder
*) NULL
), _T("m_decoder must be non-NULL"));
441 m_decoder
->GoFrame(i
);
443 wxRect
rect(m_decoder
->GetLeft(), m_decoder
->GetTop(), m_decoder
->GetWidth(), m_decoder
->GetHeight());
447 int wxGIFAnimation::GetDelay(int i
) const
449 wxASSERT_MSG( (m_decoder
!= (wxGIFDecoder
*) NULL
), _T("m_decoder must be non-NULL"));
451 m_decoder
->GoFrame(i
);
452 return m_decoder
->GetDelay();
455 wxSize
wxGIFAnimation::GetLogicalScreenSize() const
457 wxASSERT_MSG( (m_decoder
!= (wxGIFDecoder
*) NULL
), _T("m_decoder must be non-NULL"));
459 return wxSize(m_decoder
->GetLogicalScreenWidth(), m_decoder
->GetLogicalScreenHeight());
462 bool wxGIFAnimation::GetBackgroundColour(wxColour
& col
) const
464 wxASSERT_MSG( (m_decoder
!= (wxGIFDecoder
*) NULL
), _T("m_decoder must be non-NULL"));
466 int i
= m_decoder
->GetBackgroundColour();
471 unsigned char* pal
= m_decoder
->GetPalette();
475 col
= wxColour(pal
[3*i
+ 0], pal
[3*i
+ 1], pal
[3*i
+ 2]);
483 bool wxGIFAnimation::GetTransparentColour(wxColour
& col
) const
485 wxASSERT_MSG( (m_decoder
!= (wxGIFDecoder
*) NULL
), _T("m_decoder must be non-NULL"));
487 int i
= m_decoder
->GetTransparentColour();
492 unsigned char* pal
= m_decoder
->GetPalette();
496 col
= wxColour(pal
[3*i
+ 0], pal
[3*i
+ 1], pal
[3*i
+ 2]);
504 bool wxGIFAnimation::IsValid() const
506 return ((m_decoder
!= NULL
) && (m_decoder
->IsAnimation()));
509 bool wxGIFAnimation::LoadFile(const wxString
& filename
)
515 if (wxFileExists(filename
))
517 wxFileInputStream
stream(filename
);
518 m_decoder
= new wxGIFDecoder(& stream
, TRUE
);
520 if (m_decoder
->ReadGIF() != wxGIF_OK
)
527 if (!m_decoder
->IsAnimation())
542 * wxAnimationCtrlBase
543 * Abstract base class for format-specific animation controls.
544 * This class implements most of the functionality; all a derived
545 * class has to do is create the appropriate animation class on demand.
548 IMPLEMENT_ABSTRACT_CLASS(wxAnimationCtrlBase
, wxControl
)
550 BEGIN_EVENT_TABLE(wxAnimationCtrlBase
, wxControl
)
551 EVT_PAINT(wxAnimationCtrlBase::OnPaint
)
554 bool wxAnimationCtrlBase::Create(wxWindow
*parent
, wxWindowID id
,
555 const wxString
& filename
, const wxPoint
& pos
,
556 const wxSize
& size
, long style
, const wxString
& name
)
559 m_filename
= filename
;
561 if (!wxControl::Create(parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
564 SetBackgroundColour(parent
->GetBackgroundColour());
566 m_animationPlayer
.SetCustomBackgroundColour(GetBackgroundColour());
568 // Want to give the impression of transparency by painting
569 // the parent background
571 // m_animationPlayer.UseParentBackground(TRUE);
572 m_animationPlayer
.SetWindow(this);
573 m_animationPlayer
.SetPosition(wxPoint(0, 0));
574 m_animationPlayer
.SetDestroyAnimation(FALSE
);
579 wxAnimationCtrlBase::~wxAnimationCtrlBase()
581 if (m_animationPlayer
.IsPlaying())
582 m_animationPlayer
.Stop();
583 m_animationPlayer
.SetAnimation(NULL
, FALSE
);
587 bool wxAnimationCtrlBase::LoadFile(const wxString
& filename
)
589 if (m_animationPlayer
.IsPlaying())
590 m_animationPlayer
.Stop();
592 wxString
filename1(filename
);
594 if (filename1
.IsEmpty())
595 filename1
= m_filename
;
597 if (filename1
.IsEmpty())
606 m_animation
= DoCreateAnimation(filename1
);
610 if (!m_animation
->LoadFile(filename
) || !m_animation
->IsValid())
616 m_animationPlayer
.SetAnimation(m_animation
, FALSE
);
618 if (GetWindowStyle() & wxAN_FIT_ANIMATION
)
624 bool wxAnimationCtrlBase::Play(bool looped
)
626 return m_animationPlayer
.Play(*this, wxPoint(0, 0), looped
);
629 wxSize
wxAnimationCtrlBase::DoGetBestSize() const
631 if (m_animationPlayer
.HasAnimation() && (GetWindowStyle() & wxAN_FIT_ANIMATION
))
633 return m_animationPlayer
.GetLogicalScreenSize();
641 void wxAnimationCtrlBase::FitToAnimation()
643 if (!m_animationPlayer
.HasAnimation())
646 wxSize sz
= m_animationPlayer
.GetLogicalScreenSize();
650 void wxAnimationCtrlBase::OnPaint(wxPaintEvent
& event
)
654 if (GetPlayer().IsPlaying())
656 GetPlayer().Draw(dc
);
662 * Provides a GIF animation class when required.
665 IMPLEMENT_ABSTRACT_CLASS(wxGIFAnimationCtrl
, wxAnimationCtrlBase
)
667 wxAnimationBase
* wxGIFAnimationCtrl::DoCreateAnimation(const wxString
& WXUNUSED(filename
))
669 return new wxGIFAnimation
;