Comba Animation - Initial commit v1.00

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@5794 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
joshy
2017-03-06 22:32:35 +00:00
parent f041ad0063
commit 20fcc57d97
17 changed files with 6760 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,231 @@
#The following people contributed to Lazarus:
A. J. Venter
Алексей Лагунов
Alexander Grau
Alexander S. Klenin
Alexander Shiyan
Alexandr Gridnev
Alexandre Leclerc
Alexandru Alexandrov
Alexey Torgashin
Andreas Hausladen
Andreas Schneider
Andrew Haines
Andrew Johnson
Anton A. Panferov
Anton Kavalenka
Antônio Galvão
Arnold Bosch
Attila Tamás - Hungarian translation
August Klein
Babak Mahmoudabadi
Balazs Szekely
Bald Zhang
Bart Broersma
Benito van der Zander
Bent Normann Olsen
Bernd Engelhardt
Bernd Kreuss
Bernd Mueller
Bob Wingard
Bogusław Brandys
Boian Mitov
Boris Arko
Boris Glavin
Boris Popov
Brad Campbell
Bruce Tulloch
Chris Rorden
Christian Budde
Christian Iversen
Christian Ulrich
Christopher Kirkpatrick
Cliff Baeseman
Colin Western
Curtis White
Daniel Oom
Daniel Simões de Almeida
Darek Mazur
Darius Blaszijk
Dávid Fehér - Hungarian translation
David Guadagnini
David Jenkins
David Pethes
David Zimmer
Dean Zobec
Denis Golovan
Denis Kozlov
Denis Volodarsky
Derit Agustin
Diogo Piçarra
Dirk Schiphorst
Dmitry Boyarintsev
Dominique Louis
Ere Maijala
Eric Chapman
Erivelton Silva
Erwin van den Bosch
Eugene Kryukov
Evgen A. Palamarchuck
Ezik Shlomi
Fabrizio Fellini
Fathony Luthfillah (x2nie)
Felipe Monteiro de Carvalho
Flávio Etrusco
Florian Koeberle
Francisco Manuel
Gerard Visent
Gilles Vasseur - French translation
Giuliano Colla
Giulio Bernardi
GongYu
Graeme Geldenhuys
Grzegorz Zakrzewski
Hakan Kizilhan
Hans Luijten
Hans-Joachim Ott
Hans-Peter Diettrich
Haruyuki Fujimaki
Henry Vermaak
Hwang Weng Sun
Ido Kanner
Igor Paliychuk
Imad Goubaa
James Chandler Jr.
Jan Adamec
Jan Foster
Janusz Tomczak
Jarto Tarpio
Jason King
Jeffrey A. Wormsley
Jeroen van Idekinge
Jesus Reyes
JiXian Yang
Jörg Braun - German translation
Johannes Muller
Jonas Maebe
Joost van der Sluis
Jose Alonso Cardenas M.
José Martínez - Spanish translation
Jose Mejuto
Jouke Rensma
Juan Salvador Pérez García
Juha Manninen
Júnior Gonçalves
Justin Smyth
Karl Brandt
Keith Bowes
Khaled Shagrouni
Kostas Michalopoulos
Krzysztof Dibowski
Ladislav Michl
Laurent Jacques
Leslie Kaye
Louis Hoefler
Luca Olivetti
Lucas Martin
Ludo Brands
Luis R. Hilario B.
Luís Rodrigues
Luiz Américo
Maciej Izak (hnb)
Marc Fokker
Marc Geldon
Marc Weustink
Marcelo Borges de Paula
Mario Bonati
Mario Ray Mahardhika
Marius Ellen
Mark Bravington
Markus Muller
Martin Friebe
Martin Patik
Martin Smat
Márton Papp
Martyn Ranyard
Massimo Magnano
Massimo Soricetti
Matthijs Willemstein
Mattias Gärtner
Mattias Hansson
Maxim Ganetsky
Mazen Neifer
Micha Nelissen
Michael A. Hess
Michael Fuchs
Michael W. Vogel
Michal Bukovjan
Michal Gawrycki
Michalis Kamburelis
Mike Sapsard
Mike Thompson
Nikolay Ermolov
Nur Cholif Murtadho
Olivier Guilbaud
Ondrej Pokorny
Patrick Chevalley
Paul Ishenin
Paul Michell
Pawel Trochimczuk
Peter Dyson
Péter Gábor
Petr Kristan
Philip J. Hess
Philippe Picard
Pierre Gillmann
Przemyslaw Nagay
Radek Cervinka
Raul Moratalla
Razvan Adrian Bogdan
Reimar Grabowski
Reinier Olislagers
Roozbeh GHolizadeh
Rostislav Okulov
Salvatore Coppola
Samuel Herzog
Samuel Liddicott
Sandro Cumerlato
Sean McIlwain
Sebastian Gasiorek
Seppo Suutarla - Finnish translation
Sérgio Marcelo
Shane Miller
Sileno Goedicke
Silvio Clécio
Simon Ameis
Slavko Fedorik
Stefan Hille
Takeda Matsuki
Tamás Kálcza - Hungarian translation
Taras Boychuk
Theo Lustenberger
Tim P. Launchbury
Tobias Giesen
Tom Lisjac
Tomáš Gregorovič
Tomasz Wieckowski
Tony Maro
Vaclav Valicek
Valdas Jankūnas
Valdinilson Lourenço da Cunha
Vasily I. Volchenko
Vincent Beuselinck
Vincent Snijders
Vladimir Serotyukov
Vladimir Zhirov
Vojtech Cihak
Wanderlan Santos dos Anjos
Werner Pamler
Wojciech Malinowski
Yauheni Nazimau
Yuichiro Takahashi
Yuriy Yeroshkin
Yury Sidorov
Zaenal Mutaqin
Zaher Dirkey
Zdravko Gabrovski
Zeljan Rikalo
Žilvinas Ledas
#and special thanks to the FPC team.

View File

@ -0,0 +1,140 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectOptions>
<Version Value="10"/>
<PathDelim Value="\"/>
<General>
<SessionStorage Value="InProjectDir"/>
<MainUnit Value="0"/>
<Title Value="Lazarus Contributors Animation"/>
<ResourceType Value="res"/>
<UseXPManifest Value="True"/>
<XPManifest>
<TextName Value="CompanyName.ProductName.AppName"/>
<TextDesc Value="Your application description."/>
</XPManifest>
</General>
<i18n>
<EnableI18N LFM="False"/>
</i18n>
<BuildModes Count="2">
<Item1 Name="Debug" Default="True"/>
<Item2 Name="Release">
<CompilerOptions>
<Version Value="11"/>
<PathDelim Value="\"/>
<Target>
<Filename Value="..\..\output\contributors"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<OtherUnitFiles Value="..\..\src"/>
<UnitOutputDirectory Value="..\..\lib\$NameOnly($(ProjFile))\lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<CodeGeneration>
<Optimizations>
<OptimizationLevel Value="3"/>
</Optimizations>
</CodeGeneration>
<Linking>
<Debugging>
<GenerateDebugInfo Value="False"/>
</Debugging>
<Options>
<Win32>
<GraphicApplication Value="True"/>
</Win32>
</Options>
</Linking>
</CompilerOptions>
</Item2>
</BuildModes>
<PublishOptions>
<Version Value="2"/>
</PublishOptions>
<RunParams>
<local>
<FormatVersion Value="1"/>
</local>
</RunParams>
<RequiredPackages Count="1">
<Item1>
<PackageName Value="LCL"/>
</Item1>
</RequiredPackages>
<Units Count="5">
<Unit0>
<Filename Value="contributors.lpr"/>
<IsPartOfProject Value="True"/>
</Unit0>
<Unit1>
<Filename Value="uanimationcontributors.pas"/>
<IsPartOfProject Value="True"/>
</Unit1>
<Unit2>
<Filename Value="..\..\src\uanimationbasic.pas"/>
<IsPartOfProject Value="True"/>
</Unit2>
<Unit3>
<Filename Value="ufrmcontributors.pas"/>
<IsPartOfProject Value="True"/>
<ComponentName Value="frmContributors"/>
<HasResources Value="True"/>
<ResourceBaseClass Value="Form"/>
</Unit3>
<Unit4>
<Filename Value="..\..\src\uanimationtypes.pas"/>
<IsPartOfProject Value="True"/>
</Unit4>
</Units>
</ProjectOptions>
<CompilerOptions>
<Version Value="11"/>
<PathDelim Value="\"/>
<Target>
<Filename Value="..\..\output\contributors"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<OtherUnitFiles Value="..\..\src"/>
<UnitOutputDirectory Value="..\..\lib\$NameOnly($(ProjFile))\lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<Parsing>
<SyntaxOptions>
<IncludeAssertionCode Value="True"/>
</SyntaxOptions>
</Parsing>
<CodeGeneration>
<Checks>
<IOChecks Value="True"/>
<RangeChecks Value="True"/>
<OverflowChecks Value="True"/>
<StackChecks Value="True"/>
</Checks>
<VerifyObjMethodCallValidity Value="True"/>
</CodeGeneration>
<Linking>
<Debugging>
<UseHeaptrc Value="True"/>
</Debugging>
<Options>
<Win32>
<GraphicApplication Value="True"/>
</Win32>
</Options>
</Linking>
</CompilerOptions>
<Debugging>
<Exceptions Count="3">
<Item1>
<Name Value="EAbort"/>
</Item1>
<Item2>
<Name Value="ECodetoolError"/>
</Item2>
<Item3>
<Name Value="EFOpenError"/>
</Item3>
</Exceptions>
</Debugging>
</CONFIG>

View File

@ -0,0 +1,23 @@
program contributors;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Interfaces, // this includes the LCL widgetset
Forms, uanimationbasic,
uanimationcontributors,
ufrmcontributors, uanimationtypes;
{$R *.res}
begin
Application.Title:='Lazarus Contributors Animation';
RequireDerivedFormResource := True;
Application.Initialize;
Application.CreateForm(TfrmContributors, frmContributors);
Application.Run;
end.

View File

@ -0,0 +1,393 @@
unit uanimationcontributors;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Graphics, Controls, uanimationbasic,LCLIntf;
type
{ TAnimationTranslateLinear }
TAnimationTranslateLinear=class(TAnimationItem)
private
protected
public
FStartPoint: TPoint;
FEndPoint: TPoint;
end;
{ TTextLineAnimation }
TTextLineAnimation=class(TAnimationTranslateLinear)
private
protected
FText: string;
FLXTime: int64;
FTextWidth: integer;
FHighLight: Boolean;
procedure DoPerform; override;
public
property Text: string read FText write FText;
constructor Create(const aOrigin: TPoint; const aTarget: TPoint; const aDuration: int64); reintroduce;
end;
{ TBackgroundAnimation }
TBackgroundAnimation=class(TAnimationItem)
private
protected
FBackground: TBitmap;
procedure DoPerform; override;
public
constructor Create(const aBitmap: TBitMap);
procedure LoadBackgroundFromFile;
procedure LoadFromBitmap(const aBitmap: TBitmap);
destructor Destroy; override;
end;
{ TAboutTextZoomAnimation }
TAboutTextZoomAnimation=class(TAnimationItem)
private
protected
FText: string;
FFinalXY: TPoint;
FHidden: Boolean;
procedure DoPerform; override;
procedure DoFinalizeAnimation; override;
public
end;
{ TAboutAnimation }
TAboutAnimation=class (TAnimationQueue)
private
protected
FX: integer;
FTarget: TBitmap;
FPaintBuffer: TBitmap;
FRefreshObject: TControl;
FTextLines: TStringList;
FViewPort: TRect;
FAboutZoomEffect: TAboutTextZoomAnimation;
FFullAnimationTime: int64;
FMousePoint: TPoint;
FCalculatedFontSize: integer;
//Object to check upper and lower boundary animations
FFirstLine: TTextLineAnimation;
procedure PrepareLinesObjects;
public
property PaintBuffer: TBitmap read FPaintBuffer;
property RefreshObject: TControl read FRefreshObject write FRefreshObject;
property MousePosition: TPoint read FMousePoint write FMousePoint;
constructor Create(const aTargetImage: TBitmap);
destructor Destroy; override;
procedure Animate; override;
end;
implementation
const
EACHLINE_HEIGHT=20;
EACHLINE_TIME=600; //Milliseconds
INITIAL_TEXT_FONT_SIZE=13;
TEXT_ZOOM_SIZE=80;
COLOR_TEXT=clBlack;
COLOR_TEXT_HIGHLIGHT=$FF0000;
COLOR_OUTLINE=$E0E0E0;
COLOR_ZOOM_TEXT=$C0C0C0;
OUTLINE_OFFSET=1;
{ TAboutTextZoomAnimation }
procedure TAboutTextZoomAnimation.DoPerform;
var
Factor: Single;
Distance: integer;
TheBMP: TBitmap;
PreserveSize: integer;
begin
inherited DoPerform;
If FHidden then exit;
if FText='' then Exit;
Factor:=GetElapsedMilliseconds / Duration;
Distance:=TEXT_ZOOM_SIZE-TAboutAnimation(FQueue).FCalculatedFontSize;
Distance:=Distance-Trunc(Distance*Factor);
TheBmp:=TAboutAnimation(FQueue).PaintBuffer;
PreserveSize:=TheBMP.Canvas.Font.Size;
TheBMP.Canvas.Font.Size:=Distance+TAboutAnimation(FQueue).FCalculatedFontSize;
TheBMP.Canvas.Font.Color:=COLOR_ZOOM_TEXT;
TheBMP.Canvas.TextOut(TheBmp.Canvas.Width div 2 - TheBMP.Canvas.TextWidth(FText) div 2,FFinalXY.y-distance*2,FText);
TheBMP.Canvas.Font.Size:=PreserveSize;
thebmp.Canvas.Font.Color:=clBlack;
end;
procedure TAboutTextZoomAnimation.DoFinalizeAnimation;
begin
inherited DoFinalizeAnimation;
FHidden:=true;
end;
{ TBackgroundAnimation }
procedure TBackgroundAnimation.LoadBackgroundFromFile;
var
BackgroundLoad: TPicture;
begin
TAboutAnimation(FQueue).FTarget.Canvas.Clear;
BackgroundLoad:=TPicture.Create;
try
BackgroundLoad.LoadFromFile('..\images\back_400.jpg');
except
end;
FBackground:=TBitmap.Create;
FBackground.Assign(TAboutAnimation(FQueue).FTarget);
//R.Left:=0;
//R.Top:=0;
//R.Right:=FBackground.Width;
//R.Bottom:=FBackground.Height;
//FBackground.Canvas.AntialiasingMode:=amOn;
// Use StretchDraw if target does not matches source dimensions
// FBackground.Canvas.StretchDraw(R,BackgroundLoad.Bitmap);
FBackground.Canvas.Draw(0,0,BackgroundLoad.Bitmap);
BackgroundLoad.Free;
end;
procedure TBackgroundAnimation.LoadFromBitmap(const aBitmap: TBitmap);
begin
FBackground:=TBitmap.Create;
FBackground.SetSize(aBitmap.Width,aBitmap.Height);
FBackground.Canvas.Draw(0,0,aBitmap);
end;
procedure TBackgroundAnimation.DoPerform;
var
TheBMP: TBitmap;
begin
if not Assigned(FBackground) then begin
LoadBackgroundFromFile;
end;
TheBmp:=TAboutAnimation(FQueue).PaintBuffer;
TheBMP.Canvas.Draw(0,0,FBackground);
end;
constructor TBackgroundAnimation.Create(const aBitmap: TBitMap);
begin
LoadFromBitmap(aBitmap);
end;
destructor TBackgroundAnimation.Destroy;
begin
FreeAndNil(FBackground);
inherited Destroy;
end;
{ TAboutAnimation }
procedure TAboutAnimation.PrepareLinesObjects;
var
j: integer;
EachLine: TTextLineAnimation;
StartOffSet: integer;
StartPoint,EndPoint: TPoint;
EachLineDuration: int64;
BlankZone: int64;
begin
StartOffSet:=FTarget.Height;
BlankZone:=int64(StartOffSet div EACHLINE_HEIGHT)*EACHLINE_TIME;
EachLineDuration:=FTextLines.Count*int64(EACHLINE_TIME)+BlankZone;
for j := 0 to FTextLines.Count-1 do begin
StartPoint.x:=0;
StartPoint.y:=j*EACHLINE_HEIGHT+StartOffSet;
EndPoint.x:=0;
EndPoint.y:=StartPoint.y+(FTextLines.Count*EACHLINE_HEIGHT)+StartOffSet;
EachLine:=TTextLineAnimation.Create(StartPoint,EndPoint,EachLineDuration);
EachLine.FreeWithQueue:=true;
if Length(FTextLines[j])>0 then begin
if FTextLines[j][1]='#' then begin
EachLine.FHighLight:=true;
FTextLines[j]:=copy(FTextLines[j],2,Length(FTextLines[j])-1);
end;
end;
EachLine.Text:=FTextLines[j];
EachLine.FTextWidth:=FPaintBuffer.Canvas.TextWidth(FTextLines[j]);
Self.Add(EachLine);
if j=0 then begin
FFirstLine:=EachLine;
end;
end;
FFullAnimationTime:=EachLineDuration;
end;
constructor TAboutAnimation.Create(const aTargetImage: TBitmap);
var
AnimBackground: TBackgroundAnimation;
AnimTextZoom: TAboutTextZoomAnimation;
TextWidth: integer;
begin
FTarget:=aTargetImage;
FPaintBuffer:=TBitmap.Create;
with FPaintBuffer do begin
Assign(FTarget);
Canvas.Brush.Color:=clWhite;
Canvas.Brush.Style:=bsSolid;
Canvas.Pen.Color:=clBlack;
Canvas.FillRect(0,0,Width,Height);
end;
inherited Create;
FTextLines:=TStringList.Create;
try
FTextLines.LoadFromFile('Contributors.txt');
except
end;
if FTextLines.Count=0 then FTextLines.Add('Missing contributors.txt file.');
FPaintBuffer.Canvas.Font.Size:=INITIAL_TEXT_FONT_SIZE+1;
repeat
FPaintBuffer.Canvas.Font.Size:=FPaintBuffer.Canvas.Font.Size-1;
TextWidth:=FPaintBuffer.Canvas.TextWidth(FTextLines[0]);
until TextWidth<FPaintBuffer.Canvas.Width;
FCalculatedFontSize:=FPaintBuffer.Canvas.Font.Size;
AnimBackground:=TBackgroundAnimation.Create(aTargetImage);
aTargetImage.Canvas.Clear;
AnimBackground.FreeWithQueue:=true;
Self.Add(AnimBackground);
AnimTextZoom:=TAboutTextZoomAnimation.Create;
AnimTextZoom.Duration:=EACHLINE_TIME;
AnimTextZoom.Repeats:=1;
AnimTextZoom.FreeWithQueue:=true;
AnimTextZoom.FText:='This is a zooming text cache';
Self.Add(AnimTextZoom);
Self.FAboutZoomEffect:=AnimTextZoom;
PrepareLinesObjects;
end;
destructor TAboutAnimation.Destroy;
begin
FTextLines.Free;
FreeAndNil(FPaintBuffer);
inherited Destroy;
end;
procedure TAboutAnimation.Animate;
var
R1: TRect;
begin
if FState<>eAnimationQueueStarted then exit;
if Reversed then begin
if FFirstLine.GetElapsedMilliseconds<0 then begin
Reverse;
end;
end else begin
if FFirstLine.GetElapsedMilliseconds>FFullAnimationTime then begin
Start;
end;
end;
R1.Top:=0;R1.Left:=0;
FTarget.GetSize(R1.Right,R1.Bottom);
FViewPort:=R1;
// Is "Draw" faster than CopyRect ?
// FTarget.Canvas.CopyRect(R1,FPaintBuffer.Canvas,R1);
FTarget.Canvas.Draw(0,0,FPaintBuffer);
if Assigned(FRefreshObject) then begin
FRefreshObject.Refresh;
end;
inherited Animate;
end;
{ TTextLineAnimation }
constructor TTextLineAnimation.Create(const aOrigin: TPoint;
const aTarget: TPoint; const aDuration: int64);
begin
Duration:=aDuration;
FStartPoint:=aOrigin;
FEndPoint:=aTarget;
end;
procedure TTextLineAnimation.DoPerform;
var
TheBMP: TBitmap;
Factor: single;
Distance: integer;
NP: integer;
LX: integer;
LT: integer;
bInBottonLine: Boolean;
bIsMouseOver: Boolean=false;
TextRect: TRect;
begin
Factor:=GetElapsedMilliseconds / Duration;
if Factor>1.0 then exit;
Distance:=FEndPoint.y-FStartPoint.y;
NP:=Trunc(Distance * Factor);
NP:=FStartPoint.y-NP;
if NP<TAboutAnimation(FQueue).FViewPort.Top-EACHLINE_HEIGHT then exit;
if NP>TAboutAnimation(FQueue).FViewPort.Bottom then exit;
LT:=(TAboutAnimation(FQueue).FViewPort.Right div 2) - (FTextWidth div 2);
if (NP>TAboutAnimation(FQueue).FViewPort.Bottom-EACHLINE_HEIGHT) and (NP<=TAboutAnimation(FQueue).FViewPort.Bottom) then begin
bInBottonLine:=true;
if TAboutAnimation(FQueue).FAboutZoomEffect.FText<>FText then begin
TAboutAnimation(FQueue).FAboutZoomEffect.FText:=FText;
TAboutAnimation(FQueue).FAboutZoomEffect.FFinalXY.x:=LT;
TAboutAnimation(FQueue).FAboutZoomEffect.FFinalXY.Y:=TAboutAnimation(FQueue).FViewPort.Bottom-EACHLINE_HEIGHT;
TAboutAnimation(FQueue).FAboutZoomEffect.Start;
end;
if FLXTime=0 then FLXTime:=GetElapsedMilliseconds;
LX:=TAboutAnimation(FQueue).FViewPort.Right;
Distance:=LX-LT+10; // 10 stop pixels...
Factor:=(GetElapsedMilliseconds - FLXTime) / EACHLINE_TIME;
Factor:=Sin(Factor*pi/2);
Distance:=Trunc(Distance * Factor);
if Distance>(LX-LT) then Distance:=LX-LT;
LX:=LX-Distance;
NP:=TAboutAnimation(FQueue).FViewPort.Bottom-EACHLINE_HEIGHT;
end else begin
bInBottonLine:=false;
LX:=LT;
end;
TextRect:=rect(LX,NP,FTextWidth+LX,NP+EACHLINE_HEIGHT);
TheBmp:=TAboutAnimation(FQueue).PaintBuffer;
TheBMP.Canvas.Brush.Style:=bsClear;
if not bInBottonLine then begin
TheBMP.Canvas.Font.Color:=COLOR_OUTLINE; //Very light gray
TheBMP.Canvas.AntialiasingMode:=amOff;
if OUTLINE_OFFSET>0 then begin
TheBMP.Canvas.TextOut(LX+OUTLINE_OFFSET,NP+OUTLINE_OFFSET,FText);
TheBMP.Canvas.TextOut(LX-OUTLINE_OFFSET,NP+OUTLINE_OFFSET,FText);
TheBMP.Canvas.TextOut(LX+OUTLINE_OFFSET,NP-OUTLINE_OFFSET,FText);
TheBMP.Canvas.TextOut(LX-OUTLINE_OFFSET,NP-OUTLINE_OFFSET,FText);
end;
end;
if PtInRect(TextRect,(TAboutAnimation(FQueue).MousePosition)) then begin
bIsMouseOver:=true;
end;
if FHighLight or bIsMouseOver then begin
TheBMP.Canvas.Font.Color:=COLOR_TEXT_HIGHLIGHT;
TheBMP.Canvas.Font.Style:=[fsUnderline];
end else begin
TheBMP.Canvas.Font.Color:=COLOR_TEXT;
end;
// TheBMP.Canvas.AntialiasingMode:=amOn;
if not bInBottonLine then begin
TheBMP.Canvas.TextOut(LX,NP,FText);
end;
if FHighLight or bInBottonLine or bIsMouseOver then begin
TheBMP.Canvas.Font.Style:=[];
end;
end;
end.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,67 @@
unit ufrmcontributors;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls
, uanimationbasic, uanimationcontributors;
type
{ TfrmContributors }
TfrmContributors = class(TForm)
imgLazarus: TImage;
tmrAnimationCadence: TTimer;
procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure tmrAnimationCadenceTimer(Sender: TObject);
private
protected
AnimationQueue: TAboutAnimation;
public
end;
var
frmContributors: TfrmContributors;
implementation
{$R *.lfm}
{ TfrmContributors }
procedure TfrmContributors.FormCreate(Sender: TObject);
begin
imgLazarus.Canvas.Clear;
AnimationQueue:=TAboutAnimation.Create(imgLazarus.Picture.Bitmap);
AnimationQueue.Start(true);
end;
procedure TfrmContributors.FormClose(Sender: TObject;
var CloseAction: TCloseAction);
begin
AnimationQueue.Pause;
CloseAction:=caFree;
end;
procedure TfrmContributors.FormDestroy(Sender: TObject);
begin
FreeAndNil(AnimationQueue);
end;
procedure TfrmContributors.tmrAnimationCadenceTimer(Sender: TObject);
begin
AnimationQueue.MousePosition:=imgLazarus.ScreenToClient(Mouse.CursorPos);
AnimationQueue.Animate;
// Self.Repaint;
// Self.Caption:=format('FPS: %.2f',[AnimationQueue.AverageFPS]);
end;
end.

