/[pcsx2_0.9.7]/branch/r3113_0.9.7_beta/3rdparty/wxWidgets/src/generic/animateg.cpp
ViewVC logotype

Annotation of /branch/r3113_0.9.7_beta/3rdparty/wxWidgets/src/generic/animateg.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 31 - (hide annotations) (download)
Tue Sep 7 03:24:11 2010 UTC (10 years ago) by william
Original Path: trunk/3rdparty/wxWidgets/src/generic/animateg.cpp
File size: 19871 byte(s)
committing r3113 initial commit again...
1 william 31 ///////////////////////////////////////////////////////////////////////////////
2     // Name: animateg.cpp
3     // Purpose: wxAnimation and wxAnimationCtrl
4     // Author: Julian Smart and Guillermo Rodriguez Garcia
5     // Modified by: Francesco Montorsi
6     // Created: 13/8/99
7     // RCS-ID: $Id: animateg.cpp 48085 2007-08-15 11:36:50Z VZ $
8     // Copyright: (c) Julian Smart and Guillermo Rodriguez Garcia
9     // Licence: wxWindows licence
10     ///////////////////////////////////////////////////////////////////////////////
11    
12     #include "wx/wxprec.h"
13    
14     #ifdef __BORLANDC__
15     #pragma hdrstop
16     #endif //__BORLANDC__
17    
18     #if wxUSE_ANIMATIONCTRL && (!defined(__WXGTK20__) || defined(__WXUNIVERSAL__))
19    
20     #include "wx/animate.h"
21    
22     #ifndef WX_PRECOMP
23     #include "wx/log.h"
24     #include "wx/image.h"
25     #include "wx/dcmemory.h"
26     #include "wx/dcclient.h"
27     #include "wx/module.h"
28     #endif
29    
30     #include "wx/wfstream.h"
31     #include "wx/gifdecod.h"
32     #include "wx/anidecod.h"
33    
34     #include "wx/listimpl.cpp"
35     WX_DEFINE_LIST(wxAnimationDecoderList)
36    
37     wxAnimationDecoderList wxAnimation::sm_handlers;
38    
39    
40     // ----------------------------------------------------------------------------
41     // wxAnimation
42     // ----------------------------------------------------------------------------
43    
44     IMPLEMENT_DYNAMIC_CLASS(wxAnimation, wxAnimationBase)
45     #define M_ANIMDATA wx_static_cast(wxAnimationDecoder*, m_refData)
46    
47     wxSize wxAnimation::GetSize() const
48     {
49     wxCHECK_MSG( IsOk(), wxDefaultSize, wxT("invalid animation") );
50    
51     return M_ANIMDATA->GetAnimationSize();
52     }
53    
54     unsigned int wxAnimation::GetFrameCount() const
55     {
56     wxCHECK_MSG( IsOk(), 0, wxT("invalid animation") );
57    
58     return M_ANIMDATA->GetFrameCount();
59     }
60    
61     wxImage wxAnimation::GetFrame(unsigned int i) const
62     {
63     wxCHECK_MSG( IsOk(), wxNullImage, wxT("invalid animation") );
64    
65     wxImage ret;
66     if (!M_ANIMDATA->ConvertToImage(i, &ret))
67     return wxNullImage;
68     return ret;
69     }
70    
71     int wxAnimation::GetDelay(unsigned int i) const
72     {
73     wxCHECK_MSG( IsOk(), 0, wxT("invalid animation") );
74    
75     return M_ANIMDATA->GetDelay(i);
76     }
77    
78     wxPoint wxAnimation::GetFramePosition(unsigned int frame) const
79     {
80     wxCHECK_MSG( IsOk(), wxDefaultPosition, wxT("invalid animation") );
81    
82     return M_ANIMDATA->GetFramePosition(frame);
83     }
84    
85     wxSize wxAnimation::GetFrameSize(unsigned int frame) const
86     {
87     wxCHECK_MSG( IsOk(), wxDefaultSize, wxT("invalid animation") );
88    
89     return M_ANIMDATA->GetFrameSize(frame);
90     }
91    
92     wxAnimationDisposal wxAnimation::GetDisposalMethod(unsigned int frame) const
93     {
94     wxCHECK_MSG( IsOk(), wxANIM_UNSPECIFIED, wxT("invalid animation") );
95    
96     return M_ANIMDATA->GetDisposalMethod(frame);
97     }
98    
99     wxColour wxAnimation::GetTransparentColour(unsigned int frame) const
100     {
101     wxCHECK_MSG( IsOk(), wxNullColour, wxT("invalid animation") );
102    
103     return M_ANIMDATA->GetTransparentColour(frame);
104     }
105    
106     wxColour wxAnimation::GetBackgroundColour() const
107     {
108     wxCHECK_MSG( IsOk(), wxNullColour, wxT("invalid animation") );
109    
110     return M_ANIMDATA->GetBackgroundColour();
111     }
112    
113     bool wxAnimation::LoadFile(const wxString& filename, wxAnimationType type)
114     {
115     wxFileInputStream stream(filename);
116     if ( !stream.IsOk() )
117     return false;
118    
119     return Load(stream, type);
120     }
121    
122     bool wxAnimation::Load(wxInputStream &stream, wxAnimationType type)
123     {
124     UnRef();
125    
126     const wxAnimationDecoder *handler;
127     if ( type == wxANIMATION_TYPE_ANY )
128     {
129     for ( wxAnimationDecoderList::compatibility_iterator node = sm_handlers.GetFirst();
130     node; node = node->GetNext() )
131     {
132     handler=(const wxAnimationDecoder*)node->GetData();
133    
134     if ( handler->CanRead(stream) )
135     {
136     // do a copy of the handler from the static list which we will own
137     // as our reference data
138     m_refData = handler->Clone();
139     return M_ANIMDATA->Load(stream);
140     }
141    
142     }
143    
144     wxLogWarning( _("No handler found for animation type.") );
145     return false;
146     }
147    
148     handler = FindHandler(type);
149    
150     // do a copy of the handler from the static list which we will own
151     // as our reference data
152     m_refData = handler->Clone();
153    
154     if (handler == NULL)
155     {
156     wxLogWarning( _("No animation handler for type %ld defined."), type );
157    
158     return false;
159     }
160    
161     if (stream.IsSeekable() && !M_ANIMDATA->CanRead(stream))
162     {
163     wxLogError(_("Animation file is not of type %ld."), type);
164     return false;
165     }
166     else
167     return M_ANIMDATA->Load(stream);
168     }
169    
170    
171     // ----------------------------------------------------------------------------
172     // animation decoders
173     // ----------------------------------------------------------------------------
174    
175     void wxAnimation::AddHandler( wxAnimationDecoder *handler )
176     {
177     // Check for an existing handler of the type being added.
178     if (FindHandler( handler->GetType() ) == 0)
179     {
180     sm_handlers.Append( handler );
181     }
182     else
183     {
184     // This is not documented behaviour, merely the simplest 'fix'
185     // for preventing duplicate additions. If someone ever has
186     // a good reason to add and remove duplicate handlers (and they
187     // may) we should probably refcount the duplicates.
188    
189     wxLogDebug( _T("Adding duplicate animation handler for '%d' type"),
190     handler->GetType() );
191     delete handler;
192     }
193     }
194    
195     void wxAnimation::InsertHandler( wxAnimationDecoder *handler )
196     {
197     // Check for an existing handler of the type being added.
198     if (FindHandler( handler->GetType() ) == 0)
199     {
200     sm_handlers.Insert( handler );
201     }
202     else
203     {
204     // see AddHandler for additional comments.
205     wxLogDebug( _T("Inserting duplicate animation handler for '%d' type"),
206     handler->GetType() );
207     delete handler;
208     }
209     }
210    
211     const wxAnimationDecoder *wxAnimation::FindHandler( wxAnimationType animType )
212     {
213     wxAnimationDecoderList::compatibility_iterator node = sm_handlers.GetFirst();
214     while (node)
215     {
216     const wxAnimationDecoder *handler = (const wxAnimationDecoder *)node->GetData();
217     if (handler->GetType() == animType) return handler;
218     node = node->GetNext();
219     }
220     return 0;
221     }
222    
223     void wxAnimation::InitStandardHandlers()
224     {
225     #if wxUSE_GIF
226     AddHandler(new wxGIFDecoder);
227     #endif // wxUSE_GIF
228     #if wxUSE_ICO_CUR
229     AddHandler(new wxANIDecoder);
230     #endif // wxUSE_ICO_CUR
231     }
232    
233     void wxAnimation::CleanUpHandlers()
234     {
235     wxAnimationDecoderList::compatibility_iterator node = sm_handlers.GetFirst();
236     while (node)
237     {
238     wxAnimationDecoder *handler = (wxAnimationDecoder *)node->GetData();
239     wxAnimationDecoderList::compatibility_iterator next = node->GetNext();
240     delete handler;
241     node = next;
242     }
243    
244     sm_handlers.Clear();
245     }
246    
247    
248     // A module to allow wxAnimation initialization/cleanup
249     // without calling these functions from app.cpp or from
250     // the user's application.
251    
252     class wxAnimationModule: public wxModule
253     {
254     DECLARE_DYNAMIC_CLASS(wxAnimationModule)
255     public:
256     wxAnimationModule() {}
257     bool OnInit() { wxAnimation::InitStandardHandlers(); return true; }
258     void OnExit() { wxAnimation::CleanUpHandlers(); }
259     };
260    
261     IMPLEMENT_DYNAMIC_CLASS(wxAnimationModule, wxModule)
262    
263    
264     // ----------------------------------------------------------------------------
265     // wxAnimationCtrl
266     // ----------------------------------------------------------------------------
267    
268     IMPLEMENT_CLASS(wxAnimationCtrl, wxAnimationCtrlBase)
269     BEGIN_EVENT_TABLE(wxAnimationCtrl, wxAnimationCtrlBase)
270     EVT_PAINT(wxAnimationCtrl::OnPaint)
271     EVT_SIZE(wxAnimationCtrl::OnSize)
272     EVT_TIMER(wxID_ANY, wxAnimationCtrl::OnTimer)
273     END_EVENT_TABLE()
274    
275     void wxAnimationCtrl::Init()
276     {
277     m_currentFrame = 0;
278     m_looped = false;
279     m_isPlaying = false;
280    
281     // use the window background colour by default to be consistent
282     // with the GTK+ native version
283     m_useWinBackgroundColour = true;
284     }
285    
286     bool wxAnimationCtrl::Create(wxWindow *parent, wxWindowID id,
287     const wxAnimation& animation, const wxPoint& pos,
288     const wxSize& size, long style, const wxString& name)
289     {
290     m_timer.SetOwner(this);
291    
292     if (!base_type::Create(parent, id, pos, size, style, wxDefaultValidator, name))
293     return false;
294    
295     // by default we get the same background colour of our parent
296     SetBackgroundColour(parent->GetBackgroundColour());
297    
298     SetAnimation(animation);
299    
300     return true;
301     }
302    
303     wxAnimationCtrl::~wxAnimationCtrl()
304     {
305     Stop();
306     }
307    
308     bool wxAnimationCtrl::LoadFile(const wxString& filename, wxAnimationType type)
309     {
310     wxAnimation anim;
311     if (!anim.LoadFile(filename, type) ||
312     !anim.IsOk())
313     return false;
314    
315     SetAnimation(anim);
316     return true;
317     }
318    
319     wxSize wxAnimationCtrl::DoGetBestSize() const
320     {
321     if (m_animation.IsOk() && !this->HasFlag(wxAC_NO_AUTORESIZE))
322     return m_animation.GetSize();
323    
324     return wxSize(100, 100);
325     }
326    
327     void wxAnimationCtrl::SetAnimation(const wxAnimation& animation)
328     {
329     if (IsPlaying())
330     Stop();
331    
332     // set new animation even if it's wxNullAnimation
333     m_animation = animation;
334     if (!m_animation.IsOk())
335     {
336     DisplayStaticImage();
337     return;
338     }
339    
340     if (m_animation.GetBackgroundColour() == wxNullColour)
341     SetUseWindowBackgroundColour();
342     if (!this->HasFlag(wxAC_NO_AUTORESIZE))
343     FitToAnimation();
344    
345     DisplayStaticImage();
346     }
347    
348     void wxAnimationCtrl::SetInactiveBitmap(const wxBitmap &bmp)
349     {
350     // if the bitmap has an associated mask, we need to set our background to
351     // the colour of our parent otherwise when calling DrawCurrentFrame()
352     // (which uses the bitmap's mask), our background colour would be used for
353     // transparent areas - and that's not what we want (at least for
354     // consistency with the GTK version)
355     if ( bmp.GetMask() != NULL && GetParent() != NULL )
356     SetBackgroundColour(GetParent()->GetBackgroundColour());
357    
358     wxAnimationCtrlBase::SetInactiveBitmap(bmp);
359     }
360    
361     void wxAnimationCtrl::FitToAnimation()
362     {
363     SetSize(m_animation.GetSize());
364     }
365    
366     bool wxAnimationCtrl::SetBackgroundColour(const wxColour& colour)
367     {
368     if ( !wxWindow::SetBackgroundColour(colour) )
369     return false;
370    
371     // if not playing, then this change must be seen immediately (unless
372     // there's an inactive bitmap set which has higher priority than bg colour)
373     if ( !IsPlaying() )
374     DisplayStaticImage();
375    
376     return true;
377     }
378    
379    
380     // ----------------------------------------------------------------------------
381     // wxAnimationCtrl - stop/play methods
382     // ----------------------------------------------------------------------------
383    
384     void wxAnimationCtrl::Stop()
385     {
386     m_timer.Stop();
387     m_isPlaying = false;
388    
389     // reset frame counter
390     m_currentFrame = 0;
391    
392     DisplayStaticImage();
393     }
394    
395     bool wxAnimationCtrl::Play(bool looped)
396     {
397     if (!m_animation.IsOk())
398     return false;
399    
400     m_looped = looped;
401     m_currentFrame = 0;
402    
403     if (!RebuildBackingStoreUpToFrame(0))
404     return false;
405    
406     m_isPlaying = true;
407    
408     // do a ClearBackground() to avoid that e.g. the custom static bitmap which
409     // was eventually shown previously remains partially drawn
410     ClearBackground();
411    
412     // DrawCurrentFrame() will use our updated backing store
413     wxClientDC clientDC(this);
414     DrawCurrentFrame(clientDC);
415    
416     // start the timer
417     int delay = m_animation.GetDelay(0);
418     if (delay == 0)
419     delay = 1; // 0 is invalid timeout for wxTimer.
420     m_timer.Start(delay, true);
421    
422     return true;
423     }
424    
425    
426    
427     // ----------------------------------------------------------------------------
428     // wxAnimationCtrl - rendering methods
429     // ----------------------------------------------------------------------------
430    
431     bool wxAnimationCtrl::RebuildBackingStoreUpToFrame(unsigned int frame)
432     {
433     // if we've not created the backing store yet or it's too
434     // small, then recreate it
435     wxSize sz = m_animation.GetSize(),
436     winsz = GetClientSize();
437     int w = wxMin(sz.GetWidth(), winsz.GetWidth());
438     int h = wxMin(sz.GetHeight(), winsz.GetHeight());
439    
440     if ( !m_backingStore.IsOk() ||
441     m_backingStore.GetWidth() < w || m_backingStore.GetHeight() < h )
442     {
443     if (!m_backingStore.Create(w, h))
444     return false;
445     }
446    
447     wxMemoryDC dc;
448     dc.SelectObject(m_backingStore);
449    
450     // Draw the background
451     DisposeToBackground(dc);
452    
453     // Draw all intermediate frames that haven't been removed from the animation
454     for (unsigned int i = 0; i < frame; i++)
455     {
456     if (m_animation.GetDisposalMethod(i) == wxANIM_DONOTREMOVE ||
457     m_animation.GetDisposalMethod(i) == wxANIM_UNSPECIFIED)
458     {
459     DrawFrame(dc, i);
460     }
461     else if (m_animation.GetDisposalMethod(i) == wxANIM_TOBACKGROUND)
462     DisposeToBackground(dc, m_animation.GetFramePosition(i),
463     m_animation.GetFrameSize(i));
464     }
465    
466     // finally draw this frame
467     DrawFrame(dc, frame);
468     dc.SelectObject(wxNullBitmap);
469    
470     return true;
471     }
472    
473     void wxAnimationCtrl::IncrementalUpdateBackingStore()
474     {
475     wxMemoryDC dc;
476     dc.SelectObject(m_backingStore);
477    
478     // OPTIMIZATION:
479     // since wxAnimationCtrl can only play animations forward, without skipping
480     // frames, we can be sure that m_backingStore contains the m_currentFrame-1
481     // frame and thus we just need to dispose the m_currentFrame-1 frame and
482     // render the m_currentFrame-th one.
483    
484     if (m_currentFrame == 0)
485     {
486     // before drawing the first frame always dispose to bg colour
487     DisposeToBackground(dc);
488     }
489     else
490     {
491     switch (m_animation.GetDisposalMethod(m_currentFrame-1))
492     {
493     case wxANIM_TOBACKGROUND:
494     DisposeToBackground(dc, m_animation.GetFramePosition(m_currentFrame-1),
495     m_animation.GetFrameSize(m_currentFrame-1));
496     break;
497    
498     case wxANIM_TOPREVIOUS:
499     // this disposal should never be used too often.
500     // E.g. GIF specification explicitely say to keep the usage of this
501     // disposal limited to the minimum.
502     // In fact it may require a lot of time to restore
503     if (m_currentFrame == 1)
504     {
505     // if 0-th frame disposal is to restore to previous frame,
506     // the best we can do is to restore to background
507     DisposeToBackground(dc);
508     }
509     else
510     if (!RebuildBackingStoreUpToFrame(m_currentFrame-2))
511     Stop();
512     break;
513    
514     case wxANIM_DONOTREMOVE:
515     case wxANIM_UNSPECIFIED:
516     break;
517     }
518     }
519    
520     // now just draw the current frame on the top of the backing store
521     DrawFrame(dc, m_currentFrame);
522     dc.SelectObject(wxNullBitmap);
523     }
524    
525     void wxAnimationCtrl::DisplayStaticImage()
526     {
527     wxASSERT(!IsPlaying());
528    
529     // m_bmpStaticReal will be updated only if necessary...
530     UpdateStaticImage();
531    
532     if (m_bmpStaticReal.IsOk())
533     {
534     // copy the inactive bitmap in the backing store
535     // eventually using the mask if the static bitmap has one
536     if ( m_bmpStaticReal.GetMask() )
537     {
538     wxMemoryDC temp;
539     temp.SelectObject(m_backingStore);
540     DisposeToBackground(temp);
541     temp.DrawBitmap(m_bmpStaticReal, 0, 0, true /* use mask */);
542     }
543     else
544     m_backingStore = m_bmpStaticReal;
545     }
546     else
547     {
548     // put in the backing store the first frame of the animation
549     if (!m_animation.IsOk() ||
550     !RebuildBackingStoreUpToFrame(0))
551     {
552     m_animation = wxNullAnimation;
553     DisposeToBackground();
554     }
555     }
556    
557     Refresh();
558     }
559    
560     void wxAnimationCtrl::DrawFrame(wxDC &dc, unsigned int frame)
561     {
562     // PERFORMANCE NOTE:
563     // this draw stuff is not as fast as possible: the wxAnimationDecoder
564     // needs first to convert from its internal format to wxImage RGB24;
565     // the wxImage is then converted as a wxBitmap and finally blitted.
566     // If wxAnimationDecoder had a function to convert directly from its
567     // internal format to a port-specific wxBitmap, it would be somewhat faster.
568     wxBitmap bmp(m_animation.GetFrame(frame));
569     dc.DrawBitmap(bmp, m_animation.GetFramePosition(frame),
570     true /* use mask */);
571     }
572    
573     void wxAnimationCtrl::DrawCurrentFrame(wxDC& dc)
574     {
575     wxASSERT( m_backingStore.IsOk() );
576    
577     // m_backingStore always contains the current frame
578     dc.DrawBitmap(m_backingStore, 0, 0, true /* use mask in case it's present */);
579     }
580    
581     void wxAnimationCtrl::DisposeToBackground()
582     {
583     // clear the backing store
584     wxMemoryDC dc;
585     dc.SelectObject(m_backingStore);
586     if ( dc.IsOk() )
587     DisposeToBackground(dc);
588     }
589    
590     void wxAnimationCtrl::DisposeToBackground(wxDC& dc)
591     {
592     wxColour col = IsUsingWindowBackgroundColour()
593     ? GetBackgroundColour()
594     : m_animation.GetBackgroundColour();
595    
596     wxBrush brush(col);
597     dc.SetBackground(brush);
598     dc.Clear();
599     }
600    
601     void wxAnimationCtrl::DisposeToBackground(wxDC& dc, const wxPoint &pos, const wxSize &sz)
602     {
603     wxColour col = IsUsingWindowBackgroundColour()
604     ? GetBackgroundColour()
605     : m_animation.GetBackgroundColour();
606     wxBrush brush(col);
607     dc.SetBrush(brush); // SetBrush and not SetBackground !!
608     dc.SetPen(*wxTRANSPARENT_PEN);
609     dc.DrawRectangle(pos, sz);
610     }
611    
612     // ----------------------------------------------------------------------------
613     // wxAnimationCtrl - event handlers
614     // ----------------------------------------------------------------------------
615    
616     void wxAnimationCtrl::OnPaint(wxPaintEvent& WXUNUSED(event))
617     {
618     // VERY IMPORTANT: the wxPaintDC *must* be created in any case
619     wxPaintDC dc(this);
620    
621     if ( m_backingStore.IsOk() )
622     {
623     // NOTE: we draw the bitmap explicitely ignoring the mask (if any);
624     // i.e. we don't want to combine the backing store with the
625     // possibly wrong preexisting contents of the window!
626     dc.DrawBitmap(m_backingStore, 0, 0, false /* no mask */);
627     }
628     else
629     {
630     // m_animation is not valid and thus we don't have a valid backing store...
631     // clear then our area to the background colour
632     DisposeToBackground(dc);
633     }
634     }
635    
636     void wxAnimationCtrl::OnTimer(wxTimerEvent &WXUNUSED(event))
637     {
638     m_currentFrame++;
639     if (m_currentFrame == m_animation.GetFrameCount())
640     {
641     // Should a non-looped animation display the last frame?
642     if (!m_looped)
643     {
644     Stop();
645     return;
646     }
647     else
648     m_currentFrame = 0; // let's restart
649     }
650    
651     IncrementalUpdateBackingStore();
652    
653     wxClientDC dc(this);
654     DrawCurrentFrame(dc);
655    
656     #ifdef __WXMAC__
657     // without this, the animation currently doesn't redraw under Mac
658     Refresh();
659     #endif // __WXMAC__
660    
661     // Set the timer for the next frame
662     int delay = m_animation.GetDelay(m_currentFrame);
663     if (delay == 0)
664     delay = 1; // 0 is invalid timeout for wxTimer.
665     m_timer.Start(delay, true);
666     }
667    
668     void wxAnimationCtrl::OnSize(wxSizeEvent &WXUNUSED(event))
669     {
670     // NB: resizing an animation control may take a lot of time
671     // for big animations as the backing store must be
672     // extended and rebuilt. Try to avoid it e.g. using
673     // a null proportion value for your wxAnimationCtrls
674     // when using them inside sizers.
675     if (m_animation.IsOk())
676     {
677     // be careful to change the backing store *only* if we are
678     // playing the animation as otherwise we may be displaying
679     // the inactive bitmap and overwriting the backing store
680     // with the last played frame is wrong in this case
681     if (IsPlaying())
682     {
683     if (!RebuildBackingStoreUpToFrame(m_currentFrame))
684     Stop(); // in case we are playing
685     }
686     }
687     }
688    
689     #endif // wxUSE_ANIMATIONCTRL
690    

  ViewVC Help
Powered by ViewVC 1.1.22