diff --git a/AuraTrader/AuraTrader.dpr b/AuraTrader/AuraTrader.dpr
index 7cf3b33..5d16e48 100644
--- a/AuraTrader/AuraTrader.dpr
+++ b/AuraTrader/AuraTrader.dpr
@@ -11,7 +11,6 @@ uses
TestModule in 'TestModule.pas',
DynamicFMXControl in 'DynamicFMXControl.pas',
FirstStrategy in 'FirstStrategy.pas',
- Myc.Fmx.Chart in 'Myc.Fmx.Chart.pas',
Myc.Trade.DataArray in '..\Src\Myc.Trade.DataArray.pas',
Myc.FMX.Chart.Series in '..\Src\Myc.FMX.Chart.Series.pas';
diff --git a/AuraTrader/AuraTrader.dproj b/AuraTrader/AuraTrader.dproj
index 236e6a0..eca116a 100644
--- a/AuraTrader/AuraTrader.dproj
+++ b/AuraTrader/AuraTrader.dproj
@@ -139,7 +139,6 @@
-
diff --git a/Src/Myc.Core.Lazy.pas b/Src/Myc.Core.Lazy.pas
index aa297bf..89c57c2 100644
--- a/Src/Myc.Core.Lazy.pas
+++ b/Src/Myc.Core.Lazy.pas
@@ -12,8 +12,11 @@ uses
type
TMycNullMutable = class(TInterfacedObject, TMutable.IMutable)
private
+ FValue: T;
function GetChanged: TSignal;
function GetValue: T;
+ public
+ constructor Create(AValue: T);
end;
TMycMutableBase = class(TInterfacedObject, TMutable.IMutable)
@@ -50,35 +53,6 @@ type
procedure SetValue(const Value: T);
end;
- TMycNullLazy = class(TInterfacedObject, TLazy.ILazy)
- protected
- function GetChanged: TState;
- public
- function Pop(out Res: T): Boolean;
- end;
-
- TMycLazyBase = class(TInterfacedObject, TLazy.ILazy)
- strict private
- FChanged: TFlag;
- FChangeState: TSignal.TSubscription;
- function GetChanged: TState;
- protected
- function GetValue: T; virtual; abstract;
- public
- constructor Create(const AChanged: TSignal);
- destructor Destroy; override;
- function Pop(out Res: T): Boolean;
- end;
-
- TMycFuncLazy = class(TMycLazyBase)
- private
- FProc: TFunc;
- protected
- function GetValue: T; override;
- public
- constructor Create(const AChanged: TSignal.ISignal; const AProc: TFunc);
- end;
-
TMycProtectedMutable = class(TInterfacedObject, TMutable.IMutable, TWriteable.IWriteable)
private
FWriteable: TWriteable.IWriteable;
@@ -97,6 +71,12 @@ implementation
uses
System.Generics.Defaults;
+constructor TMycNullMutable.Create(AValue: T);
+begin
+ inherited Create;
+ FValue := AValue;
+end;
+
{ TMycNullMutable }
function TMycNullMutable.GetChanged: TSignal;
@@ -106,7 +86,7 @@ end;
function TMycNullMutable.GetValue: T;
begin
- Result := Default(T);
+ Result := FValue;
end;
{ TMycMutableBase }
@@ -163,64 +143,6 @@ begin
end;
end;
-{ TMycNullLazy }
-
-function TMycNullLazy.GetChanged: TState;
-begin
- Result := TState.Null;
-end;
-
-function TMycNullLazy.Pop(out Res: T): Boolean;
-begin
- Res := Default(T);
- Result := true;
-end;
-
-{ TMycLazyBase }
-
-constructor TMycLazyBase.Create(const AChanged: TSignal);
-begin
- inherited Create;
- FChanged := TFlag.CreateFlag;
- FChanged.Notify;
- FChangeState := AChanged.Subscribe(FChanged);
-end;
-
-destructor TMycLazyBase.Destroy;
-begin
- FChangeState.Unsubscribe;
- inherited;
-end;
-
-function TMycLazyBase.GetChanged: TState;
-begin
- Result := FChanged.State;
-end;
-
-function TMycLazyBase.Pop(out Res: T): Boolean;
-begin
- Result := FChanged.State.IsSet;
- if Result then
- begin
- Res := GetValue;
- FChanged.Reset;
- end;
-end;
-
-{ TMycFuncLazy }
-
-constructor TMycFuncLazy.Create(const AChanged: TSignal.ISignal; const AProc: TFunc);
-begin
- inherited Create(AChanged);
- FProc := AProc;
- Assert(Assigned(FProc));
-end;
-
-function TMycFuncLazy.GetValue: T;
-begin
- Result := FProc();
-end;
-
constructor TMycFuncMutable.Create(const AChanged: TSignal; const AProc: TFunc);
begin
inherited Create(AChanged);
diff --git a/Src/Myc.Fmx.Chart.Series.pas b/Src/Myc.Fmx.Chart.Series.pas
index 23cf722..88fb61e 100644
--- a/Src/Myc.Fmx.Chart.Series.pas
+++ b/Src/Myc.Fmx.Chart.Series.pas
@@ -7,9 +7,10 @@ uses
System.SyncObjs,
System.UITypes,
FMX.Graphics,
+ Myc.Signals,
+ Myc.Lazy,
Myc.Trade.DataArray,
Myc.Trade.DataPoint,
- Myc.Lazy,
Myc.Fmx.Chart;
type
@@ -25,13 +26,13 @@ type
TChartSeriesReceiver = class(TMycProcessor)
strict private
FCurrData: TMycDataArray;
- FLookback: TWriteable;
+ FLookback: TMutable;
private
FData: TWriteable>;
protected
function ProcessData(const Value: T): Boolean; override;
public
- constructor Create(const ALookback: TWriteable);
+ constructor Create(const ALookback: TMutable);
property Data: TWriteable> read FData;
end;
@@ -47,28 +48,46 @@ type
protected
function GetCount: Int64; override;
function GetTotalCount: Int64; override;
- procedure Update; override;
+ procedure Update;
public
- constructor Create(AOwner: TMycChart; const ADataProvider: IMycDataProvider);
+ constructor Create(const ADataProvider: IMycDataProvider; const ALookback: TMutable);
destructor Destroy; override;
property Data: TMycDataArray read FData;
end;
- { TChartOhlcSeries }
- TChartOhlcSeries = class(TChartSeriesProcessor)
+ { TChartCustomLayer }
+ TChartCustomLayer = class(TMycChart.TLayer)
private
- FUpColor: TAlphaColor;
- FDownColor: TAlphaColor;
+ FSeries: TChartSeriesProcessor;
+ protected
+ function GetSeries: TMycChart.TSeries; override;
+ function GetValueRange(First, Last: Int64; out MinValue, MaxValue: Double): Boolean; override;
+ procedure Update; override;
+ procedure Paint(const Canvas: TCanvas; First, Last: Int64; const XForm, YForm: TFunc); override;
+ public
+ constructor Create(AOwner: TMycChart; const ADataProvider: IMycDataProvider);
+ destructor Destroy; override;
+ end;
+
+ { TChartOhlcLayer }
+ TChartOhlcLayer = class(TChartCustomLayer)
+ private
+ FUpColor: TMutable;
+ FDownColor: TMutable;
protected
function GetValueRange(First, Last: Int64; out MinValue, MaxValue: Double): Boolean; override;
procedure Paint(const Canvas: TCanvas; First, Last: Int64; const XForm, YForm: TFunc); override;
public
- constructor Create(AOwner: TMycChart; const ADataProvider: IMycDataProvider; const AUpColor, ADownColor: TAlphaColor);
+ constructor Create(
+ AOwner: TMycChart;
+ const ADataProvider: IMycDataProvider;
+ const AUpColor, ADownColor: TMutable
+ );
end;
- { TChartLineSeries }
- TChartLineSeries = class(TChartSeriesProcessor)
+ { TChartLineLayer }
+ TChartLineLayer = class(TChartCustomLayer)
private
FLineColor: TAlphaColor;
FLineWidth: Single;
@@ -106,7 +125,7 @@ end;
{ TChartSeriesReceiver }
-constructor TChartSeriesReceiver.Create(const ALookback: TWriteable);
+constructor TChartSeriesReceiver.Create(const ALookback: TMutable);
begin
inherited Create;
FLookback := ALookback;
@@ -123,14 +142,14 @@ end;
{ TChartSeriesProcessor }
-constructor TChartSeriesProcessor.Create(AOwner: TMycChart; const ADataProvider: IMycDataProvider);
+constructor TChartSeriesProcessor.Create(const ADataProvider: IMycDataProvider; const ALookback: TMutable);
begin
- inherited Create(AOwner);
+ inherited Create;
+ FDataProvider := ADataProvider;
FLock := TSpinLock.Create(false);
FDataSeries := TMycDataArray.CreateEmpty;
FData := FDataSeries;
- FDataProvider := ADataProvider;
- FReceiver := TChartSeriesReceiver.Create(AOwner.Lookback);
+ FReceiver := TChartSeriesReceiver.Create(ALookback);
FReceiverTag := FDataProvider.Link(FReceiver);
end;
@@ -155,9 +174,9 @@ begin
FData := FReceiver.Data.Value;
end;
-{ TChartLineSeries }
+{ TChartLineLayer }
-constructor TChartLineSeries.Create(
+constructor TChartLineLayer.Create(
AOwner: TMycChart;
const ADataProvider: IMycDataProvider;
const ALineColor: TAlphaColor;
@@ -169,7 +188,7 @@ begin
FLineWidth := ALineWidth;
end;
-function TChartLineSeries.GetValueRange(First, Last: Int64; out MinValue, MaxValue: Double): Boolean;
+function TChartLineLayer.GetValueRange(First, Last: Int64; out MinValue, MaxValue: Double): Boolean;
var
i: Int64;
begin
@@ -177,7 +196,7 @@ begin
MaxValue := -MaxDouble;
for i := First to Last do
begin
- var v := Data.Items[i];
+ var v := FSeries.Data.Items[i];
if not IsNaN(v) then
begin
MinValue := Min(MinValue, v);
@@ -187,7 +206,7 @@ begin
Result := (MinValue <> MaxDouble);
end;
-procedure TChartLineSeries.Paint(const Canvas: TCanvas; First, Last: Int64; const XForm, YForm: TFunc);
+procedure TChartLineLayer.Paint(const Canvas: TCanvas; First, Last: Int64; const XForm, YForm: TFunc);
var
points: TPathData;
i, n: Int64;
@@ -196,15 +215,15 @@ begin
try
// Skip warmup data
n := First;
- while (n <= Last) and (IsNaN(Data[n])) do
+ while (n <= Last) and (IsNaN(FSeries.Data[n])) do
inc(n);
if (n > Last) then
exit;
- points.MoveTo(TPointF.Create(XForm(n), YForm(Data[n])));
+ points.MoveTo(TPointF.Create(XForm(n), YForm(FSeries.Data[n])));
for i := n + 1 to Last do
- if not IsNaN(Data[i]) then
- points.LineTo(TPointF.Create(XForm(i), YForm(Data[i])));
+ if not IsNaN(FSeries.Data[i]) then
+ points.LineTo(TPointF.Create(XForm(i), YForm(FSeries.Data[i])));
Canvas.Stroke.Color := FLineColor;
Canvas.Stroke.Thickness := FLineWidth;
@@ -214,20 +233,23 @@ begin
end;
end;
-{ TChartOhlcSeries }
+{ TChartOhlcLayer }
-constructor TChartOhlcSeries.Create(
+constructor TChartOhlcLayer.Create(
AOwner: TMycChart;
const ADataProvider: IMycDataProvider;
- const AUpColor, ADownColor: TAlphaColor
+ const AUpColor, ADownColor: TMutable
);
begin
inherited Create(AOwner, ADataProvider);
FUpColor := AUpColor;
FDownColor := ADownColor;
+
+ FUpColor.Changed.Subscribe(Owner.NeedRepaint);
+ FDownColor.Changed.Subscribe(Owner.NeedRepaint);
end;
-function TChartOhlcSeries.GetValueRange(First, Last: Int64; out MinValue, MaxValue: Double): Boolean;
+function TChartOhlcLayer.GetValueRange(First, Last: Int64; out MinValue, MaxValue: Double): Boolean;
var
i: Int64;
begin
@@ -236,14 +258,14 @@ begin
for i := First to Last do
begin
- var item := Data.Items[i];
+ var item := FSeries.Data.Items[i];
MinValue := Min(MinValue, item.Low);
MaxValue := Max(MaxValue, item.High);
end;
Result := (MinValue <> MaxDouble);
end;
-procedure TChartOhlcSeries.Paint(const Canvas: TCanvas; First, Last: Int64; const XForm, YForm: TFunc);
+procedure TChartOhlcLayer.Paint(const Canvas: TCanvas; First, Last: Int64; const XForm, YForm: TFunc);
var
i: Int64;
x, candleWidth: Single;
@@ -255,7 +277,7 @@ begin
for i := First to Last do
begin
- item := Data.Items[i];
+ item := FSeries.Data.Items[i];
x := XForm(i);
yOpen := YForm(item.Open);
yClose := YForm(item.Close);
@@ -264,9 +286,9 @@ begin
isUp := item.Close >= item.Open;
if isUp then
- Canvas.Stroke.Color := FUpColor
+ Canvas.Stroke.Color := FUpColor.Value
else
- Canvas.Stroke.Color := FDownColor;
+ Canvas.Stroke.Color := FDownColor.Value;
Canvas.Stroke.Thickness := 1.0;
Canvas.DrawLine(TPointF.Create(x, yHigh), TPointF.Create(x, yLow), 1);
@@ -279,4 +301,38 @@ begin
end;
end;
+{ TChartCustomLayer }
+
+constructor TChartCustomLayer.Create(AOwner: TMycChart; const ADataProvider: IMycDataProvider);
+begin
+ inherited Create(AOwner);
+ FSeries := TChartSeriesProcessor.Create(ADataProvider, AOwner.Lookback.AsMutable);
+end;
+
+destructor TChartCustomLayer.Destroy;
+begin
+ FSeries.Free;
+ inherited;
+end;
+
+function TChartCustomLayer.GetSeries: TMycChart.TSeries;
+begin
+ Result := FSeries;
+end;
+
+function TChartCustomLayer.GetValueRange(First, Last: Int64; out MinValue, MaxValue: Double): Boolean;
+begin
+ Result := false;
+end;
+
+procedure TChartCustomLayer.Paint(const Canvas: TCanvas; First, Last: Int64; const XForm, YForm: TFunc);
+begin
+ // nope
+end;
+
+procedure TChartCustomLayer.Update;
+begin
+ FSeries.Update;
+end;
+
end.
diff --git a/Src/Myc.Fmx.Chart.pas b/Src/Myc.Fmx.Chart.pas
index 83d041b..f286969 100644
--- a/Src/Myc.Fmx.Chart.pas
+++ b/Src/Myc.Fmx.Chart.pas
@@ -16,6 +16,7 @@ uses
FMX.Graphics,
FMX.Forms,
Myc.Trade.DataPoint,
+ Myc.Signals,
Myc.Lazy;
type
@@ -23,27 +24,33 @@ type
public
type
TSeries = class abstract(TObject)
- private
- FOwner: TMycChart;
- function GetMainSeries: TSeries;
protected
function GetCount: Int64; virtual; abstract;
function GetTotalCount: Int64; virtual; abstract;
- procedure Update; virtual; abstract;
- function GetValueRange(StartIndex, Count: Int64; out Min, Max: Double): Boolean; virtual;
- // The signature is changed to support viewport painting with an index offset
- procedure Paint(const Canvas: TCanvas; First, Last: Int64; const XForm, YForm: TFunc); virtual;
- property MainSeries: TSeries read GetMainSeries;
public
- constructor Create(AOwner: TMycChart);
property Count: Int64 read GetCount;
- property Owner: TMycChart read FOwner;
property TotalCount: Int64 read GetTotalCount;
end;
+ TLayer = class abstract(TObject)
+ private
+ FOwner: TMycChart;
+ protected
+ function GetSeries: TSeries; virtual; abstract;
+ procedure Update; virtual; abstract;
+ function GetValueRange(StartIndex, Count: Int64; out Min, Max: Double): Boolean; virtual; abstract;
+ // The signature is changed to support viewport painting with an index offset
+ procedure Paint(const Canvas: TCanvas; First, Last: Int64; const XForm, YForm: TFunc); virtual; abstract;
+ public
+ constructor Create(AOwner: TMycChart);
+ procedure Repaint;
+ property Owner: TMycChart read FOwner;
+ property Series: TSeries read GetSeries;
+ end;
+
private
- FSeriesList: TList;
- FXAxisSeries: TSeries;
+ FSeriesList: TList;
+ FXAxisSeries: TLayer;
FLookback: TWriteable;
FIdleSubscrId: TMessageSubscriptionId;
FViewStartIndex: Int64;
@@ -53,6 +60,7 @@ type
FJumpButtonRect: TRectF;
FJumpButtonHot: Boolean;
FJumpButtonPressed: Boolean;
+ FNeedRepaint: TFlag;
protected
procedure Paint; override;
procedure DoIdle;
@@ -66,7 +74,7 @@ type
// Sets the master series that defines the time scale (X-axis). This series is not drawn.
// The chart will not render any data until the X-axis series is set.
- function SetXAxisSeries(const DataProvider: IMycDataProvider): TSeries;
+ function SetXAxisSeries(const DataProvider: IMycDataProvider): TLayer;
// Creates an OHLC candlestick/bar series and returns it.
// The data provider directly supplies OHLC items, as timestamps are managed by the data series internally.
@@ -74,16 +82,17 @@ type
const DataProvider: IMycDataProvider;
const AUpColor: TAlphaColor = TAlphaColors.Green;
const ADownColor: TAlphaColor = TAlphaColors.Red
- ): TSeries;
+ ): TLayer;
// Creates a simple line series for double values and returns it
function AddDoubleSeries(
const DataProvider: IMycDataProvider;
const ALineColor: TAlphaColor = TAlphaColors.Cornflowerblue;
const ALineWidth: Single = 1.5
- ): TSeries;
+ ): TLayer;
property Lookback: TWriteable read FLookback write FLookback;
+ property NeedRepaint: TFlag read FNeedRepaint;
end;
implementation
@@ -92,33 +101,12 @@ uses
System.Math,
Myc.FMX.Chart.Series;
-constructor TMycChart.TSeries.Create(AOwner: TMycChart);
-begin
- inherited Create;
- FOwner := AOwner;
-end;
-
-function TMycChart.TSeries.GetMainSeries: TSeries;
-begin
- Result := Owner.FXAxisSeries;
-end;
-
-function TMycChart.TSeries.GetValueRange(StartIndex, Count: Int64; out Min, Max: Double): Boolean;
-begin
- Result := false;
-end;
-
-procedure TMycChart.TSeries.Paint(const Canvas: TCanvas; First, Last: Int64; const XForm, YForm: TFunc);
-begin
- // nothing
-end;
-
{ TMycChart }
constructor TMycChart.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
- FSeriesList := TObjectList.Create(true);
+ FSeriesList := TObjectList.Create(true);
FXAxisSeries := nil;
FLookback := TWriteable.CreateWriteable(1000); // Load more data for panning
@@ -141,7 +129,7 @@ begin
inherited;
end;
-function TMycChart.SetXAxisSeries(const DataProvider: IMycDataProvider): TSeries;
+function TMycChart.SetXAxisSeries(const DataProvider: IMycDataProvider): TLayer;
begin
// Free the old one if it exists, and create the new master series
FXAxisSeries.Free;
@@ -150,7 +138,7 @@ begin
DataProvider.Link(counter);
- FXAxisSeries := TChartSeriesProcessor.Create(Self, counter.Sender);
+ FXAxisSeries := TChartCustomLayer.Create(Self, counter.Sender);
Result := FXAxisSeries;
end;
@@ -158,9 +146,9 @@ function TMycChart.AddDoubleSeries(
const DataProvider: IMycDataProvider;
const ALineColor: TAlphaColor = TAlphaColors.Cornflowerblue;
const ALineWidth: Single = 1.5
-): TSeries;
+): TLayer;
begin
- Result := TChartLineSeries.Create(Self, DataProvider, ALineColor, ALineWidth);
+ Result := TChartLineLayer.Create(Self, DataProvider, ALineColor, ALineWidth);
FSeriesList.Add(Result);
end;
@@ -168,9 +156,10 @@ function TMycChart.AddOhlcSeries(
const DataProvider: IMycDataProvider;
const AUpColor: TAlphaColor = TAlphaColors.Green;
const ADownColor: TAlphaColor = TAlphaColors.Red
-): TSeries;
+): TLayer;
begin
- Result := TChartOhlcSeries.Create(Self, DataProvider, AUpColor, ADownColor);
+ Result :=
+ TChartOhlcLayer.Create(Self, DataProvider, TMutable.Constant(AUpColor), TMutable.Constant(ADownColor));
FSeriesList.Add(Result);
end;
@@ -181,11 +170,11 @@ begin
exit;
// First update the master series
- var prevTotalCount := FXAxisSeries.TotalCount;
+ var prevTotalCount := FXAxisSeries.Series.TotalCount;
FXAxisSeries.Update;
// Check if the master series itself has changed
- var newTotalCount := FXAxisSeries.TotalCount;
+ var newTotalCount := FXAxisSeries.Series.TotalCount;
var seriesChanged := prevTotalCount <> newTotalCount;
// Repaint if the last bar is visible, so we display live data
@@ -193,7 +182,7 @@ begin
for var series in FSeriesList do
begin
- var seriesCount := series.TotalCount;
+ var seriesCount := series.Series.TotalCount;
// Check if this series may need a repaint (if it lags behind the master series and these lags are currently visible)
if FViewStartIndex <= prevTotalCount - seriesCount then
@@ -202,7 +191,7 @@ begin
// Update the series
series.Update;
- if seriesCount <> series.TotalCount then
+ if seriesCount <> series.Series.TotalCount then
seriesChanged := true;
end;
@@ -220,7 +209,10 @@ begin
end;
end;
- if seriesRepaint and seriesChanged then
+ // finally, check the repaint signal
+ var repaintSignal := FNeedRepaint.Reset;
+
+ if repaintSignal or (seriesRepaint and seriesChanged) then
Repaint;
end;
@@ -269,7 +261,6 @@ var
isHot: Boolean;
dx: Single;
indexDelta: Int64;
- mainSeries: TSeries;
maxIndex: Int64;
begin
// Update button hot state
@@ -317,8 +308,7 @@ begin
FViewStartIndex := FViewStartIndex + indexDelta;
// Clamp values
- mainSeries := FXAxisSeries;
- maxIndex := mainSeries.Count - FViewCount;
+ maxIndex := FXAxisSeries.Series.Count - FViewCount;
if (maxIndex < 0) then
maxIndex := 0;
@@ -341,7 +331,6 @@ var
zoomFactor: Double;
newViewCount: Int64;
ratio: Double;
- mainSeries: TSeries;
begin
Handled := true;
@@ -349,8 +338,8 @@ begin
if not Assigned(FXAxisSeries) then
exit;
- mainSeries := FXAxisSeries;
- if (mainSeries.Count = 0) or (Width <= 0) then
+ var xAxisCount := FXAxisSeries.Series.Count;
+ if (xAxisCount = 0) or (Width <= 0) then
exit;
mousePos := ScreenToLocal(Screen.MousePos);
@@ -368,8 +357,8 @@ begin
// Clamp zoom level
if (newViewCount < 10) then
newViewCount := 10;
- if (newViewCount > mainSeries.Count) then
- newViewCount := mainSeries.Count;
+ if (newViewCount > xAxisCount) then
+ newViewCount := xAxisCount;
if (newViewCount = FViewCount) then
exit;
@@ -385,9 +374,9 @@ begin
// Clamp start index
if (FViewStartIndex < 0) then
FViewStartIndex := 0;
- if (FViewStartIndex + FViewCount > mainSeries.Count) then
+ if (FViewStartIndex + FViewCount > xAxisCount) then
begin
- FViewStartIndex := mainSeries.Count - FViewCount;
+ FViewStartIndex := xAxisCount - FViewCount;
end;
Repaint;
@@ -409,7 +398,6 @@ procedure TMycChart.Paint;
var
rect: TRectF;
- series: TSeries;
globalMin, globalMax, seriesMin, seriesMax, padding: Double;
rangeInitialized: Boolean;
xTransform: TFunc;
@@ -417,14 +405,13 @@ var
isButtonVisible: Boolean;
buttonColor: TAlphaColor;
path: TPathData;
- mainSeries: TSeries;
masterTotalCount, seriesFirst, seriesLast: Int64;
begin
inherited;
rect := Self.LocalRect;
// The chart requires an X-axis series to be set before it can draw anything.
- if not Assigned(FXAxisSeries) or (FXAxisSeries.Count <= 1) or (FViewCount <= 1) then
+ if not Assigned(FXAxisSeries) or (FXAxisSeries.Series.Count <= 1) or (FViewCount <= 1) then
begin
Canvas.Fill.Color := TAlphaColors.Gray;
Canvas.FillText(rect, 'No Data', false, 1, [], TTextAlign.Center, TTextAlign.Center);
@@ -432,12 +419,11 @@ begin
end;
rangeInitialized := false;
- mainSeries := FXAxisSeries;
- masterTotalCount := mainSeries.TotalCount;
- for series in FSeriesList do
+ masterTotalCount := FXAxisSeries.Series.TotalCount;
+ for var series in FSeriesList do
begin
- if CalcView(series, masterTotalCount, seriesFirst, seriesLast) then
+ if CalcView(series.Series, masterTotalCount, seriesFirst, seriesLast) then
begin
if series.GetValueRange(seriesFirst, seriesLast, seriesMin, seriesMax) then
begin
@@ -472,11 +458,11 @@ begin
// --- Draw Series with Offset Compensation ---
// The masterTotalCount is already calculated from the range finding loop
- for series in FSeriesList do
+ for var series in FSeriesList do
begin
- if CalcView(series, masterTotalCount, seriesFirst, seriesLast) then
+ if CalcView(series.Series, masterTotalCount, seriesFirst, seriesLast) then
begin
- var offset := masterTotalCount - series.TotalCount;
+ var offset := masterTotalCount - series.Series.TotalCount;
xTransform :=
function(index: Double): Single
begin
@@ -534,4 +520,15 @@ begin
end;
end;
+constructor TMycChart.TLayer.Create(AOwner: TMycChart);
+begin
+ inherited Create;
+ FOwner := AOwner;
+end;
+
+procedure TMycChart.TLayer.Repaint;
+begin
+ FOwner.Repaint;
+end;
+
end.
diff --git a/Src/Myc.Lazy.pas b/Src/Myc.Lazy.pas
index 3a528b4..6ffcd29 100644
--- a/Src/Myc.Lazy.pas
+++ b/Src/Myc.Lazy.pas
@@ -38,6 +38,7 @@ type
class property Null: IMutable read FNull;
class function Construct(const Changing: TSignal; const Proc: TFunc): TMutable; overload; static;
+ class function Constant(const Value: T): TMutable; overload; static;
property Value: T read GetValue;
property Changed: TSignal read GetChanged;
@@ -74,38 +75,15 @@ type
end;
TLazy = record
- type
- ILazy = interface
- {$REGION 'property access'}
- function GetChanged: TState;
- {$ENDREGION}
- function Pop(out Res: T): Boolean;
- property Changed: TState read GetChanged;
- end;
-
- {$REGION 'private'}
- strict private
- class var
- FNull: ILazy;
- class constructor CreateClass;
-
private
- FLazy: ILazy;
- function GetChanged: TState; inline;
- {$ENDREGION}
+ FMutable: TMutable;
+ FChanged: TFlag;
+ FChangeState: TSignal.TSubscription;
+ function GetValue: T; inline;
public
- constructor Create(const ALazy: ILazy);
- class operator Initialize(out Dest: TLazy);
- class operator Implicit(const A: ILazy): TLazy; overload;
- class operator Implicit(const A: TLazy): ILazy; overload;
-
- class function Construct(const Changing: TSignal.ISignal; const Proc: TFunc): TLazy; overload; static;
- class function Construct(const Mutable: TMutable): TLazy; overload; static;
- class property Null: ILazy read FNull;
-
- function Pop(out Res: T): Boolean; inline;
-
- property Changed: TState read GetChanged;
+ constructor Create(const AMutable: TMutable);
+ function Update: Boolean;
+ property Value: T read GetValue;
end;
implementation
@@ -123,7 +101,12 @@ end;
class constructor TMutable.CreateClass;
begin
- FNull := TMycNullMutable.Create;
+ FNull := TMycNullMutable.Create(Default(T));
+end;
+
+class function TMutable.Constant(const Value: T): TMutable;
+begin
+ Result := TMycNullMutable.Create(Value);
end;
class function TMutable.Construct(const Changing: TSignal; const Proc: TFunc): TMutable;
@@ -156,55 +139,6 @@ begin
Dest.FMutable := FNull;
end;
-{ TLazy }
-
-constructor TLazy.Create(const ALazy: ILazy);
-begin
- if Assigned(ALazy) then
- FLazy := ALazy;
-end;
-
-class function TLazy.Construct(const Changing: TSignal.ISignal; const Proc: TFunc): TLazy;
-begin
- Result := TMycFuncLazy.Create(Changing, Proc);
-end;
-
-class constructor TLazy.CreateClass;
-begin
- FNull := TMycNullLazy.Create;
-end;
-
-class function TLazy.Construct(const Mutable: TMutable): TLazy;
-begin
- var cap := Mutable;
- Result := TMycFuncLazy.Create(cap.Changed, function: T begin exit(Mutable.Value) end);
-end;
-
-function TLazy.GetChanged: TState;
-begin
- Result := FLazy.Changed;
-end;
-
-function TLazy.Pop(out Res: T): Boolean;
-begin
- Result := FLazy.Pop(Res);
-end;
-
-class operator TLazy.Implicit(const A: ILazy): TLazy;
-begin
- Result.Create(A);
-end;
-
-class operator TLazy.Implicit(const A: TLazy): ILazy;
-begin
- Result := A.FLazy;
-end;
-
-class operator TLazy.Initialize(out Dest: TLazy);
-begin
- Dest.FLazy := FNull;
-end;
-
{ TWriteable }
constructor TWriteable.Create(const AWriteable: IWriteable);
@@ -261,4 +195,26 @@ begin
Result := A.FWriteable;
end;
+{ TLazy }
+
+constructor TLazy.Create(const AMutable: TMutable);
+begin
+ FMutable := AMutable;
+ FChanged := TFlag.CreateFlag;
+ FChanged.Notify;
+ FChangeState := AMutable.Changed.Subscribe(FChanged);
+end;
+
+function TLazy.GetValue: T;
+begin
+ Result := FMutable.Value;
+end;
+
+function TLazy.Update: Boolean;
+begin
+ Result := FChanged.State.IsSet;
+ if Result then
+ FChanged.Reset;
+end;
+
end.