View File

@ -0,0 +1,135 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectOptions>
<Version Value="10"/>
<PathDelim Value="\"/>
<General>
<SessionStorage Value="InProjectDir"/>
<MainUnit Value="0"/>
<Title Value="Animated Controls Sample"/>
<ResourceType Value="res"/>
<UseXPManifest Value="True"/>
<XPManifest>
<TextName Value="CompanyName.ProductName.AppName"/>
<TextDesc Value="Your application description."/>
</XPManifest>
</General>
<i18n>
<EnableI18N LFM="False"/>
</i18n>
<BuildModes Count="2">
<Item1 Name="Debug" Default="True"/>
<Item2 Name="Release">
<CompilerOptions>
<Version Value="11"/>
<PathDelim Value="\"/>
<Target>
<Filename Value="..\..\output\controlsample"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<OtherUnitFiles Value="..\..\src"/>
<UnitOutputDirectory Value="..\..\lib\$NameOnly($(ProjFile))\lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<CodeGeneration>
<Optimizations>
<OptimizationLevel Value="3"/>
</Optimizations>
</CodeGeneration>
<Linking>
<Debugging>
<GenerateDebugInfo Value="False"/>
</Debugging>
<Options>
<Win32>
<GraphicApplication Value="True"/>
</Win32>
</Options>
</Linking>
</CompilerOptions>
</Item2>
</BuildModes>
<PublishOptions>
<Version Value="2"/>
</PublishOptions>
<RunParams>
<local>
<FormatVersion Value="1"/>
</local>
</RunParams>
<RequiredPackages Count="1">
<Item1>
<PackageName Value="LCL"/>
</Item1>
</RequiredPackages>
<Units Count="5">
<Unit0>
<Filename Value="controlsample.lpr"/>
<IsPartOfProject Value="True"/>
</Unit0>
<Unit1>
<Filename Value="frmcontrolsample.pas"/>
<IsPartOfProject Value="True"/>
<ComponentName Value="frmAnimationControls"/>
<HasResources Value="True"/>
<ResourceBaseClass Value="Form"/>
</Unit1>
<Unit2>
<Filename Value="..\..\src\uanimationcontrol.pas"/>
<IsPartOfProject Value="True"/>
</Unit2>
<Unit3>
<Filename Value="..\..\src\uanimationtypes.pas"/>
<IsPartOfProject Value="True"/>
</Unit3>
<Unit4>
<Filename Value="..\..\src\uanimationbasic.pas"/>
<IsPartOfProject Value="True"/>
</Unit4>
</Units>
</ProjectOptions>
<CompilerOptions>
<Version Value="11"/>
<PathDelim Value="\"/>
<Target>
<Filename Value="..\..\output\controlsample"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<OtherUnitFiles Value="..\..\src"/>
<UnitOutputDirectory Value="..\..\lib\$NameOnly($(ProjFile))\lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<Parsing>
<SyntaxOptions>
<IncludeAssertionCode Value="True"/>
</SyntaxOptions>
</Parsing>
<CodeGeneration>
<Checks>
<IOChecks Value="True"/>
<RangeChecks Value="True"/>
<OverflowChecks Value="True"/>
<StackChecks Value="True"/>
</Checks>
<VerifyObjMethodCallValidity Value="True"/>
</CodeGeneration>
<Linking>
<Debugging>
<UseHeaptrc Value="True"/>
</Debugging>
</Linking>
</CompilerOptions>
<Debugging>
<Exceptions Count="3">
<Item1>
<Name Value="EAbort"/>
</Item1>
<Item2>
<Name Value="ECodetoolError"/>
</Item2>
<Item3>
<Name Value="EFOpenError"/>
</Item3>
</Exceptions>
</Debugging>
</CONFIG>

View File

@ -0,0 +1,23 @@
program controlsample;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Interfaces, // this includes the LCL widgetset
Forms, frmcontrolsample,
uanimationcontrol,
uanimationtypes;
{$R *.res}
begin
Application.Title:='Animated Controls Sample';
RequireDerivedFormResource := True;
Application.Initialize;
Application.CreateForm(TfrmAnimationControls, frmAnimationControls);
Application.Run;
end.

View File

