]> git.saurik.com Git - wxWidgets.git/blame - src/generic/animateg.cpp
miscellaneous small enhancements
[wxWidgets.git] / src / generic / animateg.cpp
CommitLineData
72045d57
VZ
1///////////////////////////////////////////////////////////////////////////////
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$
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
ff654490 18#if wxUSE_ANIMATIONCTRL
72045d57 19
c2f12218
PC
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
72045d57 30#include "wx/wfstream.h"
72045d57
VZ
31#include "wx/gifdecod.h"
32#include "wx/anidecod.h"
72045d57 33
c2f12218 34#include "wx/listimpl.cpp"
14c0d834 35WX_DEFINE_LIST(wxAnimationDecoderList)
72045d57
VZ
36
37wxAnimationDecoderList wxAnimation::sm_handlers;
38
39
72045d57
VZ
40// ----------------------------------------------------------------------------
41// wxAnimation
42// ----------------------------------------------------------------------------
43
44IMPLEMENT_DYNAMIC_CLASS(wxAnimation, wxAnimationBase)
5c33522f 45#define M_ANIMDATA static_cast<wxAnimationDecoder*>(m_refData)
72045d57
VZ
46
47wxSize wxAnimation::GetSize() const
48{
49 wxCHECK_MSG( IsOk(), wxDefaultSize, wxT("invalid animation") );
50
51 return M_ANIMDATA->GetAnimationSize();
52}
53
870cf35c 54unsigned int wxAnimation::GetFrameCount() const
72045d57
VZ
55{
56 wxCHECK_MSG( IsOk(), 0, wxT("invalid animation") );
57
58 return M_ANIMDATA->GetFrameCount();
59}
60
870cf35c 61wxImage wxAnimation::GetFrame(unsigned int i) const
72045d57
VZ
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
870cf35c 71int wxAnimation::GetDelay(unsigned int i) const
72045d57
VZ
72{
73 wxCHECK_MSG( IsOk(), 0, wxT("invalid animation") );
74
75 return M_ANIMDATA->GetDelay(i);
76}
77
870cf35c 78wxPoint wxAnimation::GetFramePosition(unsigned int frame) const
72045d57
VZ
79{
80 wxCHECK_MSG( IsOk(), wxDefaultPosition, wxT("invalid animation") );
81
82 return M_ANIMDATA->GetFramePosition(frame);
83}
84
870cf35c 85wxSize wxAnimation::GetFrameSize(unsigned int frame) const
05a98b6d
RR
86{
87 wxCHECK_MSG( IsOk(), wxDefaultSize, wxT("invalid animation") );
88
89 return M_ANIMDATA->GetFrameSize(frame);
90}
91
870cf35c 92wxAnimationDisposal wxAnimation::GetDisposalMethod(unsigned int frame) const
72045d57
VZ
93{
94 wxCHECK_MSG( IsOk(), wxANIM_UNSPECIFIED, wxT("invalid animation") );
95
96 return M_ANIMDATA->GetDisposalMethod(frame);
97}
98
870cf35c 99wxColour wxAnimation::GetTransparentColour(unsigned int frame) const
05a98b6d
RR
100{
101 wxCHECK_MSG( IsOk(), wxNullColour, wxT("invalid animation") );
102
103 return M_ANIMDATA->GetTransparentColour(frame);
104}
105
72045d57
VZ
106wxColour wxAnimation::GetBackgroundColour() const
107{
108 wxCHECK_MSG( IsOk(), wxNullColour, wxT("invalid animation") );
109
110 return M_ANIMDATA->GetBackgroundColour();
111}
112
113bool wxAnimation::LoadFile(const wxString& filename, wxAnimationType type)
114{
115 wxFileInputStream stream(filename);
9d9e3858 116 if ( !stream.IsOk() )
72045d57
VZ
117 return false;
118
119 return Load(stream, type);
120}
121
122bool wxAnimation::Load(wxInputStream &stream, wxAnimationType type)
123{
124 UnRef();
125
126 const wxAnimationDecoder *handler;
127 if ( type == wxANIMATION_TYPE_ANY )
128 {
9d9e3858 129 for ( wxAnimationDecoderList::compatibility_iterator node = sm_handlers.GetFirst();
72045d57
VZ
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 }
72045d57
VZ
141 }
142
143 wxLogWarning( _("No handler found for animation type.") );
144 return false;
145 }
146
147 handler = FindHandler(type);
148
72045d57
VZ
149 if (handler == NULL)
150 {
151 wxLogWarning( _("No animation handler for type %ld defined."), type );
152
153 return false;
154 }
155
ba578767
VZ
156
157 // do a copy of the handler from the static list which we will own
158 // as our reference data
159 m_refData = handler->Clone();
160
72045d57
VZ
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
175void 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.
72045d57
VZ
188
189 wxLogDebug( _T("Adding duplicate animation handler for '%d' type"),
190 handler->GetType() );
191 delete handler;
192 }
193}
194
195void 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
211const 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
223void wxAnimation::InitStandardHandlers()
224{
d18868bb 225#if wxUSE_GIF
72045d57 226 AddHandler(new wxGIFDecoder);
d18868bb
WS
227#endif // wxUSE_GIF
228#if wxUSE_ICO_CUR
72045d57 229 AddHandler(new wxANIDecoder);
d18868bb 230#endif // wxUSE_ICO_CUR
72045d57
VZ
231}
232
233void 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
252class wxAnimationModule: public wxModule
253{
254DECLARE_DYNAMIC_CLASS(wxAnimationModule)
255public:
256 wxAnimationModule() {}
47b378bd
VS
257 bool OnInit() { wxAnimation::InitStandardHandlers(); return true; }
258 void OnExit() { wxAnimation::CleanUpHandlers(); }
72045d57
VZ
259};
260
261IMPLEMENT_DYNAMIC_CLASS(wxAnimationModule, wxModule)
262
263
72045d57
VZ
264// ----------------------------------------------------------------------------
265// wxAnimationCtrl
266// ----------------------------------------------------------------------------
267
268IMPLEMENT_CLASS(wxAnimationCtrl, wxAnimationCtrlBase)
269BEGIN_EVENT_TABLE(wxAnimationCtrl, wxAnimationCtrlBase)
270 EVT_PAINT(wxAnimationCtrl::OnPaint)
271 EVT_SIZE(wxAnimationCtrl::OnSize)
272 EVT_TIMER(wxID_ANY, wxAnimationCtrl::OnTimer)
273END_EVENT_TABLE()
274
05a98b6d 275void wxAnimationCtrl::Init()
c2f12218
PC
276{
277 m_currentFrame = 0;
278 m_looped = false;
279 m_isPlaying = false;
05a98b6d
RR
280
281 // use the window background colour by default to be consistent
282 // with the GTK+ native version
283 m_useWinBackgroundColour = true;
c2f12218
PC
284}
285
72045d57
VZ
286bool wxAnimationCtrl::Create(wxWindow *parent, wxWindowID id,
287 const wxAnimation& animation, const wxPoint& pos,
288 const wxSize& size, long style, const wxString& name)
289{
72045d57
VZ
290 m_timer.SetOwner(this);
291
c2f12218 292 if (!base_type::Create(parent, id, pos, size, style, wxDefaultValidator, name))
72045d57
VZ
293 return false;
294
295 // by default we get the same background colour of our parent
296 SetBackgroundColour(parent->GetBackgroundColour());
4683dc1c
VZ
297
298 SetAnimation(animation);
299
72045d57
VZ
300 return true;
301}
302
303wxAnimationCtrl::~wxAnimationCtrl()
304{
305 Stop();
306}
307
308bool wxAnimationCtrl::LoadFile(const wxString& filename, wxAnimationType type)
462167a9
VZ
309{
310 wxFileInputStream fis(filename);
9690b006
FM
311 if (!fis.Ok())
312 return false;
462167a9
VZ
313 return Load(fis, type);
314}
315
316bool wxAnimationCtrl::Load(wxInputStream& stream, wxAnimationType type)
72045d57
VZ
317{
318 wxAnimation anim;
462167a9 319 if ( !anim.Load(stream, type) || !anim.IsOk() )
72045d57
VZ
320 return false;
321
322 SetAnimation(anim);
323 return true;
324}
325
326wxSize wxAnimationCtrl::DoGetBestSize() const
327{
328 if (m_animation.IsOk() && !this->HasFlag(wxAC_NO_AUTORESIZE))
329 return m_animation.GetSize();
330
331 return wxSize(100, 100);
332}
333
334void wxAnimationCtrl::SetAnimation(const wxAnimation& animation)
335{
336 if (IsPlaying())
337 Stop();
338
1afdfc9d 339 // set new animation even if it's wxNullAnimation
72045d57 340 m_animation = animation;
1afdfc9d
VZ
341 if (!m_animation.IsOk())
342 {
1bd2ceb5 343 DisplayStaticImage();
1afdfc9d
VZ
344 return;
345 }
72045d57
VZ
346
347 if (m_animation.GetBackgroundColour() == wxNullColour)
348 SetUseWindowBackgroundColour();
349 if (!this->HasFlag(wxAC_NO_AUTORESIZE))
350 FitToAnimation();
351
1bd2ceb5 352 DisplayStaticImage();
8e458bb5 353}
72045d57 354
8e458bb5
RR
355void wxAnimationCtrl::SetInactiveBitmap(const wxBitmap &bmp)
356{
1afdfc9d
VZ
357 // if the bitmap has an associated mask, we need to set our background to
358 // the colour of our parent otherwise when calling DrawCurrentFrame()
359 // (which uses the bitmap's mask), our background colour would be used for
360 // transparent areas - and that's not what we want (at least for
361 // consistency with the GTK version)
362 if ( bmp.GetMask() != NULL && GetParent() != NULL )
363 SetBackgroundColour(GetParent()->GetBackgroundColour());
364
1bd2ceb5 365 wxAnimationCtrlBase::SetInactiveBitmap(bmp);
72045d57
VZ
366}
367
368void wxAnimationCtrl::FitToAnimation()
369{
370 SetSize(m_animation.GetSize());
371}
372
1afdfc9d
VZ
373bool wxAnimationCtrl::SetBackgroundColour(const wxColour& colour)
374{
375 if ( !wxWindow::SetBackgroundColour(colour) )
376 return false;
377
378 // if not playing, then this change must be seen immediately (unless
379 // there's an inactive bitmap set which has higher priority than bg colour)
380 if ( !IsPlaying() )
1bd2ceb5 381 DisplayStaticImage();
1afdfc9d
VZ
382
383 return true;
384}
385
72045d57
VZ
386
387// ----------------------------------------------------------------------------
388// wxAnimationCtrl - stop/play methods
389// ----------------------------------------------------------------------------
390
391void wxAnimationCtrl::Stop()
392{
72045d57
VZ
393 m_timer.Stop();
394 m_isPlaying = false;
8e458bb5 395
1afdfc9d
VZ
396 // reset frame counter
397 m_currentFrame = 0;
398
1bd2ceb5 399 DisplayStaticImage();
72045d57
VZ
400}
401
402bool wxAnimationCtrl::Play(bool looped)
403{
404 if (!m_animation.IsOk())
405 return false;
406
72045d57
VZ
407 m_looped = looped;
408 m_currentFrame = 0;
72045d57 409
8434297d
RD
410 if (!RebuildBackingStoreUpToFrame(0))
411 return false;
05a98b6d
RR
412
413 m_isPlaying = true;
72045d57 414
8e458bb5
RR
415 // do a ClearBackground() to avoid that e.g. the custom static bitmap which
416 // was eventually shown previously remains partially drawn
417 ClearBackground();
418
72045d57
VZ
419 // DrawCurrentFrame() will use our updated backing store
420 wxClientDC clientDC(this);
421 DrawCurrentFrame(clientDC);
422
423 // start the timer
424 int delay = m_animation.GetDelay(0);
425 if (delay == 0)
426 delay = 1; // 0 is invalid timeout for wxTimer.
48271822 427 m_timer.Start(delay, true);
72045d57
VZ
428
429 return true;
430}
431
432
433
434// ----------------------------------------------------------------------------
435// wxAnimationCtrl - rendering methods
436// ----------------------------------------------------------------------------
437
870cf35c 438bool wxAnimationCtrl::RebuildBackingStoreUpToFrame(unsigned int frame)
72045d57
VZ
439{
440 // if we've not created the backing store yet or it's too
441 // small, then recreate it
442 wxSize sz = m_animation.GetSize(),
443 winsz = GetClientSize();
444 int w = wxMin(sz.GetWidth(), winsz.GetWidth());
445 int h = wxMin(sz.GetHeight(), winsz.GetHeight());
446
9d9e3858 447 if ( !m_backingStore.IsOk() ||
6003de2f
VZ
448 m_backingStore.GetWidth() < w || m_backingStore.GetHeight() < h )
449 {
05a98b6d
RR
450 if (!m_backingStore.Create(w, h))
451 return false;
6003de2f 452 }
72045d57
VZ
453
454 wxMemoryDC dc;
455 dc.SelectObject(m_backingStore);
456
457 // Draw the background
458 DisposeToBackground(dc);
459
460 // Draw all intermediate frames that haven't been removed from the animation
870cf35c 461 for (unsigned int i = 0; i < frame; i++)
72045d57
VZ
462 {
463 if (m_animation.GetDisposalMethod(i) == wxANIM_DONOTREMOVE ||
464 m_animation.GetDisposalMethod(i) == wxANIM_UNSPECIFIED)
465 {
466 DrawFrame(dc, i);
467 }
05a98b6d
RR
468 else if (m_animation.GetDisposalMethod(i) == wxANIM_TOBACKGROUND)
469 DisposeToBackground(dc, m_animation.GetFramePosition(i),
470 m_animation.GetFrameSize(i));
72045d57
VZ
471 }
472
473 // finally draw this frame
474 DrawFrame(dc, frame);
475 dc.SelectObject(wxNullBitmap);
05a98b6d
RR
476
477 return true;
72045d57
VZ
478}
479
480void wxAnimationCtrl::IncrementalUpdateBackingStore()
481{
482 wxMemoryDC dc;
483 dc.SelectObject(m_backingStore);
484
485 // OPTIMIZATION:
486 // since wxAnimationCtrl can only play animations forward, without skipping
487 // frames, we can be sure that m_backingStore contains the m_currentFrame-1
488 // frame and thus we just need to dispose the m_currentFrame-1 frame and
489 // render the m_currentFrame-th one.
490
491 if (m_currentFrame == 0)
492 {
493 // before drawing the first frame always dispose to bg colour
494 DisposeToBackground(dc);
495 }
496 else
497 {
498 switch (m_animation.GetDisposalMethod(m_currentFrame-1))
499 {
500 case wxANIM_TOBACKGROUND:
05a98b6d
RR
501 DisposeToBackground(dc, m_animation.GetFramePosition(m_currentFrame-1),
502 m_animation.GetFrameSize(m_currentFrame-1));
72045d57
VZ
503 break;
504
505 case wxANIM_TOPREVIOUS:
506 // this disposal should never be used too often.
507 // E.g. GIF specification explicitely say to keep the usage of this
9d9e3858
VZ
508 // disposal limited to the minimum.
509 // In fact it may require a lot of time to restore
72045d57
VZ
510 if (m_currentFrame == 1)
511 {
512 // if 0-th frame disposal is to restore to previous frame,
513 // the best we can do is to restore to background
514 DisposeToBackground(dc);
515 }
516 else
05a98b6d
RR
517 if (!RebuildBackingStoreUpToFrame(m_currentFrame-2))
518 Stop();
72045d57
VZ
519 break;
520
521 case wxANIM_DONOTREMOVE:
522 case wxANIM_UNSPECIFIED:
523 break;
524 }
525 }
526
527 // now just draw the current frame on the top of the backing store
528 DrawFrame(dc, m_currentFrame);
529 dc.SelectObject(wxNullBitmap);
530}
531
1bd2ceb5 532void wxAnimationCtrl::DisplayStaticImage()
8e458bb5
RR
533{
534 wxASSERT(!IsPlaying());
535
1bd2ceb5
RR
536 // m_bmpStaticReal will be updated only if necessary...
537 UpdateStaticImage();
538
539 if (m_bmpStaticReal.IsOk())
8e458bb5
RR
540 {
541 // copy the inactive bitmap in the backing store
1afdfc9d 542 // eventually using the mask if the static bitmap has one
1bd2ceb5 543 if ( m_bmpStaticReal.GetMask() )
1afdfc9d
VZ
544 {
545 wxMemoryDC temp;
546 temp.SelectObject(m_backingStore);
547 DisposeToBackground(temp);
1bd2ceb5 548 temp.DrawBitmap(m_bmpStaticReal, 0, 0, true /* use mask */);
1afdfc9d
VZ
549 }
550 else
1bd2ceb5 551 m_backingStore = m_bmpStaticReal;
8e458bb5
RR
552 }
553 else
554 {
555 // put in the backing store the first frame of the animation
556 if (!m_animation.IsOk() ||
557 !RebuildBackingStoreUpToFrame(0))
558 {
559 m_animation = wxNullAnimation;
560 DisposeToBackground();
561 }
562 }
563
564 Refresh();
565}
566
870cf35c 567void wxAnimationCtrl::DrawFrame(wxDC &dc, unsigned int frame)
72045d57
VZ
568{
569 // PERFORMANCE NOTE:
570 // this draw stuff is not as fast as possible: the wxAnimationDecoder
571 // needs first to convert from its internal format to wxImage RGB24;
572 // the wxImage is then converted as a wxBitmap and finally blitted.
573 // If wxAnimationDecoder had a function to convert directly from its
574 // internal format to a port-specific wxBitmap, it would be somewhat faster.
575 wxBitmap bmp(m_animation.GetFrame(frame));
576 dc.DrawBitmap(bmp, m_animation.GetFramePosition(frame),
577 true /* use mask */);
578}
579
580void wxAnimationCtrl::DrawCurrentFrame(wxDC& dc)
581{
9d9e3858 582 wxASSERT( m_backingStore.IsOk() );
72045d57
VZ
583
584 // m_backingStore always contains the current frame
8e458bb5
RR
585 dc.DrawBitmap(m_backingStore, 0, 0, true /* use mask in case it's present */);
586}
587
588void wxAnimationCtrl::DisposeToBackground()
589{
590 // clear the backing store
591 wxMemoryDC dc;
592 dc.SelectObject(m_backingStore);
988bbabb
VZ
593 if ( dc.IsOk() )
594 DisposeToBackground(dc);
72045d57
VZ
595}
596
597void wxAnimationCtrl::DisposeToBackground(wxDC& dc)
87d2b3f1
CE
598{
599 wxColour col = IsUsingWindowBackgroundColour()
9d9e3858 600 ? GetBackgroundColour()
05a98b6d 601 : m_animation.GetBackgroundColour();
1afdfc9d 602
87d2b3f1 603 wxBrush brush(col);
72045d57
VZ
604 dc.SetBackground(brush);
605 dc.Clear();
606}
607
05a98b6d
RR
608void wxAnimationCtrl::DisposeToBackground(wxDC& dc, const wxPoint &pos, const wxSize &sz)
609{
610 wxColour col = IsUsingWindowBackgroundColour()
611 ? GetBackgroundColour()
612 : m_animation.GetBackgroundColour();
613 wxBrush brush(col);
614 dc.SetBrush(brush); // SetBrush and not SetBackground !!
615 dc.SetPen(*wxTRANSPARENT_PEN);
616 dc.DrawRectangle(pos, sz);
617}
618
72045d57
VZ
619// ----------------------------------------------------------------------------
620// wxAnimationCtrl - event handlers
621// ----------------------------------------------------------------------------
622
623void wxAnimationCtrl::OnPaint(wxPaintEvent& WXUNUSED(event))
624{
625 // VERY IMPORTANT: the wxPaintDC *must* be created in any case
626 wxPaintDC dc(this);
627
9d9e3858 628 if ( m_backingStore.IsOk() )
1afdfc9d
VZ
629 {
630 // NOTE: we draw the bitmap explicitely ignoring the mask (if any);
631 // i.e. we don't want to combine the backing store with the
632 // possibly wrong preexisting contents of the window!
633 dc.DrawBitmap(m_backingStore, 0, 0, false /* no mask */);
634 }
8e458bb5
RR
635 else
636 {
637 // m_animation is not valid and thus we don't have a valid backing store...
638 // clear then our area to the background colour
639 DisposeToBackground(dc);
640 }
72045d57
VZ
641}
642
643void wxAnimationCtrl::OnTimer(wxTimerEvent &WXUNUSED(event))
644{
645 m_currentFrame++;
646 if (m_currentFrame == m_animation.GetFrameCount())
647 {
648 // Should a non-looped animation display the last frame?
649 if (!m_looped)
650 {
8e458bb5 651 Stop();
72045d57
VZ
652 return;
653 }
654 else
655 m_currentFrame = 0; // let's restart
656 }
657
658 IncrementalUpdateBackingStore();
659
660 wxClientDC dc(this);
661 DrawCurrentFrame(dc);
662
7444cb50
VZ
663#ifdef __WXMAC__
664 // without this, the animation currently doesn't redraw under Mac
665 Refresh();
666#endif // __WXMAC__
667
72045d57
VZ
668 // Set the timer for the next frame
669 int delay = m_animation.GetDelay(m_currentFrame);
670 if (delay == 0)
671 delay = 1; // 0 is invalid timeout for wxTimer.
48271822 672 m_timer.Start(delay, true);
72045d57
VZ
673}
674
675void wxAnimationCtrl::OnSize(wxSizeEvent &WXUNUSED(event))
676{
677 // NB: resizing an animation control may take a lot of time
678 // for big animations as the backing store must be
580ca0a4
VZ
679 // extended and rebuilt. Try to avoid it e.g. using
680 // a null proportion value for your wxAnimationCtrls
681 // when using them inside sizers.
72045d57 682 if (m_animation.IsOk())
580ca0a4
VZ
683 {
684 // be careful to change the backing store *only* if we are
685 // playing the animation as otherwise we may be displaying
686 // the inactive bitmap and overwriting the backing store
687 // with the last played frame is wrong in this case
688 if (IsPlaying())
689 {
1afdfc9d
VZ
690 if (!RebuildBackingStoreUpToFrame(m_currentFrame))
691 Stop(); // in case we are playing
580ca0a4
VZ
692 }
693 }
72045d57
VZ
694}
695
ff654490 696#endif // wxUSE_ANIMATIONCTRL
72045d57 697