home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2233.zip / wxOS2-2_3_3.zip / wxWindows-2.3.3 / contrib / src / animate / animate.cpp next >
C/C++ Source or Header  |  2002-04-08  |  17KB  |  667 lines

  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Name:        animate.cpp
  3. // Purpose:     Implementation of wxAnimation classes
  4. // Author:      Julian Smart and Guillermo Rodriguez Garcia
  5. // Modified by:
  6. // Created:     13/8/99
  7. // RCS-ID:      $Id: animate.cpp,v 1.2 2002/04/07 22:58:15 JS Exp $
  8. // Copyright:   (c) Julian Smart and Guillermo Rodriguez Garcia
  9. // Licence:     wxWindows licence
  10. ///////////////////////////////////////////////////////////////////////////////
  11.  
  12. #ifdef __GNUG__
  13.     #pragma implementation "animate.h"
  14. #endif
  15.  
  16. #include "wx/wxprec.h"
  17.  
  18. #ifdef    __BORLANDC__
  19.   #pragma hdrstop
  20. #endif  //__BORLANDC__
  21.  
  22. #include "wx/wfstream.h"
  23. #include "wx/image.h"
  24. #include "wx/gifdecod.h"
  25. #include "wx/animate/animate.h"
  26.  
  27. /*
  28.  * wxAnimationPlayer
  29.  */
  30.  
  31. IMPLEMENT_CLASS(wxAnimationPlayer, wxObject)
  32.  
  33. wxAnimationPlayer::wxAnimationPlayer(wxAnimationBase *animation, bool destroyAnimation)
  34. {
  35.     m_animation = animation;
  36.     m_destroyAnimation = destroyAnimation;
  37.     m_currentFrame = 0;
  38.     m_window = (wxWindow*) NULL;
  39.     m_position = wxPoint(0, 0);
  40.     m_looped = TRUE;
  41.     m_isPlaying = FALSE;
  42.     m_useBackgroundColour = FALSE;
  43.     m_customBackgroundColour = wxColour(0, 0, 0);
  44.     m_useCustomBackgroundColour = FALSE;
  45.     m_useParentBackground = FALSE;
  46.     m_timer.SetPlayer(this);
  47. }
  48.  
  49. wxAnimationPlayer::~wxAnimationPlayer()
  50. {
  51.     Stop();
  52.     ClearCache();
  53.  
  54.     if (m_destroyAnimation)
  55.         delete m_animation;
  56. }
  57.  
  58. void wxAnimationPlayer::SetAnimation(wxAnimationBase* animation, bool destroyAnimation)
  59. {
  60.     ClearCache();
  61.     if (m_destroyAnimation)
  62.         delete m_animation;
  63.     m_animation = animation;
  64.     m_destroyAnimation = destroyAnimation;
  65. }
  66.  
  67. // Play
  68. bool wxAnimationPlayer::Play(wxWindow& window, const wxPoint& pos, bool looped)
  69. {
  70.     m_window = & window;
  71.  
  72.     if (!m_animation || !m_animation->IsValid())
  73.         return FALSE;
  74.  
  75.     wxSize sz = GetLogicalScreenSize();
  76.     wxRect rect(pos, sz);
  77.     SaveBackground(rect);
  78.  
  79.     if (m_frames.Number() == 0)
  80.     {
  81.         if (!Build())
  82.         {
  83.             wxLogWarning("wxAnimationPlayer::Play: could not build the image cache.");
  84.             return FALSE;
  85.         }
  86.     }
  87.     m_currentFrame = 0;
  88.  
  89.     // Create the backing store
  90.     m_backingStore.Create(sz.x, sz.y);
  91.  
  92.     PlayFrame();
  93.  
  94.     return TRUE;
  95. }
  96.  
  97. // Build animation (list of wxImages). If not called before Play
  98. // is called, Play will call this automatically.
  99. bool wxAnimationPlayer::Build()
  100. {
  101.     ClearCache();
  102.     if (m_animation)
  103.     {
  104.         int n = GetFrameCount();
  105.         int i;
  106.         for (i = 0; i < n; i++)
  107.         {
  108.             wxBitmap* bitmap = NULL;
  109.             wxImage* image = GetFrame(i);
  110.             if (image)
  111.             {
  112.                 // If the frame has transparency,
  113.                 // set the colour so converting to a bitmap
  114.                 // will create a mask
  115.                 wxColour transparentColour;
  116.                 if (GetTransparentColour(transparentColour))
  117.                     image->SetMaskColour(transparentColour.Red(), transparentColour.Green(), transparentColour.Blue());
  118.  
  119.                 bitmap = new wxBitmap(* image);
  120.                 delete image;
  121.                 if (bitmap)
  122.                     m_frames.Append(bitmap);
  123.                 else
  124.                     return FALSE;
  125.             }
  126.             else
  127.                 return FALSE;
  128.         }
  129.         return TRUE;
  130.     }
  131.     else
  132.         return FALSE;
  133. }
  134.  
  135. // Stop the animation
  136. void wxAnimationPlayer::Stop()
  137. {
  138.     m_timer.Stop();
  139.     m_isPlaying = FALSE;
  140. }
  141.  
  142. // Draw the current view of the animation into this DC.
  143. // Call this from your OnPaint, for example.
  144. void wxAnimationPlayer::Draw(wxDC& dc)
  145. {
  146.     dc.DrawBitmap(m_backingStore, m_position.x, m_position.y);
  147. }
  148.  
  149.  
  150. int wxAnimationPlayer::GetFrameCount() const
  151. {
  152.     if (m_animation)
  153.         return m_animation->GetFrameCount();
  154.     else
  155.         return 0;
  156. }
  157.  
  158. wxImage* wxAnimationPlayer::GetFrame(int i) const
  159. {
  160.     if (m_animation)
  161.         return m_animation->GetFrame(i);
  162.     else
  163.         return (wxImage*) NULL;
  164. }
  165.  
  166. wxAnimationDisposal wxAnimationPlayer::GetDisposalMethod(int i) const
  167. {
  168.     if (m_animation)
  169.         return m_animation->GetDisposalMethod(i);
  170.     else
  171.         return wxANIM_UNSPECIFIED;
  172. }
  173.  
  174. wxRect wxAnimationPlayer::GetFrameRect(int i) const
  175. {
  176.     if (m_animation)
  177.         return m_animation->GetFrameRect(i);
  178.     else
  179.         return wxRect(0, 0, 0, 0);
  180. }
  181.  
  182. int wxAnimationPlayer::GetDelay(int i) const
  183. {
  184.     if (m_animation)
  185.         return m_animation->GetDelay(i);
  186.     else
  187.         return 0;
  188. }
  189.  
  190. wxSize wxAnimationPlayer::GetLogicalScreenSize() const
  191. {
  192.     if (m_animation)
  193.         return m_animation->GetLogicalScreenSize();
  194.     else
  195.         return wxSize(0, 0);
  196. }
  197.  
  198. bool wxAnimationPlayer::GetBackgroundColour(wxColour& col) const
  199. {
  200.     if (m_animation)
  201.         return m_animation->GetBackgroundColour(col);
  202.     else
  203.         return FALSE;
  204. }
  205.  
  206. bool wxAnimationPlayer::GetTransparentColour(wxColour& col) const
  207. {
  208.     if (m_animation)
  209.         return m_animation->GetTransparentColour(col);
  210.     else
  211.         return FALSE;
  212. }
  213.  
  214. // Play the frame
  215. bool wxAnimationPlayer::PlayFrame(int frame, wxWindow& window, wxPoint& pos)
  216. {
  217.     wxMemoryDC dc;
  218.     dc.SelectObject(m_backingStore);
  219.  
  220.     // Draw the background: colour or area beneath animation
  221.     wxColour col(255, 255, 255);
  222.  
  223.     if (UsingBackgroundColour())
  224.     {
  225.         if (UsingCustomBackgroundColour())
  226.             col = GetCustomBackgroundColour();
  227.         else
  228.         {
  229.             GetBackgroundColour(col);
  230.         }
  231.  
  232.         // Draw the background colour loaded from the animation
  233.         // (or set by the user)
  234.         DrawBackground(dc, wxPoint(0, 0), col);
  235.     }
  236.     else
  237.     {
  238.         // Draw background we saved
  239.         dc.DrawBitmap(m_savedBackground, 0, 0);
  240.     }
  241.  
  242.     // Draw all intermediate frames that haven't been removed from the
  243.     // animation
  244.     int i;
  245.     for (i = 0; i < (frame - 1); i++)
  246.     {
  247.         if ((GetDisposalMethod(i) == wxANIM_DONOTREMOVE) || (GetDisposalMethod(i) == wxANIM_UNSPECIFIED))
  248.         {
  249.             DrawFrame(i, dc, wxPoint(0, 0));
  250.         }
  251.     }
  252.     DrawFrame(frame, dc, wxPoint(0, 0));
  253.  
  254.     dc.SelectObject(wxNullBitmap);
  255.  
  256.     // Draw from backing bitmap onto window
  257.     wxClientDC clientDC(& window);
  258.     Draw(clientDC);
  259.  
  260.     return TRUE;
  261. }
  262.  
  263. bool wxAnimationPlayer::PlayFrame()
  264. {
  265.     m_isPlaying = TRUE;
  266.  
  267.     PlayFrame(GetCurrentFrame(), * GetWindow(), GetPosition());
  268.  
  269.     // Set the timer for the next frame
  270.     m_timer.Start(GetDelay(GetCurrentFrame()));
  271.  
  272.     m_currentFrame ++;
  273.  
  274.     if (m_currentFrame == GetFrameCount())
  275.     {
  276.         // Should a non-looped animation display the last frame?
  277.         if (!m_looped)
  278.         {
  279.             m_timer.Stop();
  280.             m_isPlaying = FALSE;
  281.         }
  282.         else
  283.             m_currentFrame = 0;
  284.     }
  285.  
  286.     return TRUE;
  287. }
  288.  
  289. // Clear the wxImage cache
  290. void wxAnimationPlayer::ClearCache()
  291. {
  292.     wxNode* node = m_frames.First();
  293.     while (node)
  294.     {
  295.         wxNode* next = node->Next();
  296.         wxBitmap* bitmap = (wxBitmap*) node->Data();
  297.         delete bitmap;
  298.         delete node;
  299.         node = next;
  300.     }
  301. }
  302.  
  303. // Draw the background colour
  304. void wxAnimationPlayer::DrawBackground(wxDC& dc, const wxPoint& pos, const wxColour& colour)
  305. {
  306.     wxASSERT_MSG( (m_animation != NULL), "Animation not present in wxAnimationPlayer");
  307.     wxASSERT_MSG( (m_frames.Number() != 0), "Animation cache not present in wxAnimationPlayer");
  308.  
  309.     // Optimization: if the first frame fills the whole area, and is non-transparent,
  310.     // don't bother drawing the background
  311.  
  312.     wxBitmap* firstBitmap = (wxBitmap*) m_frames.First()->Data() ;
  313.     wxSize screenSize = GetLogicalScreenSize();
  314.     if (!firstBitmap->GetMask() && (firstBitmap->GetWidth() == screenSize.x) && (firstBitmap->GetHeight() == screenSize.y))
  315.     {
  316.         return;
  317.     }
  318.  
  319.     wxBrush brush(colour, wxSOLID);
  320.     wxPen pen(colour, 1, wxSOLID);
  321.     dc.SetBrush(brush);
  322.     dc.SetPen(pen);
  323.     dc.SetLogicalFunction(wxCOPY);
  324.  
  325.     dc.DrawRectangle(pos.x, pos.y, screenSize.x, screenSize.y);
  326. }
  327.  
  328. // Save the pertinent area of the window so we can restore
  329. // it if drawing transparently
  330. void wxAnimationPlayer::SaveBackground(const wxRect& rect)
  331. {
  332.     wxASSERT( GetWindow() );
  333.  
  334.     if (!GetWindow())
  335.         return;
  336.  
  337.     m_savedBackground.Create(rect.width, rect.height);
  338.  
  339.     wxMemoryDC memDC;
  340.     memDC.SelectObject(m_savedBackground);
  341.  
  342.     if (m_useParentBackground && GetWindow()->GetParent())
  343.     {
  344.         wxWindow* parent = GetWindow()->GetParent();
  345.         wxClientDC dc(parent);
  346.  
  347.         // Translate the point to coordinates in the
  348.         // parent's client area, going via screen coordinates
  349.         wxPoint pt(rect.x, rect.y);
  350.         wxPoint screenPt = GetWindow()->ClientToScreen(pt);
  351.         wxPoint parentPt = parent->ScreenToClient(screenPt);
  352.  
  353.         memDC.Blit(0, 0, rect.width, rect.height, & dc, parentPt.x, parentPt.y);
  354.     }
  355.     else
  356.     {
  357.         wxClientDC dc(GetWindow());
  358.  
  359.         memDC.Blit(0, 0, rect.width, rect.height, & dc, rect.x, rect.y);
  360.     }
  361.     memDC.SelectObject(wxNullBitmap);
  362. }
  363.  
  364. // Draw this frame
  365. void wxAnimationPlayer::DrawFrame(int frame, wxDC& dc, const wxPoint& pos)
  366. {
  367.     wxASSERT_MSG( (m_animation != NULL), "Animation not present in wxAnimationPlayer");
  368.     wxASSERT_MSG( (m_frames.Number() != 0), "Animation cache not present in wxAnimationPlayer");
  369.     wxASSERT_MSG( (m_frames.Nth(frame) != (wxNode*) NULL), "Image not present in wxAnimationPlayer::DrawFrame");
  370.  
  371.     wxBitmap* bitmap = (wxBitmap*) m_frames.Nth(frame)->Data() ;
  372.  
  373.     wxRect rect = GetFrameRect(frame);
  374.  
  375.     dc.DrawBitmap(* bitmap, pos.x + rect.x, pos.y + rect.y, (bitmap->GetMask() != NULL));
  376. }
  377.  
  378. void wxAnimationTimer::Notify()
  379. {
  380.     m_player->PlayFrame();
  381. }
  382.  
  383. /*
  384.  * wxAnimationBase
  385.  */
  386.  
  387. IMPLEMENT_ABSTRACT_CLASS(wxAnimationBase, wxObject)
  388.  
  389. /*
  390.  * wxGIFAnimation
  391.  */
  392.  
  393. IMPLEMENT_CLASS(wxGIFAnimation, wxAnimationBase)
  394.  
  395. wxGIFAnimation::wxGIFAnimation()
  396. {
  397.     m_decoder = (wxGIFDecoder*) NULL;
  398. }
  399.  
  400. wxGIFAnimation::~wxGIFAnimation()
  401. {
  402.     delete m_decoder;
  403. }
  404.  
  405. int wxGIFAnimation::GetFrameCount() const
  406. {
  407.     wxASSERT_MSG( (m_decoder != (wxGIFDecoder*) NULL), "m_decoder must be non-NULL");
  408.  
  409.     return m_decoder->GetNumberOfFrames();
  410. }
  411.  
  412. wxImage* wxGIFAnimation::GetFrame(int i) const
  413. {
  414.     wxASSERT_MSG( (m_decoder != (wxGIFDecoder*) NULL), "m_decoder must be non-NULL");
  415.  
  416.     m_decoder->GoFrame(i);
  417.  
  418.     wxImage* image = new wxImage;
  419.     m_decoder->ConvertToImage(image);
  420.     return image;
  421. }
  422.  
  423. wxAnimationDisposal wxGIFAnimation::GetDisposalMethod(int i) const
  424. {
  425.     wxASSERT_MSG( (m_decoder != (wxGIFDecoder*) NULL), "m_decoder must be non-NULL");
  426.  
  427.     m_decoder->GoFrame(i);
  428.  
  429.     int disposalMethod = m_decoder->GetDisposalMethod();
  430.     return (wxAnimationDisposal) disposalMethod;
  431. }
  432.  
  433. wxRect wxGIFAnimation::GetFrameRect(int i) const
  434. {
  435.     wxASSERT_MSG( (m_decoder != (wxGIFDecoder*) NULL), "m_decoder must be non-NULL");
  436.  
  437.     m_decoder->GoFrame(i);
  438.  
  439.     wxRect rect(m_decoder->GetLeft(), m_decoder->GetTop(), m_decoder->GetWidth(), m_decoder->GetHeight());
  440.     return rect;
  441. }
  442.  
  443. int wxGIFAnimation::GetDelay(int i) const
  444. {
  445.     wxASSERT_MSG( (m_decoder != (wxGIFDecoder*) NULL), "m_decoder must be non-NULL");
  446.  
  447.     m_decoder->GoFrame(i);
  448.     return m_decoder->GetDelay();
  449. }
  450.  
  451. wxSize wxGIFAnimation::GetLogicalScreenSize() const
  452. {
  453.     wxASSERT_MSG( (m_decoder != (wxGIFDecoder*) NULL), "m_decoder must be non-NULL");
  454.  
  455.     return wxSize(m_decoder->GetLogicalScreenWidth(), m_decoder->GetLogicalScreenHeight());
  456. }
  457.  
  458. bool wxGIFAnimation::GetBackgroundColour(wxColour& col) const
  459. {
  460.     wxASSERT_MSG( (m_decoder != (wxGIFDecoder*) NULL), "m_decoder must be non-NULL");
  461.  
  462.     int i = m_decoder->GetBackgroundColour();
  463.     if (i == -1)
  464.         return FALSE;
  465.     else
  466.     {
  467.         unsigned char* pal = m_decoder->GetPalette();
  468.  
  469.         if (pal)
  470.         {
  471.             col = wxColour(pal[3*i + 0], pal[3*i + 1], pal[3*i + 2]);
  472.             return TRUE;
  473.         }
  474.         else
  475.             return FALSE;
  476.     }
  477. }
  478.  
  479. bool wxGIFAnimation::GetTransparentColour(wxColour& col) const
  480. {
  481.     wxASSERT_MSG( (m_decoder != (wxGIFDecoder*) NULL), "m_decoder must be non-NULL");
  482.  
  483.     int i = m_decoder->GetTransparentColour();
  484.     if (i == -1)
  485.         return FALSE;
  486.     else
  487.     {
  488.         unsigned char* pal = m_decoder->GetPalette();
  489.  
  490.         if (pal)
  491.         {
  492.             col = wxColour(pal[3*i + 0], pal[3*i + 1], pal[3*i + 2]);
  493.             return TRUE;
  494.         }
  495.         else
  496.             return FALSE;
  497.     }
  498. }
  499.  
  500. bool wxGIFAnimation::IsValid() const
  501. {
  502.     return ((m_decoder != NULL) && (m_decoder->IsAnimation()));
  503. }
  504.  
  505. bool wxGIFAnimation::LoadFile(const wxString& filename)
  506. {
  507.     if (m_decoder)
  508.         delete m_decoder;
  509.     m_decoder = NULL;
  510.  
  511.     if (wxFileExists(filename))
  512.     {
  513.         wxFileInputStream stream(filename);
  514.         m_decoder = new wxGIFDecoder(& stream, TRUE);
  515.  
  516.         if (m_decoder->ReadGIF() != wxGIF_OK)
  517.         {
  518.             delete m_decoder;
  519.             m_decoder = NULL;
  520.             return FALSE;
  521.         }
  522.  
  523.         if (!m_decoder->IsAnimation())
  524.         {
  525.             delete m_decoder;
  526.             m_decoder = NULL;
  527.  
  528.             return FALSE;
  529.         }
  530.         else
  531.             return TRUE;
  532.     }
  533.     else
  534.         return FALSE;
  535. }
  536.  
  537. /*
  538.  * wxAnimationCtrlBase
  539.  * Abstract base class for format-specific animation controls.
  540.  * This class implements most of the functionality; all a derived
  541.  * class has to do is create the appropriate animation class on demand.
  542.  */
  543.  
  544. IMPLEMENT_ABSTRACT_CLASS(wxAnimationCtrlBase, wxControl)
  545.  
  546. BEGIN_EVENT_TABLE(wxAnimationCtrlBase, wxControl)
  547.     EVT_PAINT(wxAnimationCtrlBase::OnPaint)
  548. END_EVENT_TABLE()
  549.  
  550. bool wxAnimationCtrlBase::Create(wxWindow *parent, wxWindowID id,
  551.             const wxString& filename, const wxPoint& pos,
  552.             const wxSize& size, long style, const wxString& name)
  553. {
  554.     m_animation = NULL;
  555.     m_filename = filename;
  556.  
  557.     if (!wxControl::Create(parent, id, pos, size, style, wxDefaultValidator, name))
  558.         return FALSE;
  559.  
  560.     SetBackgroundColour(parent->GetBackgroundColour());
  561.  
  562.     m_animationPlayer.SetCustomBackgroundColour(GetBackgroundColour());
  563.  
  564.     // Want to give the impression of transparency by painting
  565.     // the parent background
  566. //    if (parent)
  567. //        m_animationPlayer.UseParentBackground(TRUE);
  568.     m_animationPlayer.SetWindow(this);
  569.     m_animationPlayer.SetPosition(wxPoint(0, 0));
  570.     m_animationPlayer.SetDestroyAnimation(FALSE);
  571.  
  572.     return TRUE;
  573. }
  574.  
  575. wxAnimationCtrlBase::~wxAnimationCtrlBase()
  576. {
  577.     if (m_animationPlayer.IsPlaying())
  578.         m_animationPlayer.Stop();
  579.     m_animationPlayer.SetAnimation(NULL, FALSE);
  580.     delete m_animation;
  581. }
  582.  
  583. bool wxAnimationCtrlBase::LoadFile(const wxString& filename)
  584. {
  585.     if (m_animationPlayer.IsPlaying())
  586.         m_animationPlayer.Stop();
  587.  
  588.     wxString filename1(filename);
  589.  
  590.     if (filename1.IsEmpty())
  591.         filename1 = m_filename;
  592.  
  593.     if (filename1.IsEmpty())
  594.         return FALSE;
  595.  
  596.     if (m_animation)
  597.     {
  598.         delete m_animation;
  599.         m_animation = NULL;
  600.     }
  601.  
  602.     m_animation = DoCreateAnimation(filename1);
  603.     if (!m_animation)
  604.         return FALSE;
  605.  
  606.     if (!m_animation->LoadFile(filename) || !m_animation->IsValid())
  607.     {
  608.         delete m_animation;
  609.         m_animation = NULL;
  610.         return FALSE;
  611.     }
  612.     m_animationPlayer.SetAnimation(m_animation, FALSE);
  613.  
  614.     if (GetWindowStyle() & wxAN_FIT_ANIMATION)
  615.         FitToAnimation();
  616.  
  617.     return TRUE;
  618. }
  619.  
  620. bool wxAnimationCtrlBase::Play(bool looped)
  621. {
  622.     return m_animationPlayer.Play(*this, wxPoint(0, 0), looped);
  623. }
  624.  
  625. wxSize wxAnimationCtrlBase::DoGetBestSize() const
  626. {
  627.     if (m_animationPlayer.HasAnimation() && (GetWindowStyle() & wxAN_FIT_ANIMATION))
  628.     {
  629.         return m_animationPlayer.GetLogicalScreenSize();
  630.     }
  631.     else
  632.     {
  633.         return GetSize();
  634.     }
  635. }
  636.  
  637. void wxAnimationCtrlBase::FitToAnimation()
  638. {
  639.     if (!m_animationPlayer.HasAnimation())
  640.         return;
  641.  
  642.     wxSize sz = m_animationPlayer.GetLogicalScreenSize();
  643.     SetClientSize(sz);
  644. }
  645.  
  646. void wxAnimationCtrlBase::OnPaint(wxPaintEvent& event)
  647. {
  648.     wxPaintDC dc(this);
  649.  
  650.     if (GetPlayer().IsPlaying())
  651.     {
  652.         GetPlayer().Draw(dc);
  653.     }
  654. }
  655.  
  656. /*
  657.  * wxGIFAnimationCtrl
  658.  * Provides a GIF animation class when required.
  659.  */
  660.  
  661. IMPLEMENT_ABSTRACT_CLASS(wxGIFAnimationCtrl, wxAnimationCtrlBase)
  662.  
  663. wxAnimationBase* wxGIFAnimationCtrl::DoCreateAnimation(const wxString& WXUNUSED(filename))
  664. {
  665.     return new wxGIFAnimation;
  666. }
  667.