@ -0,0 +1,869 @@
object frmAnimationControls: TfrmAnimationControls
Left = 497
Height = 544
Top = 268
Width = 514
Caption = 'LCL Controls animated'
ClientHeight = 544
ClientWidth = 514
OnCreate = FormCreate
OnDestroy = FormDestroy
OnResize = FormResize
Position = poDesktopCenter
LCLVersion = '1.7'
object butReverse: TButton
AnchorSideRight.Control = Owner
AnchorSideRight.Side = asrBottom
Left = 390
Height = 30
Top = 4
Width = 122
Anchors = [akTop, akLeft, akRight]
BorderSpacing.Right = 2
Caption = 'Reverse'
OnClick = butReverseClick
TabOrder = 2
end
object butPause: TButton
Left = 282
Height = 30
Top = 4
Width = 101
Caption = 'Pause'
OnClick = butPauseClick
TabOrder = 1
end
object shpSliding: TShape
Left = 8
Height = 30
Top = 4
Width = 258
end
object butSliding: TBitBtn
AnchorSideTop.Control = shpSliding
AnchorSideRight.Side = asrBottom
AnchorSideBottom.Control = shpSliding
AnchorSideBottom.Side = asrBottom
Left = 8
Height = 30
Top = 4
Width = 96
Anchors = [akTop, akLeft, akBottom]
Caption = 'Sliding'
OnClick = butSlidingClick
TabOrder = 0
end
object pnlCheckbox: TPanel
AnchorSideLeft.Control = Owner
Left = 2
Height = 31
Top = 48
Width = 117
AutoSize = True
BorderSpacing.Left = 2
BevelOuter = bvNone
ClientHeight = 31
ClientWidth = 117
TabOrder = 3
object CheckBox1: TCheckBox
Left = 6
Height = 19
Top = 6
Width = 105
BorderSpacing.Around = 6
Caption = 'Checkbox effect'
OnChange = CheckBox1Change
TabOrder = 0
end
end
object pnlText1: TPanel
AnchorSideLeft.Control = pnlCheckbox
AnchorSideLeft.Side = asrBottom
AnchorSideTop.Control = pnlCheckbox
AnchorSideRight.Control = Owner
AnchorSideRight.Side = asrBottom
Left = 123
Height = 56
Top = 48
Width = 389
Anchors = [akTop, akLeft, akRight]
BorderSpacing.Left = 4
BorderSpacing.Right = 2
ClientHeight = 56
ClientWidth = 389
TabOrder = 4
object Label1: TLabel
Left = 3
Height = 50
Top = 3
Width = 383
Align = alClient
AutoSize = False
BorderSpacing.Around = 2
Caption = 'The checkbox is into a panel (autosize) and with a BorderSpacing to allow the panel color change to be visible around.'
ParentColor = False
WordWrap = True
end
end
object grpButtons: TGroupBox
AnchorSideLeft.Control = Owner
AnchorSideTop.Control = pnlText1
AnchorSideTop.Side = asrBottom
AnchorSideRight.Control = Owner
AnchorSideRight.Side = asrBottom
Left = 4
Height = 72
Top = 104
Width = 506
Anchors = [akTop, akLeft, akRight]
BorderSpacing.Left = 4
BorderSpacing.Right = 4
Caption = 'Some buttons effects'
ClientHeight = 52
ClientWidth = 502
TabOrder = 5
object butBounceCaption: TButton
Left = 8
Height = 30
Top = 8
Width = 120
Caption = 'Bounce caption'
OnClick = butBounceCaptionClick
TabOrder = 0
end
object butZoomTest: TButton
Left = 136
Height = 30
Top = 8
Width = 120
Caption = 'Click Zoom'
OnClick = butZoomTestClick
TabOrder = 1
end
object BitBtn1: TBitBtn
Left = 264
Height = 30
Top = 8
Width = 232
Caption = 'Button icon animation'
Enabled = False
Font.Style = [fsStrikeOut]
Glyph.Data = {
36090000424D3609000000000000360000002800000018000000180000000100
2000000000000009000064000000640000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000003000000080000000D000000120000
00170000001B0000001E0000001D0000001A00000017000000120000000D0000
0007000000030000000000000000000000000000000000000000000000000000
0000000000017B441E52000000130000001B0000002200000029000000300000
00350000003A0000003D0F070342331E0C541E0F0743000000320000002C0000
00250000001E0000001500000008000000010000000000000000000000000000
000000000008874920F76338174D000000220000002B000000340000003C4223
106B77411CC3854920F5874A20FC894D25F7874A20FA86491FFA7B441DBE4B2A
1255000000260000001D000000140000000A0000000000000000000000000000
000000000003864A20FE8A4F27F25530143F130D062768381775864B24DD9A68
43F8AB7A57FDB68662FFBA8B66FFB5825BFFB07A50FFA86E42FF975B2FFD884A
20F7753F1D80000000160000000E000000060000000000000000000000000000
000000000000884920FEBD9578FE884B22EF874C21F1A37351F5C39D81FFBB8D
68FFB88862FFB78660FFB48058FFB37F57FFB27D54FFAE764BFFAA6F41FFA264
35FF894C21F38547216300000000000000000000000000000000000000000000
000000000000874B20FDCFAE95FFBC9374FFC7A286FFC39979FFB5825BFFBF94
72FFBB8E6CFFA5714BFB9A643AF290552CF48B4E24FF8B5026FF92572BFF9B5E
30FF9F6131FF884B21F280402008000000000000000000000000000000000000
000000000000874B1FFDCEAD93FFBF9472FFAF784DFFB98862FFC8A386FFA36E
46FC884B21F5874B208886492154894C2136995B2D3AA16232C6A16438FC9053
28FF8C4E23FE8B4E23FA89481F63000000000000000000000000000000000000
000000000000884B1FFCCDAB91FFA56837FFB78660FFC9A58AFF90562DF6884C
21B98446231D00000000000000000000000000000000A467372AA66837ECC48E
65BFA1673CEC864A20FF8A4C22C7000000000000000000000000000000000000
000000000000884A20FCCCAB90FFA86D3FFFA86C3EFFC8A387FFA16D4BF6874B
218C0000000000000000000000000000000000000000A464371CA86B3AB3CE9B
7463CC977178965A30DF8B4D22E9000000000000000000000000000000000000
000000000000874A21FBC9A489FFCBA98FFFCBA98FFFCBA98FFFC7A285FF9159
31F888481E5C0000000000000000000000000000000099663305AA66330FDB92
6D07D59F8018A56C4452884A21EC000000000000000000000000000000000000
000000000000884B21EB874B20F7874B20F7874B20F7874B20F7874B20F7874B
20F7874A21EA884C212F92492407805020108050201080502010805020108050
201080502010805020107F4A1F17FF0000010000000000000000000000000000
0000000000008040400480800002000000000000000000000000000000000000
0000000000000000000085471F19874B1FE5874A20FE894D24F8884C22F8884C
22F8884B21F8884B21F8874A20FE805020100000000000000000000000000000
000000000000884C20E3A3694075D29F7928D9997314AA633912BF8040040000
0000000000000000000000000000884A222D874B21F4B58764FFC59D7EFFC7A1
83FFCBA78BFFCEAC91FF884B21F88E471C120000000000000000000000000000
000000000000894C21ED96592FE4CA966C86CB977171A96A3AC0A86633230000
00000000000000000000000000000000000087491F428B4E26F8BA8F6DFFB07A
4FFFA46534FFCBA78BFF874C21F78C4D26140000000000000000000000000000
000000000000894B21E6874A20FFAF7449EDC38D62CDA7693AE6A26736340000
0000000000000000000000000000854A2030894C21C990552BF4B58764FFBB8C
67FFA46534FFC8A184FF8A4F25F68B4623160000000000000000000000000000
000000000000884B229F8C4E24FE894C22FEA26538FEAB6F40F7A46736A90000
0000874B1E11894C2136894C21A8894C21F5A36B43FEBA8A64FFAF784DFFAE77
4BFFBE916EFFC69E80FF8C5127F58A4A20180000000000000000000000000000
000000000000864A2037894D23F39C5D2EFF8C4F23FD894C21FF8C4E24FF884B
20FE884A1FFA8D5228F09D643AFAB07B51FFB17B51FFAD7448FFB78660FFB484
5FFFA6714BFEC49B7BFF8C5028F4894E1D1A0000000000000000000000000000
00000000000000000000884B229F8D4F24F4A36433FFA16231FF9E6030FFA467
38FFA86D3FFFAC7246FFAE764BFFAF784EFFB17C53FFB07D54FF995E35F6874B
21F1884B21D7A16B44F88D532BF38949241C0000000000000000000000000000
00000000000000000000FF000001884B229D884C21F595562AFB9E6030FFA263
33FFA66939FFA66B3DFFA3683CFF9C6135FC8E5429F0884A21F4894B217D8040
2B0C8049240E884B21D9874A20FF884D221E0000000000000000000000000000
000000000000000000000000000000000000864A2226884B229C894C21DE884A
20F7884B20FC884B21F0884C21DA884B209885481E4399333305000000000000
000000000000854E2117874B1FDD844A211F0000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000AA5500030000000000000000000000000000000000000000000000000000
00000000000000000000874820208E471C120000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000
}
OnClick = BitBtn1Click
ParentFont = False
TabOrder = 2
end
end
object pnlDropDown: TPanel
AnchorSideLeft.Control = Owner
AnchorSideTop.Control = grpButtons
AnchorSideTop.Side = asrBottom
AnchorSideRight.Control = Owner
AnchorSideRight.Side = asrBottom
Left = 2
Height = 142
Top = 178
Width = 510
Anchors = [akTop, akLeft, akRight]
BorderSpacing.Left = 2
BorderSpacing.Top = 2
BorderSpacing.Right = 2
ClientHeight = 142
ClientWidth = 510
TabOrder = 6
object pnlDropDownHeader: TPanel
Left = 1
Height = 24
Top = 1
Width = 508
Align = alTop
ClientHeight = 24
ClientWidth = 508
TabOrder = 0
object lblDropDownMessage: TLabel
Left = 1
Height = 22
Top = 1
Width = 477
Align = alClient
Caption = 'Press the button to collapse the panel below.'
Color = 39423
Layout = tlCenter
ParentColor = False
Transparent = False
end
object butDropDown: TButton
Left = 478
Height = 22
Top = 1
Width = 29
Align = alRight
Caption = '^'
OnClick = butDropDownClick
TabOrder = 0
end
end
object pnlDropDownContents: TPanel
Left = 1
Height = 116
Top = 25
Width = 508
Align = alClient
ClientHeight = 116
ClientWidth = 508
TabOrder = 1
object Label3: TLabel
AnchorSideLeft.Control = pnlDropDownContents
AnchorSideTop.Control = pnlDropDownContents
Left = 5
Height = 15
Top = 5
Width = 124
BorderSpacing.Left = 4
BorderSpacing.Top = 4
Caption = 'Some sample content...'
ParentColor = False
end
object lbSampleEntries: TListBox
AnchorSideLeft.Control = Label3
AnchorSideLeft.Side = asrBottom
AnchorSideTop.Control = pnlDropDownContents
AnchorSideRight.Control = pnlDropDownContents
AnchorSideRight.Side = asrBottom
AnchorSideBottom.Control = pnlDropDownContents
AnchorSideBottom.Side = asrBottom
Left = 133
Height = 106
Top = 5
Width = 370
Anchors = [akTop, akLeft, akRight, akBottom]
BorderSpacing.Left = 4
BorderSpacing.Top = 4
BorderSpacing.Right = 4
BorderSpacing.Bottom = 4
Items.Strings = (
'Sample entry 1'
'Sample entry 2'
'Sample entry 3'
'Sample entry 4'
'Sample entry 5'
'And a final, and a bit larger than previous, entry'
)
ItemHeight = 15
ParentFont = False
TabOrder = 0
end
end
end
object pnlAttached: TPanel
AnchorSideLeft.Control = pnlDropDown
AnchorSideTop.Control = pnlDropDown
AnchorSideTop.Side = asrBottom
AnchorSideRight.Control = pnlDropDown
AnchorSideRight.Side = asrBottom
Left = 2
Height = 25
Top = 320
Width = 510
Anchors = [akTop, akLeft, akRight]
ClientHeight = 25
ClientWidth = 510
TabOrder = 7
object Label4: TLabel
Left = 1
Height = 23
Top = 1
Width = 508
Align = alClient
Alignment = taCenter
Caption = 'This is an attached panel to DropDown content.'
Layout = tlCenter
ParentColor = False
end
end
object pnlMarquee: TPanel
Left = 0
Height = 24
Top = 520
Width = 514
Align = alBottom
BevelOuter = bvNone
ClientHeight = 24
ClientWidth = 514
Color = clSilver
ParentColor = False
TabOrder = 10
object imgFlareMarquee: TImage
Left = 0
Height = 24
Top = 0
Width = 378
AutoSize = True
Picture.Data = {
1754506F727461626C654E6574776F726B477261706869634F28000089504E47
0D0A1A0A0000000D494844520000017A000000180806000000F4EB3675000000
06624B4744000000000000F943BB7F000000097048597300000B1300000B1301
009A9C180000000774494D4507E102180A1C3AD34D4FAE0000000C6954587443
6F6D6D656E740000000000BCAEB299000020004944415478DA957DDD8E64C971
DE1791A7BAA7A77B6696BB4BD186B15C5994E54B1BB24018346D7A97D41B18BE
D02BD84FA07BCA2F20C07E02E925BCBB16281BA02C58BA236142062DCA00C9DD
1972667A7ABAAB4E66F8227EF354F5CC6A809AEAAA3A3F79CEC98C8CF8E28B2F
0927FEC977BF4BF4C92722BFFFFB84F540A00600041984F7DE173CFD82204220
02440810C2E595E0E68600E84B84707E2EB8BBD3DFCFCE05FB3D814000118610
CE7682C39E2044200010D21690BDDBB1DA2258573BB69D1742FAB3D8EFDD8E0D
02448FD158D0BB1EBFEEC74D30BA9F97C02CE8C3F767DB9FA76BF1766B1BED6F
3F1FD8EE1CDBE9F57B0201C2711E8020F6BD8040421062BB76B673B29D53DF89
DAE63C9CC714FB1C6D65883008E5773FA6501E9B1A48C87E5B0034081A080DB0
976001A4818821D240B41C6D03347023B4C668C4E0C6684DDF9909AD35342630
EBF7CDB625662C5CB663062FACEFCC7A4C662C8D7079D5F0E811E3EA11E3F123
C6A32BC6E515E1F2B2E1F292F0F092F5FD2183CB7D98EED7F4B7BF5AF9AD0318
F7BCE4C4DF82DE075E5D0F5C5F0BAE6F065EBD1AB87935707D3DF0F25AF0F265
C7CB9782972F066E6F07C6E8E85D30C6C018036B178C3ED0EDF3289FFB18BA6D
1F1843D07B8F773F46EFBA5F1F82B10E805640F43A042B88BA7EA60E4107A103
58211800561006446C3B74400640E5BA454034202420FB2CC86D48EC7E50B937
710C01D021D07DF33DF7D5E3FA3E0288DF5BE8670844044452EEBD985D38FD59
20201180F46FF66D482043403CDCC4E9F9A81E436D0235FD8D6A3B003089EE02
B515DCEC5C501BD3163F26A21DEB202C4DB721E86F7E3C40C0A4367159F43A99
CB67362B42B97D63C1EBD784070F745F3543FACE24383F177CF1B9DAE8F373C1
6FFD96E0073F207CFBDBC2A70C7DD8D977BE02FCEB7F2378EF5D3590C3AE6559
80DD4E8DFCB2A8BD10D1776280EDB087BD19B406ECF78CDDCE6CA500BBDD405F
A1938800ECF693ED6F9F48EC7EEB7700B3DD70B61B60465A8DA26DBFE843EC83
F278A4FB12098610C06A6809C0188CC6DA366201C84CB1CD256CED229A6CB13D
38BBD920807C1FD27D88F481D9F7C85DAC23213A801F3FA637DBDFBF2122FBAC
E7616F006DFA6E7C5D7EB373881D58CFE99389DD33D4898BA27D7A6E9D287C82
8A6DFC1A6DE223BB61FE3DDB75B05F1B9509501F01D8F741DE4BF66334023780
1BD0967CE92402B4062C0D581AE5A5CE77F8C477E5C185B1207CB97F126F7D05
7ACFD728EFEB2A5857603D08FA5083350641C4A60AD18E2A66A36410446DA9BE
0645D344B49F8B68BF07EA760086A471251D2C7135548C0CF26FB28BA04D178A
7B644ED430A749864E1FE2271E79E7F4AB7A6DDBB6EA3146DA5C7372FCB8D5D4
6ADFF6D3B8B17767CBFF0D3B1FC43B7E5EAE9D4ECF09D1F60C339842763CC973
FAB33007D086461C4744C7B2C481DD0609BA685BC86C12289F0D0868369989B5
6BD83CD3573D41EF84B33389DBBE76C26E27F12847CFF9D3FB07A0C759BB5ED3
CD2B423FE81879FD9A70F54870792938EC813E74EC3D7F8EE56477F606BDF304
F8F18F090F1F0277B782972FBD4312D6AE5EFCE14058576DD0D280D6B493FBE0
A6AE837EF5C9BA013B33C260C2B08B13212CA40382480700B358C7D063B5A677
705974FB66DF0F9F00A05E3CFC1894C3D38F23663C09026A7A1C46DE440C3772
C5EA96014693FD241D0C31A8283A900F16A991CAD6F45807221F50543ABC19D2
E19DD4A399327427E34573A400A21C506033BEC88844CA64E29DB8DA3F428942
CAA4B6B90A9A8CBE1A6EA63A91CDBF473B884A0047D3CB8FBB3460B7A8215F98
2C3A2070990038269253861D6FF98E379EA1DCF39A8DBDD0C03A04EB1074516F
710C41B70138BA4D04C306AB3B03226A9C453D4E487A6B528C8F1AA58D612D86
DF3BABB86189A95972C3DA6EF1EE48277ED389422427048AD6D867F77C3D88DE
4C1C82119EF9FC14EC38A41E2E4120347BD3546CB59EC7C79C649FB46B1E2030
0DBB3FBA37FB7DF3FE2CF30093F088292CB0140F1E66A4D91DC3B0417ED3440D
334BB10F0266A00BD9F5D85D919C4065E8D5F7EE3691726851DA4808D07B4E7C
7E31EB9D4617EB5E11873108BDFBF6BACF18405B04B7776A031F3D163CFB82D0
5775809B3DAFA7CF70D2A3A74F3F15F9C33F24FCE427847FF23BDAD8B373E0BD
F7D3B03F793CC2B85F3C542FB935600C7D273613C4E9C5D7E1C6043416EC1609
430010C6D09BDB9A8644D3C32FC66A0C32EF5B8DFC6493A97467F18840C2D3CE
68212704A21C06DA6639B20F44C5245827ACCE3D497AE352C242B7A5EED9D374
4C8946A7278FE8B13C79F679BC44286432451C03D2072ED9B5A7E7059BF004F3
67F79C84789A4CA87AFC9210947BDECC7344229823208F72EAF5C53DAB914C79
D7E3125A23F3DAD391589AA031D018061DE18441C63DC67EEBD5D77DE9C4B6C7
BFCB208C553DB3EAD5F755B07618BC220AC78CE29185CD92D91336A32643278D
3EF274436C1AA8EFE1D10AD274593F2089BEE79382D028DB486988C22A321206
4DBFA44C0BE134FB392C2E906244A9B8D2BEDFB0238CFCAE3A4DB2099664507A
D8A08041259C108979CC7BA1A30CD94E0588A444116293B1FE36470CD11E774E
061492B10336CA063796F0F2FBA0723D82210ABDC850033C86DA30813AC580A0
2D238D3909DA22D81F6C3AEC7A8EE1933A09CE16495B2382DD998E976EDEFCF9
8541D604DCDD119E7DA1CF6FBF07EE6E757C1083FEF44FE4A4472F1F7F4CF8E1
5F2844F33FFE3B9BD74CF8EAFB82EB6BDDE8C50B7BD8068F88102E1E08EEF6DE
4309E70F04FD809831F5A2158FDEEDF42299F4E1B6457426F2D0C606D5DA190B
FBC3619BDD60BFB9170BF562CD6011340CD31930BD449DB5ADEF39DCE3C793F4
307B3FC6E4C3F32EF0858CEABB90FA17430D73853824BC752E183D9B2D2FDF0D
4E836AC6D6626848C91960980535DC9D8AF517B173E7EC82616DF3B12CA0D970
53F5CC79BA26314C9BA4C22F28300E36D3819E0B11A954379E2D04CF634484B1
8557488D7C63F3DE17185CA3DFB3BDB785404C1B3C8D4E60F4F7C137E304EE7B
0A17CEBF45046B178828B6DEFD3580DE07568375D68EF068A51C57AAE71D137D
C177CD7088CCED9130D68A758B1B6BB750861147C4509C0DF5878719EF0132B8
87DCE38618046193032B96CEE1852331613B9690C79F89917B0440DEE6D867BE
978E7767B430E3F2147982F977C7E07502331CDEEE2FC1A197C4EBD9612DD627
CA6654B99550DF7B06E7F9FB2034DFA70DF4AEFDA51914DB574316EC3CDDE036
6E924E221C8590880CDAA2DBB712F59EEDB27F1DF60A871F56A0837076AECFCC
21EB8B0BCD855E5C28627775A913D020E07CD16DAE1EA9ED1B03F8E6BF147CF2
C9B1472FDFFB2ED1A79F0ADE79025C5CE8971F7C20383F137CFE39A12D3A0134
D641FAF0520293DF1F1436383F5758E4B052625C661A1C0BEFAB1A826637C60D
AF26268A6717989C7AF762DB71933284FD38894DFAF1BC6DC43A9B7219EB3E3B
13A96BCE5CA000DE789E1B9B563DD3F4BCD50B559C59D2630F435ACD4D460C5C
71F9925B75AF06A4212AF9E0F08823EC5841613D72F046A51F1A9315C936F14D
05324A78275B8D309A6206942A64421B6FDD23172E91DDD6FB377C27EEB3D965
87FC2A26BF2C0ADDB01B7826F356D49B676C3DFAFBFEBE0FD29113DBE2C4F79E
7C339CF484473F56A00FC1E1A01EBDC23A9BA9C29D1237AA6E22A578B0E908A7
072A748C8DD3E47AA4A1A5198A09EFBCE48B8E067F8184BC8F8C094EC2F4A2B4
B9EAF4385C221579D17E37C6BC6F84BF28DE758593A6D449F1F48DC821741C7F
8900C233942306AF8AB8D76CE3AB40657DB88394FF1A7B1237ED52E451A0061D
9074F64A84326C9C6AFF48E74C9107F5C265689F395B060E07E070D06D7767FA
795914E31783A1D735DF7767EA50DFDEE9310F2B70BE137CF194B03F20BCFA9F
FF12F49FBE2F48B648B95FFFF5136DEE3BEF020F2E32C1B2DB019797C07A205C
5E6AD87176AEB3CBF9996067AFB6D3994B0661B7881A6E4BA61D0E6CC654C04D
67224FC436B6CF66141633DCCCF38BD8664937FEFE404493BE6CD1054322811B
86CF92AD4CFE424C201A7ED50CAB8685151A394A5E9971F20E55E0D364252193
8DB33174186A3A651CC793C0152AF104AABE281D9D192D8FC1963D378DB3273C
88B149BED27C5D25415613BB84320155A809331B89A8266DA94C8A9409EE6043
E9844CC5D366320F3E3C797B593F68ECB83D360CA853100D9D30F2742F067FEC
C9CF3FAFE6BD0FC3E6C74863BF0EC5E7FDBB805386C30208FC3D219C927C34AF
3630FC62D9A56C1C7870B5302427DB3BC1A672DF75D6278E92D89519662C0E8A
9060B843C325E95B92C06ED49D941098BF14024189777CA61150245D27FC5E9C
4D733C9D8BC3B2C5F267E450C71322393E06D06894E740310603AB2785911D26
1A3DF7A5207DA803209BFC3E517E5F022E8B0008EB81D19A60B7D388ED70B0A4
B091590E7BC2E1A013E57EAF98FC61AFCEDABA023737849B1BC28BE784F7DF17
BCBC26FCE297849B1BE0D933C8471FD149432FDFF9B7DAC2AF7D15F89D7F2AF8
E01F69EBCECE7496F17FBB1D70B6082E1EEAEF8D15636BAD1830F8A09429BFE2
2E2CB1C22F306C8B58BD77660B0E0DAF979295EE1DD159DA22C1DE08632A2511
4892CC43A1603B50790889EF97C44E61CEB8EB30DB649A92A66ACC4A7269FAEC
E166DA16D9B01B026AE1B299940453B5A12C13B325DA42952583085D484E8D76
8407E350CAF0F6C48BCBFE693CA54C2875E2AB9E393115164D31B14C47DEA41A
008FAE33699B987C35F86AD8D5CB17F02268CB9BD8367F1F7C5EDEE2FDBB33A0
035D211B37F062AC1B415F25BF73A6E250E3EE2499C45D291E4D60F51BCF7736
4030CFD89E9DB31A69869D64F33791531B6BB23607A46C12B79958C4719E2290
2675B6C8DAE286B382EFB2B1C2017D8FF4DC835459D0B23125FE2999360528F2
EDA7086360CA790CC97DC72800D398AFB95B563BD2B4C3081ECD93A0347591FA
4CC6A0B8954E1219837058955A392C51AB14F51A402B863F8270E1390DED5FFD
609101AB33B13BD3C9E6F56B45462E1E8845236AC70E2BF0F419F0F50F07EE6E
81DB5BE0F9F3B075CB8CCD7F44680BE4A38F183FFCA13EBC0F3E14FCDDFF35AC
D71829CF9F276E7FF5D0F8F3E438B6192E06EEEE3866E8B37389D0C34350C7D7
FBCA91D176043066DECE969875EF95267CBE022184CC96F6C1D196C699E01A95
9182998F1F494929187BF1A865EB354A31F604C3B37DE6E6D22EB610AC62FE76
A841990845E1F283155B971A98E7C04A2E29A6FC4150C6AC1E401C1B375EBD50
C96BD8F7284C1DBF762AFBE5EF954533E3E2F5FC847BBC6CC1C4108A73A0E260
645C7AE7DE27FF5E0DBEC23764DFD7C96EC6E6B738FDA9C940EEC1E7EF67DF88
2887BE576CBE1B36DFD3C877C3F027EAE3188143AB9DDC62F7983C624C98BC1C
FDA6587B31E8E1D84BF0D49D876DA3C92018C3E827FAA5B715C5EB36FEBB63E5
9489FEB088DE06DB57282D70E5A2C3B8F381F92379E22874D0E4BF8FCC2D88CC
D185453CC4F37DA2290211B0F1E6C56A025092D66CAC1B6E256740C978F2E8C7
317632588848A1972400E4F97A774879C464BC2C23984A3E39EC96AC1720A843
A3CEB3C4775478FBFEAFF2E7070197578A829C9D09BEF882F0FE7BC058816F7F
7BA077D01FFD9154DCB5B06D3E137CF5AB7ED07C96CB4E67976527683BC7A88C
DA685EFBF903B186AA510FD8C4C6DC7A487AA087E9CB2281890705AF7A8ABCF5
FED22BE68DB316383D6B78A330504198FD3C8E274B411BEC9C7A4D3263F0EC8C
1D39C6E939C352D9B2CC0BA77E6BE75038E5E0C4F70934991FA69CC6D89CF984
5D2A5CE249BF0DAC4434112183AD0656A33FC13525315BE845640558F0E22F49
18A672DEE728A3406D86D3548FBFE64E1D46AB3572CCE9C92FAC183D378D1498
48BFB3C42CD329CF53EE61D4C809232F5F82A593FF9CDAD62DBAEC03E8626C9B
D539F41EAE53899C6403EF25042385591178F70457276CA0CC142B00229A79F2
053BA4722F089B22203A91BBF0488E64E3C093D138698E3C44F2CC710D62F31A
151E3A928CE04E8A3B84B4497F0783A5DE13C3E3A5708B36CCB5528B34B3E282
12AD9EF9187340A3E3B624700B3DB27E861979C7F297569F1B29163F08CC4323
3B493AA658F8D1D79C1C9CE5D48752CB074ABD1980BDC13564E41166C1ED6B52
6795B49F11EC9D819BD74A9439EC81D7AF759B67BF3AE211CFFFDE7D57DFFFF9
3F13BCFB15C18B5F139E3C012E1E00BBC52A65015C3C109CED3C93AC5892881A
D9FD5DE2F38D81B35D42285E05D65AC22EA3EBCCC72C3A03921A6AB697189C53
8D411467B5348851B430F2C6B3F15C87C1299EC4649609C6C9F1EF138164688C
52BD5B3AD9CC2099D9368299533A41305292419283E588D4273433604A1B6758
24992E5233CD9B0098A898FC8AADFB81F944D7D8D04CA9241A0A8833C3674471
6F625290C4EA3D4260CCB384F3E8DDD0EF96C4E89D53DF76060D91E1F36F8468
B6100CDF439BBC6F82D878D62259DDDA951933BA266047DF1650CD18BBD4631A
467D44F173230AA30306A5B218F2F0FC6B2442C19E99A19B8D2D0F6AA2F57D3F
9755C0CA06F6F1E3311526894DCA3215E295B1C495CC9419DB005EFC9C718ABC
41A5167DCE3139BCB429269BB0F9A95C25698995AE586B481C72A14D32B60F9D
54FD77C7E6C7AAAC3DA54EDA717B75E80CBA0E8AA5D12C3B05DBA677AD1B5A0D
0E12511C7E582E67ED4AC5F4F31C0E6A6FF786DB2F8BE0E6B5B6E7F6B5C23337
37C0C30BF5E86FEF80A7CF087FFD5784CF7F11F8FC91A197EF7C87E88FFF58F0
7BDF14FCEDDF11AE1EE9C0FAE52F955DB3EC045757FA1A4369406C854CAD213E
9F9F9B712E78BD57CFA260E82E47A038AB199C6183DE3C724F7838E6DE582797
08D364E6CF4791EA9440B50923B69148CC7A489A5EB475759E0829899B1F9993
C2AE41267E1DBEA009DD4E94288C1E49C22251B94A539233D93F251AB1C90747
C5491BC36CFF8FC9843166603FA9B255F661A627D6CA56C9B6064349BD6D4F4E
F3861FEF137D5EF71C4DD184CF9379F194744ACE6840FB9A9887446FAE62BD17
B77F134B474E1E43A454C10E4C18FDBA31F47DA078F209D7A891A0A9BAB5B254
501837A34E140517864870C48BDB38D3145112B827B0FB09A51E25BFE5CE82A4
81B5D4C1D496A0498E19F28F0A589F181C770F8C7E66B7D48AD38C6668867D4A
4EC9A1A888006A2159A421129B0FEC5B12928ADAE0A9EDC9EC81685E71C834B8
147E454E7A52271B7BDE9A644D3E7CDB99008471E9BB38C5D39C5D3BF7E14053
7EC0D93B6215B2A3136E5F2B5B675D8143D77B74D8139E3E25434DD47EFDEEEF
0A9EFD9A70761EB77939D2B7F9DEF708FFEB2F33C900107EE33704CF9E12FA60
A08214B5F8A86ADF6C59278ED39F8985249A18A5AA2963C66BD919454D921FDE
D784213C0FD03B4F5E1B897E47066F305BE51B9DC0D529CF2785873F888EB07A
6C356A24218E48E38AF1E227DE266535A2D0CC5DCFE9C14B9C26AC1EC5D3DF62
F493C9AF3982A0E6CDB9805179F25E7E4E9BEDC83078D7C4A19958B94D6452C5
D482A540A9F7B36D6754F5164F7F2A6BCF77262A9CF902E10456AF1124F3CCEC
39C6E6BF0CF3A6E8AB9C34F2C71EFDE82A6BE005516AF0E5E8E5615A7AB26929
0903C3328751DC143C78892A558F2CE3FCC588532D8422E7C91B0FDF71F228C1
1FE11849E1CE1F55BE9A760D8904179DB7387E8D4808C9538FECDA5CA0E57792
29AF8D51789924364E2A2F1F718D1A89485013A5440644F3A4959F4730798846
D1A0B1B6B04CDFB556AB7567BC9D448C51637A36958269E67369230BD79C6544
73CDC0B2D4024A0906CEEE4C263C3EE8B2CE482CFA36EEE85EBF223CBAB28942
005E048F1F2921E0EB1F0AFEECCF08FFEA5B42DF3F81D1D3279F887CF411E1DD
AFE80CF2F0A1E0C30F058F1F6BB295C8920570AC29B1E5F3738571969633B9E3
E500B4388052E3219C8FA28BB3ECF28626FF3D43FD56D9269CD85B788D4DE2E1
3A5592D82A3839932BAE59563D7AE7D1134BD1BA9971E5402C9C2E29950A6C1C
FF09879F934D9BA8F2584A8066F828FC1ADAF00FA23D32315A82EF53316BD9C0
3B9C469A8E340DF222A570E6D3E4F024E53073E2932E4924A171431BFD37A692
8FE0CC9980D2632752EA646BF38B2D6A548AA5FECDF74237B88759832FC9B839
1D21781154502923F14AEAD5073E2F930C9A6CBC73D75F910AE198573A46EAE1
24134702C30DF79A64C2E1DD7DA6131314517AFB74448929E8510908B71CFEEA
8D8F8052A4545B4B78F434E9DFCC94D009582A709F471154D92D5B5C55E6944B
A5334F51845333437B67661205C45B20A8895A6D859464DF8B68FE6FA24EB344
B453FD05AD983547598075652C4BCACA7854A7B99D02178D949FA1281AD5DCE6
C5850433E7B0AAF44C5F81FD1DB03B57398521C0CFFE1FE17FFF84F08DDF9E8C
FC64E8E5E38F893EFB4CF0DEFB2A64F6E001F0AB5F11CECEB4716B273CBC50EE
7C5B74225816E0C1B9F1E6A1504D6BAE3889D03C698BF2E661D8AB882621880D
9FB7CA338F02FC8634C3EBD9A50E90C685ED388EE3731889A2B3435AC2ACBA3A
0270FAC48EDD47386661E8B04449ED0422B3E81615FE7CF8E7A69993066F8E74
AA6C8117815571B0519439E5888A59EA00242384F4A42B6843275440E790568E
D437E7EA9324B2A5F05BE646AAB8DACCBF0F60A770E9990B4B6783ED23EB6863
9085076F74CA25746D28E8952E8D70BFB7FE363EBDFC3DF1F91C84C999D7C1E6
B4CAD50AA5BC4236129645E02BE4092676A37ADC131C8214F41A1AEC19322F41
11AC70CC313DF2CD40D5917223CDEC8E60B484933257A84EA91D9292B8D45D06
667C7EDA76D38C5A5815C263C091068ECF6F91C8AD7223554AC4211A9609261E
A12743098B54E1CC30C23451277DF21A36B9F6356B54A4A79335BCA29ED4B376
9B5979F48EF93B9434567D35E3E97B21D5DD5EDF0F0775805FDF6A22F6EE0ED8
2D8257D784C30ABCBE25BC7C41B8BB4D5B74730DFCCDDF90FCC11FD049434F9F
7EAA2DB97A0CFC9F9F121E5EE9601301760D78FC440DE6FE4E8D74EF84FD9D1A
ACC35A55254B890E2963E7B057754826E5A62ECDA53FF577F7E8BC2A56202160
36CC484BF1B087252C5A9B755E68AE778A86288FDF0DA956F23AE364F62AAD0E
A068D7B81E8E6C54225D20AD8AA4614AB26262B54C916160D81991F0942C4544
14515854AB4FAB8857D5C5114C8351B6607DCD910047D4517923DC414EC89C12
50B54DE04DA5ABB54059563215584505EDA62EA0350A23DF8C271F06BE01BC50
F0EBDFCE9E791B6C03BC59BD32BF576CD4E09A5569C28AD94B481E8CD5067297
82ABD3E4ED4AA9924570E2694A1C8A1563852ECE481D18FD3B2B69C3599F12BD
354C18618A246409E4B86EAA585E3A45B79F18A832313D27965031E62E809803
E6FEB4C830A72BEB1572A0256E4F85A6E8798C74627A61C28861E5B512D72783
31B6F83A95C4B9C155454C318EBFD2948BF0DFC798F3285A453B478ECB22580F
5E7390859A8BEBDD78BB863ECBDD99E6416F6FF5AABD08EFE52BFDBC1E74FCEC
F78AD93B21E5EE0E5858F0F39F4F1D3931FA8F3ED601F43F7F98E264AE2C3806
E19D278217D77A61D7D759D7CE0675DCDE51CA0BD81DDC5B03A2D4782D5C732F
C621A559AE1D45268042A7C6D92EEB9A05426278BC5408A2E8DB50E1C6CBA443
8F08A9AA7853C5D4AB96BC141E7B358464DAFC14387DC9178C22C63492AF2F7E
2D8342B7C6C58651346DDC0519A163439B42AD13C64B92F3AE7AF476AE49C5B2
D60F7086242704CBFC378157AF6666DA8527E25950D1DD91CA8F4FAF5F0CD70F
FA289D9E50C8AB618D33BF344EC903F7E8A9E2F3B80797BF4FA06CAB6FF326D5
4A4CD8F310F7D68D6D23CE9B575EFD081EFD880428510A874DC7AE1A02635682
DCC22D34316C0A27DFF56A64839F6F70EC490C4F2A0F7ECC38893B08542A7069
83DF572FDD630B83434936B87F243EC74C1AA639E7A1D780925748368F73FFA5
E617A8E0F355E3A6461BE5B8A0AA8209A5400E83862531F1AA7B3300B436D423
7738770248A5D4B088924ECABD5D57C3F779A864C19293CD6E41E43E7C32DD19
13518C6EEC93C9C5C5307C3E8928D7D73A9E2EAE040FAD68EAF2A1E0A73F257C
F081E0377F533006E8FBDF3F0DDDE01FFE03F5522E2F613AC97A594B4BC6C9B2
64956265EAB2B35D3867C0D5B46C9645A195EEBA372CC16E7126CDBA261FDAE9
975478F463546A5E2212C133F744CD4841B34A69741DFAF00C9C31123736593E
69CA2ABF7DC33F09EE7FE19157168B879FD14968C2D3A792EC8D3C2695888433
DD1B09673AC90F4F9C273470CAE325C9C2013EF25E79F6E68983377DCCB699E9
6454747AA2EA9536183E0A6F7EA321C42136679FC3A063D29B6F9CEFAA7F9339
9CFB9527EFA9EC7C233C733F4E9F2C1B9A28947D557ADCEA98FD40E1BC57CDF9
B4F1A3307082A72D5B75CB120548DD662E8E4AC38B997943270C35CB0CC84F09
CDF95E51D1AD9960A6915EF32821EE36C298E440B677BC449652E8C5EAA86C02
50A149E66353363B3D4D325D7FD7D771AD9A896F348B6C668EC4E013F7D24508
CD6A3C469FE5707DFB2A69505490A7DA15759A0DC26EB670C96A2C1C52E1B221
299D713035CBB1D19F4F390D550B164BA23C7D4A78FE82F0DE7B82AF7F5DF0E7
7F4E78FEFCA8FB6665ECBB5F017EFB1B821FFD8870F30AF8DAD704CF9E694875
7129B8BBD599657FD0446B5FB5E1875507E7306D1BD7481E9D80D56751170A4A
784539A88844C790D45D6E4D2F8C5981B9880A481F64423694D2A0A64EE94FD3
F7712C1E5C1C2916D0982958D8243E8F3A11D5CE5972CA21AB20760E9A38EBD8
8825D16444535BA18688B52D54543585E858830695E554A991948A9EEEC5D331
8D1225593B79F87402E6604BE86EAA5B296025DA144ECD4CA4AAAA9374CBC473
A604AC433406D9906BD1DBE7FBF56BE89E6227DA4C0C6F122F3B36FA23F46BA4
C0348ACB4F1AF46B615B540F9B8A00162523C7F17C915982B7F2EEA5C081B3DE
7CA97A95AA8459FAD391EAD75C309586D5447CE330398138394E660D84D49847
EAD55418A9CAF816BEE6F19D36CAB3B34E0495CB598C283652227422A16C2969
B244315857372112F4323623D8E184595C0414A635CF54A0361F9B75BC9AC0A0
7442A77942F7E7A630B3093EB2B5C12AF5D91CDBFD9EC271DCED04777B36DC3E
9D0C112DA45A9A56C23E7FA10E0741F9F4777BC25FFF959EFAD9B3A30E9E1EFD
A37774A3F3074AD179754DB87EA9195F74E7C6EBC08310EEF6263F6C6C95B3B3
1421F32AD6DDB998F222451894D5FB6AB4B5400A937E4A78F933EE000007B849
44415466B9532AC03D415EE6605082E6350BC4774BB256653C9E74D025F8FA3E
5332CD3A3D55CC2C269AA2AD3EEB7815D95ECA4E3AA9F47AA73E62F35076A2B2
3C582A064CD5484024302BEE2D531155A5B7D50477C0434572408EDC23134F43
5D86D03D6F9AD426C1B3979F390599F4F78F78F5441396EF399765C944ACAB55
BAEE8D336F96099FA737306CEE9B104E19F7FB8DBD0CE822231DA135AE9A3726
70662B4A8D916C19C7611D7B76A6CA18125CE9B1156CB4D2FE49C37E14468EB8
2321456AC3A51630C12F292F39026A718135AF6A4549E44EF5B454253E52E307
F778E9A82B4A61CB869113DB639A0468B31A15CAAA4F429B15A84AA403C124F0
361DDF12D91A81CC9A34359D5D736842AABADB2D5790AB3A953A9C5ABD7B82B4
E5F79809580F9C4C9A9223736F7D74D59157B55DCD47DDEDF51A7B51CA1C6B4E
38BDE7D05DF7A63A6039D2DFFB17FA544F18FA45BEFB31D1279F0AFEF22F520A
D3717930F0EC29E3C913C1F35FCF7A364C84D7B7A6417FB75D435647F3D99926
0B5CAA568B0268921F580F9C6BBF5A9217625AD006B5247E9FD69217CD6E8FA2
C1A252A9D9C6D1398489AA673D3AA7C44DB4FB583D6FBB749E08923F2F5CBC69
144E7D2948AA1EBD246E2E1BDC3DCFCBB19DCA1438B7DFE70F0A4D0E2918BF17
3749A90D08CDFBA2779FDA355C34F167ED7D294A93D14EE293DE31153E29A1F4
0FF1F56C4BFD80CCDAF022332F9F6883C773EACFA7C157ED1BA237F1E6F92D4C
9C8A678F2FC19F1F467BB455A47A52289D79A3544BD5BF91BA665EE1C627BC9E
1CF78A55CF2C988A85CF7A38557327F468A8144D5159D569C2EB8D531E1A2B23
7465EA2A5013CF9E045BEDF8C4DDC74C8270ED1D190911CD997F54FD7B88C412
7CB12EAA0CBB16831F036BAFFB20F6CD95B66CC451E2FE626A5186E998BEFC26
B208E5CD11D5EAA32B6443AC86DED93BCE97EFDDBC6FBBBFC9AF2FDA349C7916
D7AC57FDFA9C8C199A843DDB153144129CEF4CC8CC174B625D2EF0F202A16A39
3AF0DE7B035F7CA190CDF903C137FEB1E070007DF6D938853C32C680FCFB7FA7
19E56F7D4B7071613AC9677A81CB2278F54A07CDE543F5BA9A25171A0B6EEFD4
A0EF76CE90902863F775625138E8BB25F9F53E5E7D31DCB1DA422694BC566E12
587C334903319A52E5D9675529727D589660354C6A8F9CF8714D0157379B3639
3C29D4483A418A674A2D1AD0CC71C746AA18A815A1758D5909F960B6BFA70A5F
CC8A95BC3D36E7F281952614798852C21449E54DE294362A9588E46BC921142F
9D699621A602DC735116054B309E6A84C36525AAA5192DB7AA55B68D547593C2
9FFF327A356F8271F0162827BDA8F54006CDCC104EEF30D68D2FAA53356968C2
DD93774E31C7CC3CF502E314AC7F523CAD454E75822084B0D8AC4D8F14249319
B2A19AEE9D38EE542A4F298AA622E7200E0B1E4B2DD7D71029120EF37C4A9B25
3AF36F29089361EC31C68B18A06CE40FCA718645F34328042368C3981B4E53AE
95FA8C499658287324EE54A6D89B1555711AF9F0FA81928FD41CA44A2318F572
68A4B73435DAAE1936BA2D3862344BAF3DBABCD48A5AD5A957A8D01DBEC39DEA
41FDE8C7846507F98FFFE124838CE9B3FFA6DC79418A993D79023C7E0C3CBC04
1E3ED481777925D8AF140BD89EED743192C5A48247940EDB606C62A2F88A2BF1
46DF4693B43306CE2648E609542E9C5D66D7A1A092C844E8DA7BC23575AF73B1
709749D6106A8421142FCC72F69094453A0A65B2ACDA57F07099D822938780B2
28C466E9BC714211D3B71F2EA55C4BB25157629A0BAAB26C9E22E94705BFF181
3C061F15471588F2A4CDA323E261AEA5EBB8FC2CC140930C316DD60D24D92E2A
9E1451C12C47ECEBC4BA91CFA229AFD3781B7DF24D2C9CB7AD097B3A113BA454
C45AC18BC336C19FEF32AF1E55FE26B265ECAAA2CCB47E2C26D95D4C85465274
70B68F4AE67564E5C47AB1BE6F5D4D89361B4C776EC366A9457D0E7D5059683C
163A29C672BAFB32D14A2BEC11EA9A542A46EAC220654D566C16F6DE5E42C226
4ECC3806F5B6DD3D248C4D8746CA22477E9C4A81750AF9BAF284F5E7FE4037FD
7826DD8E59AFB91B23CF8BEE7C9DDAB5EBD294ABC9201C0E6AAB5EBF561CFEEE
16D835454E5E5EABFEFCCB17FA74EEF6C0CFFE96F0FA06F8C10FE8146C133E21
FDE7FF22F8E637053FFB19E1EA4A07DBE79F6B8194D8BAB0D72F35CCD0EFD4F3
EAA2A1F6DDAD79A4AC419D4B0AB7A6D5B45E4CE537C6133BBEC008468A624D7A
F1D53E918488556B1AFAB6C2779552A5EA7CDC79C1619F68BCEAADA82FF80A58
3C07FF5321515DDFA176CE09BF2F55BFB461AFD555F57853229D7672CE236C16
2909EE8BE51784371D7993F19FEF2701A356B752593E71A64EBA1E3D552AEC86
6D33A996140F1E1B2D1B0D53E72A63DF8638A39930E8EC2C9B0ADFF85AB18ECF
D35B12A9F7F1E1BFCC2A54B3672F66D0D75E2A1A8BC64D1FE9D927F77DD6980F
864D68B69B02E5C4449150A59C5838A1015545CF469131C0AC0B431B6D1BA9CA
AB2704CFA4C88B7895E85C41905EF09CF18CF51DA6094A0A8559322AD0252D37
4F431006F9449E782AD79DA15594022A1CADBA3542E1D3F320E918A98822E7A2
27A528D11742F2BA85DE338FD1DA8810C20BA1D8F4707AB7DCE1482859C4D78A
CDF62E8B2D5262DCFD4307CECE46889A79D2F9C1B9AD976DCEE93A08AF6EEC1A
BA8ED4274FB4ADFB83CAC6BCBAD1E2AA9FFFE26447FEFF3BD70300455D759800
00000049454E44AE426082
}
Transparent = True
end
object lblMarqueeText: TLabel
Left = 0
Height = 24
Top = 0
Width = 514
Align = alClient
Alignment = taCenter
Caption = 'This is a marquee background effect with transparency.'
Font.Style = [fsBold, fsItalic]
Layout = tlCenter
ParentColor = False
ParentFont = False
end
end
object Panel1: TPanel
Left = 0
Height = 48
Top = 472
Width = 514
Align = alBottom
BevelOuter = bvNone
ClientHeight = 48
ClientWidth = 514
TabOrder = 9
object shpTri2: TShape
AnchorSideTop.Control = Label5
AnchorSideTop.Side = asrBottom
AnchorSideBottom.Control = Panel1
AnchorSideBottom.Side = asrBottom
Left = 256
Height = 33
Top = 15
Width = 81
Anchors = [akTop, akLeft, akBottom]
Shape = stTriangleRight
end
object shpTri1: TShape
AnchorSideTop.Control = Label5
AnchorSideTop.Side = asrBottom
AnchorSideBottom.Control = Panel1
AnchorSideBottom.Side = asrBottom
Left = 176
Height = 33
Top = 15
Width = 81
Anchors = [akTop, akLeft, akBottom]
Shape = stTriangleLeft
end
object Shape1: TShape
AnchorSideLeft.Control = Panel1
AnchorSideTop.Control = Label5
AnchorSideTop.Side = asrBottom
AnchorSideRight.Control = Panel1
AnchorSideRight.Side = asrBottom
AnchorSideBottom.Control = Label5
AnchorSideBottom.Side = asrBottom
Left = 1
Height = 1
Top = 11
Width = 512
Anchors = [akLeft, akRight, akBottom]
BorderSpacing.Left = 1
BorderSpacing.Right = 1
BorderSpacing.Bottom = 3
Brush.Style = bsClear
Pen.Color = clGray
end
object Label5: TLabel
AnchorSideLeft.Control = Panel1
AnchorSideTop.Control = Panel1
Left = 12
Height = 15
Top = 0
Width = 216
BorderSpacing.Left = 12
Caption = 'Animated metronome with color change'
Color = clBtnFace
ParentColor = False
ShowAccelChar = False
Transparent = False
end
end
object butAlphaBlend: TButton
Left = 8
Height = 32
Top = 360
Width = 160
Caption = 'Alpha blend form'
OnClick = butAlphaBlendClick
TabOrder = 8
end
object chkLabelFlashing: TCheckBox
Left = 192
Height = 19
Top = 360
Width = 92
Caption = 'Flashing label'
OnChange = chkLabelFlashingChange
TabOrder = 11
end
object lblFlashingLabel: TLabel
AnchorSideLeft.Control = chkLabelFlashing
AnchorSideLeft.Side = asrBottom
AnchorSideTop.Control = chkLabelFlashing
AnchorSideRight.Control = Owner
AnchorSideRight.Side = asrBottom
AnchorSideBottom.Control = chkLabelFlashing
AnchorSideBottom.Side = asrBottom
Left = 288
Height = 19
Top = 360
Width = 222
Alignment = taCenter
Anchors = [akTop, akLeft, akRight, akBottom]
BorderSpacing.Left = 4
BorderSpacing.Right = 4
Caption = 'Flashing message'
Layout = tlCenter
ParentColor = False
end
object lblFPS: TLabel
AnchorSideLeft.Control = chkMarquee
AnchorSideTop.Control = chkMarquee
AnchorSideTop.Side = asrBottom
Left = 192
Height = 15
Top = 429
Width = 31
BorderSpacing.Top = 4
Caption = 'FPS: 0'
ParentColor = False
end
object chkMetronome: TCheckBox
AnchorSideLeft.Control = chkLabelFlashing
AnchorSideTop.Control = chkLabelFlashing
AnchorSideTop.Side = asrBottom
Left = 192
Height = 19
Top = 383
Width = 138
BorderSpacing.Top = 4
Caption = 'Animated metronome'
OnChange = chkMetronomeChange
TabOrder = 12
end
object chkMarquee: TCheckBox
AnchorSideLeft.Control = chkLabelFlashing
AnchorSideTop.Control = chkMetronome
AnchorSideTop.Side = asrBottom
Left = 192
Height = 19
Top = 406
Width = 101
BorderSpacing.Top = 4
Caption = 'Marquee demo'
OnChange = chkMarqueeChange
TabOrder = 13
end
object tmrAnimatedCadence: TTimer
Interval = 15
OnTimer = tmrAnimatedCadenceTimer
Left = 456
Top = 128
end
end

