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