lazarus/components/tachart/talegend.pas
ask 91daeebbea TAChart: Simplify InitHelper interface
git-svn-id: trunk@22694 -
2009-11-20 11:47:12 +00:00

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.