View File

@ -0,0 +1,621 @@
unit frmcontrolsample;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls,
StdCtrls, Buttons, uanimationbasic, uanimationcontrol
(* Still not working
, uanimationbitmap
*)
;
type
{ TfrmAnimationControls }
TfrmAnimationControls = class(TForm)
BitBtn1: TBitBtn;
butSliding: TBitBtn;
butReverse: TButton;
butPause: TButton;
butBounceCaption: TButton;
butDropDown: TButton;
butAlphaBlend: TButton;
butZoomTest: TButton;
CheckBox1: TCheckBox;
chkMetronome: TCheckBox;
chkLabelFlashing: TCheckBox;
chkMarquee: TCheckBox;
grpButtons: TGroupBox;
imgFlareMarquee: TImage;
Label1: TLabel;
lblFPS: TLabel;
lblFlashingLabel: TLabel;
lblDropDownMessage: TLabel;
Label3: TLabel;
Label4: TLabel;
Label5: TLabel;
lblMarqueeText: TLabel;
lbSampleEntries: TListBox;
Panel1: TPanel;
pnlMarquee: TPanel;
pnlAttached: TPanel;
pnlDropDownContents: TPanel;
pnlDropDownHeader: TPanel;
pnlDropDown: TPanel;
pnlText1: TPanel;
pnlCheckbox: TPanel;
Shape1: TShape;
shpTri1: TShape;
shpTri2: TShape;
shpSliding: TShape;
tmrAnimatedCadence: TTimer;
procedure BitBtn1Click(Sender: TObject);
procedure butAlphaBlendClick(Sender: TObject);
procedure butBounceCaptionClick(Sender: TObject);
procedure butDropDownClick(Sender: TObject);
procedure butReverseClick(Sender: TObject);
procedure butPauseClick(Sender: TObject);
procedure butSlidingClick(Sender: TObject);
procedure butZoomTestClick(Sender: TObject);
procedure CheckBox1Change(Sender: TObject);
procedure chkMarqueeChange(Sender: TObject);
procedure chkMetronomeChange(Sender: TObject);
procedure chkLabelFlashingChange(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormResize(Sender: TObject);
procedure tmrAnimatedCadenceTimer(Sender: TObject);
private
{ private declarations }
AnimationQueue: TAnimationQueue;
FDropDownExpandedHeight: Integer;
FAnimateTri1: TAnimationControlTranslate;
FAnimateTri2: TAnimationControlTranslate;
procedure DropPanelEndAnimationCollapse(Sender: TAnimationItem);
procedure MetronomeEndAnimation(Sender: TAnimationItem);
public
{ public declarations }
end;
{ TAnimationSampleBrushColor }
TAnimationSampleBrushColor=class(TAnimationCustomControlColor)
protected
procedure DoChangeColor(const aNewColor: integer); override;
public
property InitialColor;
property FinalColor;
property TransitionMode;
end;
var
frmAnimationControls: TfrmAnimationControls;
implementation
{$R *.lfm}
{ TAnimationSampleBrushColor }
procedure TAnimationSampleBrushColor.DoChangeColor(const aNewColor: integer);
begin
// Brush color instead Control.Color
(Self.FControl as TShape).Brush.Color:=aNewColor;
end;
{ TfrmAnimationControls }
procedure TfrmAnimationControls.butBounceCaptionClick(Sender: TObject);
var
Ef: TAnimationControlCaptionCapital;
begin
AnimationQueue.RemoveGroupID(butBounceCaption);
Ef:=TAnimationControlCaptionCapital.Create(butBounceCaption);
{$PUSH}{$HINTS OFF} // Hide hint about use int64
Ef.Duration:=50*Length(butBounceCaption.Caption);
{$POP}
ef.Repeats:=2;
ef.AutoReverse:=true;
ef.TransitionMode:=eAnimationTransitionBallisticBoth;
EF.AnimationOnEndAction:=eAnimationOnEndFree;
AnimationQueue.Add(Ef);
EF.Start;
end;
procedure TfrmAnimationControls.butAlphaBlendClick(Sender: TObject);
var
lAlphaBlend: TAnimationControlAlphaBlend;
begin
AnimationQueue.RemoveGroupID(Self);
lAlphaBlend:=TAnimationControlAlphaBlend.Create(Self);
lAlphaBlend.AnimationOnEndAction:=TAnimationOnEndAction.eAnimationOnEndFree;
lAlphaBlend.Duration:=1000;
lAlphaBlend.Repeats:=2;
lAlphaBlend.AutoReverse:=true;
lAlphaBlend.TransitionMode:=TAnimationTransitionMode.eAnimationTransitionLinear;
lAlphaBlend.InitialBlend:=255;
lAlphaBlend.FinalBlend:=0;
lAlphaBlend.FinalizeBehavior:=eAnimationFinalizeBehaviorInitial;
AnimationQueue.Add(lAlphaBlend);
lAlphaBlend.Start;
end;
procedure TfrmAnimationControls.BitBtn1Click(Sender: TObject);
(* Still not working
var
lAnimBitmap: TAnimationControlBitBtnPicture;
*)
begin
(* Still not working
AnimationQueue.RemoveGroupID(BitBtn1);
lAnimBitmap:=TAnimationControlBitBtnPicture.Create(BitBtn1);
lAnimBitmap.AnimationOnEndAction:=TAnimationOnEndAction.eAnimationOnEndFree;
lAnimBitmap.Duration:=2000;
lAnimBitmap.Repeats:=1;
lAnimBitmap.InitialAngle:=0;
lAnimBitmap.FinalAngle:=360;
AnimationQueue.Add(lAnimBitmap);
lAnimBitmap.Start;
*)
end;
procedure TfrmAnimationControls.butDropDownClick(Sender: TObject);
var
lDropAnimation: TAnimationControlZoom;
lDropRotate: TAnimationControlFontRotator;
lDropText: TAnimationControlCaptionReplace;
lFinalRect: TRect;
lList: TFPList;
procedure ReverseList(aList: TFPList);
var
j: integer;
begin
for j := 0 to Pred(aList.Count) do begin
if not TAnimationItem(lList[j]).Reverse then begin
//writeln('Can''t reverse now');
end;
end;
end;
begin
lList:=AnimationQueue.FindGroupID(pnlDropDown);
try
if lList.Count>0 then begin
// Reverse all the related controls
ReverseList(lList);
lList.Free;
lList:=AnimationQueue.FindGroupID(lbSampleEntries);
ReverseList(lList);
lList.Free;
lList:=AnimationQueue.FindGroupID(lblDropDownMessage);
ReverseList(lList);
end else begin
AnimationQueue.RemoveGroupID(pnlDropDown);
AnimationQueue.RemoveGroupID(lbSampleEntries);
AnimationQueue.RemoveGroupID(lblDropDownMessage);
lDropAnimation:=TAnimationControlZoom.Create(pnlDropDown);
lDropAnimation.AnimationOnEndAction:=TAnimationOnEndAction.eAnimationOnEndFree;
lDropAnimation.Duration:=500;
lDropAnimation.Repeats:=1;
lDropAnimation.TransitionMode:=TAnimationTransitionMode.eAnimationTransitionBallisticBoth;
lDropRotate:=TAnimationControlFontRotator.Create(lbSampleEntries);
lDropRotate.AnimationOnEndAction:=TAnimationOnEndAction.eAnimationOnEndFree;
lDropRotate.Duration:=lDropAnimation.Duration;
lDropRotate.Repeats:=lDropAnimation.Repeats;
lDropRotate.TransitionMode:=TAnimationTransitionMode.eAnimationTransitionLinear;
lDropText:=TAnimationControlCaptionReplace.Create(lblDropDownMessage);
lDropText.AnimationOnEndAction:=TAnimationOnEndAction.eAnimationOnEndFree;
lDropText.Duration:=lDropAnimation.Duration;
lDropText.Repeats:=lDropAnimation.Repeats;
lDropText.TransitionMode:=TAnimationTransitionMode.eAnimationTransitionLinear;
if butDropDown.Tag=0 then begin
//writeln('Collapse');
// DropDown panel is expanded
// Store current height to recover when expand
if FDropDownExpandedHeight=0 then begin
FDropDownExpandedHeight:=pnlDropDown.Height;
end;
butDropDown.Caption:='_';
lFinalRect:=pnlDropDown.BoundsRect;
lFinalRect.Bottom:=pnlDropDownHeader.Height+pnlDropDown.Top;
lDropAnimation.SetFinalSize(lFinalRect);
lDropAnimation.OnAnimationEnd:=@DropPanelEndAnimationCollapse;
lDropRotate.InitialAngle:=0;
lDropRotate.FinalAngle:=90;
lDropText.FinalText:='Now press the button again to expand the panel.';
end else begin
//writeln('Expand');
butDropDown.Caption:='^';
lFinalRect:=pnlDropDown.BoundsRect;
lFinalRect.Bottom:=FDropDownExpandedHeight+pnlDropDown.Top;
lDropAnimation.SetFinalSize(lFinalRect);
lDropAnimation.OnAnimationEnd:=@DropPanelEndAnimationCollapse;
lDropRotate.InitialAngle:=90;
lDropRotate.FinalAngle:=0;
pnlDropDownContents.Enabled:=true;
lDropText.FinalText:='Press the button to collapse the panel below.';
end;
AnimationQueue.Add(lDropAnimation);
AnimationQueue.Add(lDropRotate);
AnimationQueue.Add(lDropText);
lDropAnimation.Start;
lDropRotate.Start;
lDropText.Start;
end;
finally
lList.Free;
end;
end;
procedure TfrmAnimationControls.DropPanelEndAnimationCollapse(
Sender: TAnimationItem);
begin
// Disable contents so controls will not be reached by tabstop even when
// its visual size is zero.
if Sender.Reversed then begin
if butDropDown.Tag=1 then begin
// Reversed expansion, disable again
//writeln('End reversed expand');
pnlDropDownContents.Enabled:=false;
end else begin
// Reversed collapse, do nothing
//writeln('End reversed collapse');
end;
end else begin
if butDropDown.Tag=1 then begin
// Finished expansion
//writeln('End expand');
butDropDown.Tag:=0;
end else begin
// Finished collapse
//writeln('End collapse');
butDropDown.Tag:=1;
pnlDropDownContents.Enabled:=false;
end;
end;
end;
procedure TfrmAnimationControls.butReverseClick(Sender: TObject);
begin
AnimationQueue.Reversed:=not AnimationQueue.Reversed;
end;
procedure TfrmAnimationControls.butPauseClick(Sender: TObject);
begin
AnimationQueue.Paused:=not AnimationQueue.Paused;
end;
procedure TfrmAnimationControls.butSlidingClick(Sender: TObject);
var
Button: TAnimationControlTranslate;
Zoom: TAnimationControlZoom;
lList: TFPList;
begin
lList:=AnimationQueue.FindGroupID(butSliding);
try
if lList.Count>0 then begin
// Do not start new animation until current finish.
exit;
end;
Button:=TAnimationControlTranslate.Create(butSliding);
Button.Duration:=1500;
Button.Repeats:=4;
Button.AnimationOnEndAction:=eAnimationOnEndFree;
Button.AutoReverse:=true;
Button.SetFinalPosition(Point(shpSliding.Left+shpSliding.Width-butSliding.Width,butSliding.Top));
Button.AnchorLocation:=eAnimationAnchorLocationLeft;
Button.FreeWithQueue:=true;
Button.TransitionMode:=eAnimationTransitionBallisticBoth;
Button.FinalizeBehavior:=eAnimationFinalizeBehaviorInitial;
AnimationQueue.Add(Button);
Zoom:=TAnimationControlZoom.Create(butSliding);
Zoom.Duration:=750;
Zoom.Repeats:=2;
Zoom.AutoReverse:=true;
Zoom.AnimationOnEndAction:=eAnimationOnEndFree;
Zoom.SetFinalZoom(0.1);
Zoom.FreeWithQueue:=true;
Zoom.ZoomMode:=eAnimationZoomModeHeightBottom;
Zoom.FinalizeBehavior:=eAnimationFinalizeBehaviorInitial;
Zoom.RemoveAnchors:=true;
Button.AddSyncStartStopAnimation(Zoom); //Synchronize restart/reverse action for Zoom when button restarts.
//This can cause problems with Repeats counter
AnimationQueue.Add(Zoom);
Button.Start;
Zoom.Start;
finally
lList.Free;
end;
end;
procedure TfrmAnimationControls.butZoomTestClick(Sender: TObject);
var
butAnim: TAnimationControlZoom;
begin
// All animation references to butZoomTest must be removed
// before as in the creation process we capture the current
// dimensions. Removing ID before creation of new animation
// first finalizes control and then captures original dimensions.
// If not done this way starting butZoomTest dimensions will be
// the current Zoom factor which is almost always small.
AnimationQueue.RemoveGroupID(butZoomTest);
butAnim:=TAnimationControlZoom.Create(butZoomTest);
butAnim.SetFinalZoom(0.25);
butAnim.ZoomMode:=TAnimationZoomMode.eAnimationZoomModeAll;
butAnim.TransitionMode:=TAnimationTransitionMode.eAnimationTransitionLinear;
butAnim.AutoReverse:=true;
butAnim.Repeats:=2;
butAnim.AnimationOnEndAction:=TAnimationOnEndAction.eAnimationOnEndFree;
butAnim.Duration:=100;
butAnim.GroupID:=butZoomTest;
AnimationQueue.Add(butAnim,true);
butAnim.Start;
end;
procedure TfrmAnimationControls.CheckBox1Change(Sender: TObject);
var
CheckboxAnim: TAnimationControlZoom;
LightAnim: TAnimationControlColor;
begin
AnimationQueue.RemoveGroupID(CheckBox1);
CheckboxAnim:=TAnimationControlZoom.Create(CheckBox1);
CheckboxAnim.SetFinalZoom(0.25);
CheckboxAnim.ZoomMode:=TAnimationZoomMode.eAnimationZoomModeWidthLeft;
CheckboxAnim.TransitionMode:=TAnimationTransitionMode.eAnimationTransitionLinear;
CheckboxAnim.AutoReverse:=true;
CheckboxAnim.Repeats:=2;
CheckboxAnim.AnimationOnEndAction:=TAnimationOnEndAction.eAnimationOnEndFree;
CheckboxAnim.Duration:=250;
AnimationQueue.Add(CheckboxAnim,true);
CheckboxAnim.Start;
LightAnim:=TAnimationControlColor.Create(pnlCheckbox);
LightAnim.InitialColor:=ColorToRGB(clBtnFace);
LightAnim.FinalColor:=$00FF00;
LightAnim.TransitionMode:=TAnimationTransitionMode.eAnimationTransitionBallisticOut;
LightAnim.AutoReverse:=true;
LightAnim.Repeats:=2;
LightAnim.AnimationOnEndAction:=TAnimationOnEndAction.eAnimationOnEndFree;
LightAnim.Duration:=150;
LightAnim.FinalizeBehavior:=eAnimationFinalizeBehaviorInitial;
AnimationQueue.Add(LightAnim);
LightAnim.Start;
end;
procedure TfrmAnimationControls.chkMarqueeChange(Sender: TObject);
var
lMarqueeBackground: TAnimationControlTranslate;
lList: TFPList;
begin
lList:=AnimationQueue.FindGroupID(imgFlareMarquee);
try
if lList.Count=0 then exit;
lMarqueeBackground:=TObject(lList[0]) as TAnimationControlTranslate;
if chkMarquee.Checked then begin
if lMarqueeBackground.State=eAnimationStatePaused then begin
lMarqueeBackground.Pause;
end else begin
lMarqueeBackground.Start;
end;
end else begin
lMarqueeBackground.Pause;
end;
finally
lList.Free;
end;
end;
procedure TfrmAnimationControls.chkMetronomeChange(Sender: TObject);
var
TriangleColor1,TriangleColor2: TAnimationSampleBrushColor;
begin
if not chkMetronome.Checked then begin
AnimationQueue.RemoveGroupID(shpTri1);
AnimationQueue.RemoveGroupID(shpTri2);
end else begin
FAnimateTri1:=TAnimationControlTranslate.Create(shpTri1);
FAnimateTri1.Duration:=1000;
FAnimateTri1.AnimationOnEndAction:=eAnimationOnEndStop;
FAnimateTri1.AutoReverse:=true;
FAnimateTri1.Repeats:=2;
FAnimateTri1.SetInitialPosition(Point((Self.Width div 2)-shpTri1.Width,shpTri1.Top));
FAnimateTri1.SetFinalPosition(Point(0,shpTri1.Top));
FAnimateTri1.FreeWithQueue:=true;
FAnimateTri1.TransitionMode:=eAnimationTransitionBallisticIn;
FAnimateTri1.FinalizeBehavior:=eAnimationFinalizeBehaviorInitial;
FAnimateTri1.OnAnimationEnd:=@MetronomeEndAnimation;
AnimationQueue.Add(FAnimateTri1);
TriangleColor1:=TAnimationSampleBrushColor.Create(shpTri1);
TriangleColor1.Duration:=2000;
TriangleColor1.AnimationOnEndAction:=eAnimationOnEndStop;
TriangleColor1.AutoReverse:=false;
TriangleColor1.Repeats:=1;
TriangleColor1.InitialColor:=ColorToRGB(clRed);
TriangleColor1.FinalColor:=ColorToRGB(clWhite);
TriangleColor1.FreeWithQueue:=true;
TriangleColor1.TransitionMode:=eAnimationTransitionBallisticOut;
AnimationQueue.Add(TriangleColor1);
FAnimateTri2:=TAnimationControlTranslate.Create(shpTri2);
FAnimateTri2.Duration:=1000;
FAnimateTri2.AnimationOnEndAction:=eAnimationOnEndStop;
FAnimateTri2.AutoReverse:=true;
FAnimateTri2.Repeats:=2;
FAnimateTri2.SetInitialPosition(Point((Self.Width div 2),shpTri2.Top));
FAnimateTri2.SetFinalPosition(Point(Self.Width-shpTri2.Width,shpTri2.Top));
FAnimateTri2.FreeWithQueue:=true;
FAnimateTri2.TransitionMode:=eAnimationTransitionBallisticIn;
FAnimateTri2.FinalizeBehavior:=eAnimationFinalizeBehaviorInitial;
FAnimateTri2.OnAnimationEnd:=@MetronomeEndAnimation;
AnimationQueue.Add(FAnimateTri2);
TriangleColor2:=TAnimationSampleBrushColor.Create(shpTri2);
TriangleColor2.Duration:=2000;
TriangleColor2.AnimationOnEndAction:=eAnimationOnEndStop;
TriangleColor2.AutoReverse:=false;
TriangleColor2.Repeats:=1;
TriangleColor2.InitialColor:=ColorToRGB(clRed);
TriangleColor2.FinalColor:=ColorToRGB(clWhite);
TriangleColor2.FreeWithQueue:=true;
TriangleColor2.TransitionMode:=eAnimationTransitionBallisticOut;
AnimationQueue.Add(TriangleColor2);
TriangleColor1.Start;
FAnimateTri1.Start;
end;
end;
procedure TfrmAnimationControls.chkLabelFlashingChange(Sender: TObject);
var
lFlashing: TAnimationControlColor;
lList: TFPList;
begin
if TCheckBox(Sender).Checked then begin
AnimationQueue.RemoveGroupID(lblFlashingLabel);
lFlashing:=TAnimationControlColor.Create(lblFlashingLabel);
lFlashing.Duration:=1000;
lFlashing.InitialColor:=ColorToRGB(clBtnFace);
lFlashing.FinalColor:=ColorToRGB(TColor($000000FF));
lFlashing.AutoReverse:=true;
lFlashing.Repeats:=0; // infinite
lFlashing.FinalizeBehavior:=eAnimationFinalizeBehaviorInitial;
AnimationQueue.Add(lFlashing);
lFlashing.Start;
end else begin
lList:=AnimationQueue.FindGroupID(lblFlashingLabel);
try
if lList.Count>0 then begin
lFlashing:=TObject(lList[0]) as TAnimationControlColor;
lFlashing.FinalizeASAP(true);
end;
finally
lList.Free;
end;
end;
end;
procedure TfrmAnimationControls.FormCreate(Sender: TObject);
var
Button: TAnimationControlTranslate;
MarqueeBackground: TAnimationControlTranslate;
begin
AnimationQueue:=TAnimationQueue.Create;
Button:=TAnimationControlTranslate.Create(butPause);
Button.Duration:=2000;
Button.AnimationOnEndAction:=eAnimationOnEndFree;
Button.AutoReverse:=false;
Button.Repeats:=1;
Button.SetFinalPosition(Point(0,butPause.Top));
Button.AnchorLocation:=eAnimationAnchorLocationCenter;
Button.SwapOriginWithFinal;
Button.FreeWithQueue:=true;
Button.TransitionMode:=eAnimationTransitionBallisticIn;
AnimationQueue.Add(Button);
AnimationQueue.Start(true);
MarqueeBackground:=TAnimationControlTranslate.Create(imgFlareMarquee);
MarqueeBackground.Duration:=Trunc(imgFlareMarquee.Parent.Width*10);
MarqueeBackground.AnimationOnEndAction:=eAnimationOnEndFree;
MarqueeBackground.AutoReverse:=false;
MarqueeBackground.Repeats:=0;
MarqueeBackground.SetInitialPosition(Point(imgFlareMarquee.Width*-1,0));
MarqueeBackground.SetFinalPosition(Point(imgFlareMarquee.Parent.Width,0));
MarqueeBackground.AnchorLocation:=eAnimationAnchorLocationCenter;
MarqueeBackground.FreeWithQueue:=true;
MarqueeBackground.TransitionMode:=eAnimationTransitionLinear;
AnimationQueue.Add(MarqueeBackground);
MarqueeBackground.Stop;
end;
procedure TfrmAnimationControls.FormDestroy(Sender: TObject);
begin
FreeAndNil(AnimationQueue);
end;
procedure TfrmAnimationControls.FormResize(Sender: TObject);
var
lAnimations: TFPList;
lFlareAnimation: TAnimationControlTranslate;
begin
// Find the animation related to imgFlareMarquee
lAnimations:=AnimationQueue.FindGroupID(imgFlareMarquee);
try
if lAnimations.Count=0 then begin
// Not found ? Exit
exit;
end;
try
lFlareAnimation:=TObject(lAnimations[0]) as TAnimationControlTranslate;
// Now readjust final position and animation duration
// Changing duration we get a constant speed, but better is constant time in this case.
//lFlareAnimation.Duration:=Trunc(lFlareAnimation.Control.Parent.Width*10);
lFlareAnimation.SetFinalPosition(Point(lFlareAnimation.Control.Parent.Width,lFlareAnimation.Control.Top));
except
// Eat exceptions, so program will not break if something
// goes really wrong.
end;
finally
lAnimations.Free;
end;
end;
procedure TfrmAnimationControls.MetronomeEndAnimation(Sender: TAnimationItem);
var
lList: TFPList=nil;
j: integer;
A: TAnimationItem;
begin
try
if Sender=FAnimateTri1 then begin
lList:=AnimationQueue.FindGroupID(shpTri2);
end else begin
lList:=AnimationQueue.FindGroupID(shpTri1);
end;
for j := 0 to Pred(lList.Count) do begin
A:=TAnimationItem(lList[j]);
A.Start;
end;
finally
lList.Free;
end;
end;
procedure TfrmAnimationControls.tmrAnimatedCadenceTimer(Sender: TObject);
begin
Self.DisableAlign;
AnimationQueue.Animate;
Self.EnableAlign;
// Adding Self.Invalidate improves smooth animation but can make
// the form less responsive in low power machines.
// When used removes some animation artifacts in controls translation.
//Self.Invalidate;
lblFPS.Caption:=format('FPS: %.2f',[AnimationQueue.AverageFPS]);
end;
end.

View File

@ -0,0 +1,864 @@
unit uanimationbasic;
(*
Comba - Animation main module
-----------------------------
@Licence: (c) 2017 José Mejuto // joshyfun at gmail.com
@Licence: LGPL when compiled with FPC (Free Pascal), GNU GPL V3 in other cases.
@Links:
GPL: https://www.gnu.org/licenses/gpl-3.0.en.html
LGPL: https://www.gnu.org/licenses/lgpl-3.0.en.html
@Description:
This file implements an animation queue and animation item base class.
*)
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Graphics, math;
type
TAnimationTransitionMode=(eAnimationTransitionLinear,eAnimationTransitionBallisticIn,eAnimationTransitionBallisticOut,eAnimationTransitionBallisticBoth,eAnimationTransitionBallisticEdge);
TAnimationFinalizeBehavior=(eAnimationFinalizeBehaviorCurrent,eAnimationFinalizeBehaviorInitial,eAnimationFinalizeBehaviorFinal);
TAnimationOnEndAction=(eAnimationOnEndStop,eAnimationOnEndFree);
TAnimationState=(eAnimationStateStopped,eAnimationStateStarted,eAnimationStatePaused,eAnimationStateToBeFreed);
TAnimationItem=class;
TAnimationOnPerform=procedure (const aElapedMilliseconds: int64) of object;
TAnimationOnAnimationEnd=procedure (Sender: TAnimationItem) of object;
TAnimationQueue=class;
TAnimationException=class(Exception);
{ TAnimationItem }
TAnimationItem=class(TObject)
private
FFinalizeASAPMode: integer;
FUserData: Pointer;
FOnPerform: TAnimationOnPerform;
FOnAnimationEnd: TAnimationOnAnimationEnd;
FFreeWithQueue: Boolean;
FDuration: int64;
FGroupID: pointer;
FAnimationOnEndAction: TAnimationOnEndAction;
FTransitionMode: TAnimationTransitionMode;
FReverse: Boolean;
FRepeats: integer;
FAutoReverse: Boolean;
FFinalizeBehavior: TAnimationFinalizeBehavior;
procedure SetReverse(aValue: Boolean);
protected
FState: TAnimationState;
FStartTick: int64;
FPauseTick: int64;
FQueue: TAnimationQueue;
FStartStopSynchAnimationList: TFPList;
FRepeated: integer;
FFinalizeAnimation: Boolean;
(* TransitionMode: (TAnimationTransitionMode) Linear or "curved" transition between animation values
eAnimationTransitionLinear: Transition is linear in time.
eAnimationTransitionBallisticIn: Fast -> Slow
eAnimationTransitionBallisticOut: Slow -> Fast
eAnimationTransitionBallisticBoth: Slow -> Fast -> Slow
eAnimationTransitionBallisticEdge: Fast -> Slow -> Fast
Calculations are done in CalculateLinearPosition.
@Note: This transitions are not fine right now as some transitios
are quite difficult to distinguish from others. It will be
fixed in the future.
*)
property TransitionMode: TAnimationTransitionMode read FTransitionMode write FTransitionMode;
(* Calculate linear position is the default functions to calculate current
animation value based in a source and a target value using the elapsed
time. Derived classes can use it or define a new ones with different
signatures and names *)
function CalculateLinearPosition(const aSource,aTarget: integer; const aElapsedMilliseconds,aDuration: int64): integer; overload;
function CalculateLinearPosition(const aSource,aTarget: Single; const aElapsedMilliseconds,aDuration: int64): Single; overload;
(* Overridable
DoInitialize: This method is called when animation starts or restarts.
*)
procedure DoInitialize; virtual;
(* Overridable
DoPerform: In this method derived classes must perform the calculations
needed for the animation
*)
procedure DoPerform; virtual;
(* Overridable
DoFinalizeAnimation: Method called when animation is about to be finished.
Useful to set EXACT values for final animation based on
TAnimationFinalizeBehavior
*)
procedure DoFinalizeAnimation; virtual;
(* Animate: Do some calcs and call DoPerform *)
procedure Animate;
(* ProcessAnimationEnd: Adjust some values to end an animation *)
procedure ProcessAnimationEnd;
(* FinalizeBehavior: (TAnimationFinalizeBehavior) Which value is expected when animation ends ?
eAnimationFinalizeBehaviorCurrent: Respects actual values, whichever it be
eAnimationFinalizeBehaviorFinal: (default) At end it is the final value
eAnimationFinalizeBehaviorInitial: At end the values is initial value.
This set is quite important when playing animations in with AutoReverse and when
reversing animations using Reverse()
*)
property FinalizeBehavior: TAnimationFinalizeBehavior read FFinalizeBehavior write FFinalizeBehavior;
public
constructor Create;
destructor Destroy; override;
(* UserData: carries a pointer to user data *)
property UserData: Pointer read FUserData write FUserData;
(* OnPerform: This event will be called instead class
perform if assigned *)
property OnPerform: TAnimationOnPerform read FOnPerform write FOnPerform;
(* OnAnimationEnd: This event will be called when animation ends *)
property OnAnimationEnd: TAnimationOnAnimationEnd read FOnAnimationEnd write FOnAnimationEnd;
(* FreeWithQueue: The TAnimationItem will be freed when the Queue is destroyed *)
property FreeWithQueue: Boolean read FFreeWithQueue write FFreeWithQueue;
(* Duration: How many milliseconds will the animation take *)
property Duration: int64 read FDuration write FDuration;
(* Reversed: Is animation being played in reverse time ? *)
property Reversed: Boolean read FReverse write SetReverse;
(*
AnimationOnEndAction: What happends when animation is finished:
eAnimationOnEndStop: (Default) The animation just finish
eAnimationOnEndFree: The animation finished and then the object is freed
*)
property AnimationOnEndAction: TAnimationOnEndAction read FAnimationOnEndAction write FAnimationOnEndAction;
(* AutoReverse: When animation reaches the end it will be played in reverse
order if there are enought Repeats to be played *)
property AutoReverse: Boolean read FAutoReverse write FAutoReverse;
(* Repeats: How many times the animation should be repeated.
0 = means infinite *)
property Repeats: integer read FRepeats write FRepeats;
(* GroupID: Pointer with an identifier to select a group of animations
from the queue. This is useful in example when animating controls
as all animations related to a control will share the same GroupID
which could be the memory address of the control *)
property GroupID: pointer read FGroupID write FGroupID;
(*
State: The animation play state (TAnimationState)
eAnimationStateStopped: Animation in stopped state
eanimationStateStarted: Animation is running
eAnimationStatePaused: Animation is paused
eAnimationStateToBeFreed: Animation is stopped and waiting to be freed
*)
property State: TAnimationState read FState;
(* GetElapsedMilliseconds: Returns the animation elapsed milliseconds *)
function GetElapsedMilliseconds: int64;
(*
FinalizeASAP: Finalizes an animation as soon as possible but waiting the
needed time to complete the programmed animation time.
@Parameters:
aReverseIfNeeded: If True and animation is running in forward mode, it
will wait to be run in reverse mode to stop it.
*)
procedure FinalizeASAP(const aReverseIfNeeded: Boolean=true);
(*
Reverse: Reverses current animation direction.
@Parameters:
aReverseFinalBehavior: If True Initial and Final behavior will be interchanged.
*)
function Reverse(const aReverseFinalBehavior: Boolean=true): Boolean;
(* Perform: Just perform the animation *)
procedure Perform;
(* Start: Starts animation *)
procedure Start;
(* Pause: Pauses animation *)
procedure Pause;
(* Stop: Stops animation *)
procedure Stop;
(* AddSyncStartStopAnimation: When this objects reaches the animation end, in forward
or reverse mode, animations added with this function will
be reversed or restarted at the same time. This is useful
to synchronize some animations for large repeats *)
procedure AddSyncStartStopAnimation(const aAnimationItem: TAnimationItem);
end;
{ TAnimationQueue }
TAnimationQueue=class(TObject)
private
FTick: int64;
function GetAverageFPS: single;
function GetPaused: Boolean;
procedure SetPaused(AValue: Boolean);
procedure SetReverse(aValue: Boolean);
protected
type
TAnimationQueueState=(eAnimationQueueStopped,eAnimationQueueStarted,eAnimationQueuePaused);
protected
FState: TAnimationQueueState;
FFramesCounter: integer;
FStartTick: int64;
FReverse: Boolean;
FPauseElapsed: int64;
FAnimationItems: TFPList;
function GetAnimationTick: int64;
function intfGetTickCount64: int64; inline;
public
constructor Create;
destructor Destroy; override;
(* Start: Starts the animation
@Parameters:
aStartQueuedAnimations: If True it starts all animations already in the queue
@Note: There is no Stop procedure because not calling "Animate" is just a stop. *)
procedure Start(const aStartQueuedAnimations: Boolean=false);
(* Pause: Pauses animation. It can be unpaused calling it again *)
procedure Pause;
(* Reverse: Reverses all animations in queue *)
procedure Reverse;
(* Animate: Animate all objects in the queue. It is the main heartbeat *)
procedure Animate; virtual;
(* Paint: Animate just only the supplied animation
@Parameters:
aPerformItem: The animation to be animated :-)
*)
procedure Paint(const aPerformItem: TAnimationItem);
(* Add: Adds one animation to the queue
@Parameters:
aAnimationItem: The animation to be added
aRemoveSameID: Before adding it removes all animations in the queue
with the same GroupID, if GroupID is different than nil
*)
procedure Add(const aAnimationItem: TAnimationItem; const aRemoveSameGroupID: Boolean=false); virtual;
(* Remove: Removes one animation from the queue
@Parameters:
aAnimationItem: The animation to be removed. If animation to be removed
has been selected to be freed on stop it will be automatically freed.
*)
procedure Remove(const aAnimationItem: TAnimationItem); virtual;
(* GetAbsoluteAnimationClock: Milliseconds since animation start *)
function GetAbsoluteAnimationClock: int64;
(* RemoveGroupID: Removes all animations with a given GroupID
@Parameters:
aClass: It can filter and remove only GroupID animations of the given class
*)
function RemoveGroupID(const aID: pointer; const aClass: TClass=nil): integer;
(* FindGroupID: Returns a TFPList containing all animations of a given GroupID
@Parameters:
aGroupID: The ID of the group to be returned.
@Note: Programmer must free the TFPList returned
*)
function FindGroupID(const aGroupID: pointer): TFPList;
(* AverageFPS: Returns average animations per second since animation start *)
property AverageFPS: single read GetAverageFPS;
(* Reversed: Is the animation being played in reverse time ? *)
property Reversed: Boolean read FReverse write SetReverse;
(* Paused: Is animation in pause state ? *)
property Paused: Boolean read GetPaused write SetPaused;
end;
implementation
{$IFDEF WINDOWS}
Uses windows; //For QueryPerformanceCounter only and it is not a must.
{$ENDIF}
resourcestring
rs_AnimationInOtherQueue='The animation is already in other queue.';
const
TFINALIZEASAPMODE_NONE=0;
TFINALIZEASAPMODE_NOW=1;
TFINALIZEASAPMODE_NEXT=2;
TFINALIZEASAPMODE_REVERSED=3;
type
TSplinePoint=record
x,y: single;
end;
function SplinePoint(x,y: single): TSplinePoint;
begin
Result.x:=x;
Result.y:=y;
end;
function CalculateSpline(const aPoint0, aPoint3, aPoint1, aPoint2: TSplinePoint; t: single ): TSplinePoint;
begin
Result.x := power(t,3)*(aPoint3.x+3*(aPoint1.x-aPoint2.x)-aPoint0.x)+3*power(t,2)*(aPoint0.x-2*aPoint1.x+aPoint2.x)+3*t*(aPoint1.x-aPoint0.x)+aPoint0.x;
Result.y := power(t,3)*(aPoint3.y+3*(aPoint1.y-aPoint2.y)-aPoint0.y)+3*power(t,2)*(aPoint0.y-2*aPoint1.y+aPoint2.y)+3*t*(aPoint1.y-aPoint0.y)+aPoint0.y;
end;
function CalculateElastic(const aFactor: single; const aDistance: integer; const aIntensity: single=1.5): integer;
begin
Result:=trunc(Power(2,10*(aFactor-1))*cos(20*PI*aIntensity/3*aFactor)*aDistance)
end;
{ TAnimationItem }
procedure TAnimationItem.SetReverse(aValue: Boolean);
begin
if FReverse=aValue then Exit;
if FDuration=0 then begin
FReverse:=aValue;
exit;
end;
if Assigned(FQueue) then begin
if aValue then begin
FStartTick:=FQueue.GetAbsoluteAnimationClock-(FDuration-GetElapsedMilliseconds);
end else begin
FStartTick:=FQueue.GetAbsoluteAnimationClock-GetElapsedMilliseconds;
end;
end;
FReverse:=aValue;
end;
function TAnimationItem.CalculateLinearPosition(const aSource,
aTarget: integer; const aElapsedMilliseconds, aDuration: int64): integer;
var
Factor: Single;
Distance: integer;
begin
if aDuration=0 then begin
Result:=aSource;
exit;
end;
Factor:=aElapsedMilliseconds / aDuration;
if Factor>1.0 then Factor:=1.0;
if Factor<0.0 then Factor:=0.0;
case FTransitionMode of
eAnimationTransitionLinear:
begin
end;
eAnimationTransitionBallisticIn:
begin
Factor:=CalculateSpline(SplinePoint(0,0),SplinePoint(1,0),SplinePoint(0.9,1),SplinePoint(0.999,1),Factor).x;
end;
eAnimationTransitionBallisticOut:
begin
Factor:=CalculateSpline(SplinePoint(0,0),SplinePoint(1,0),SplinePoint(0.001,1),SplinePoint(0.1,1),Factor).x;
end;
eAnimationTransitionBallisticBoth:
begin
Factor:=CalculateSpline(SplinePoint(0,0),SplinePoint(1,0),SplinePoint(0,1),SplinePoint(1,1),Factor).x;
end;
eAnimationTransitionBallisticEdge:
begin
Factor:=CalculateSpline(SplinePoint(0,0),SplinePoint(1,0),SplinePoint(1,0),SplinePoint(0,1),Factor).x;
end;
end;
Distance:=aTarget-aSource;
Distance:=Round(Distance*Factor);
Result:=aSource+Distance;
end;
function TAnimationItem.CalculateLinearPosition(const aSource, aTarget: Single;
const aElapsedMilliseconds, aDuration: int64): Single;
var
Factor: Single;
Distance: Single;
begin
if aDuration=0 then begin
Result:=aSource;
exit;
end;
Factor:=aElapsedMilliseconds / aDuration;
if Factor>1.0 then Factor:=1.0;
if Factor<0.0 then Factor:=0.0;
case FTransitionMode of
eAnimationTransitionLinear:
begin
end;
eAnimationTransitionBallisticIn:
begin
Factor:=CalculateSpline(SplinePoint(0,0),SplinePoint(1,0),SplinePoint(0.9,1),SplinePoint(0.9,1),Factor).x;
end;
eAnimationTransitionBallisticOut:
begin
Factor:=CalculateSpline(SplinePoint(0,0),SplinePoint(1,0),SplinePoint(0.1,1),SplinePoint(0.1,1),Factor).x;
end;
eAnimationTransitionBallisticBoth:
begin
Factor:=CalculateSpline(SplinePoint(0,0),SplinePoint(1,0),SplinePoint(0,1),SplinePoint(1,1),Factor).x;
end;
eAnimationTransitionBallisticEdge:
begin
Factor:=CalculateSpline(SplinePoint(0,0),SplinePoint(1,0),SplinePoint(1,0),SplinePoint(0,1),Factor).x;
end;
end;
Distance:=aTarget-aSource;
Distance:=Distance*Factor;
Result:=aSource+Distance;
end;
function TAnimationItem.GetElapsedMilliseconds: int64;
var
LocalReversed: Boolean;
begin
if FFinalizeAnimation and ((FRepeats-FRepeated)>=0) then begin
LocalReversed:=false;
if FAutoReverse then begin
if (FRepeats-FRepeated) mod 2 = 1 then begin
LocalReversed:=false;
end else begin
LocalReversed:=true;
end;
end;
FRepeated:=FRepeats;
if LocalReversed then begin
Result:=0;
end else begin
Result:=Duration;
end;
end else begin
if FReverse then begin
Result:=Duration - (FQueue.GetAbsoluteAnimationClock - FStartTick);
end else begin
Result:=FQueue.GetAbsoluteAnimationClock - FStartTick;
end;
end;
end;
procedure TAnimationItem.FinalizeASAP(const aReverseIfNeeded: Boolean);
begin
if aReverseIfNeeded then begin
FFinalizeASAPMode:=TFINALIZEASAPMODE_REVERSED;
end else begin
FFinalizeASAPMode:=TFINALIZEASAPMODE_NEXT;
end;
end;
procedure TAnimationItem.ProcessAnimationEnd;
var
lShouldRepeat: Boolean=false;
procedure Restart;
var
j: integer;
begin
Start;
if Assigned(FStartStopSynchAnimationList) then begin
for j := 0 to FStartStopSynchAnimationList.Count-1 do begin
TAnimationItem(FStartStopSynchAnimationList[j]).Start;
end;
end;
end;
procedure ReverseIt;
var
j: integer;
begin
Reversed:=not Reversed;
if Assigned(FStartStopSynchAnimationList) then begin
for j := 0 to FStartStopSynchAnimationList.Count-1 do begin
TAnimationItem(FStartStopSynchAnimationList[j]).ProcessAnimationEnd;
end;
end;
end;
procedure DoFinalize;
begin
case FAnimationOnEndAction of
eAnimationOnEndStop: FState:=eAnimationStateStopped;
eAnimationOnEndFree: FState:=eAnimationStateToBeFreed;
end;
if Assigned(FOnAnimationEnd) then begin
FOnAnimationEnd(Self);
end;
end;
begin
inc(FRepeated);
case FFinalizeASAPMode of
TFINALIZEASAPMODE_NOW,
TFINALIZEASAPMODE_NEXT:
begin
DoFinalize;
end;
TFINALIZEASAPMODE_REVERSED:
begin
if not Reversed then begin
ReverseIt;
end else begin
DoFinalize;
end;
end;
TFINALIZEASAPMODE_NONE:
begin
if FRepeats=0 then begin
lShouldRepeat:=true;
end else begin
if FRepeated<FRepeats then begin
lShouldRepeat:=true;
end;
end;
if lShouldRepeat and FAutoReverse then begin
ReverseIt;
end else if lShouldRepeat then begin
Restart;
end else begin
DoFinalize;
end;
end;
end;
end;
constructor TAnimationItem.Create;
begin
FFreeWithQueue:=true;
FRepeats:=1;
FFinalizeBehavior:=eAnimationFinalizeBehaviorFinal;
end;
destructor TAnimationItem.Destroy;
begin
if Assigned(FStartStopSynchAnimationList) then FreeAndNil(FStartStopSynchAnimationList);
inherited Destroy;
end;
function TAnimationItem.Reverse(const aReverseFinalBehavior: Boolean): Boolean;
begin
if FState=eAnimationStateStarted then begin
Reversed:=not FReverse;
if aReverseFinalBehavior then begin
case FFinalizeBehavior of
eAnimationFinalizeBehaviorCurrent: ;
eAnimationFinalizeBehaviorInitial: FFinalizeBehavior:=eAnimationFinalizeBehaviorFinal;
eAnimationFinalizeBehaviorFinal: FFinalizeBehavior:=eAnimationFinalizeBehaviorInitial;
end;
end;
Result:=true;
end else begin
Result:=false;
end;
end;
procedure TAnimationItem.Perform;
begin
if Assigned(FQueue) then begin
FQueue.Paint(Self);
end else begin
if Assigned(FOnPerform) then begin
FOnPerform(GetElapsedMilliseconds);
end;
end;
end;
procedure TAnimationItem.DoPerform;
begin
// Nothing, nada.
end;
procedure TAnimationItem.Animate;
var
lElapsedMilliseconds: int64;
begin
if FState=eAnimationStateStarted then begin
lElapsedMilliseconds:=GetElapsedMilliseconds;
if Assigned(FOnPerform) then begin
FOnPerform(lElapsedMilliseconds);
end else begin
DoPerform;
end;
if FFinalizeASAPMode=TFINALIZEASAPMODE_NOW then begin
ProcessAnimationEnd;
end else begin
if FReverse then begin
if lElapsedMilliseconds<=0 then begin
ProcessAnimationEnd;
end;
end else begin
if lElapsedMilliseconds>=FDuration then begin
ProcessAnimationEnd;
end;
end;
end;
end;
end;
procedure TAnimationItem.DoFinalizeAnimation;
begin
FFinalizeAnimation:=true;
end;
procedure TAnimationItem.DoInitialize;
begin
//Do nothing
end;
procedure TAnimationItem.Start;
begin
FStartTick:=FQueue.GetAbsoluteAnimationClock;
FState:=eAnimationStateStarted;
FRepeated:=0;
FReverse:=false;
FFinalizeAnimation:=false;
end;
procedure TAnimationItem.Pause;
begin
if FState=eAnimationStateStarted then begin
FState:=eAnimationStatePaused;
if Assigned(FQueue) then begin
FPauseTick:=GetElapsedMilliseconds;
end;
end else if FState=eAnimationStatePaused then begin
if Assigned(FQueue) then begin
FStartTick:=FQueue.GetAbsoluteAnimationClock-FPauseTick;
end;
FState:=eAnimationStateStarted;
end;
end;
procedure TAnimationItem.Stop;
begin
if (FState=eAnimationStateStarted) or (FState=eAnimationStatePaused) or (FState=eAnimationStateStopped) then begin
FState:=eAnimationStateStopped;
DoFinalizeAnimation;
end;
end;
procedure TAnimationItem.AddSyncStartStopAnimation(
const aAnimationItem: TAnimationItem);
begin
if not Assigned(FStartStopSynchAnimationList) then begin
FStartStopSynchAnimationList:=TFPList.Create;
end;
FStartStopSynchAnimationList.Add(aAnimationItem);
end;
{ TAnimationQueue }
function TAnimationQueue.GetAbsoluteAnimationClock: int64;
begin
Result:=GetAnimationTick - FStartTick;
end;
function TAnimationQueue.RemoveGroupID(const aID: pointer; const aClass: TClass
): integer;
var
j: Integer;
A: TAnimationItem;
begin
Result:=0;
for j := Pred(FAnimationItems.Count) downto 0 do begin
A:=TAnimationItem(FAnimationItems[j]);
if A.GroupID=aID then begin
if (Assigned(aClass) and (A is aClass)) or not Assigned(aClass) then begin
Remove(A);
inc(Result);
end;
end;
end;
end;
function TAnimationQueue.FindGroupID(const aGroupID: pointer): TFPList;
var
j: Integer;
A: TAnimationItem;
begin
Result:=TFPList.Create;
for j := Pred(FAnimationItems.Count) downto 0 do begin
A:=TAnimationItem(FAnimationItems[j]);
if A.GroupID=aGroupID then begin
Result.Add(A);
end;
end;
end;
procedure TAnimationQueue.SetReverse(aValue: Boolean);
var
j: integer;
begin
if FReverse=aValue then Exit;
for j := 0 to FAnimationItems.Count-1 do begin
TAnimationItem(FAnimationItems[j]).Reversed:=not TAnimationItem(FAnimationItems[j]).Reversed;
end;
FReverse:=aValue;
end;
function TAnimationQueue.GetAverageFPS: single;
begin
if FState=eAnimationQueueStarted then begin
if GetAbsoluteAnimationClock>0 then begin
Result:=(FFramesCounter * 1000) / GetAbsoluteAnimationClock;
end else begin
Result:=0;
end;
end else begin
Result:=0;
end;
end;
function TAnimationQueue.GetPaused: Boolean;
begin
if FState=eAnimationQueuePaused then begin
Result:=true;
end else begin
Result:=false;
end;
end;
constructor TAnimationQueue.Create;
begin
FAnimationItems:=TFPList.Create;
FState:=eAnimationQueueStopped;
end;
destructor TAnimationQueue.Destroy;
var
j: integer;
begin
for j := Pred(FAnimationItems.Count) downto 0 do begin
if TAnimationItem(FAnimationItems[j]).FFreeWithQueue then begin
TAnimationItem(FAnimationItems[j]).Free;
FAnimationItems.Delete(j);
end;
end;
FreeAndNil(FAnimationItems);
inherited Destroy;
end;
procedure TAnimationQueue.SetPaused(AValue: Boolean);
begin
If AValue then begin
if (FState=eAnimationQueueStarted) then begin
FPauseElapsed:=GetAbsoluteAnimationClock;
FState:=eAnimationQueuePaused;
end;
end else begin
if FState=eAnimationQueuePaused then begin
FStartTick:=GetTickCount64-FPauseElapsed;
FState:=eAnimationQueueStarted;
end;
end;
end;
procedure TAnimationQueue.Start(const aStartQueuedAnimations: Boolean);
var
j: Integer;
begin
FTick:=GetTickCount64;
if FState=eAnimationQueuePaused then begin
SetPaused(false);
end else begin
FStartTick:=FTick;
if aStartQueuedAnimations then begin
for j := 0 to FAnimationItems.Count-1 do begin
TAnimationItem(FAnimationItems[j]).Start;
end;
end;
FState:=eAnimationQueueStarted;
FFramesCounter:=0;
end;
end;
procedure TAnimationQueue.Pause;
begin
FPauseElapsed:=GetAbsoluteAnimationClock;
FState:=eAnimationQueuePaused;
end;
procedure TAnimationQueue.Reverse;
begin
Reversed:=not Reversed;
end;
procedure TAnimationQueue.Animate;
var
j: integer;
A: TAnimationItem;
begin
if FState<>eAnimationQueueStarted then exit;
FTick:=GetTickCount64;
for j := FAnimationItems.Count-1 downto 0 do begin
A:=TAnimationItem(FAnimationItems[j]);
if A.FState=eAnimationStateToBeFreed then begin
Remove(A);
end;
end;
for j := 0 to FAnimationItems.Count-1 do begin
A:=TAnimationItem(FAnimationItems[j]);
if A.FState=eAnimationStateStarted then begin
A.Animate;
end;
end;
inc(FFramesCounter);
end;
procedure TAnimationQueue.Paint(const aPerformItem: TAnimationItem);
begin
aPerformItem.DoPerform;
end;
procedure TAnimationQueue.Add(const aAnimationItem: TAnimationItem;
const aRemoveSameGroupID: Boolean);
begin
if Assigned(aAnimationItem.FQueue) then begin
Raise TAnimationException.Create(rs_AnimationInOtherQueue);
end;
if aRemoveSameGroupID and (aAnimationItem.GroupID<>nil) then begin
RemoveGroupID(aAnimationItem.GroupID);
end;
FAnimationItems.Add(aAnimationItem);
aAnimationItem.FQueue:=Self;
aAnimationItem.DoInitialize;
end;
procedure TAnimationQueue.Remove(const aAnimationItem: TAnimationItem);
var
Index: integer;
A: TAnimationItem;
j: integer;
begin
Index:=FAnimationItems.IndexOf(aAnimationItem);
if Index<0 then begin
Raise TAnimationException.Create('Trying to remove non exist animation');
end;
FAnimationItems.Delete(Index);
aAnimationItem.DoFinalizeAnimation;
//Check if object is in the synchronization list of other object
for j := 0 to Pred(FAnimationItems.Count) do begin
A:=TAnimationItem(FAnimationItems[j]);
if Assigned(A.FStartStopSynchAnimationList) then begin
Index:=A.FStartStopSynchAnimationList.IndexOf(aAnimationItem);
if Index>-1 then begin
//Delete it to avoid crash when synch takes place
A.FStartStopSynchAnimationList.Delete(Index);
end;
end;
end;
aAnimationItem.Free;
end;
function TAnimationQueue.GetAnimationTick: int64;
begin
Result:=FTick;
end;
function TAnimationQueue.intfGetTickCount64: int64;
{$IFDEF WINDOWS}
const
lUseHighPrecision: Boolean=true;
{$ENDIF}
begin
{$IFDEF WINDOWS}
if lUseHighPrecision then begin
Result:=0;
if not QueryPerformanceCounter(Result) then begin
Result:=GetTickCount64;
lUseHighPrecision:=false;
end;
end else begin
Result:=GetTickCount64;
end;
{$ELSE}
Result:=GetTickCount64;
{$ENDIF}
end;
end.

