BSOne.SFC/EM.Lib/ImageEn_SRC/Source/ieanimation.pas

2157 lines
61 KiB
Plaintext

(* ImageEn Build 7.0.0.06.2637 @ 7-4-17 14:58:42.679 *)
(*
Copyright (c) 1998-2017 by Carlotta Calandra. All rights reserved.
Copyright (c) 2011-2017 by Xequte Software.
This software comes without express or implied warranty.
In no case shall the author be liable for any damage or unwanted behavior of any
computer hardware and/or software.
Author grants you the right to include the component
in your application, whether COMMERCIAL, SHAREWARE, or FREEWARE.
ImageEn, IEvolution and ImageEn ActiveX may not be included in any
commercial, shareware or freeware libraries or components.
www.ImageEn.com
*)
(*
File version 1009
*)
unit ieanimation;
{$R-}
{$Q-}
{$I ie.inc}
interface
uses
Windows, Messages, SysUtils, Classes, SyncObjs, iexBitmaps,
{$ifdef IEHASTYPES} Types, {$endif}
{$ifdef IEHASUITYPES} System.UITypes, {$endif}
Graphics, hyiedefs;
type
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
// TIEAnimation
{!!
<FS>TIEAnimationGetImageInfoEvent
<FM>Declaration<FC>
TIEAnimationGetImageInfoEvent = procedure(Sender: TObject; imageIndex: integer; isVisible: boolean; var imageWidth: integer; var imageHeight: integer; var text: WideString) of object;
<FM>Description<FN>
Event called when only the image info is needed (not the whole image).
<TABLE>
<R> <H>Parameter</H> <H>Description</H> </R>
<R> <C><FC>Sender<FN></C> <C>The caller, a subclass of <A TIEAnimation> class.</C> </R>
<R> <C><FC>imageIndex<FN></C> <C>Index of the required image info.</C> </R>
<R> <C><FC>isVisible<FN></C> <C>False if the required image may not be visible (hence you can provide estimated values).</C> </R>
<R> <C><FC>imageWidth<FN></C> <C>Return value for image width.</C> </R>
<R> <C><FC>imageHeight<FN></C> <C>Return value for image height</C> </R>
<R> <C><FC>text<FN></C> <C>Return value for image textual info (ie a filename).</C> </R>
</TABLE>
!!}
TIEAnimationGetImageInfoEvent = procedure(Sender: TObject; imageIndex: integer; isVisible: boolean; var imageWidth: integer; var imageHeight: integer; var text: WideString) of object;
{!!
<FS>TIEAnimationGetImageEvent
<FM>Declaration<FC>
TIEAnimationGetImageEvent = procedure(Sender: TObject; imageIndex: integer; var image: <A TIEBitmap>; var text: WideString) of object;
<FM>Description<FN>
Event called when the whole image is needed.
<TABLE>
<R> <H>Parameter</H> <H>Description</H> </R>
<R> <C><FC>Sender<FN></C> <C>The caller, a subclass of <A TIEAnimation> class.</C> </R>
<R> <C><FC>imageIndex<FN></C> <C>Index of the required image.</C> </R>
<R> <C><FC>image<FN></C> <C>Return value for image bitmap.</C> </R>
<R> <C><FC>text<FN></C> <C>Return value for image textual info (ie a filename).</C> </R>
</TABLE>
!!}
TIEAnimationGetImageEvent = procedure(Sender: TObject; imageIndex: integer; var image: TIEBitmap; var text: WideString) of object;
{!!
<FS>TIEAnimationReleaseImageEvent
<FM>Declaration<FC>
TIEAnimationReleaseImageEvent = procedure(Sender: TObject; imageIndex: integer; var image: <A TIEBitmap>) of object;
<FM>Description<FN>
Event called when the image can be released.
<TABLE>
<R> <H>Parameter</H> <H>Description</H> </R>
<R> <C><FC>Sender<FN></C> <C>The caller, a subclass of <A TIEAnimation> class.</C> </R>
<R> <C><FC>imageIndex<FN></C> <C>Index of the image to release.</C> </R>
<R> <C><FC>image<FN></C> <C>The bitmap to release.</C> </R>
</TABLE>
!!}
TIEAnimationReleaseImageEvent = procedure(Sender: TObject; imageIndex: integer; var image: TIEBitmap) of object;
{!!
<FS>TIEAnimationImageInfo
<FM>Declaration<FC>
TIEAnimationImageInfo = class;
<FM>Description<FN>
Objects of this class contain the animation state of each image like positions and rotations, other than timing info.
<FM>Fields<FN>
}
TIEAnimationImageInfo = class
public
startTime : dword; // when transition was started
endTime : dword; // when transition must ends
startAlpha : integer; // the starting alpha (0..255)
endAlpha : integer; // the ending alpha (0..255)
lastAlpha : integer; // last calculated alpha (0..255)
startAngleX : double; // the starting angle X in degrees
endAngleX : double; // the ending angle X in degrees
lastAngleX : double; // last calculated angle X in degrees
startAngleY : double; // the starting angle Y in degrees
endAngleY : double; // the ending angle Y in degrees
lastAngleY : double; // last calculated angle Y in degrees
startCenterX : integer; // the starting X position
endCenterX : integer; // the ending X position
lastCenterX : integer; // last calculated X position
startCenterY : integer; // the starting Y position
endCenterY : integer; // the ending Y position
lastCenterY : integer; // last calculated Y position
startWidth : integer; // the starting width
endWidth : integer; // the ending width
lastWidth : integer; // last calculated width
startHeight : integer; // the starting height
endHeight : integer; // the ending height
lastHeight : integer; // last calculated height
lastCoords : TIEQuadCoords; // last calculated coordinates
end;
{!!}
{!!
<FS>TIEAnimation
<FM>Declaration<FC>
TIEAnimation = class;
<FM>Description<FN>
This is the base abstract class for animation classes like coverflow-like (<A TIEHorizontalFlow>) and circular flow (<A TIECircularFlow>) or any user custom animation classes.
<FM>Methods and Properties<FN>
<FI>Protected<FN>
<TABLE2>
<R> <C_IMG_METHOD> <C><A TIEAnimation.DoGetImage></C> </R>
<R> <C_IMG_METHOD> <C><A TIEAnimation.DoGetImageInfo></C> </R>
<R> <C_IMG_METHOD> <C><A TIEAnimation.DoReleaseImage></C> </R>
<R> <C_IMG_METHOD> <C><A TIEAnimation.drawImage> virtual</C> </R>
<R> <C_IMG_METHOD> <C><A TIEAnimation.PaintScrollBar></C> </R>
<R> <C_IMG_METHOD> <C><A TIEAnimation.PaintText></C> </R>
<R> <C_IMG_METHOD> <C><A TIEAnimation.SetEndValues> virtual</C> </R>
<R> <C_IMG_METHOD> <C><A TIEAnimation.SetInitialValues> virtual</C> </R>
<R> <C_IMG_METHOD> <C><A TIEAnimation.SetStartEndValues></C> </R>
<R> <C_IMG_METHOD> <C><A TIEAnimation.SetStartValues> virtual</C> </R>
</TABLE>
<FI>Public<FN>
<TABLE2>
<R> <C_IMG_METHOD> <C>constructor <A TIEAnimation.Create></C> </R>
<R> <C_IMG_METHOD> <C>destructor <A TIEAnimation.Destroy></C> </R>
</TABLE>
<TABLE2>
<R> <C_IMG_PROPERTY> <C><A TIEAnimation.AnimDuration></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEAnimation.CurrentImage></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEAnimation.BorderPen></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEAnimation.Depth></C> </R>
<R> <C_IMG_METHOD> <C><A TIEAnimation.DeleteImage></C> </R>
<R> <C_IMG_METHOD> <C><A TIEAnimation.Display> virtual abstract</C> </R>
<R> <C_IMG_METHOD> <C><A TIEAnimation.FindImageAt></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEAnimation.Font></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEAnimation.FramesZoomFilter></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEAnimation.ImageCount></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEAnimation.Images></C> </R>
<R> <C_IMG_METHOD> <C><A TIEAnimation.InsertImage></C> </R>
<R> <C_IMG_METHOD> <C><A TIEAnimation.IsInsideScrollbar></C> </R>
<R> <C_IMG_METHOD> <C><A TIEAnimation.IsInsideScrollbarSlider></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEAnimation.LastFrameZoomFilter></C> </R>
<R> <C_IMG_METHOD> <C><A TIEAnimation.MoveScrollbarSliderTo></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEAnimation.NeedRefresh></C> </R>
<R> <C_IMG_METHOD> <C><A TIEAnimation.RestartAnimation></C> </R>
<R> <C_IMG_METHOD> <C><A TIEAnimation.SetupEvents></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEAnimation.ShadowAlphaMax></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEAnimation.ShadowAlphaMin></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEAnimation.ShowBorder></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEAnimation.ShowScrollbar></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEAnimation.ShowText></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEAnimation.ViewHeight></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEAnimation.ViewWidth></C> </R>
</TABLE>
<FM>Demos<FN>
<TABLE2>
<R> <C_IMG_DEMO> <C>Demos\Display\MviewFlow\MViewFlow.dpr </C> </R>
<R> <C_IMG_DEMO> <C>Demos\Display\ManualFlow\ManualFlow.dpr </C> </R>
</TABLE>
!!}
TIEAnimation = class
private
m_getImageInfo: TIEAnimationGetImageInfoEvent;
m_getImage: TIEAnimationGetImageEvent;
m_releaseImage: TIEAnimationReleaseImageEvent;
m_images: array of TIEAnimationImageInfo;
m_currentImage: integer;
m_viewWidth: integer;
m_viewHeight: integer;
m_animDuration: dword; // in ms
m_depth: integer;
m_needRefresh: boolean;
m_showBorder: boolean;
m_borderPen: TPen;
m_shadowAlphaMin: integer;
m_shadowAlphaMax: integer;
m_lastScrollbarSlideRect: TIERectangle;
m_lastScrollbarBoundRect: TIERectangle;
m_showScrollbar: boolean;
m_showText: boolean;
m_lastFrameZoomFilter: TResampleFilter;
m_FramesZoomFilter: TResampleFilter;
m_canvasCriticalSection: TCriticalSection;
fFont : TFont;
procedure SetCurrentImage(value: integer);
procedure SetViewWidth(value: integer);
procedure SetViewHeight(value: integer);
procedure SetDepth(value: integer);
function GetImageCount(): integer;
procedure SetImageCount(value: integer);
procedure SetShowBorder(value: boolean);
procedure SetShadowAlphaMin(value: integer);
procedure SetShadowAlphaMax(value: integer);
procedure SetShowScrollbar(value: boolean);
procedure FreeImageInfo(first, last: integer);
function GetImages(idx: integer): TIEAnimationImageInfo;
procedure PaintBorder(i: integer; dest: TIEBitmap);
procedure SetShowText(value: boolean);
function isVisible(const coords: TIEQuadCoords): boolean; virtual;
procedure SetFont(const Value: TFont);
protected
procedure SetStartEndValues();
procedure SetInitialValues(first, last: integer); virtual;
procedure SetStartValues(); virtual;
procedure SetEndValues(); virtual;
function drawImage(dest: TIEBitmap; imageIndex: integer): boolean; virtual;
procedure DoGetImageInfo(imageIndex: integer; isVisible: boolean; var imageWidth: integer; var imageHeight: integer; var text: WideString);
procedure DoGetImage(imageIndex: integer; var image: TIEBitmap; var text: WideString);
procedure DoReleaseImage(imageIndex: integer; var image: TIEBitmap);
procedure PaintScrollBar(dest: TIEBitmap);
procedure PaintText(posY: integer; dest: TIEBitmap);
public
constructor Create();
destructor Destroy(); override;
procedure SetupEvents(getImage: TIEAnimationGetImageEvent; releaseImage: TIEAnimationReleaseImageEvent = nil; getImageInfo: TIEAnimationGetImageInfoEvent = nil);
procedure RestartAnimation();
procedure Display(dest: TIEBitmap); virtual; abstract;
function FindImageAt(X, Y: integer): integer;
procedure MoveScrollbarSliderTo(X: integer);
function IsInsideScrollbarSlider(X, Y: integer): boolean;
function IsInsideScrollbar(X, Y: integer): boolean;
procedure DeleteImage(imageIndex: integer);
procedure InsertImage(imageIndex: integer);
property ViewWidth: integer read m_viewWidth write SetViewWidth;
property ViewHeight: integer read m_viewHeight write SetViewHeight;
property Depth: integer read m_depth write SetDepth;
property ShowBorder: boolean read m_showBorder write SetShowBorder;
property ShadowAlphaMin: integer read m_shadowAlphaMin write SetShadowAlphaMin;
property ShadowAlphaMax: integer read m_shadowAlphaMax write SetShadowAlphaMax;
property ImageCount: integer read GetImageCount write SetImageCount;
property Images[idx: integer]: TIEAnimationImageInfo read GetImages;
property CurrentImage: integer read m_currentImage write SetCurrentImage;
property ShowScrollbar: boolean read m_showScrollbar write SetShowScrollbar;
property ShowText: boolean read m_showText write SetShowText;
property Font: TFont read fFont write SetFont;
{!!
<FS>TIEAnimation.BorderPen
<FM>Declaration<FC>
property BorderPen: TPen;
<FM>Description<FN>
Specifies pen to use when painting the frames border. A frame border is painted when <A TIEAnimation.ShowBorder> is true.
!!}
property BorderPen: TPen read m_borderPen;
{!!
<FS>TIEAnimation.LastFrameZoomFilter
<FM>Declaration<FC>
property LastFrameZoomFilter: <A TResampleFilter>;
<FM>Description<FN>
Specifies the interpolation filter to apply when the last frame is showed (when the animation ends).
Default: rfFastLinear
!!}
property LastFrameZoomFilter: TResampleFilter read m_lastFrameZoomFilter write m_lastFrameZoomFilter;
{!!
<FS>TIEAnimation.FramesZoomFilter
<FM>Declaration<FC>
property FramesZoomFilter: <A TResampleFilter>;
<FM>Description<FN>
Specifies the interpolation filter to apply when the animation runs.
Default: rfNone
!!}
property FramesZoomFilter: TResampleFilter read m_FramesZoomFilter write m_FramesZoomFilter;
{!!
<FS>TIEAnimation.AnimDuration
<FM>Declaration<FC>
property AnimDuration: dword;
<FM>Description<FN>
Specifies the animation duration in milliseconds.
Default: 800ms
!!}
property AnimDuration: dword read m_animDuration write m_animDuration;
{!!
<FS>TIEAnimation.NeedRefresh
<FM>Declaration<FC>
property NeedRefresh: boolean;
<FM>Description<FN>
Applications will read this value to determine whether a call to <A TIEAnimation.Display> is necessary.
This property is True when animation is running, and False when the last frame has been painted.
NeedRefresh can be also True just after a property has been changed.
<FM>Example<FC>
// repaint frame (if necessary)
procedure TMainForm.Timer1Timer(Sender: TObject);
begin
if m_animation.NeedRefresh then
begin
ImageEnView1.IEBitmap.Fill(clBlack);
ImageEnView1.IEBitmap.AlphaChannel.Fill(255);
m_animation.Display(ImageEnView1.IEBitmap);
ImageEnView1.Update();
end;
end;
!!}
property NeedRefresh: boolean read m_needRefresh write m_needRefresh;
end;
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
// TIEHorizontalFlow
{!!
<FS>TIEHorizontalFlow
<FM>Declaration<FC>
TIEHorizontalFlow = class(<A TIEAnimation>);
<FM>Description<FN>
Implements a coverflow-like animation.
<IMG help_images\Coverflow.jpg>
<FM>Methods and Properties<FN>
<TABLE2>
<R> <C_IMG_PROPERTY> <C><A TIEHorizontalFlow.CurrentImageZoom></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEHorizontalFlow.HorizontalDistance></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEHorizontalFlow.ImagesHorizontalPercentage></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEHorizontalFlow.ImagesVerticalPercentage></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEHorizontalFlow.ImagesZoom></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIEHorizontalFlow.RotateAngle></C> </R>
</TABLE>
Also inherits all properties and methods of <A TIEAnimation>
<FM>Demos<FN>
<TABLE2>
<R> <C_IMG_DEMO> <C>Demos\Display\MviewFlow\MViewFlow.dpr </C> </R>
<R> <C_IMG_DEMO> <C>Demos\Display\ManualFlow\ManualFlow.dpr </C> </R>
</TABLE>
!!}
TIEHorizontalFlow = class(TIEAnimation)
private
m_horizontalDistance: integer;
m_imagesHorizontalPercentage: double; // in %
m_imagesVerticalPercentage: double; // in %
m_rotateAngle: double; // in degrees
m_imagesZoom: double; // 0..1
m_currentImageZoom: double; // 0..1
procedure SetHorizontalDistance(value: integer);
procedure SetImagesHorizontalPercentage(value: double);
procedure SetImagesVerticalPercentage(value: double);
procedure SetRotateAngle(value: double);
procedure SetImagesZoom(value: double);
procedure SetCurrentImageZoom(value: double);
protected
procedure SetInitialValues(first, last: integer); override;
procedure SetStartValues(); override;
procedure SetEndValues(); override;
public
constructor Create();
destructor Destroy(); override;
procedure Display(dest: TIEBitmap); override;
property HorizontalDistance: integer read m_horizontalDistance write SetHorizontalDistance;
property ImagesHorizontalPercentage: double read m_imagesHorizontalPercentage write SetImagesHorizontalPercentage;
property ImagesVerticalPercentage: double read m_imagesVerticalPercentage write SetImagesVerticalPercentage;
property RotateAngle: double read m_rotateAngle write SetRotateAngle;
property ImagesZoom: double read m_imagesZoom write SetImagesZoom;
property CurrentImageZoom: double read m_currentImageZoom write SetCurrentImageZoom;
end;
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
// TIECircularFlow
{!!
<FS>TIECircularFlow
<FM>Declaration<FC>
TIECircularFlow = class(<A TIEAnimation>);
<FM>Description<FN>
Implements a circular animation.
<FM>Methods and Properties<FN>
<TABLE2>
<R> <C_IMG_PROPERTY> <C><A TIECircularFlow.CurrentImageZoom></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIECircularFlow.EllipseAngle></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIECircularFlow.ImagesSizePercentage></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIECircularFlow.ImagesZoom></C> </R>
<R> <C_IMG_PROPERTY> <C><A TIECircularFlow.VisibleImages></C> </R>
</TABLE>
Also inherits all properties and methods of <A TIEAnimation>
<FM>Demos<FN>
<TABLE2>
<R> <C_IMG_DEMO> <C>Demos\Display\MviewFlow\MViewFlow.dpr </C> </R>
<R> <C_IMG_DEMO> <C>Demos\Display\ManualFlow\ManualFlow.dpr </C> </R>
</TABLE>
!!}
TIECircularFlow = class(TIEAnimation)
private
m_imagesSizePercentage: double; // in %
m_imagesZoom: double; // 0..1
m_currentImageZoom: double; // 0..1
m_visibleImages: integer;
m_ellipseAngle: double; // in degrees
protected
procedure SetInitialValues(first, last: integer); override;
procedure SetStartValues(); override;
procedure SetEndValues(); override;
procedure SetImagesSizePercentage(value: double);
procedure SetImagesZoom(value: double);
procedure SetCurrentImageZoom(value: double);
procedure SetVisibleImages(value: integer);
procedure SetEllipseAngle(value: double);
public
constructor Create();
destructor Destroy(); override;
procedure Display(dest: TIEBitmap); override;
property ImagesSizePercentage: double read m_imagesSizePercentage write SetImagesSizePercentage;
property ImagesZoom: double read m_imagesZoom write SetImagesZoom;
property CurrentImageZoom: double read m_currentImageZoom write SetCurrentImageZoom;
property VisibleImages: integer read m_visibleImages write SetVisibleImages;
property EllipseAngle: double read m_ellipseAngle write SetEllipseAngle;
end;
implementation
uses
iegdiplus, imageenio, imageenproc, hyieutils;
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
// TIEAnimation
{!!
<FS>TIEAnimation.Create
<FM>Declaration<FC>
constructor Create();
<FM>Description<FN>
Creates the TIEAnimation object. You should call this constructor on your subclass.
!!}
constructor TIEAnimation.Create();
begin
inherited Create();
IEGDIPLoadLibrary();
// default values for properties
m_animDuration := 800;
m_depth := 500;
m_showBorder := false;
m_shadowAlphaMin := 0;
m_shadowAlphaMax := 40;
m_showScrollbar := true;
m_showText := true;
m_lastFrameZoomFilter := rfFastLinear;
m_FramesZoomFilter := rfNone;
m_viewWidth := 0;
m_viewHeight := 0;
m_currentImage := 0;
m_borderPen := TPen.Create();
m_borderPen.Style := psSolid;
m_borderPen.Mode := pmCopy;
m_borderPen.Color := clWhite;
m_borderPen.Width := 2;
SetLength(m_images, 0);
fFont := TFont.Create;
fFont.Charset := DEFAULT_CHARSET;
fFont.Color := clWhite;
fFont.Height := 18;
fFont.Name := 'Arial';
fFont.Style := [fsBold];
m_canvasCriticalSection := TCriticalSection.Create();
end;
{!!
<FS>TIEAnimation.SetupEvents
<FM>Declaration<FC>
procedure SetupEvents(getImage: <A TIEAnimationGetImageEvent>; releaseImage: <A TIEAnimationReleaseImageEvent> = nil; getImageInfo: <A TIEAnimationGetImageInfoEvent> = nil);
<FM>Description<FN>
Setup events necessary to show images.
<TABLE>
<R> <H>Parameter</H> <H>Description</H> </R>
<R> <C><FC>getImage<FN></C> <C>The event called whenever a new image needs to be drawn. Cannot be nil.</C> </R>
<R> <C><FC>releaseImage<FN></C> <C>The event called whenever an image can be released. Can be nil.</C> </R>
<R> <C><FC>getImageInfo<FN></C> <C>The event called whenever only image info are needed. Can be nil.</C> </R>
</TABLE>
!!}
procedure TIEAnimation.SetupEvents(getImage: TIEAnimationGetImageEvent; releaseImage: TIEAnimationReleaseImageEvent; getImageInfo: TIEAnimationGetImageInfoEvent);
begin
m_getImageInfo := getImageInfo;
m_getImage := getImage;
m_releaseImage := releaseImage;
SetInitialValues(0, ImageCount-1);
SetEndValues();
end;
function TIEAnimation.GetImageCount(): integer;
begin
result := length(m_images);
end;
{!!
<FS>TIEAnimation.ImageCount
<FM>Declaration<FC>
property ImageCount: integer;
<FM>Description<FN>
Specifies the number of images that TIEAnimation should handle. This value could not match the number of visible images.
Setting this property reinitializes the animation and set the current image to 0.
!!}
procedure TIEAnimation.SetImageCount(value: integer);
var
i: integer;
begin
FreeImageInfo(0, length(m_images)-1);
SetLength(m_images, value);
for i := 0 to length(m_images)-1 do
m_images[i] := TIEAnimationImageInfo.Create();
m_currentImage := 0;
SetInitialValues(0, length(m_images)-1);
SetEndValues();
end;
{!!
<FS>TIEAnimation.DeleteImage
<FM>Declaration<FC>
procedure DeleteImage(imageIndex: integer);
<FM>Description<FN>
Removes the specified image.
!!}
procedure TIEAnimation.DeleteImage(imageIndex: integer);
begin
FreeImageInfo(imageIndex, imageIndex);
m_currentImage := imin(m_currentImage, length(m_images)-1);
SetStartEndValues();
end;
{!!
<FS>TIEAnimation.InsertImage
<FM>Declaration<FC>
procedure InsertImage(imageIndex: integer);
<FM>Description<FN>
Inserts a new image at specified position.
!!}
procedure TIEAnimation.InsertImage(imageIndex: integer);
var
i: integer;
begin
SetLength(m_images, length(m_images)+1);
for i := length(m_images)-1 downto imageIndex+1 do
m_images[i] := m_images[i-1];
m_images[imageIndex] := TIEAnimationImageInfo.Create();
m_currentImage := imageIndex;
SetInitialValues(imageIndex, imageIndex);
SetStartEndValues();
end;
procedure TIEAnimation.FreeImageInfo(first, last: integer);
var
i: integer;
count: integer;
begin
count := last - first + 1;
for i := first to last do
m_images[i].Free();
for i := last+1 to length(m_images)-1 do
begin
m_images[first] := m_images[i];
inc(first);
end;
SetLength(m_images, length(m_images)-count);
end;
{!!
<FS>TIEAnimation.Destroy
<FM>Declaration<FC>
destructor Destroy(); override;
<FM>Description<FN>
Destroys the TIEAnimation object. You should call this destructor on your subclass.
!!}
destructor TIEAnimation.Destroy();
begin
FreeImageInfo(0, length(m_images)-1);
FreeAndNil(m_canvasCriticalSection);
FreeAndNil(m_borderPen);
IEGDIPUnLoadLibrary();
inherited;
end;
{!!
<FS>TIEAnimation.SetInitialValues
<FM>Declaration<FC>
procedure SetInitialValues(first, last: integer); virtual;
<FM>Description<FN>
Sets initial animation values (image position, rotation, etc). This is called one time when the object is initialized.
This method need to be overloaded to implement animations.
<TABLE>
<R> <H>Parameter</H> <H>Description</H> </R>
<R> <C><FC>first<FN></C> <C>Index of first image to set values.</C> </R>
<R> <C><FC>last<FN></C> <C>Index of last image to set values..</C> </R>
</TABLE>
!!}
procedure TIEAnimation.SetInitialValues(first, last: integer);
var
i: integer;
begin
for i := first to last do
begin
Images[i].startTime := GetTickCount();
Images[i].startAlpha := 255;
Images[i].startAngleX := 0.0;
Images[i].startAngleY := 0.0;
Images[i].startCenterX := 0;
Images[i].startCenterY := 0;
Images[i].startWidth := 0;
Images[i].startHeight := 0;
end;
NeedRefresh := true;
end;
{!!
<FS>TIEAnimation.SetStartValues
<FM>Declaration<FC>
procedure SetStartValues(); virtual;
<FM>Description<FN>
Sets starting values (image position, rotation, etc) whenever the animation is about to begin.
This method needs to be overloaded to implement animations.
!!}
procedure TIEAnimation.SetStartValues();
var
i: integer;
begin
for i := 0 to ImageCount-1 do
begin
Images[i].startTime := GetTickCount();
Images[i].startAlpha := Images[i].lastAlpha;
Images[i].startAngleX := Images[i].lastAngleX;
Images[i].startAngleY := Images[i].lastAngleY;
Images[i].startCenterX := Images[i].lastCenterX;
Images[i].startCenterY := Images[i].lastCenterY;
Images[i].startWidth := Images[i].lastWidth;
Images[i].startHeight := Images[i].lastHeight;
end;
NeedRefresh := true;
end;
{!!
<FS>TIEAnimation.SetEndValues
<FM>Declaration<FC>
procedure SetEndValues(); virtual;
<FM>Description<FN>
Sets ending values (image position, rotation, etc) whenever the animation is about to begin.
This method needs to be overloaded to implement animations.
!!}
procedure TIEAnimation.SetEndValues();
var
i: integer;
begin
for i := 0 to length(m_images)-1 do
Images[i].endTime := Images[i].startTime + AnimDuration;
NeedRefresh := true;
end;
{!!
<FS>TIEAnimation.Font
<FM>Declaration<FC>
property Font: TFont;
<FM>Description<FN>
The font of the text if <A TIEAnimation.ShowText> is enabled.
Default values: Height: 18; Style: [fsBold]; Color: clWhite; Name: 'Arial'
<FM>Example<FC>
ImageEnMView1.Animation.Font.Color := clRed;
ImageEnMView1.Animation.Font.Height := 30;
ImageEnMView1.Animation.Font.Name := 'Tahoma';
ImageEnMView1.Animation.Font..Style := [fsBold];
ImageEnMView1.Update;
!!}
procedure TIEAnimation.SetFont(const Value: TFont);
begin
fFont := Value;
NeedRefresh := true;
end;
{!!
<FS>TIEAnimation.RestartAnimation
<FM>Declaration<FC>
procedure RestartAnimation();
<FM>Description<FN>
Restarts the animation.
!!}
procedure TIEAnimation.RestartAnimation();
begin
SetStartEndValues();
end;
{!!
<FS>TIEAnimation.Images
<FM>Declaration<FC>
property Images[index: integer]: <A TIEAnimationImageInfo>;
<FM>Description<FN>
Get or set the animation parameters for the image of the specified index.
<FM>Example<FC>
animation.Images[0].startAngleX := 45;
!!}
function TIEAnimation.GetImages(idx: integer): TIEAnimationImageInfo;
begin
result := m_images[idx];
end;
function TIEAnimation.isVisible(const coords: TIEQuadCoords): boolean;
begin
result := IEPointInRect(coords.x0, coords.y0, 0, 0, m_viewWidth-1, m_viewHeight-1) or IEPointInRect(coords.x1, coords.y1, 0, 0, m_viewWidth-1, m_viewHeight-1) or
IEPointInRect(coords.x2, coords.y2, 0, 0, m_viewWidth-1, m_viewHeight-1) or IEPointInRect(coords.x3, coords.y3, 0, 0, m_viewWidth-1, m_viewHeight-1);
end;
{!!
<FS>TIEAnimation.Display
<FM>Declaration<FC>
procedure Display(dest: <A TIEBitmap>); virtual; abstract;
<FM>Description<FN>
This method must be implemented by the subclass. It should loop among images calling <A TIEAnimation.drawImage> for each image.
<TABLE>
<R> <H>Parameter</H> <H>Description</H> </R>
<R> <C><FC>dest<FN></C> <C>The destination bitmap.</C> </R>
</TABLE>
!!}
{!!
<FS>TIEAnimation.drawImage
<FM>Declaration<FC>
function drawImage(dest: <A TIEBitmap>; imageIndex: integer): boolean; virtual;
<FM>Description<FN>
Draws the specified image. This method reads the timers to draw the image correctly (at calculated position, rotation, etc...).
Returns true when the image doesn't need to be drawn again (the animation is finished).
<TABLE>
<R> <H>Parameter</H> <H>Description</H> </R>
<R> <C><FC>dest<FN></C> <C>The destination bitmap. Must be at least <A TIEAnimation.ViewWidth> and <A TIEAnimation.ViewHeight> pixels.</C> </R>
<R> <C><FC>imageIndex<FN></C> <C>The image index to draw.</C> </R>
</TABLE>
!!}
function TIEAnimation.drawImage(dest: TIEBitmap; imageIndex: integer): boolean;
var
image: TIEAnimationImageInfo;
thisStep: double; // 0..1
bmp, abmp: TIEBitmap;
lastCenterX, lastCenterY: integer;
lastAngleX, lastAngleY: double;
lastWidth, lastHeight: integer;
lastAlpha: integer;
text: WideString;
begin
image := m_images[imageIndex];
thisStep := (GetTickCount()-image.startTime) / (image.endTime-image.startTime); // linear 0..1
if thisStep < 0.0 then thisStep := 0.0;
if thisStep > 1.0 then thisStep := 1.0;
thisStep := thisStep*thisStep*thisStep + 1.0*3.0*thisStep*thisStep*(1.0-thisStep) + 0.1*3.0*thisStep*(1.0-thisStep)*(1.0-thisStep); // bezier-bicubic
if thisStep >= 1.0 then
begin
// go directly to ending values
image.startAlpha := image.endAlpha;
image.startAngleX := image.endAngleX;
image.startAngleY := image.endAngleY;
image.startCenterX := image.endCenterX;
image.startCenterY := image.endCenterY;
image.startWidth := image.endWidth;
image.startHeight := image.endHeight;
end;
lastAlpha := trunc( image.startAlpha + (image.endAlpha - image.startAlpha) * thisStep );
lastCenterX := trunc( image.startCenterX + (image.endCenterX - image.startCenterX) * thisStep );
lastCenterY := trunc( image.startCenterY + (image.endCenterY - image.startCenterY) * thisStep );
lastAngleX := image.startAngleX + (image.endAngleX - image.startAngleX) * thisStep;
lastAngleY := image.startAngleY + (image.endAngleY - image.startAngleY) * thisStep;
lastWidth := trunc( image.startWidth + (image.endWidth - image.startWidth) * thisStep );
lastHeight := trunc( image.startHeight + (image.endHeight - image.startHeight) * thisStep );
result := (lastCenterX <> image.endCenterX) or
(lastCenterY <> image.endCenterY) or
(lastAngleX <> image.endAngleX) or
(lastAngleY <> image.endAngleY) or
(lastWidth <> image.endWidth) or
(lastHeight <> image.endHeight) or
(lastAlpha <> image.endAlpha);
image.lastAlpha := lastAlpha;
image.lastCenterX := lastCenterX;
image.lastCenterY := lastCenterY;
image.lastAngleX := lastAngleX;
image.lastAngleY := lastAngleY;
image.lastWidth := lastWidth;
image.lastHeight := lastHeight;
if (image.lastWidth = 0) or (image.lastHeight = 0) then
exit;
// calculate image rect
IEProjectBitmap1(nil, nil,
image.lastCenterX, image.lastCenterY, // centerDstX, centerDstY
image.lastWidth, image.lastHeight, // dstWidth, dstHeight
0, 0, // translateX, translateY
m_depth, // depth
image.lastAngleX, image.lastAngleY, // rotateX, rotateY
m_shadowAlphaMin, m_shadowAlphaMax, // specularAlphaMin, specularAlphaMax
image.lastCoords, // output coordinates
ieovoCALCRECTONLY, true,
image.lastAlpha);
if isVisible(image.lastCoords) and (image.lastWidth > 0) and (image.lastHeight > 0) then
begin
bmp := nil;
DoGetImage(imageIndex, bmp, text);
abmp := TIEBitmap.Create(image.lastWidth, image.lastHeight, bmp.PixelFormat);
if result then
_IEResampleIEBitmap(bmp, abmp, m_framesZoomFilter, nil, nil)
else
_IEResampleIEBitmap(bmp, abmp, m_lastFrameZoomFilter, nil, nil);
abmp.PixelFormat := ie24RGB;
IEProjectBitmap1(abmp, dest,
0, 0, // centerDstX, centerDstY
0, 0, // dstWidth, dstHeight
0, 0, // translateX, translateY
0.0, // depth
0.0, 0.0, // rotateX, rotateY
m_shadowAlphaMin, m_shadowAlphaMax, // specularAlphaMin, specularAlphaMax
image.lastCoords, // output coordinates
ieovoDRAWONLY, true,
image.lastAlpha);
abmp.Free();
DoReleaseImage(imageIndex, bmp);
// draw border
if m_showBorder then
PaintBorder(imageIndex, dest);
end;
end;
{!!
<FS>TIEAnimation.FindImageAt
<FM>Declaration<FC>
function FindImageAt(X, Y: integer): integer;
<FM>Description<FN>
Returns the index of the image that is under the specified coordinates, or -1 if there is no image.
<TABLE>
<R> <H>Parameter</H> <H>Description</H> </R>
<R> <C><FC>X<FN></C> <C>Horizontal coordinate.</C> </R>
<R> <C><FC>Y<FN></C> <C>Vertical coordinate.</C> </R>
</TABLE>
!!}
function TIEAnimation.FindImageAt(X, Y: integer): integer;
function IsInsideImage(i: integer): boolean;
begin
if (i >= length(m_images)) or (i < 0) then
result := false
else
with m_images[i].lastCoords do
result := IEISPointInPoly(X, Y, [Point(x0, y0), Point(x1, y1), Point(x2, y2), Point(x3, y3)]);
end;
var
i: integer;
begin
// look for current image
if IsInsideImage(m_currentImage) then
begin
result := m_currentImage;
exit;
end
else
begin
// look on the left
for i := m_currentImage-1 downto 0 do
if IsInsideImage(i) then
begin
result := i;
exit;
end;
// look on the right
for i := m_currentImage+1 to length(m_images)-1 do
if IsInsideImage(i) then
begin
result := i;
exit;
end;
end;
result := -1;
end;
// thread safe
procedure TIEAnimation.PaintBorder(i: integer; dest: TIEBitmap);
begin
if assigned(m_borderPen) then
begin
m_canvasCriticalSection.Enter();
try
with TIECanvas.Create(dest.Canvas) do
begin
Pen.Style := m_borderPen.Style;
Pen.Mode := m_borderPen.Mode;
Pen.Color := m_borderPen.Color;
Pen.Width := m_borderPen.Width;
Brush.style := bsClear;
with m_images[i].lastCoords do
begin
MoveTo(x0, y0);
LineTo(x1, y1);
LineTo(x2, y2);
LineTo(x3, y3);
LineTo(x0, y0);
end;
Free();
end;
finally
m_canvasCriticalSection.Leave();
end;
end;
end;
{!!
<FS>TIEAnimation.PaintText
<FM>Declaration<FC>
procedure PaintText(posY: integer; dest: <A TIEBitmap>);
<FM>Description<FN>
Paints the text (ie filename) at the specified row. You should call this method inside <A TIEAnimation.Display> method.
<TABLE>
<R> <H>Parameter</H> <H>Description</H> </R>
<R> <C><FC>posY<FN></C> <C>Vertical position where to draw the text.</C> </R>
<R> <C><FC>dest<FN></C> <C>The destination bitmap.</C> </R>
</TABLE>
!!}
procedure TIEAnimation.PaintText(posY: integer; dest: TIEBitmap);
const
Default_Font_Height = 18; // Fixed font height used prior to v5.0.7
var
posX: integer;
text: WideString;
iw, ih: integer;
iTextOffsetY: Integer;
begin
if m_showText then
begin
with TIECanvas.Create(dest.Canvas) do
begin
Brush.Style := bsClear;
Font.Assign(fFont);
DoGetImageInfo(CurrentImage, true, iw, ih, text);
posX := Images[CurrentImage].endCenterX - TextWidth(text) div 2;
// Adjust text position for increased font size, while maintaining legacy support
iTextOffsetY := (Default_Font_Height - fFont.Height) div 2;
TextOut(posX, posY + iTextOffsetY, text);
Free();
end;
end;
end;
{!!
<FS>TIEAnimation.PaintScrollBar
<FM>Declaration<FC>
procedure PaintScrollBar(dest: <A TIEBitmap>);
<FM>Description<FN>
Paints the scroll bar. You should call this method inside <A TIEAnimation.Display> method.
<TABLE>
<R> <H>Parameter</H> <H>Description</H> </R>
<R> <C><FC>dest<FN></C> <C>The destination bitmap.</C> </R>
</TABLE>
!!}
procedure TIEAnimation.PaintScrollBar(dest: TIEBitmap);
const
VERTGAP = 5; // gap from bottom border
XPER = 0.8; // 80% of the width
HEIGHT = 16; // height in pixels
RX = 12; // round width
RY = 12; // round height
BUTTONW = 18; // buttons width
MINSLIDERW = 8; // minimum slider width
var
boundwidth: integer;
sliderWidth, asliderWidth: double;
begin
if m_showScrollbar then
begin
with TIECanvas.Create(dest.Canvas) do
begin
// paint brush and border
Brush.Style := bsSolid;
Brush.Color := clWhite;
Brush.Transparency := 64;
Pen.Color := clWhite;
Pen.Style := psSolid;
Pen.Mode := pmCopy;
Pen.Width := 1;
Pen.Transparency := 128;
boundwidth := trunc(ViewWidth * XPER); // width of the scrollbar
m_lastScrollbarBoundRect.x := (ViewWidth - boundwidth) div 2;
m_lastScrollbarBoundRect.y := ViewHeight - HEIGHT - VERTGAP;
m_lastScrollbarBoundRect.width := boundwidth;
m_lastScrollbarBoundRect.height := HEIGHT;
with m_lastScrollbarBoundRect do
RoundRect(x, y, x+width, y+height, RX, RY);
// paint slider
Brush.Style := bsSolid;
Brush.Color := clBlack;
Brush.Transparency := 128;
Pen.Width := 1;
Pen.Transparency := 128;
sliderWidth := boundwidth / ImageCount;
asliderWidth := dmax(MINSLIDERW, sliderWidth);
m_lastScrollbarSlideRect.x := m_lastScrollbarBoundRect.x + trunc(CurrentImage * sliderWidth);
if m_lastScrollbarSlideRect.x + asliderWidth > m_lastScrollbarBoundRect.x + m_lastScrollbarBoundRect.width then
m_lastScrollbarSlideRect.x := trunc(m_lastScrollbarBoundRect.x + m_lastScrollbarBoundRect.width - asliderWidth);
m_lastScrollbarSlideRect.y := m_lastScrollbarBoundRect.y + 1;
m_lastScrollbarSlideRect.width := trunc(asliderWidth);
m_lastScrollbarSlideRect.height := m_lastScrollbarBoundRect.height - 1;
with m_lastScrollbarSlideRect do
RoundRect(x, y, x+width, y+height, RX, RY);
Free();
end;
end;
end;
{!!
<FS>TIEAnimation.MoveScrollbarSliderTo
<FM>Declaration<FC>
procedure MoveScrollbarSliderTo(X: integer);
<FM>Description<FN>
Moves the scrollbar slider to the specified horizontal position.
<TABLE>
<R> <H>Parameter</H> <H>Description</H> </R>
<R> <C><FC>X<FN></C> <C>Horizontal slider position.</C> </R>
</TABLE>
<FM>Example<FC>
procedure TMainForm.ImageEnView1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
// directly move to the clicked scrollbar position
if m_animation.IsInsideScrollbar(X, Y) then
m_animation.MoveScrollbarSliderTo(X);
end;
!!}
procedure TIEAnimation.MoveScrollbarSliderTo(X: integer);
begin
CurrentImage := round((X - m_lastScrollbarBoundRect.x - m_lastScrollbarSlideRect.width / 2) / (m_lastScrollbarBoundRect.width / ImageCount));
end;
{!!
<FS>TIEAnimation.IsInsideScrollbarSlider
<FM>Declaration<FC>
function IsInsideScrollbarSlider(X, Y: integer): boolean;
<FM>Description<FN>
Returns true if the specified coordinates are inside the scrollbar slider.
This function is useful to start dragging the scrollbar slider.
<TABLE>
<R> <H>Parameter</H> <H>Description</H> </R>
<R> <C><FC>X<FN></C> <C>Horizontal coordinate.</C> </R>
<R> <C><FC>Y<FN></C> <C>Vertical coordinate.</C> </R>
</TABLE>
<FM>See Also<FN>
- <A TIEAnimation.MoveScrollbarSliderTo>
!!}
function TIEAnimation.IsInsideScrollbarSlider(X, Y: integer): boolean;
begin
result := IEPointInRect(X, Y,
m_lastScrollbarSlideRect.x,
m_lastScrollbarSlideRect.y,
m_lastScrollbarSlideRect.x + m_lastScrollbarSlideRect.width,
m_lastScrollbarSlideRect.y + m_lastScrollbarSlideRect.height);
end;
{!!
<FS>TIEAnimation.IsInsideScrollbar
<FM>Declaration<FC>
function IsInsideScrollbar(X, Y: integer): boolean;
<FM>Description<FN>
Returns true if the specified coordinates are inside the scrollbar.
<TABLE>
<R> <H>Parameter</H> <H>Description</H> </R>
<R> <C><FC>X<FN></C> <C>Horizontal coordinate.</C> </R>
<R> <C><FC>Y<FN></C> <C>Vertical coordinate.</C> </R>
</TABLE>
!!}
function TIEAnimation.IsInsideScrollbar(X, Y: integer): boolean;
begin
result := IEPointInRect(X, Y,
m_lastScrollbarBoundRect.x,
m_lastScrollbarBoundRect.y,
m_lastScrollbarBoundRect.x + m_lastScrollbarBoundRect.width,
m_lastScrollbarBoundRect.y + m_lastScrollbarBoundRect.height);
end;
{!!
<FS>TIEAnimation.SetStartEndValues
<FM>Declaration<FC>
procedure SetStartEndValues();
<FM>Description<FN>
This method just calls <A TIEAnimation.SetStartValues> and <A TIEAnimation.SetEndValues>.
!!}
procedure TIEAnimation.SetStartEndValues();
begin
SetStartValues();
SetEndValues();
end;
{!!
<FS>TIEAnimation.CurrentImage
<FM>Declaration<FC>
property CurrentImage: integer;
<FM>Description<FN>
Specifies current image index. Current image is often the most visible or the central image.
!!}
procedure TIEAnimation.SetCurrentImage(value: integer);
begin
if (value <> m_currentImage) then
begin
m_currentImage := imin(imax(0, value), length(m_images)-1);
SetStartEndValues();
end;
end;
{!!
<FS>TIEAnimation.ViewWidth
<FM>Declaration<FC>
property ViewWidth: integer;
<FM>Description<FN>
Specifies the width of area reserved for the animation.
<FM>See Also<FN>
- <A TIEAnimation.ViewHeight>
<FM>Example<FC>
animation.ViewWidth := ImageEnView.IEBitmap.Width;
animation.ViewHeight := ImageEnView.IEBitmap.Height;
!!}
procedure TIEAnimation.SetViewWidth(value: integer);
begin
if (value <> m_viewWidth) and (value > 0) then
begin
m_viewWidth := value;
SetStartEndValues();
end;
end;
{!!
<FS>TIEAnimation.ViewHeight
<FM>Declaration<FC>
property ViewHeight: integer;
<FM>Description<FN>
Specifies the height of area reserved for the animation.
<FM>See Also<FN>
- <A TIEAnimation.ViewWidth>
<FM>Example<FC>
animation.ViewWidth := ImageEnView.IEBitmap.Width;
animation.ViewHeight := ImageEnView.IEBitmap.Height;
!!}
procedure TIEAnimation.SetViewHeight(value: integer);
begin
if (value <> m_viewHeight) and (value > 0) then
begin
m_viewHeight := value;
SetStartEndValues();
end;
end;
{!!
<FS>TIEAnimation.Depth
<FM>Declaration<FC>
property Depth: integer;
<FM>Description<FN>
Specifies the 3D projection depth.
Default: 500
!!}
procedure TIEAnimation.SetDepth(value: integer);
begin
if (value <> m_depth) and (value > 0) then
begin
m_depth := value;
SetStartEndValues();
end;
end;
{!!
<FS>TIEAnimation.ShowBorder
<FM>Declaration<FC>
property ShowBorder: boolean;
<FM>Description<FN>
If true a border will be painted around all images.
See also: <A TIEAnimation.BorderPen>.
!!}
procedure TIEAnimation.SetShowBorder(value: boolean);
begin
if (value <> m_showBorder) then
begin
m_showBorder := value;
m_needRefresh := true;
end;
end;
{!!
<FS>TIEAnimation.ShadowAlphaMin
<FM>Declaration<FC>
property ShadowAlphaMin: integer;
<FM>Description<FN>
Specifies the minimum alpha value for the shadow.
Default: 0
!!}
procedure TIEAnimation.SetShadowAlphaMin(value: integer);
begin
if (value <> m_shadowAlphaMin) then
begin
m_shadowAlphaMin := value;
m_needRefresh := true;
end;
end;
{!!
<FS>TIEAnimation.ShadowAlphaMax
<FM>Declaration<FC>
property ShadowAlphaMax: integer;
<FM>Description<FN>
Specifies the maximum alpha value for the shadow.
Default: 40
!!}
procedure TIEAnimation.SetShadowAlphaMax(value: integer);
begin
if (value <> m_shadowAlphaMax) then
begin
m_shadowAlphaMax := value;
m_needRefresh := true;
end;
end;
{!!
<FS>TIEAnimation.ShowScrollbar
<FM>Declaration<FC>
property ShowScrollbar: boolean;
<FM>Description<FN>
If true the scrollbar will be painted.
!!}
procedure TIEAnimation.SetShowScrollbar(value: boolean);
begin
if (value <> m_showScrollbar) then
begin
m_showScrollbar := value;
NeedRefresh := true;
end;
end;
{!!
<FS>TIEAnimation.ShowText
<FM>Declaration<FC>
property ShowText: boolean;
<FM>Description<FN>
Whether the current image text will be painted. Styling of the text is specified using <A TIEAnimation.Font>
!!}
procedure TIEAnimation.SetShowText(value: boolean);
begin
if (value <> m_showText) then
begin
m_showText := value;
NeedRefresh := true;
end;
end;
{!!
<FS>TIEAnimation.DoGetImageInfo
<FM>Declaration<FC>
procedure DoGetImageInfo(imageIndex: integer; isVisible: boolean; var imageWidth: integer; var imageHeight: integer; var text: WideString);
<FM>Description<FN>
Calls the <A TIEAnimationGetImageInfoEvent> event, if assigned on creation. If no event was assigned just calls the <A TIEAnimationGetImageEvent> event.
<TABLE>
<R> <H>Parameter</H> <H>Description</H> </R>
<R> <C><FC>imageIndex<FN></C> <C>Index of the required image info.</C> </R>
<R> <C><FC>isVisible<FN></C> <C>False if the required image may not be visible (hence you can provide estimated values).</C> </R>
<R> <C><FC>imageWidth<FN></C> <C>Return value for image width.</C> </R>
<R> <C><FC>imageHeight<FN></C> <C>Return value for image height</C> </R>
<R> <C><FC>text<FN></C> <C>Return value for image textual info (ie a filename).</C> </R>
</TABLE>
!!}
procedure TIEAnimation.DoGetImageInfo(imageIndex: integer; isVisible: boolean; var imageWidth: integer; var imageHeight: integer; var text: WideString);
var
image: TIEBitmap;
begin
if assigned(m_getImageInfo) then
m_getImageInfo(self, imageindex, isVisible, imageWidth, imageHeight, text)
else
begin
DoGetImage(imageIndex, image, text);
imageWidth := image.Width;
imageHeight := image.Height;
DoReleaseImage(imageIndex, image);
end;
end;
{!!
<FS>TIEAnimation.DoGetImage
<FM>Declaration<FC>
procedure DoGetImage(imageIndex: integer; var image: <A TIEBitmap>; var text: WideString);
<FM>Description<FN>
Calls the <A TIEAnimationGetImageEvent> event, assigned on creation.
<TABLE>
<R> <H>Parameter</H> <H>Description</H> </R>
<R> <C><FC>imageIndex<FN></C> <C>Index of the required image.</C> </R>
<R> <C><FC>image<FN></C> <C>Return value for image bitmap.</C> </R>
<R> <C><FC>text<FN></C> <C>Return value for image textual info (ie a filename).</C> </R>
</TABLE>
!!}
procedure TIEAnimation.DoGetImage(imageIndex: integer; var image: TIEBitmap; var text: WideString);
begin
if assigned(m_getImage) then
m_getImage(self, imageIndex, image, text)
else
raise EIEException.Create('GetImageEvent not assigned');
end;
{!!
<FS>TIEAnimation.DoReleaseImage
<FM>Declaration<FC>
procedure DoReleaseImage(imageIndex: integer; var image: TIEBitmap);
<FM>Description<FN>
Calls the <A TIEAnimationReleaseImageEvent> event, if assigned on creation.
<TABLE>
<R> <H>Parameter</H> <H>Description</H> </R>
<R> <C><FC>imageIndex<FN></C> <C>Index of the image to release.</C> </R>
<R> <C><FC>image<FN></C> <C>The bitmap to release.</C> </R>
</TABLE>
!!}
procedure TIEAnimation.DoReleaseImage(imageIndex: integer; var image: TIEBitmap);
begin
if assigned(m_releaseImage) then
m_releaseImage(self, imageIndex, image);
end;
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
// TIEHorizontalFlow
constructor TIEHorizontalFlow.Create();
begin
// default values for properties
m_horizontalDistance := 80;
m_imagesHorizontalPercentage := 40;
m_imagesVerticalPercentage := 80;
m_rotateAngle := 40;
m_imagesZoom := 0.7;
m_currentImageZoom := 1.0;
inherited;
end;
destructor TIEHorizontalFlow.Destroy();
begin
inherited;
end;
procedure TIEHorizontalFlow.SetInitialValues(first, last: integer);
var
i: integer;
begin
inherited;
for i := first to last do
begin
Images[i].startAlpha := 0;
Images[i].startAngleX := 0.0;
Images[i].startAngleY := m_rotateAngle;
Images[i].startCenterX := ViewWidth div 2 + i * m_horizontalDistance;
Images[i].startCenterY := trunc(ViewHeight * m_imagesVerticalPercentage / 100);
Images[i].startWidth := 0;
Images[i].startHeight := 0;
end;
end;
procedure TIEHorizontalFlow.SetStartValues();
begin
inherited;
end;
procedure TIEHorizontalFlow.SetEndValues();
var
i: integer;
viewCenterX: integer;
width, height, imWidth, imHeight, w, h: integer;
filename: WideString;
isVis: boolean;
endx: integer;
begin
inherited;
if ImageCount > 0 then
begin
viewCenterX := ViewWidth div 2;
width := trunc(ViewWidth * m_imagesHorizontalPercentage / 100);
height := trunc(ViewHeight * m_imagesVerticalPercentage / 100);
// images on the left
for i := 0 to CurrentImage-1 do
begin
endx := viewCenterX - ((CurrentImage-i) * m_horizontalDistance) - width div 2;
isVis := endx + m_horizontalDistance >= 0;
DoGetImageInfo(i, isVis, imWidth, imHeight, filename);
IEGetFitResampleSize(imWidth, imHeight, width, height, w, h);
w := trunc(w * m_imagesZoom);
h := trunc(h * m_imagesZoom);
Images[i].endAlpha := 255;
Images[i].endAngleX := 0.0;
Images[i].endAngleY := -m_rotateAngle;
Images[i].endCenterX := endx;
Images[i].endCenterY := height - h div 2;
Images[i].endWidth := w;
Images[i].endheight := h;
end;
// images on the right
for i := CurrentImage+1 to ImageCount-1 do
begin
endx := viewCenterX + ((i-CurrentImage) * m_horizontalDistance) + width div 2;
isVis := endx - m_horizontalDistance <= ViewWidth;
DoGetImageInfo(i, isVis, imWidth, imHeight, filename);
IEGetFitResampleSize(imWidth, imHeight, width, height, w, h);
w := trunc(w * m_imagesZoom);
h := trunc(h * m_imagesZoom);
Images[i].endAlpha := 255;
Images[i].endAngleX := 0.0;
Images[i].endAngleY := m_rotateAngle;
Images[i].endCenterX := endx;
Images[i].endCenterY := height - h div 2;
Images[i].endWidth := w;
Images[i].endheight := h;
end;
// image at the center (CurrentImage)
DoGetImageInfo(CurrentImage, true, imWidth, imHeight, filename);
IEGetFitResampleSize(imWidth, imHeight, width, height, w, h);
w := trunc(w * m_currentImageZoom);
h := trunc(h * m_currentImageZoom);
Images[CurrentImage].endAlpha := 255;
Images[CurrentImage].endAngleX := 0.0;
Images[CurrentImage].endAngleY := 0.0;
Images[CurrentImage].endCenterX := ViewCenterX;
Images[CurrentImage].endCenterY := height - h div 2;
Images[CurrentImage].endWidth := w;
Images[CurrentImage].endHeight := h;
end;
end;
type TIEHorizontalFlowThreadSide = (iecfLEFT, iecfRIGHT);
type TIEHorizontalFlowThread = class(TIEExecutor)
private
m_horizontalflow: TIEHorizontalFlow;
m_side: TIEHorizontalFlowThreadSide;
m_needrefresh: boolean;
m_dest: TIEBitmap;
public
procedure Execute; override;
constructor Create(horizontalflow: TIEHorizontalFlow; side: TIEHorizontalFlowThreadSide; dest: TIEBitmap);
end;
constructor TIEHorizontalFlowThread.Create(horizontalflow: TIEHorizontalFlow; side: TIEHorizontalFlowThreadSide; dest: TIEBitmap);
begin
inherited Create(true);
m_horizontalflow := horizontalflow;
m_side := side;
m_needrefresh := false;
m_dest := dest;
end;
procedure TIEHorizontalFlowThread.Execute;
var
i: integer;
begin
if m_side = iecfLEFT then
begin
// images on the left
for i := 0 to m_horizontalflow.CurrentImage-1 do
m_needRefresh := m_horizontalflow.drawImage(m_dest, i) or m_needRefresh;
end
else
begin
// images on the right
for i := m_horizontalflow.ImageCount-1 downto m_horizontalflow.CurrentImage+1 do
m_needRefresh := m_horizontalflow.drawImage(m_dest, i) or m_needRefresh;
end;
end;
procedure TIEHorizontalFlow.Display(dest: TIEBitmap);
var
threads: TIEThreadPool;
begin
NeedRefresh := false;
if ImageCount > 0 then
begin
threads := TIEThreadPool.Create();
threads.Add( TIEHorizontalFlowThread.Create(self, iecfLEFT, dest) );
threads.Add( TIEHorizontalFlowThread.Create(self, iecfRIGHT, dest) );
threads.WaitFor();
NeedRefresh := (threads[0] as TIEHorizontalFlowThread).m_needrefresh or (threads[1] as TIEHorizontalFlowThread).m_needrefresh;
threads.Free();
// central image
NeedRefresh := drawImage(dest, CurrentImage) or NeedRefresh;
// draw filename of central image
PaintText(ViewHeight div 2 + trunc(ViewHeight * m_imagesVerticalPercentage / 100) div 2, dest);
// draw scrollbar
PaintScrollBar(dest);
end;
end;
{!!
<FS>TIEHorizontalFlow.HorizontalDistance
<FM>Declaration<FC>
property HorizontalDistance: integer;
<FM>Description<FN>
Specifies the horizontal distance among images, in pixels.
Default: 80
!!}
procedure TIEHorizontalFlow.SetHorizontalDistance(value: integer);
begin
if (value <> m_horizontalDistance) and (value > 0) then
begin
m_horizontalDistance := value;
SetStartEndValues();
end;
end;
{!!
<FS>TIEHorizontalFlow.ImagesHorizontalPercentage
<FM>Declaration<FC>
property ImagesHorizontalPercentage: double;
<FM>Description<FN>
Specifies the percentage (1..100) of view-width used by a single image.
Default: 40
!!}
procedure TIEHorizontalFlow.SetImagesHorizontalPercentage(value: double);
begin
if (value <> m_imagesHorizontalPercentage) and (value > 0) then
begin
m_imagesHorizontalPercentage := value;
SetStartEndValues();
end;
end;
{!!
<FS>TIEHorizontalFlow.ImagesVerticalPercentage
<FM>Declaration<FC>
property ImagesVerticalPercentage: double;
<FM>Description<FN>
Specifies the percentage (1..100) of view-height used by a single image.
Default: 80
!!}
procedure TIEHorizontalFlow.SetImagesVerticalPercentage(value: double);
begin
if (value <> m_imagesVerticalPercentage) and (value > 0) then
begin
m_imagesVerticalPercentage := value;
SetStartEndValues();
end;
end;
{!!
<FS>TIEHorizontalFlow.RotateAngle
<FM>Declaration<FC>
property RotateAngle: double;
<FM>Description<FN>
Specifies the rotation in degrees (0..359) of the non-central images.
Default: 40 degrees
!!}
procedure TIEHorizontalFlow.SetRotateAngle(value: double);
begin
if (value <> m_rotateAngle) then
begin
m_rotateAngle := value;
SetStartEndValues();
end;
end;
{!!
<FS>TIEHorizontalFlow.ImagesZoom
<FM>Declaration<FC>
property ImagesZoom: double;
<FM>Description<FN>
Specifies the zoom (0..1) for non-central images.
Default: 0.7
!!}
procedure TIEHorizontalFlow.SetImagesZoom(value: double);
begin
if (value <> m_imagesZoom) then
begin
m_imagesZoom := value;
SetStartEndValues();
end;
end;
{!!
<FS>TIEHorizontalFlow.CurrentImageZoom
<FM>Declaration<FC>
property CurrentImageZoom: double;
<FM>Description<FN>
Specifies the zoom (0..1) for central image.
Default: 1.0
!!}
procedure TIEHorizontalFlow.SetCurrentImageZoom(value: double);
begin
if (value <> m_currentImageZoom) then
begin
m_currentImageZoom := value;
SetStartEndValues();
end;
end;
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
// TIECircularFlow
constructor TIECircularFlow.Create();
begin
// default parameters
m_imagesSizePercentage := 40;
m_imagesZoom := 0.2;
m_currentImageZoom := 1.0;
m_visibleImages := 15;
m_ellipseAngle := 0;
inherited;
end;
destructor TIECircularFlow.Destroy();
begin
inherited;
end;
procedure TIECircularFlow.SetInitialValues(first, last: integer);
var
i: integer;
begin
inherited;
for i := first to last do
begin
Images[i].startAlpha := 0;
Images[i].startAngleX := 0.0;
Images[i].startAngleY := 0.0;
Images[i].startCenterX := ViewWidth div 2;
Images[i].startCenterY := ViewHeight div 2;
Images[i].startWidth := 0;
Images[i].startHeight := 0;
end;
end;
procedure TIECircularFlow.SetStartValues();
var
i: integer;
begin
inherited;
for i := 0 to ImageCount-1 do
begin
Images[i].startAlpha := Images[i].lastAlpha;
Images[i].startAngleX := 0.0;
Images[i].startAngleY := Images[i].lastAngleY;
Images[i].startCenterX := Images[i].lastCenterX;
Images[i].startCenterY := Images[i].lastCenterY;
Images[i].startWidth := Images[i].lastWidth;
Images[i].startHeight := Images[i].lastHeight;
end;
end;
procedure TIECircularFlow.SetEndValues();
var
i, a, iindex: integer;
viewCenterX, viewCenterY: integer;
alpha, beta, sinbeta, cosbeta, sinalpha, cosalpha: double;
ellipseX, ellipseY: integer;
x, y: integer;
width, height, imWidth, imHeight, w, h: integer;
filename: WideString;
steps: integer;
m_ellipseRatio: double;
semimaj, semimin: double;
begin
inherited;
if ImageCount > 0 then
begin
m_ellipseRatio := 0.7;
viewCenterX := ViewWidth div 2;
viewCenterY := ViewHeight div 2;
width := trunc(ViewWidth * m_imagesSizePercentage / 100);
height := trunc(ViewHeight * m_imagesSizePercentage / 100);
steps := imin(ImageCount, m_visibleImages);
semimaj := m_ellipseRatio * imin(ViewWidth-width, ViewHeight-height);
semimin := (1.0-m_ellipseRatio) * imin(ViewWidth-width, ViewHeight-height);
for i := 0 to ImageCount-1 do
begin
Images[i].endAlpha := 0;
Images[i].endAngleX := 0.0;
Images[i].endAngleY := 0.0;
Images[i].endCenterX := viewCenterX;
Images[i].endCenterY := viewCenterY;
Images[i].endWidth := 0;
Images[i].endheight := 0;
end;
// build ellipse points
ellipseX := viewCenterX;
ellipseY := viewCenterY;
beta := -m_ellipseAngle * (PI / 180);
sinbeta := sin(beta);
cosbeta := cos(beta);
a := 90;
iindex := CurrentImage;
for i := 0 to STEPS-1 do
begin
alpha := a * (PI / 180) ;
sinalpha := sin(alpha);
cosalpha := cos(alpha);
x := round( ellipseX + (semimaj * cosalpha * cosbeta - semimin * sinalpha * sinbeta) );
y := round( ellipseY + (semimaj * cosalpha * sinbeta + semimin * sinalpha * cosbeta) );
DoGetImageInfo(iindex, true, imWidth, imHeight, filename);
IEGetFitResampleSize(imWidth, imHeight, width, height, w, h);
if (iindex <> CurrentImage) then
begin
w := trunc(w * m_imagesZoom);
h := trunc(h * m_imagesZoom);
Images[iindex].endAlpha := 255;
Images[iindex].endAngleX := 0.0;
Images[iindex].endAngleY := 0.0;
Images[iindex].endCenterX := x;
Images[iindex].endCenterY := y;
Images[iindex].endWidth := round(w * (1.5+sinalpha));
Images[iindex].endheight := round(h * (1.5+sinalpha));
end
else
begin
w := trunc(w * m_currentImageZoom);
h := trunc(h * m_currentImageZoom);
Images[CurrentImage].endAlpha := 255;
Images[CurrentImage].endAngleX := 0.0;
Images[CurrentImage].endAngleY := 0.0;
Images[CurrentImage].endCenterX := viewCenterX;
Images[CurrentImage].endCenterY := y - h div 4;
Images[CurrentImage].endWidth := w;
Images[CurrentImage].endheight := h;
end;
dec(a, 360 div STEPS);
inc(iindex);
if iindex >= ImageCount then
iindex := 0;
end;
end;
end;
procedure TIECircularFlow.Display(dest: TIEBitmap);
var
i: integer;
begin
NeedRefresh := false;
if ImageCount > 0 then
begin
for i := ImageCount-1 downto 0 do
begin
if i <> CurrentImage then
NeedRefresh := drawImage(dest, i) or NeedRefresh;
end;
// central image
NeedRefresh := drawImage(dest, CurrentImage) or NeedRefresh;
// draw filename of central image
//PaintText(ViewHeight div 2 - 50, dest);
PaintText(ViewHeight div 2 + trunc(ViewHeight * m_imagesSizePercentage / 100), dest);
// draw scrollbar
PaintScrollBar(dest);
end;
end;
{!!
<FS>TIECircularFlow.ImagesSizePercentage
<FM>Declaration<FC>
property ImagesSizePercentage: double;
<FM>Description<FN>
Specifies the percentage (1..100) of view size used for images.
Default: 40
!!}
procedure TIECircularFlow.SetImagesSizePercentage(value: double);
begin
if (value <> m_imagesSizePercentage) and (value > 0) then
begin
m_imagesSizePercentage := value;
SetStartEndValues();
end;
end;
{!!
<FS>TIECircularFlow.ImagesZoom
<FM>Declaration<FC>
property ImagesZoom: double;
<FM>Description<FN>
Specifies the zoom (0..1) for non-central images.
Default: 0.2
!!}
procedure TIECircularFlow.SetImagesZoom(value: double);
begin
if (value <> m_imagesZoom) then
begin
m_imagesZoom := value;
SetStartEndValues();
end;
end;
{!!
<FS>TIECircularFlow.CurrentImageZoom
<FM>Declaration<FC>
property CurrentImageZoom: double;
<FM>Description<FN>
Specifies the zoom (0..1) for central image.
Default: 1.0
!!}
procedure TIECircularFlow.SetCurrentImageZoom(value: double);
begin
if (value <> m_currentImageZoom) then
begin
m_currentImageZoom := value;
SetStartEndValues();
end;
end;
{!!
<FS>TIECircularFlow.VisibleImages
<FM>Declaration<FC>
property VisibleImages: integer;
<FM>Description<FN>
Specifies the number of visible images.
Default: 15
!!}
procedure TIECircularFlow.SetVisibleImages(value: integer);
begin
if (value <> m_visibleImages) then
begin
m_visibleImages := value;
SetStartEndValues();
end;
end;
{!!
<FS>TIECircularFlow.EllipseAngle
<FM>Declaration<FC>
property EllipseAngle: double;
<FM>Description<FN>
Specifies the ellipse (the curve where images are placed) angle in degrees.
Default: 0 degrees
!!}
procedure TIECircularFlow.SetEllipseAngle(value: double);
begin
if (value <> m_ellipseAngle) then
begin
m_ellipseAngle := value;
SetStartEndValues();
end;
end;
end.