mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-27 10:14:03 +02:00
221 lines
5.6 KiB
ObjectPascal
221 lines
5.6 KiB
ObjectPascal
{
|
|
|
|
*****************************************************************************
|
|
See the file COPYING.modifiedLGPL.txt, included in this distribution,
|
|
for details about the license.
|
|
*****************************************************************************
|
|
|
|
Authors: Alexander Klenin
|
|
|
|
}
|
|
|
|
unit TAAnimatedSource;
|
|
|
|
{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, CustomTimer,
|
|
TAChartUtils, TACustomSource;
|
|
|
|
type
|
|
TCustomAnimatedChartSource = class;
|
|
|
|
TAnimatedChartSourceItemEvent = procedure (
|
|
ASender: TCustomAnimatedChartSource;
|
|
AIndex: Integer; var AItem: TChartDataItem) of object;
|
|
TAnimatedChartSourceEvent = procedure (
|
|
ASender: TCustomAnimatedChartSource) of object;
|
|
|
|
TCustomAnimatedChartSource = class(TCustomChartSource)
|
|
strict private
|
|
FAnimationInterval: Cardinal;
|
|
FAnimationTime: Cardinal;
|
|
FCurrentStep: Cardinal;
|
|
FItem: TChartDataItem;
|
|
FListener: TListener;
|
|
FOnGetItem: TAnimatedChartSourceItemEvent;
|
|
FOnStop: TAnimatedChartSourceEvent;
|
|
FOrigin: TCustomChartSource;
|
|
FProjectedSteps: Cardinal;
|
|
FSkippedFramesCount: Cardinal;
|
|
FStartTime: Cardinal;
|
|
FTimer: TCustomTimer;
|
|
procedure Changed(ASender: TObject);
|
|
procedure OnTimer(ASender: TObject);
|
|
procedure SetOrigin(AValue: TCustomChartSource);
|
|
protected
|
|
function GetCount: Integer; override;
|
|
function GetItem(AIndex: Integer): PChartDataItem; override;
|
|
procedure SetYCount(AValue: Cardinal); override;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
|
|
function Extent: TDoubleRect; override;
|
|
function ExtentCumulative: TDoubleRect; override;
|
|
function ExtentList: TDoubleRect; override;
|
|
|
|
function IsAnimating: Boolean; inline;
|
|
function Progress: Double; inline;
|
|
procedure Start;
|
|
procedure Stop(ACallEvent: Boolean = false);
|
|
|
|
property CurrentStep: Cardinal read FCurrentStep;
|
|
property ProjectedSteps: Cardinal read FProjectedSteps;
|
|
property SkippedFramesCount: Cardinal read FSkippedFramesCount;
|
|
published
|
|
property AnimationInterval: Cardinal
|
|
read FAnimationInterval write FAnimationInterval default 0;
|
|
property AnimationTime: Cardinal
|
|
read FAnimationTime write FAnimationTime default 0;
|
|
property Origin: TCustomChartSource read FOrigin write SetOrigin;
|
|
published
|
|
property OnGetItem: TAnimatedChartSourceItemEvent
|
|
read FOnGetItem write FOnGetItem;
|
|
property OnStop: TAnimatedChartSourceEvent read FOnStop write FOnStop;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
LCLIntf, Math, SysUtils;
|
|
|
|
{ TCustomAnimatedChartSource }
|
|
|
|
procedure TCustomAnimatedChartSource.Changed(ASender: TObject);
|
|
begin
|
|
Unused(ASender);
|
|
Notify;
|
|
end;
|
|
|
|
constructor TCustomAnimatedChartSource.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
FListener := TListener.Create(@FOrigin, @Changed);
|
|
FTimer := TCustomTimer.Create(nil);
|
|
FTimer.Enabled := false;
|
|
FTimer.OnTimer := @OnTimer;
|
|
end;
|
|
|
|
destructor TCustomAnimatedChartSource.Destroy;
|
|
begin
|
|
FreeAndNil(FTimer);
|
|
FreeAndNil(FListener);
|
|
inherited;
|
|
end;
|
|
|
|
function TCustomAnimatedChartSource.Extent: TDoubleRect;
|
|
begin
|
|
if Origin = nil then
|
|
Result := EmptyExtent
|
|
else
|
|
Result := Origin.Extent;
|
|
end;
|
|
|
|
function TCustomAnimatedChartSource.ExtentCumulative: TDoubleRect;
|
|
begin
|
|
if Origin = nil then
|
|
Result := EmptyExtent
|
|
else
|
|
Result := Origin.ExtentCumulative;
|
|
end;
|
|
|
|
function TCustomAnimatedChartSource.ExtentList: TDoubleRect;
|
|
begin
|
|
if Origin = nil then
|
|
Result := EmptyExtent
|
|
else
|
|
Result := Origin.ExtentList;
|
|
end;
|
|
|
|
function TCustomAnimatedChartSource.GetCount: Integer;
|
|
begin
|
|
if Origin = nil then
|
|
Result := 0
|
|
else
|
|
Result := Origin.Count;
|
|
end;
|
|
|
|
function TCustomAnimatedChartSource.GetItem(AIndex: Integer): PChartDataItem;
|
|
begin
|
|
if Origin = nil then exit(nil);
|
|
if not IsAnimating then exit(Origin.Item[AIndex]);
|
|
FItem := Origin.Item[AIndex]^;
|
|
Result := @FItem;
|
|
if Assigned(OnGetItem) then
|
|
OnGetItem(Self, AIndex, FItem);
|
|
end;
|
|
|
|
function TCustomAnimatedChartSource.IsAnimating: Boolean;
|
|
begin
|
|
Result := FTimer.Enabled;
|
|
end;
|
|
|
|
procedure TCustomAnimatedChartSource.OnTimer(ASender: TObject);
|
|
var
|
|
d, s: Cardinal;
|
|
begin
|
|
Unused(ASender);
|
|
d := GetTickCount - FStartTime;
|
|
if d >= AnimationTime then
|
|
Stop(true);
|
|
s := Round(d * ProjectedSteps / AnimationTime);
|
|
if FCurrentStep + 1 <> s then
|
|
FSkippedFramesCount += 1;
|
|
FCurrentStep := s;
|
|
Notify;
|
|
end;
|
|
|
|
function TCustomAnimatedChartSource.Progress: Double;
|
|
begin
|
|
if ProjectedSteps = 0 then
|
|
Result := 0
|
|
else
|
|
Result := (FCurrentStep - 1) / ProjectedSteps;
|
|
end;
|
|
|
|
procedure TCustomAnimatedChartSource.SetOrigin(AValue: TCustomChartSource);
|
|
begin
|
|
if AValue = Self then
|
|
AValue := nil;
|
|
if FOrigin = AValue then exit;
|
|
if FOrigin <> nil then
|
|
FOrigin.Broadcaster.Unsubscribe(FListener);
|
|
FOrigin := AValue;
|
|
if FOrigin <> nil then
|
|
FOrigin.Broadcaster.Subscribe(FListener);
|
|
end;
|
|
|
|
procedure TCustomAnimatedChartSource.SetYCount(AValue: Cardinal);
|
|
begin
|
|
Unused(AValue);
|
|
raise EYCountError.Create('Can not set YCount');
|
|
end;
|
|
|
|
procedure TCustomAnimatedChartSource.Start;
|
|
begin
|
|
Stop;
|
|
FSkippedFramesCount := 0;
|
|
if (AnimationInterval = 0) or (AnimationTime <= AnimationInterval) then exit;
|
|
FProjectedSteps := Round(AnimationTime / AnimationInterval);
|
|
FStartTime := GetTickCount;
|
|
FTimer.Interval := AnimationInterval;
|
|
FTimer.Enabled := true;
|
|
end;
|
|
|
|
procedure TCustomAnimatedChartSource.Stop(ACallEvent: Boolean);
|
|
begin
|
|
FTimer.Enabled := false;
|
|
FCurrentStep := 0;
|
|
if ACallEvent and Assigned(OnStop) then
|
|
OnStop(Self);
|
|
end;
|
|
|
|
initialization
|
|
if ZeroValue = 0 then; // Workaround for an incorrect "unused unit" hint.
|
|
|
|
end.
|
|
|