View File

@ -0,0 +1,761 @@
unit uanimationcontrol;
(*
Comba - Animation controls module
---------------------------------
@Licence: (c) 2017 José Mejuto // joshyfun at gmail.com
@Licence: LGPL when compiled with FPC (Free Pascal), GNU GPL V3 in other cases.
@Links:
GPL: https://www.gnu.org/licenses/gpl-3.0.en.html
LGPL: https://www.gnu.org/licenses/lgpl-3.0.en.html
@Description:
This file implements an animation base class for LCL visual controls
animation and implements some basic animations.
*)
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Controls, Graphics, Forms
, uanimationbasic
, uanimationtypes
;
type
TAnimationZoomMode=(eAnimationZoomModeAll,eAnimationZoomModeWidthLeft,eAnimationZoomModeWidthRight,eAnimationZoomModeHeightTop,eAnimationZoomModeHeightBottom,eAnimationZoomModeWidth,eAnimationZoomModeHeight);
TAnimationAnchorLocation=(eAnimationAnchorLocationLeftTop,eAnimationAnchorLocationLeft,eAnimationAnchorLocationTop,eAnimationAnchorLocationCenter);
{ TAnimationCustomControl }
TAnimationCustomControl=class(TAnimationItem)
private
protected
FControl: TControl;
procedure DoFinalizeAnimation; override;
function GetControl: TControl;
property Control: TControl read FControl;
public
constructor Create(const aControl: TControl);
end;
TAnimationControl=class(TAnimationCustomControl)
public
property Control;
end;
{ TAnimationCustomControlDimensions }
TAnimationCustomControlDimensions=class(TAnimationControl)
private
protected
FInitialRect: TAnimationRect;
FFinalRect: TAnimationRect;
procedure DoFinalizeAnimation; override;
procedure DoMoveControlPosition(const aX,aY: integer); virtual;
procedure DoMoveControlAsRect(const aRect: TRect); virtual;
public
constructor Create(const aControl: TControl);
procedure SetInitialPosition(const aInitialPosition: TPoint); virtual;
procedure SetFinalPosition(const aFinalPosition: TPoint); virtual;
procedure SwapOriginWithFinal; virtual;
end;
{ TAnimationControlTranslate }
TAnimationControlTranslate=class(TAnimationCustomControlDimensions)
protected
FInitialCenter: TPoint;
FFinalCenter: TPoint;
FAnchorLocation: TAnimationAnchorLocation;
FAnchors: TAnchors;
FRemoveAnchors: Boolean;
procedure DoPerform; override;
procedure DoInitialize; override;
procedure DoFinalizeAnimation; override;
public
procedure SetInitialPosition(const aInitialPosition: TPoint); override;
procedure SetFinalPosition(const aFinalPosition: TPoint); override;
property RemoveAnchors: Boolean read FRemoveAnchors write FRemoveAnchors;
property AnchorLocation: TAnimationAnchorLocation read FAnchorLocation write FAnchorLocation;
property TransitionMode;
property FinalizeBehavior;
end;
{ TAnimationControlZoom }
TAnimationControlZoom=class(TAnimationCustomControlDimensions)
protected
FAutoSized: Boolean;
FAnchors: TAnchors;
FFinalZoom: single;
FZoomMode: TAnimationZoomMode;
FZoomByRectangle: Boolean;
FRemoveAnchors: Boolean;
procedure DoPerform; override;
procedure DoInitialize; override;
procedure DoFinalizeAnimation; override;
public
procedure SetFinalZoom(const aFinalZoom: Single);
procedure SetFinalSize(const aRect: TRect);
property ZoomMode: TAnimationZoomMode read FZoomMode write FZoomMode;
property TransitionMode;
property FinalizeBehavior;
property RemoveAnchors: Boolean read FRemoveAnchors write FRemoveAnchors;
end;
{ TAnimationControlCaptionCapital }
TAnimationControlCaptionCapital=class(TAnimationControl)
private
protected
FOriginalCaption: string;
procedure DoInitialize; override;
procedure DoPerform; override;
procedure DoFinalizeAnimation; override;
public
property TransitionMode;
end;
{ TAnimationCustomControlColor }
TAnimationCustomControlColor=class(TAnimationControl)
private
protected
FInitialColor: integer;
FFinalColor: integer;
procedure DoPerform; override;
procedure DoFinalizeAnimation; override;
procedure DoChangeColor(const aNewColor: TColor); virtual; abstract;
property InitialColor: integer read FInitialColor write FInitialColor;
property FinalColor: integer read FFinalColor write FFinalColor;
public
end;
{ TAnimationControlColor }
TAnimationControlColor=class(TAnimationCustomControlColor)
private
protected
procedure DoChangeColor(const aNewColor: TColor); override;
public
property InitialColor;
property FinalColor;
property TransitionMode;
property FinalizeBehavior;
end;
{ TAnimationCustomControlRotator }
TAnimationCustomControlRotator=class(TAnimationControl)
private
protected
FInitialAngle: Single;
FFinalAngle: Single;
procedure DoPerform; override;
procedure DoFinalizeAnimation; override;
procedure DoRotate(const aAngle: Single); virtual; abstract;
property InitialAngle: Single read FInitialAngle write FInitialAngle;
property FinalAngle: Single read FFinalAngle write FFinalAngle;
public
end;
{ TAnimationControlFontRotator }
TAnimationControlFontRotator=class(TAnimationCustomControlRotator)
private
protected
procedure DoRotate(const aAngle: Single); override;
public
property InitialAngle;
property FinalAngle;
property TransitionMode;
end;
{ TAnimationCustomControlTextChange }
TAnimationCustomControlTextChange=class(TAnimationControl)
private
FSameLenInitialText: string;
FSameLenFinalText: string;
FMaxLength: integer;
protected
FInitialText: String;
FFinalText: String;
FCursorString: string;
procedure DoPerform; override;
procedure DoInitialize; override;
procedure DoFinalizeAnimation; override;
procedure DoChangeText(const aNewText: String); virtual; abstract;
property InitialText: String read FInitialText write FInitialText;
property FinalText: String read FFinalText write FFinalText;
property CursorString: String read FCursorString write FCursorString;
public
end;
{ TAnimationControlCaptionReplace }
TAnimationControlCaptionReplace=class(TAnimationCustomControlTextChange)
private
protected
procedure DoChangeText(const aNewText: String); override;
public
constructor Create(const aControl: TControl);
property InitialText;
property FinalText;
property CursorString;
property TransitionMode;
end;
{ TAnimationCustomControlInteger }
TAnimationCustomControlInteger=class(TAnimationControl)
private
protected
FInitialInteger: Integer;
FFinalInteger: Integer;
procedure DoPerform; override;
procedure DoFinalizeAnimation; override;
procedure DoSetValue(const aValue: Integer); virtual; abstract;
property InitialInteger: Integer read FInitialInteger write FInitialInteger;
property FinalInteger: Integer read FFinalInteger write FFinalInteger;
public
end;
{ TAnimationControlAlphaBlend }
TAnimationControlAlphaBlend=class(TAnimationCustomControlInteger)
private
function GetFinalBlend: Byte;
function GetInitialBlend: Byte;
procedure SetFinalBlend(AValue: Byte);
procedure SetInitialBlend(AValue: Byte);
protected
procedure DoSetValue(const aValue: Integer); override;
procedure DoInitialize; override;
public
constructor Create(const aForm: TCustomForm);
property InitialBlend: Byte read GetInitialBlend write SetInitialBlend;
property FinalBlend: Byte read GetFinalBlend write SetFinalBlend;
property TransitionMode;
property FinalizeBehavior;
end;
implementation
{ TAnimationControlAlphaBlend }
function TAnimationControlAlphaBlend.GetFinalBlend: Byte;
begin
Result:=Byte(FFinalInteger);
end;
function TAnimationControlAlphaBlend.GetInitialBlend: Byte;
begin
Result:=Byte(FInitialInteger);
end;
procedure TAnimationControlAlphaBlend.SetFinalBlend(AValue: Byte);
begin
if FFinalInteger=AValue then Exit;
FFinalInteger:=AValue;
end;
procedure TAnimationControlAlphaBlend.SetInitialBlend(AValue: Byte);
begin
if FInitialInteger=AValue then Exit;
FInitialInteger:=AValue;
end;
procedure TAnimationControlAlphaBlend.DoSetValue(const aValue: Integer);
begin
TCustomForm(FControl).AlphaBlendValue:=aValue;
end;
procedure TAnimationControlAlphaBlend.DoInitialize;
begin
inherited DoInitialize;
TCustomForm(FControl).AlphaBlend:=true;
end;
constructor TAnimationControlAlphaBlend.Create(const aForm: TCustomForm);
begin
inherited Create(aForm);
FInitialInteger:=aForm.AlphaBlendValue;
end;
{ TAnimationCustomControlInteger }
procedure TAnimationCustomControlInteger.DoPerform;
var
NZ: Integer;
begin
inherited DoPerform;
NZ:=CalculateLinearPosition(FInitialInteger,FFinalInteger,GetElapsedMilliseconds,Duration);
DoSetValue(NZ);
end;
procedure TAnimationCustomControlInteger.DoFinalizeAnimation;
begin
inherited DoFinalizeAnimation;
case FinalizeBehavior of
eAnimationFinalizeBehaviorCurrent:
begin
// Do nothing
end;
eAnimationFinalizeBehaviorInitial:
begin
DoSetValue(FInitialInteger);
end;
eAnimationFinalizeBehaviorFinal:
begin
DoSetValue(FFinalInteger);
end;
end;
end;
{ TAnimationCustomControlTextChange }
procedure TAnimationCustomControlTextChange.DoPerform;
var
NZ: Integer;
begin
inherited DoPerform;
NZ:=CalculateLinearPosition(1,FMaxLength,GetElapsedMilliseconds,Duration);
// This is not UTF8 aware!!!
DoChangeText(copy(FSameLenFinalText,1,NZ-1)+CursorString+copy(FSameLenInitialText,NZ));
end;
procedure TAnimationCustomControlTextChange.DoInitialize;
begin
inherited DoInitialize;
if Length(FInitialText)>Length(FFinalText) then begin
FMaxLength:=Length(FInitialText);
end else begin
FMaxLength:=Length(FFinalText);
end;
FSameLenInitialText:=FInitialText+StringOfChar(' ',FMaxLength-Length(FInitialText));
FSameLenFinalText:=FFinalText+StringOfChar(' ',FMaxLength-Length(FFinalText));
end;
procedure TAnimationCustomControlTextChange.DoFinalizeAnimation;
begin
inherited DoFinalizeAnimation;
case FinalizeBehavior of
eAnimationFinalizeBehaviorCurrent:
begin
// Do nothing
end;
eAnimationFinalizeBehaviorInitial:
begin
DoChangeText(FInitialText);
end;
eAnimationFinalizeBehaviorFinal:
begin
DoChangeText(FFinalText);
end;
end;
end;
{ TAnimationControlCaptionReplace }
procedure TAnimationControlCaptionReplace.DoChangeText(const aNewText: String);
begin
FControl.Caption:=aNewText;
end;
constructor TAnimationControlCaptionReplace.Create(const aControl: TControl);
begin
inherited Create(aControl);
FInitialText:=aControl.Caption;
FFinalText:=aControl.Caption;
// It proceduces a quite good eraser effect (8 spaces).
FCursorString:=StringOfChar(' ',8);
end;
{ TAnimationControlFontRotator }
procedure TAnimationControlFontRotator.DoRotate(const aAngle: Single);
begin
FControl.Font.Orientation:=trunc(aAngle*10);
end;
{ TAnimationCustomControlRotator }
procedure TAnimationCustomControlRotator.DoPerform;
var
lDistance: Single;
begin
inherited DoPerform;
lDistance:=CalculateLinearPosition(FInitialAngle,FFinalAngle,GetElapsedMilliseconds,Duration);
DoRotate(lDistance);
end;
procedure TAnimationCustomControlRotator.DoFinalizeAnimation;
begin
inherited DoFinalizeAnimation;
case FinalizeBehavior of
eAnimationFinalizeBehaviorCurrent:
begin
// Do nothing
end;
eAnimationFinalizeBehaviorInitial:
begin
DoRotate(FInitialAngle);
end;
eAnimationFinalizeBehaviorFinal:
begin
DoRotate(FFinalAngle);
end;
end;
end;
{ TAnimationCustomColor }
procedure TAnimationCustomControlColor.DoPerform;
var
tmpBaseColor: integer;
tmpColor1: integer;
tmpColor2: integer;
NewColor: integer;
NZ: Single;
j: integer;
begin
inherited DoPerform;
NewColor:=0;
NZ:=CalculateLinearPosition(1.0,0,GetElapsedMilliseconds,Duration);
// Loop works in the RGB 24 bits colors (0..2)
for j := 0 to 2 do begin
tmpBaseColor:=(FFinalColor shr (8*j)) and 255;
tmpColor2:=(FInitialColor shr (8*j)) and 255;
tmpColor1:=trunc((tmpColor2-tmpBaseColor) * NZ);
tmpColor1:=tmpBaseColor+tmpColor1;
NewColor:=NewColor or (tmpColor1 shl (8*j));
end;
DoChangeColor(NewColor);
end;
procedure TAnimationCustomControlColor.DoFinalizeAnimation;
begin
inherited DoFinalizeAnimation;
case FinalizeBehavior of
eAnimationFinalizeBehaviorCurrent:
begin
// Do nothing, is current
end;
eAnimationFinalizeBehaviorInitial:
begin
DoChangeColor(FInitialColor);
end;
eAnimationFinalizeBehaviorFinal:
begin
DoChangeColor(FFinalColor);
end;
end;
end;
{ TAnimationCustomControlDimensions }
procedure TAnimationCustomControlDimensions.DoFinalizeAnimation;
begin
inherited DoFinalizeAnimation;
case FinalizeBehavior of
eAnimationFinalizeBehaviorCurrent:
begin
// Do nothing, it is current
end;
eAnimationFinalizeBehaviorInitial:
begin
DoMoveControlAsRect(FInitialRect.GetAsRect);
end;
eAnimationFinalizeBehaviorFinal:
begin
DoMoveControlAsRect(FFinalRect.GetAsRect);
end;
end;
// When animated positions sometimes the control
// ends with some fails in paint, so refresh it.
FControl.Repaint;
end;
procedure TAnimationCustomControlDimensions.DoMoveControlPosition(const aX, aY: integer);
begin
FControl.SetBounds(aX,aY,FControl.Width,FControl.Height);
end;
procedure TAnimationCustomControlDimensions.DoMoveControlAsRect(
const aRect: TRect);
begin
FControl.BoundsRect:=aRect;
end;
constructor TAnimationCustomControlDimensions.Create(const aControl: TControl);
begin
inherited Create(aControl);
FInitialRect.SetFromRect(aControl.BoundsRect);
FFinalRect:=FInitialRect;
end;
procedure TAnimationCustomControlDimensions.SetInitialPosition(
const aInitialPosition: TPoint);
begin
FInitialRect.MoveTo(aInitialPosition);
end;
procedure TAnimationCustomControlDimensions.SetFinalPosition(
const aFinalPosition: TPoint);
begin
FFinalRect.MoveTo(aFinalPosition);
end;
procedure TAnimationCustomControlDimensions.SwapOriginWithFinal;
var
Temp: TAnimationRect;
begin
Temp:=FInitialRect;
FInitialRect:=FFinalRect;
FFinalRect:=Temp;
end;
{ TAnimationCustomControl }
procedure TAnimationCustomControl.DoFinalizeAnimation;
begin
inherited DoFinalizeAnimation;
end;
function TAnimationCustomControl.GetControl: TControl;
begin
Result:=FControl;
end;
constructor TAnimationCustomControl.Create(const aControl: TControl);
begin
inherited Create;
FControl:=aControl;
GroupID:=aControl;
end;
{ TAnimationControlCaptionCapital }
procedure TAnimationControlCaptionCapital.DoInitialize;
begin
inherited DoInitialize;
FOriginalCaption:=FControl.Caption;
end;
procedure TAnimationControlCaptionCapital.DoPerform;
var
NZ: Integer;
begin
inherited DoPerform;
NZ:=CalculateLinearPosition(integer(1),integer(Length(FOriginalCaption)),GetElapsedMilliseconds,Duration);
// This is not UTF8 aware!!!
FControl.Caption:=copy(FOriginalCaption,1,NZ-1)+Uppercase(FOriginalCaption[NZ])+copy(FOriginalCaption,NZ+1);
end;
procedure TAnimationControlCaptionCapital.DoFinalizeAnimation;
begin
inherited DoFinalizeAnimation;
FControl.Caption:=FOriginalCaption;
end;
{ TAnimationControlCustomTranslate }
procedure TAnimationControlTranslate.DoPerform;
var
NX,NY: integer;
begin
inherited DoPerform;
case FAnchorLocation of
eAnimationAnchorLocationLeft:
begin
NX:=CalculateLinearPosition(FInitialRect.Left,FFinalRect.Left,GetElapsedMilliseconds,Duration);
DoMoveControlPosition(NX,FControl.Top);
end;
eAnimationAnchorLocationTop:
begin
NY:=CalculateLinearPosition(FInitialRect.Top,FFinalRect.Top,GetElapsedMilliseconds,Duration);
DoMoveControlPosition(FControl.Left,NY);
end;
eAnimationAnchorLocationLeftTop:
begin
NX:=CalculateLinearPosition(FInitialRect.Left,FFinalRect.Left,GetElapsedMilliseconds,Duration);
NY:=CalculateLinearPosition(FInitialRect.Top,FFinalRect.Top,GetElapsedMilliseconds,Duration);
DoMoveControlPosition(NX,NY);
end;
eAnimationAnchorLocationCenter:
begin
NX:=CalculateLinearPosition(FInitialCenter.x,FFinalCenter.x,GetElapsedMilliseconds,Duration);
NX:=NX-FControl.Width div 2;
NY:=CalculateLinearPosition(FInitialCenter.y,FFinalCenter.y,GetElapsedMilliseconds,Duration);
NY:=NY-FControl.Height div 2;
DoMoveControlPosition(NX,NY);
end;
end;
end;
procedure TAnimationControlTranslate.DoInitialize;
begin
inherited DoInitialize;
FInitialCenter:=FInitialRect.GetCenter;
FFinalCenter:=FFinalRect.GetCenter;
//Anchors could be a problem sometimes
FAnchors:=FControl.Anchors;
if FRemoveAnchors then begin
FControl.Anchors:=[];
end;
end;
procedure TAnimationControlTranslate.DoFinalizeAnimation;
begin
inherited DoFinalizeAnimation;
if FRemoveAnchors then begin
FControl.Anchors:=FAnchors;
end;
end;
procedure TAnimationControlTranslate.SetInitialPosition(
const aInitialPosition: TPoint);
begin
inherited SetInitialPosition(aInitialPosition);
FInitialCenter:=FInitialRect.GetCenter;
end;
procedure TAnimationControlTranslate.SetFinalPosition(
const aFinalPosition: TPoint);
begin
inherited SetFinalPosition(aFinalPosition);
FFinalCenter:=FFinalRect.GetCenter;
end;
{ TAnimationControlZoom }
procedure TAnimationControlZoom.DoPerform;
var
NZ: Single;
NRect: TAnimationRect;
NewBottom: integer;
Center: TPoint;
AnimRect: TAnimationRect;
TR: TAnimationRect;
begin
inherited DoPerform;
if not FZoomByRectangle then begin
NZ:=CalculateLinearPosition(1.0,FFinalZoom,GetElapsedMilliseconds,Duration);
case FZoomMode of
eAnimationZoomModeAll:
begin
AnimRect.SetFromRect(FControl.BoundsRect);
Center:=AnimRect.GetCenter;
TR.Left:=Center.x-Round(FInitialRect.Width*NZ) div 2;
TR.Right:=TR.Left+Round(FInitialRect.Width*NZ);
TR.Top:=Center.y-Round(FInitialRect.Height*NZ) div 2;
TR.Bottom:=TR.Top+Round(FInitialRect.Height*NZ);
DoMoveControlAsRect(TR.GetAsRect);
end;
eAnimationZoomModeWidth:
begin
TR.SetFromRect(FControl.BoundsRect);
Center:=TR.GetCenter;
TR.Left:=Center.x-Round(FInitialRect.Width*NZ) div 2;
TR.Width:=Round(FInitialRect.Width*NZ);
DoMoveControlAsRect(TR.GetAsRect);
end;
eAnimationZoomModeHeight:
begin
TR.SetFromRect(FControl.BoundsRect);
Center:=TR.GetCenter;
TR.Top:=Center.y-Round(FInitialRect.Height*NZ) div 2;
TR.Height:=Round(FInitialRect.Height*NZ);
DoMoveControlAsRect(TR.GetAsRect);
end;
eAnimationZoomModeWidthLeft:
begin
TR.SetFromRect(FControl.BoundsRect);
TR.Width:=Round(FInitialRect.Width*NZ);
DoMoveControlAsRect(TR.GetAsRect);
end;
eAnimationZoomModeWidthRight:
begin
TR.SetFromRect(FControl.BoundsRect);
TR.Left:=TR.Right-integer(Round(FInitialRect.Width*NZ));
TR.Width:=Round(FInitialRect.Width*NZ);
DoMoveControlAsRect(TR.GetAsRect);
end;
eAnimationZoomModeHeightTop:
begin
TR.SetFromRect(FControl.BoundsRect);
TR.Height:=Round(FInitialRect.Height*NZ);
DoMoveControlAsRect(TR.GetAsRect);
end;
eAnimationZoomModeHeightBottom:
begin
TR.SetFromRect(FControl.BoundsRect);
NewBottom:=FControl.Top+FControl.Height;
TR.Top:=NewBottom - Round(FInitialRect.Height*NZ);
TR.Height:=Round(FInitialRect.Height*NZ);
DoMoveControlAsRect(TR.GetAsRect);
end;
end;
end else begin
NRect.Left:=CalculateLinearPosition(FInitialRect.Left,FFinalRect.Left,GetElapsedMilliseconds,Duration);
NRect.Top:=CalculateLinearPosition(FInitialRect.Top,FFinalRect.Top,GetElapsedMilliseconds,Duration);
NRect.Width:=CalculateLinearPosition(FInitialRect.Width,FFinalRect.Width,GetElapsedMilliseconds,Duration);
NRect.Height:=CalculateLinearPosition(FInitialRect.Height,FFinalRect.Height,GetElapsedMilliseconds,Duration);
DoMoveControlAsRect(NRect.GetAsRect);
end;
end;
procedure TAnimationControlZoom.DoInitialize;
begin
inherited DoInitialize;
if FControl.AutoSize then begin
FAutoSized:=true;
//Autosize and zoom effect do not work well together ;)
FControl.AutoSize:=false;
end else begin
FAutoSized:=false;
end;
//Anchors can influence zoom in some cases
FAnchors:=FControl.Anchors;
if FRemoveAnchors then begin
FControl.Anchors:=[];
end;
end;
procedure TAnimationControlZoom.DoFinalizeAnimation;
begin
inherited DoFinalizeAnimation;
if FAutoSized then FControl.AutoSize:=true;
if FRemoveAnchors then begin
FControl.Anchors:=FAnchors;
end;
end;
procedure TAnimationControlZoom.SetFinalZoom(const aFinalZoom: Single);
begin
FFinalZoom:=aFinalZoom;
FZoomByRectangle:=false;
end;
procedure TAnimationControlZoom.SetFinalSize(const aRect: TRect);
begin
FFinalRect.SetFromRect(aRect);
FZoomByRectangle:=true;
end;
{ TAnimationControlColor }
procedure TAnimationControlColor.DoChangeColor(const aNewColor: TColor);
begin
FControl.Color:=aNewColor;
end;
end.

