mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-05-02 19:23:40 +02:00
346 lines
8.4 KiB
ObjectPascal
346 lines
8.4 KiB
ObjectPascal
unit TALegend;
|
|
|
|
{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, Contnrs, SysUtils, Graphics, TAChartUtils, TATypes;
|
|
|
|
const
|
|
DEF_LEGEND_SPACING = 4;
|
|
DEF_LEGEND_MARGIN = 4;
|
|
DEF_LEGEND_SYMBOL_WIDTH = 20;
|
|
|
|
type
|
|
{ TLegendItem }
|
|
|
|
TLegendItem = class
|
|
private
|
|
FText: String;
|
|
public
|
|
constructor Create(const AText: String);
|
|
procedure Draw(ACanvas: TCanvas; const ARect: TRect); virtual;
|
|
end;
|
|
|
|
{ TLegendItemLine }
|
|
|
|
TLegendItemLine = class(TLegendItem)
|
|
private
|
|
FPen: TPen;
|
|
public
|
|
constructor Create(APen: TPen; const AText: String);
|
|
procedure Draw(ACanvas: TCanvas; const ARect: TRect); override;
|
|
end;
|
|
|
|
{ TLegendItemBrushRect }
|
|
|
|
TLegendItemBrushRect = class(TLegendItem)
|
|
private
|
|
FBrush: TBrush;
|
|
public
|
|
constructor Create(ABrush: TBrush; const AText: String);
|
|
procedure Draw(ACanvas: TCanvas; const ARect: TRect); override;
|
|
end;
|
|
|
|
{ TLegendItemColorRect }
|
|
|
|
TLegendItemColorRect = class(TLegendItem)
|
|
private
|
|
FColor: TColor;
|
|
public
|
|
constructor Create(AColor: TColor; const AText: String);
|
|
procedure Draw(ACanvas: TCanvas; const ARect: TRect); override;
|
|
end;
|
|
|
|
TChartLegendItems = TObjectList;
|
|
|
|
TChartLegendBrush = class(TBrush)
|
|
published
|
|
property Color default clWhite;
|
|
end;
|
|
|
|
TLegendAlignment = (laTopLeft, laBottomLeft, laTopRight, laBottomRight);
|
|
|
|
{ TChartLegend }
|
|
|
|
TChartLegend = class(TChartElement)
|
|
private
|
|
FAlignment: TLegendAlignment;
|
|
FBackgroundBrush: TChartLegendBrush;
|
|
FFont: TFont;
|
|
FFrame: TChartPen;
|
|
FMargin: TChartDistance;
|
|
FSpacing: TChartDistance;
|
|
FSymbolWidth: TChartDistance;
|
|
FUseSidebar: Boolean;
|
|
|
|
procedure SetAlignment(AValue: TLegendAlignment);
|
|
procedure SetBackgroundBrush(AValue: TChartLegendBrush);
|
|
procedure SetFont(AValue: TFont);
|
|
procedure SetFrame(AValue: TChartPen);
|
|
procedure SetMargin(AValue: TChartDistance);
|
|
procedure SetSpacing(AValue: TChartDistance);
|
|
procedure SetSymbolWidth(AValue: TChartDistance);
|
|
procedure SetUseSidebar(AValue: Boolean);
|
|
public
|
|
constructor Create(AOwner: TCustomChart);
|
|
destructor Destroy; override;
|
|
|
|
public
|
|
procedure Assign(Source: TPersistent); override;
|
|
procedure Draw(
|
|
ACanvas: TCanvas; AItems: TObjectList; const ABounds: TRect);
|
|
function Prepare(
|
|
ACanvas: TCanvas; AItems: TObjectList; var AClipRect: TRect): TRect;
|
|
published
|
|
property Alignment: TLegendAlignment
|
|
read FAlignment write SetAlignment default laTopRight;
|
|
property BackgroundBrush: TChartLegendBrush
|
|
read FBackgroundBrush write SetBackgroundBrush;
|
|
property Font: TFont read FFont write SetFont;
|
|
property Frame: TChartPen read FFrame write SetFrame;
|
|
property Margin: TChartDistance
|
|
read FMargin write SetMargin default DEF_LEGEND_MARGIN;
|
|
property Spacing: TChartDistance
|
|
read FSpacing write SetSpacing default DEF_LEGEND_SPACING;
|
|
property SymbolWidth: TChartDistance
|
|
read FSymbolWidth write SetSymbolWidth default DEF_LEGEND_SYMBOL_WIDTH;
|
|
property UseSidebar: Boolean read FUseSidebar write SetUseSidebar default true;
|
|
property Visible default false;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
Math, Types;
|
|
|
|
const
|
|
SYMBOL_TEXT_SPACING = 4;
|
|
|
|
{ TLegendItem }
|
|
|
|
constructor TLegendItem.Create(const AText: String);
|
|
begin
|
|
FText := AText;
|
|
end;
|
|
|
|
procedure TLegendItem.Draw(ACanvas: TCanvas; const ARect: TRect);
|
|
begin
|
|
ACanvas.TextOut(ARect.Right + SYMBOL_TEXT_SPACING, ARect.Top, FText);
|
|
end;
|
|
|
|
{ TLegendItemLine }
|
|
|
|
constructor TLegendItemLine.Create(APen: TPen; const AText: String);
|
|
begin
|
|
inherited Create(AText);
|
|
FPen := APen;
|
|
end;
|
|
|
|
procedure TLegendItemLine.Draw(ACanvas: TCanvas; const ARect: TRect);
|
|
var
|
|
y: Integer;
|
|
begin
|
|
inherited Draw(ACanvas, ARect);
|
|
ACanvas.Pen.Assign(FPen);
|
|
y := (ARect.Top + ARect.Bottom) div 2;
|
|
ACanvas.Line(ARect.Left, y, ARect.Right, y);
|
|
end;
|
|
|
|
{ TLegendItemBrushRect }
|
|
|
|
constructor TLegendItemBrushRect.Create(ABrush: TBrush; const AText: String);
|
|
begin
|
|
inherited Create(AText);
|
|
FBrush := ABrush;
|
|
end;
|
|
|
|
procedure TLegendItemBrushRect.Draw(ACanvas: TCanvas; const ARect: TRect);
|
|
begin
|
|
inherited Draw(ACanvas, ARect);
|
|
ACanvas.Brush.Assign(FBrush);
|
|
ACanvas.Rectangle(ARect);
|
|
end;
|
|
|
|
{ TLegendItemColorRect }
|
|
|
|
constructor TLegendItemColorRect.Create(AColor: TColor; const AText: String);
|
|
begin
|
|
inherited Create(AText);
|
|
FColor := AColor;
|
|
end;
|
|
|
|
procedure TLegendItemColorRect.Draw(ACanvas: TCanvas; const ARect: TRect);
|
|
begin
|
|
inherited Draw(ACanvas, ARect);
|
|
ACanvas.Brush.Color := FColor;
|
|
ACanvas.Brush.Style := bsSolid;
|
|
ACanvas.Rectangle(ARect);
|
|
end;
|
|
|
|
{ TChartLegend }
|
|
|
|
procedure TChartLegend.Assign(Source: TPersistent);
|
|
begin
|
|
if Source is TChartLegend then
|
|
with TChartLegend(Source) do
|
|
Self.FAlignment := FAlignment;
|
|
|
|
inherited Assign(Source);
|
|
end;
|
|
|
|
constructor TChartLegend.Create(AOwner: TCustomChart);
|
|
begin
|
|
inherited Create(AOwner);
|
|
FAlignment := laTopRight;
|
|
FMargin := DEF_LEGEND_MARGIN;
|
|
FSpacing := DEF_LEGEND_SPACING;
|
|
FSymbolWidth := DEF_LEGEND_SYMBOL_WIDTH;
|
|
FUseSidebar := true;
|
|
Visible := false;
|
|
|
|
InitHelper(FBackgroundBrush, TChartLegendBrush);
|
|
InitHelper(FFont, TFont);
|
|
InitHelper(FFrame, TChartPen);
|
|
end;
|
|
|
|
destructor TChartLegend.Destroy;
|
|
begin
|
|
FBackgroundBrush.Free;
|
|
FFont.Free;
|
|
FFrame.Free;
|
|
|
|
inherited;
|
|
end;
|
|
|
|
procedure TChartLegend.Draw(
|
|
ACanvas: TCanvas; AItems: TObjectList; const ABounds: TRect);
|
|
var
|
|
i, h: Integer;
|
|
pbf: TPenBrushFontRecall;
|
|
r: TRect;
|
|
begin
|
|
if not Visible then exit;
|
|
pbf := TPenBrushFontRecall.Create(ACanvas, [pbfPen, pbfBrush, pbfFont]);
|
|
try
|
|
// Draw the background and the border.
|
|
ACanvas.Font.Assign(Font);
|
|
ACanvas.Brush.Assign(BackgroundBrush);
|
|
ACanvas.Pen.Assign(Frame);
|
|
ACanvas.Rectangle(ABounds);
|
|
|
|
// Draw items.
|
|
h := TypicalTextHeight(ACanvas);
|
|
r := Bounds(ABounds.Left + Spacing, ABounds.Top + Spacing, SymbolWidth, h);
|
|
for i := 0 to AItems.Count - 1 do begin
|
|
ACanvas.Brush.Assign(BackgroundBrush);
|
|
ACanvas.Pen.Assign(Frame);
|
|
(AItems[i] as TLegendItem).Draw(ACanvas, r);
|
|
OffsetRect(r, 0, h + Spacing);
|
|
end;
|
|
finally
|
|
pbf.Free;
|
|
end;
|
|
end;
|
|
|
|
function TChartLegend.Prepare(
|
|
ACanvas: TCanvas; AItems: TObjectList; var AClipRect: TRect): TRect;
|
|
var
|
|
w, x, y, i, textHeight, legendWidth, legendHeight: Integer;
|
|
f: TPenBrushFontRecall;
|
|
begin
|
|
if not Visible then exit;
|
|
|
|
f := TPenBrushFontRecall.Create(ACanvas, [pbfFont]);
|
|
try
|
|
ACanvas.Font.Assign(Font);
|
|
|
|
// Measure the legend.
|
|
legendWidth := 0;
|
|
for i := 0 to AItems.Count - 1 do
|
|
with AItems[i] as TLegendItem do
|
|
legendWidth := Max(ACanvas.TextWidth(FText), legendWidth);
|
|
legendWidth += 2 * Spacing + SYMBOL_TEXT_SPACING + SymbolWidth;
|
|
textHeight := TypicalTextHeight(ACanvas);
|
|
legendHeight := Spacing + AItems.Count * (textHeight + Spacing);
|
|
w := legendWidth + 2 * Margin;
|
|
|
|
// Determine position according to the alignment.
|
|
if Alignment in [laTopLeft, laBottomLeft] then begin
|
|
x := AClipRect.Left + Margin;
|
|
if UseSidebar then
|
|
AClipRect.Left += w;
|
|
end
|
|
else begin
|
|
x := AClipRect.Right - legendWidth - Margin;
|
|
if UseSidebar then
|
|
AClipRect.Right -= w;
|
|
end;
|
|
if Alignment in [laTopLeft, laTopRight] then
|
|
y := AClipRect.Top + Margin
|
|
else
|
|
y := AClipRect.Bottom - Margin - legendHeight;
|
|
|
|
Result := Bounds(x, y, legendWidth, legendHeight);
|
|
finally
|
|
f.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TChartLegend.SetAlignment(AValue: TLegendAlignment);
|
|
begin
|
|
if FAlignment = AValue then exit;
|
|
FAlignment := AValue;
|
|
StyleChanged(Self);
|
|
end;
|
|
|
|
procedure TChartLegend.SetBackgroundBrush(AValue: TChartLegendBrush);
|
|
begin
|
|
FBackgroundBrush.Assign(AValue);
|
|
StyleChanged(Self);
|
|
end;
|
|
|
|
procedure TChartLegend.SetFont(AValue: TFont);
|
|
begin
|
|
FFont.Assign(AValue);
|
|
StyleChanged(Self);
|
|
end;
|
|
|
|
procedure TChartLegend.SetFrame(AValue: TChartPen);
|
|
begin
|
|
FFrame.Assign(AValue);
|
|
StyleChanged(Self);
|
|
end;
|
|
|
|
procedure TChartLegend.SetMargin(AValue: TChartDistance);
|
|
begin
|
|
if FMargin = AValue then exit;
|
|
FMargin := AValue;
|
|
StyleChanged(Self);
|
|
end;
|
|
|
|
procedure TChartLegend.SetSpacing(AValue: TChartDistance);
|
|
begin
|
|
if FSpacing = AValue then exit;
|
|
FSpacing := AValue;
|
|
StyleChanged(Self);
|
|
end;
|
|
|
|
procedure TChartLegend.SetSymbolWidth(AValue: TChartDistance);
|
|
begin
|
|
if FSymbolWidth = AValue then exit;
|
|
FSymbolWidth := AValue;
|
|
StyleChanged(Self);
|
|
end;
|
|
|
|
procedure TChartLegend.SetUseSidebar(AValue: Boolean);
|
|
begin
|
|
if FUseSidebar = AValue then exit;
|
|
FUseSidebar := AValue;
|
|
StyleChanged(Self);
|
|
end;
|
|
|
|
end.
|
|
|