]> git.saurik.com Git - wxWidgets.git/blobdiff - src/generic/animateg.cpp
call Init() from wxBufferedDC ctors to ensure that layout direction is inherited...
[wxWidgets.git] / src / generic / animateg.cpp
index 124f394071f3be406db10096cb2e97931887d275..2035cbb4f4b665900d77c7a0972600e2d1561801 100644 (file)
@@ -15,7 +15,7 @@
   #pragma hdrstop
 #endif  //__BORLANDC__
 
-#if wxUSE_ANIMATIONCTRL
+#if wxUSE_ANIMATIONCTRL && (!defined(__WXGTK20__) || defined(__WXUNIVERSAL__))
 
 #include "wx/animate.h"
 
@@ -32,7 +32,7 @@
 #include "wx/anidecod.h"
 
 #include "wx/listimpl.cpp"
-WX_DEFINE_LIST(wxAnimationDecoderList);
+WX_DEFINE_LIST(wxAnimationDecoderList)
 
 wxAnimationDecoderList wxAnimation::sm_handlers;
 
@@ -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") );
@@ -209,8 +223,12 @@ const wxAnimationDecoder *wxAnimation::FindHandler( wxAnimationType animType )
 
 void wxAnimation::InitStandardHandlers()
 {
+#if wxUSE_GIF
     AddHandler(new wxGIFDecoder);
+#endif // wxUSE_GIF
+#if wxUSE_ICO_CUR
     AddHandler(new wxANIDecoder);
+#endif // wxUSE_ICO_CUR
 }
 
 void wxAnimation::CleanUpHandlers()
@@ -255,12 +273,15 @@ 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,
@@ -268,10 +289,6 @@ bool wxAnimationCtrl::Create(wxWindow *parent, wxWindowID id,
             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))
@@ -318,21 +335,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)
+{
+    wxAnimationCtrlBase::SetInactiveBitmap(bmp);
+
+    // if not playing, update the backing store now
+    if (!IsPlaying())
+        UpdateBackingStoreWithStaticImage();
 }
 
 void wxAnimationCtrl::FitToAnimation()
@@ -347,9 +362,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)
@@ -360,12 +376,18 @@ bool wxAnimationCtrl::Play(bool looped)
     int oldframe = m_currentFrame;
     m_looped = looped;
     m_currentFrame = 0;
-    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);
+        if (!RebuildBackingStoreUpToFrame(0))
+            return false;
+
+    m_isPlaying = true;
+
+    // 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);
@@ -386,7 +408,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
@@ -398,7 +420,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;
@@ -415,11 +438,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()
@@ -443,7 +471,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:
@@ -458,7 +487,8 @@ void wxAnimationCtrl::IncrementalUpdateBackingStore()
                 DisposeToBackground(dc);
             }
             else
-                RebuildBackingStoreUpToFrame(m_currentFrame-2);
+                if (!RebuildBackingStoreUpToFrame(m_currentFrame-2))
+                    Stop();
             break;
 
         case wxANIM_DONOTREMOVE:
@@ -472,6 +502,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:
@@ -490,18 +543,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(wxDC& dc)
+void wxAnimationCtrl::DisposeToBackground()
 {
-    wxBrush brush(IsUsingWindowBackgroundColour()
+    // 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
 // ----------------------------------------------------------------------------
@@ -511,10 +584,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))
@@ -525,8 +602,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
@@ -556,7 +632,8 @@ void wxAnimationCtrl::OnSize(wxSizeEvent &WXUNUSED(event))
     //     for big animations as the backing store must be
     //     extended and rebuilt. Try to avoid it!!
     if (m_animation.IsOk())
-        RebuildBackingStoreUpToFrame(m_currentFrame);
+        if (!RebuildBackingStoreUpToFrame(m_currentFrame))
+            Stop();     // in case we are playing
 }
 
 #endif      // wxUSE_ANIMATIONCTRL