View File

@ -0,0 +1,101 @@
unit uanimationtypes;
(*
Comba - Animation controls helper
---------------------------------
@Licence: (c) 2017 José Mejuto // joshyfun at gmail.com
@Licence: LGPL when compiled with FPC (Free Pascal), GNU GPL V3 in other cases.
@Links:
GPL: https://www.gnu.org/licenses/gpl-3.0.en.html
LGPL: https://www.gnu.org/licenses/lgpl-3.0.en.html
@Description:
Helper unit.
*)
{$mode objfpc}{$H+}
{$modeswitch advancedrecords}
interface
uses
Classes, SysUtils;
type
{ TAnimationRect }
TAnimationRect=record
private
function GetBottom: integer;
function GetRight: integer;
procedure SetBottom(aValue: integer);
procedure SetRight(aValue: integer);
public
Left: integer;
Top: integer;
Width: integer;
Height: integer;
property Right: integer read GetRight write SetRight;
property Bottom: integer read GetBottom write SetBottom;
function GetAsRect: TRect;
function GetCenter: TPoint;
procedure SetFromRect(const aRect: TRect);
procedure MoveTo(const aNewLeftTop: TPoint);
end;
implementation
{ TAnimationRect }
function TAnimationRect.GetBottom: integer;
begin
Result:=Top+Height;
end;
function TAnimationRect.GetRight: integer;
begin
Result:=Left+Width;
end;
procedure TAnimationRect.SetBottom(aValue: integer);
begin
Height:=aValue-Top;
end;
procedure TAnimationRect.SetRight(aValue: integer);
begin
Width:=aValue-Left;
end;
function TAnimationRect.GetAsRect: TRect;
begin
Result.Left:=Left;
Result.Right:=Left+Width;
Result.Top:=Top;
Result.Bottom:=Top+Height;
end;
function TAnimationRect.GetCenter: TPoint;
begin
Result.x:=Left+(Width div 2);
Result.y:=Top+(Height div 2);
end;
procedure TAnimationRect.SetFromRect(const aRect: TRect);
begin
Left:=aRect.Left;
Top:=aRect.Top;
Width:=aRect.Right-aRect.Left;
Height:=aRect.Bottom-aRect.Top;
end;
procedure TAnimationRect.MoveTo(const aNewLeftTop: TPoint);
begin
Left:=aNewLeftTop.x;
Top:=aNewLeftTop.y;
end;
end.