X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/87d2b3f172cf3cd59ad59d27b0f443fd42394658..1dab6da91b702ad41b249ecaf826a628bad05fce:/src/generic/animateg.cpp diff --git a/src/generic/animateg.cpp b/src/generic/animateg.cpp index 062855d926..c7e55f4f92 100644 --- a/src/generic/animateg.cpp +++ b/src/generic/animateg.cpp @@ -15,7 +15,7 @@ #pragma hdrstop #endif //__BORLANDC__ -#if wxUSE_ANIMATIONCTRL +#if wxUSE_ANIMATIONCTRL && (!defined(__WXGTK20__) || defined(__WXUNIVERSAL__)) #include "wx/animate.h" @@ -82,6 +82,13 @@ wxPoint wxAnimation::GetFramePosition(size_t frame) const return M_ANIMDATA->GetFramePosition(frame); } +wxSize wxAnimation::GetFrameSize(size_t frame) const +{ + wxCHECK_MSG( IsOk(), wxDefaultSize, wxT("invalid animation") ); + + return M_ANIMDATA->GetFrameSize(frame); +} + wxAnimationDisposal wxAnimation::GetDisposalMethod(size_t frame) const { wxCHECK_MSG( IsOk(), wxANIM_UNSPECIFIED, wxT("invalid animation") ); @@ -89,6 +96,13 @@ wxAnimationDisposal wxAnimation::GetDisposalMethod(size_t frame) const return M_ANIMDATA->GetDisposalMethod(frame); } +wxColour wxAnimation::GetTransparentColour(size_t frame) const +{ + wxCHECK_MSG( IsOk(), wxNullColour, wxT("invalid animation") ); + + return M_ANIMDATA->GetTransparentColour(frame); +} + wxColour wxAnimation::GetBackgroundColour() const { wxCHECK_MSG( IsOk(), wxNullColour, wxT("invalid animation") ); @@ -259,23 +273,21 @@ BEGIN_EVENT_TABLE(wxAnimationCtrl, wxAnimationCtrlBase) EVT_TIMER(wxID_ANY, wxAnimationCtrl::OnTimer) END_EVENT_TABLE() -wxAnimationCtrl::wxAnimationCtrl() +void wxAnimationCtrl::Init() { m_currentFrame = 0; m_looped = false; m_isPlaying = false; - m_useWinBackgroundColour = false; + + // use the window background colour by default to be consistent + // with the GTK+ native version + m_useWinBackgroundColour = true; } bool wxAnimationCtrl::Create(wxWindow *parent, wxWindowID id, const wxAnimation& animation, const wxPoint& pos, const wxSize& size, long style, const wxString& name) { - m_animation = animation; - m_currentFrame = 0; - m_looped = true; - m_isPlaying = false; - m_useWinBackgroundColour = false; m_timer.SetOwner(this); if (!base_type::Create(parent, id, pos, size, style, wxDefaultValidator, name)) @@ -283,6 +295,9 @@ bool wxAnimationCtrl::Create(wxWindow *parent, wxWindowID id, // by default we get the same background colour of our parent SetBackgroundColour(parent->GetBackgroundColour()); + + SetAnimation(animation); + return true; } @@ -322,21 +337,19 @@ void wxAnimationCtrl::SetAnimation(const wxAnimation& animation) if (!this->HasFlag(wxAC_NO_AUTORESIZE)) FitToAnimation(); - // display first frame + // reset frame counter m_currentFrame = 0; - if (m_animation.IsOk()) - RebuildBackingStoreUpToFrame(0); - else - { - // clear to - wxMemoryDC dc; - dc.SelectObject(m_backingStore); - // Draw the background - DisposeToBackground(dc); - } + UpdateBackingStoreWithStaticImage(); +} - Refresh(); +void wxAnimationCtrl::SetInactiveBitmap(const wxBitmap &bmp) +{ + m_bmpStatic = bmp; + + // if not playing, update the backing store now + if (!IsPlaying()) + UpdateBackingStoreWithStaticImage(); } void wxAnimationCtrl::FitToAnimation() @@ -351,9 +364,10 @@ void wxAnimationCtrl::FitToAnimation() void wxAnimationCtrl::Stop() { - // leave current frame displayed until Play() is called again m_timer.Stop(); m_isPlaying = false; + + UpdateBackingStoreWithStaticImage(); } bool wxAnimationCtrl::Play(bool looped) @@ -361,15 +375,17 @@ bool wxAnimationCtrl::Play(bool looped) if (!m_animation.IsOk()) return false; - int oldframe = m_currentFrame; m_looped = looped; m_currentFrame = 0; + + if (!RebuildBackingStoreUpToFrame(0)) + return false; + m_isPlaying = true; - // small optimization: if the back store was already updated to the - // first frame, don't rebuild it - if (oldframe != 0) - RebuildBackingStoreUpToFrame(0); + // do a ClearBackground() to avoid that e.g. the custom static bitmap which + // was eventually shown previously remains partially drawn + ClearBackground(); // DrawCurrentFrame() will use our updated backing store wxClientDC clientDC(this); @@ -390,7 +406,7 @@ bool wxAnimationCtrl::Play(bool looped) // wxAnimationCtrl - rendering methods // ---------------------------------------------------------------------------- -void wxAnimationCtrl::RebuildBackingStoreUpToFrame(size_t frame) +bool wxAnimationCtrl::RebuildBackingStoreUpToFrame(size_t frame) { // if we've not created the backing store yet or it's too // small, then recreate it @@ -402,7 +418,8 @@ void wxAnimationCtrl::RebuildBackingStoreUpToFrame(size_t frame) if ( !m_backingStore.IsOk() || m_backingStore.GetWidth() < w || m_backingStore.GetHeight() < h ) { - m_backingStore.Create(w, h); + if (!m_backingStore.Create(w, h)) + return false; } wxMemoryDC dc; @@ -419,11 +436,16 @@ void wxAnimationCtrl::RebuildBackingStoreUpToFrame(size_t frame) { DrawFrame(dc, i); } + else if (m_animation.GetDisposalMethod(i) == wxANIM_TOBACKGROUND) + DisposeToBackground(dc, m_animation.GetFramePosition(i), + m_animation.GetFrameSize(i)); } // finally draw this frame DrawFrame(dc, frame); dc.SelectObject(wxNullBitmap); + + return true; } void wxAnimationCtrl::IncrementalUpdateBackingStore() @@ -447,7 +469,8 @@ void wxAnimationCtrl::IncrementalUpdateBackingStore() switch (m_animation.GetDisposalMethod(m_currentFrame-1)) { case wxANIM_TOBACKGROUND: - DisposeToBackground(dc); + DisposeToBackground(dc, m_animation.GetFramePosition(m_currentFrame-1), + m_animation.GetFrameSize(m_currentFrame-1)); break; case wxANIM_TOPREVIOUS: @@ -462,7 +485,8 @@ void wxAnimationCtrl::IncrementalUpdateBackingStore() DisposeToBackground(dc); } else - RebuildBackingStoreUpToFrame(m_currentFrame-2); + if (!RebuildBackingStoreUpToFrame(m_currentFrame-2)) + Stop(); break; case wxANIM_DONOTREMOVE: @@ -476,6 +500,29 @@ void wxAnimationCtrl::IncrementalUpdateBackingStore() dc.SelectObject(wxNullBitmap); } +void wxAnimationCtrl::UpdateBackingStoreWithStaticImage() +{ + wxASSERT(!IsPlaying()); + + if (m_bmpStatic.IsOk()) + { + // copy the inactive bitmap in the backing store + m_backingStore = m_bmpStatic; + } + else + { + // put in the backing store the first frame of the animation + if (!m_animation.IsOk() || + !RebuildBackingStoreUpToFrame(0)) + { + m_animation = wxNullAnimation; + DisposeToBackground(); + } + } + + Refresh(); +} + void wxAnimationCtrl::DrawFrame(wxDC &dc, size_t frame) { // PERFORMANCE NOTE: @@ -494,19 +541,38 @@ void wxAnimationCtrl::DrawCurrentFrame(wxDC& dc) wxASSERT( m_backingStore.IsOk() ); // m_backingStore always contains the current frame - dc.DrawBitmap(m_backingStore, 0, 0); + dc.DrawBitmap(m_backingStore, 0, 0, true /* use mask in case it's present */); +} + +void wxAnimationCtrl::DisposeToBackground() +{ + // clear the backing store + wxMemoryDC dc; + dc.SelectObject(m_backingStore); + DisposeToBackground(dc); } void wxAnimationCtrl::DisposeToBackground(wxDC& dc) { wxColour col = IsUsingWindowBackgroundColour() ? GetBackgroundColour() - : m_animation.GetBackgroundColour() ; + : m_animation.GetBackgroundColour(); wxBrush brush(col); dc.SetBackground(brush); dc.Clear(); } +void wxAnimationCtrl::DisposeToBackground(wxDC& dc, const wxPoint &pos, const wxSize &sz) +{ + wxColour col = IsUsingWindowBackgroundColour() + ? GetBackgroundColour() + : m_animation.GetBackgroundColour(); + wxBrush brush(col); + dc.SetBrush(brush); // SetBrush and not SetBackground !! + dc.SetPen(*wxTRANSPARENT_PEN); + dc.DrawRectangle(pos, sz); +} + // ---------------------------------------------------------------------------- // wxAnimationCtrl - event handlers // ---------------------------------------------------------------------------- @@ -516,10 +582,14 @@ void wxAnimationCtrl::OnPaint(wxPaintEvent& WXUNUSED(event)) // VERY IMPORTANT: the wxPaintDC *must* be created in any case wxPaintDC dc(this); - // both if we are playing or not, we need to refresh the current frame if ( m_backingStore.IsOk() ) DrawCurrentFrame(dc); - //else: m_animation is not valid and thus we don't have a valid backing store... + else + { + // m_animation is not valid and thus we don't have a valid backing store... + // clear then our area to the background colour + DisposeToBackground(dc); + } } void wxAnimationCtrl::OnTimer(wxTimerEvent &WXUNUSED(event)) @@ -530,8 +600,7 @@ void wxAnimationCtrl::OnTimer(wxTimerEvent &WXUNUSED(event)) // Should a non-looped animation display the last frame? if (!m_looped) { - m_timer.Stop(); - m_isPlaying = false; + Stop(); return; } else @@ -559,9 +628,21 @@ void wxAnimationCtrl::OnSize(wxSizeEvent &WXUNUSED(event)) { // NB: resizing an animation control may take a lot of time // for big animations as the backing store must be - // extended and rebuilt. Try to avoid it!! + // extended and rebuilt. Try to avoid it e.g. using + // a null proportion value for your wxAnimationCtrls + // when using them inside sizers. if (m_animation.IsOk()) - RebuildBackingStoreUpToFrame(m_currentFrame); + { + // be careful to change the backing store *only* if we are + // playing the animation as otherwise we may be displaying + // the inactive bitmap and overwriting the backing store + // with the last played frame is wrong in this case + if (IsPlaying()) + { + if (!RebuildBackingStoreUpToFrame(m_currentFrame)) + Stop(); // in case we are playing + } + } } #endif // wxUSE_ANIMATIONCTRL