TAChart: Extend charteditor by an "all-in-one" editor.

git-svn-id: trunk@65054 -
This commit is contained in:
wp 2021-04-22 22:56:58 +00:00
parent 038cc46fc5
commit 492321d819
15 changed files with 927 additions and 86 deletions

4
.gitattributes vendored
View File

@ -5164,8 +5164,12 @@ components/tachart/demo/charteditor/ceaxisframe.lfm svneol=native#text/plain
components/tachart/demo/charteditor/ceaxisframe.pas svneol=native#text/pascal
components/tachart/demo/charteditor/cebrushframe.lfm svneol=native#text/plain
components/tachart/demo/charteditor/cebrushframe.pas svneol=native#text/pascal
components/tachart/demo/charteditor/cecharteditor.lfm svneol=native#text/plain
components/tachart/demo/charteditor/cecharteditor.pas svneol=native#text/pascal
components/tachart/demo/charteditor/cefontframe.lfm svneol=native#text/plain
components/tachart/demo/charteditor/cefontframe.pas svneol=native#text/pascal
components/tachart/demo/charteditor/ceimages.lfm svneol=native#text/plain
components/tachart/demo/charteditor/ceimages.pas svneol=native#text/pascal
components/tachart/demo/charteditor/celegenddlg.lfm svneol=native#text/plain
components/tachart/demo/charteditor/celegenddlg.pas svneol=native#text/pascal
components/tachart/demo/charteditor/celegendframe.lfm svneol=native#text/plain

View File

@ -6,9 +6,9 @@ unit ceAxisDlg;
interface
uses
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ButtonPanel,
ExtCtrls, Buttons, ComCtrls, Spin,
TAChartAxis, TAChartAxisUtils, TATextElements, TAChartCombos, TAGraph,
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ButtonPanel,
ExtCtrls, Buttons, ComCtrls,
TAChartAxis, TAChartAxisUtils, TATextElements, TAGraph,
ceAxisFrame;
type

View File

@ -0,0 +1,127 @@
object ChartEditorForm: TChartEditorForm
Left = 443
Height = 454
Top = 161
Width = 791
Caption = 'Chart Editor'
ClientHeight = 454
ClientWidth = 791
OnActivate = FormActivate
OnCloseQuery = FormCloseQuery
OnCreate = FormCreate
OnDestroy = FormDestroy
LCLVersion = '2.1.0.0'
object ButtonPanel: TButtonPanel
Left = 6
Height = 34
Top = 414
Width = 779
OKButton.Name = 'OKButton'
OKButton.DefaultCaption = True
OKButton.OnClick = OKButtonClick
HelpButton.Name = 'HelpButton'
HelpButton.DefaultCaption = True
CloseButton.Name = 'ApplyButton'
CloseButton.Caption = 'Apply'
CloseButton.OnClick = ApplyButtonClick
CancelButton.Name = 'CancelButton'
CancelButton.DefaultCaption = True
TabOrder = 0
ShowButtons = [pbOK, pbCancel, pbClose]
end
object Tree: TTreeView
Left = 6
Height = 402
Top = 6
Width = 150
Align = alLeft
BorderSpacing.Left = 6
BorderSpacing.Top = 6
BorderSpacing.Right = 3
Constraints.MinWidth = 120
Images = ChartImagesDM.ChartImages
TabOrder = 1
OnDeletion = TreeDeletion
OnSelectionChanged = TreeSelectionChanged
end
object Splitter1: TSplitter
Left = 159
Height = 408
Top = 0
Width = 5
ResizeStyle = rsPattern
end
object Notebook: TNotebook
AnchorSideLeft.Control = Splitter1
AnchorSideLeft.Side = asrBottom
AnchorSideTop.Control = TitlePanel
AnchorSideTop.Side = asrBottom
AnchorSideRight.Control = Owner
AnchorSideRight.Side = asrBottom
AnchorSideBottom.Control = ButtonPanel
Left = 167
Height = 367
Top = 41
Width = 618
Anchors = [akTop, akLeft, akRight, akBottom]
BorderSpacing.Left = 3
BorderSpacing.Top = 6
BorderSpacing.Right = 6
BorderSpacing.Bottom = 6
TabOrder = 3
end
object TitlePanel: TPanel
AnchorSideLeft.Control = Splitter1
AnchorSideLeft.Side = asrBottom
AnchorSideTop.Control = Owner
AnchorSideRight.Control = Owner
AnchorSideRight.Side = asrBottom
Left = 167
Height = 29
Top = 6
Width = 618
Alignment = taLeftJustify
Anchors = [akTop, akLeft, akRight]
AutoSize = True
BorderSpacing.Left = 3
BorderSpacing.Top = 6
BorderSpacing.Right = 6
BevelInner = bvRaised
BevelOuter = bvLowered
ClientHeight = 29
ClientWidth = 618
Color = clWindowText
Font.Color = clWindow
ParentColor = False
ParentFont = False
TabOrder = 4
object Label1: TLabel
AnchorSideLeft.Control = Image1
AnchorSideLeft.Side = asrBottom
AnchorSideTop.Control = TitlePanel
Left = 30
Height = 21
Top = 4
Width = 50
BorderSpacing.Left = 8
BorderSpacing.Top = 2
BorderSpacing.Bottom = 2
Caption = 'Label1'
Font.Color = clWindow
Font.Height = -16
Font.Style = [fsBold]
ParentColor = False
ParentFont = False
end
object Image1: TImage
AnchorSideLeft.Control = TitlePanel
AnchorSideTop.Control = TitlePanel
AnchorSideTop.Side = asrCenter
Left = 6
Height = 16
Top = 6
Width = 16
BorderSpacing.Left = 4
end
end
end

View File

@ -0,0 +1,562 @@
unit ceChartEditor;
{$mode ObjFPC}{$H+}
interface
uses
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ButtonPanel, ComCtrls,
ExtCtrls, StdCtrls,
TAGraph, TAChartAxis, TACustomSeries, TASeries, TAChartImageList,
ceAxisFrame;
type
{ TChartEditorForm }
TChartEditorForm = class(TForm)
ApplyButton: TPanelBitBtn;
ButtonPanel: TButtonPanel;
Image1: TImage;
Label1: TLabel;
Notebook: TNotebook;
TitlePanel: TPanel;
Splitter1: TSplitter;
Tree: TTreeView;
procedure ApplyButtonClick(Sender: TObject);
procedure FormActivate(Sender: TObject);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure OKButtonClick(Sender: TObject);
procedure TreeDeletion(Sender: TObject; Node: TTreeNode);
procedure TreeSelectionChanged(Sender: TObject);
private
FChart: TChart;
FSavedChartStream: TMemoryStream;
FSavedSeriesStreams: array of TMemoryStream;
FTitleNode: TTreeNode;
FFooterNode: TTreeNode;
FLegendNode: TTreeNode;
FAxesNode: TTreeNode;
FSeriesNode: TTreeNode;
FOKClicked: Boolean;
function AddFrame(AParentNode: TTreeNode; ACaption: String; AFrame: TFrame;
AImageIndex: Integer): TTreeNode;
procedure FindComponentClass({%H-}AReader: TReader; const AClassName: String;
var AClass: TComponentClass);
function GetPageIndexOfNode(ANode: TTreeNode): Integer;
procedure SeriesChangedHandler(Sender: TObject);
procedure SetChart(AValue: TChart);
procedure UpdateImages;
protected
procedure CalculatePreferredSize(var PreferredWidth, PreferredHeight: integer;
{%H-}WithThemeSpace: Boolean); override;
procedure PopulateAxes(AChart: TChart);
procedure PopulateSeries(AChart: TChart);
procedure SaveChartToStream;
procedure SelectNode(ANode: TTreeNode);
procedure RestoreChartFromStream;
public
procedure SelectAxis(AxisIndex: Integer; APage: TChartAxisEditorPage);
procedure SelectFooter;
procedure SelectLegend;
procedure SelectSeries(ASeriesIndex: Integer);
procedure SelectTitle;
property Chart: TChart read FChart write SetChart;
end;
var
ChartEditorForm: TChartEditorForm;
procedure EditChartTitle(AChart: TChart);
procedure EditChartFooter(AChart: TChart);
procedure EditChartLegend(AChart: TChart);
procedure EditChartAxis(AChartAxis: TChartAxis; APage: TChartAxisEditorPage);
procedure EditChartSeries(ASeries: TBasicChartSeries);
implementation
{$R *.lfm}
uses
LResources, Math,
TAEnumerators,
ceTitleFootFrame, ceLegendFrame, ceSeriesFrame, ceImages;
const
TITLE_NODE_NAME = 'Title';
FOOTER_NODE_NAME = 'Footer';
LEGEND_NODE_NAME = 'Legend';
AXIS_NODE_NAME = 'Axes';
SERIES_NODE_NAME = 'Series';
{ Helper procedures }
function CreateChartEditorForm(AChart: TChart): TChartEditorForm;
begin
Result := TChartEditorForm.Create(nil);
Result.Position := poScreenCenter;
Result.Chart := AChart;
end;
procedure SelectChartElement(AChart: TChart; ATreeCaption: String);
var
F: TChartEditorForm;
begin
F := TChartEditorForm.Create(nil);
try
F.Position := poScreenCenter;
F.Chart := AChart;
F.Tree.Selected := F.Tree.Items.FindNodeWithText(ATreeCaption);
F.TreeSelectionChanged(nil);
F.ShowModal;
finally
F.Free;
end;
end;
{ Global procedures }
procedure EditChartTitle(AChart: TChart);
var
F: TChartEditorForm;
begin
F := CreateChartEditorForm(AChart);
try
F.SelectTitle;
F.ShowModal;
finally
F.Free;
end;
end;
procedure EditChartFooter(AChart: TChart);
var
F: TChartEditorForm;
begin
F := CreateChartEditorForm(AChart);
try
F.SelectFooter;
F.ShowModal;
finally
F.Free;
end;
end;
procedure EditChartLegend(AChart: TChart);
var
F: TChartEditorForm;
begin
F := CreateChartEditorForm(AChart);
try
F.SelectLegend;
F.ShowModal;
finally
F.Free;
end;
end;
procedure EditChartAxis(AChartAxis: TChartAxis; APage: TChartAxisEditorPage);
var
F: TChartEditorForm;
begin
F := CreateChartEditorForm(AChartAxis.GetChart as TChart);
try
F.SelectAxis(AChartAxis.Index, APage);
F.ShowModal;
finally
F.Free;
end;
end;
procedure EditChartSeries(ASeries: TBasicChartSeries);
var
F: TChartEditorForm;
begin
if not ( (ASeries is TLineSeries) or
(ASeries is TBarSeries) or
(ASeries is TAreaSeries)
) then
begin
raise Exception.Create('Series type not supported for direct editing.');
end;
F := CreateChartEditorForm(ASeries.ParentChart);
try
F.SelectSeries(ASeries.Index);
F.ShowModal;
finally
F.Free;
end;
end;
{ TChartEditorForm }
function TChartEditorForm.AddFrame(AParentNode: TTreeNode; ACaption: String;
AFrame: TFrame; AImageIndex: Integer): TTreeNode;
var
page: TPage;
begin
NoteBook.Pages.Add(ACaption);
page := NoteBook.Page[Notebook.PageCount-1];
AFrame.Parent := page;
AFrame.Name := '';
AFrame.Align := alClient;
Result := Tree.Items.AddChildObject(AParentNode, ACaption, AFrame);
Result.ImageIndex := AImageIndex;
Result.SelectedIndex := AImageIndex;
end;
procedure TChartEditorForm.ApplyButtonClick(Sender: TObject);
begin
RestoreChartFromStream;
end;
procedure TChartEditorForm.FormActivate(Sender: TObject);
var
w: Integer = 0;
h: Integer = 0;
begin
GetPreferredSize(w, h);
Constraints.MinWidth := w;
Constraints.MinHeight := h;
end;
procedure TChartEditorForm.CalculatePreferredSize(var PreferredWidth, PreferredHeight: integer;
{%H-}WithThemeSpace: Boolean);
var
w: Integer = 0;
h: Integer = 0;
wm, hm: Integer;
node: TTreeNode;
begin
TChartTitleFootFrame(FTitleNode.Data).GetPreferredSize(w, h);
wm := w;
hm := h;
TChartLegendFrame(FLegendNode.Data).GetPreferredSize(w, h);
wm := Max(w, wm);
hm := Max(h, hm);
node := FAxesNode.GetFirstChild;
if node <> nil then
begin
TChartAxisFrame(node.Data).GetPreferredSize(w, h);
wm := Max(w, wm);
hm := Max(h, hm);
end;
node := FSeriesNode.GetFirstChild;
if node <> nil then
begin
TChartSeriesFrame(node.Data).GetPreferredSize(w, h);
wm := Max(w, wm);
hm := Max(h, hm);
end;
PreferredWidth := Tree.Constraints.MinWidth +
Tree.BorderSpacing.Left + Tree.Borderspacing.Right + Splitter1.Width +
wm + Notebook.BorderSpacing.Left + Notebook.BorderSpacing.Right;
PreferredHeight := TitlePanel.Height + TitlePanel.BorderSpacing.Top + hm +
Notebook.BorderSpacing.Top + Notebook.BorderSpacing.Bottom +
ButtonPanel.Height + 2*ButtonPanel.BorderSpacing.Around;
end;
// Adapted from private TChart method
procedure TChartEditorForm.FindComponentClass(AReader: TReader;
const AClassName: String; var AClass: TComponentClass);
var
i: Integer;
begin
if AClassName = FChart.ClassName then begin
AClass := TChart;
exit;
end;
for i := 0 to SeriesClassRegistry.Count - 1 do begin
AClass := TSeriesClass(SeriesClassRegistry.GetClass(i));
if AClass.ClassNameIs(AClassName) then exit;
end;
AClass := nil;
end;
procedure TChartEditorForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
if not CanClose then
exit;
if not FOKClicked then
RestoreChartFromStream;
end;
procedure TChartEditorForm.FormCreate(Sender: TObject);
begin
Tree.Items.BeginUpdate;
try
Tree.Items.Clear;
FTitleNode := AddFrame(nil, TITLE_NODE_NAME, TChartTitleFootFrame.Create(self), 0);
FFooterNode := AddFrame(nil, FOOTER_NODE_NAME, TChartTitleFootFrame.Create(self), 1);
FLegendNode := AddFrame(nil, LEGEND_NODE_NAME, TChartLegendFrame.Create(self), 2);
FAxesNode := Tree.Items.AddChildObject(nil, AXIS_NODE_NAME, nil);
FSeriesNode := Tree.Items.AddChildObject(nil, SERIES_NODE_NAME, nil);
Tree.FullExpand;
finally
Tree.Items.EndUpdate;
end;
AutoSize := true;
end;
procedure TChartEditorForm.FormDestroy(Sender: TObject);
var
i: Integer;
begin
FSavedChartStream.Free;
for i:=0 to FChart.SeriesCount-1 do
FSavedSeriesStreams[i].Free;
end;
function TChartEditorForm.GetPageIndexOfNode(ANode: TTreeNode): Integer;
var
i: Integer;
page: TPage;
frame: TFrame;
begin
frame := TFrame(ANode.Data);
for i := 0 to Notebook.PageCount-1 do
begin
page := Notebook.Page[i];
if page.ContainsControl(frame) then
begin
Result := i;
exit;
end;
end;
Result := -1;
end;
procedure TChartEditorForm.OKButtonClick(Sender: TObject);
begin
FOKClicked := true;
end;
procedure TChartEditorForm.PopulateAxes(AChart: TChart);
var
i: Integer;
frame: TChartAxisFrame;
axis: TChartAxis;
imgIdx: Integer;
begin
FAxesNode.DeleteChildren;
if AChart <> nil then
begin
for i := 0 to AChart.AxisList.Count-1 do
begin
axis := AChart.AxisList.Axes[i];
frame := TChartAxisFrame.Create(self);
frame.Prepare(axis);
imgIdx := ord(axis.Alignment) + 3;
AddFrame(FAxesNode, axis.DisplayName, frame, imgIdx);
end;
FAxesNode.Expand(true);
end;
end;
procedure TChartEditorForm.PopulateSeries(AChart: TChart);
var
ser: TCustomChartSeries;
frame: TChartSeriesFrame;
imgIdx: Integer;
begin
FSeriesNode.DeleteChildren;
if AChart <> nil then
begin
ChartImagesDM.ChartImages.Chart := nil;
imgIdx := ChartImagesDM.ChartImages.Count;
ChartImagesDM.ChartImages.Chart := AChart;
for ser in CustomSeries(AChart) do
begin
frame := TChartSeriesFrame.Create(self);
frame.Prepare(ser);
frame.OnChanged := @SeriesChangedHandler;
AddFrame(FSeriesNode, ser.Title, frame, imgIdx);
inc(imgIdx);
end;
FSeriesNode.Expand(true);
end;
end;
procedure TChartEditorForm.RestoreChartFromStream;
var
i: Integer;
ser: TBasicChartSeries;
begin
FSavedChartStream.Position := 0;
ReadComponentFromTextStream(FSavedChartStream, TComponent(FChart), @FindComponentClass);
for i := 0 to FChart.SeriesCount-1 do
begin
FSavedSeriesStreams[i].Position := 0;
ser := nil;
ReadComponentFromTextStream(FSavedSeriesStreams[i], TComponent(ser), @FindComponentClass);
FChart.Series[i].Assign(ser);
end;
FChart.Invalidate;
end;
procedure TChartEditorForm.SaveChartToStream;
var
i: Integer;
begin
WriteComponentAsTextToStream(FSavedChartStream, FChart);
for i := 0 to FChart.SeriesCount-1 do
WriteComponentAsTextToStream(FSavedSeriesStreams[i], FChart.Series[i]);
end;
procedure TChartEditorForm.SelectAxis(AxisIndex: Integer; APage: TChartAxisEditorPage);
var
node: TTreeNode;
idx: Integer;
frame: TChartAxisFrame;
begin
idx := 0;
node := FAxesNode.GetFirstChild;
while node <> nil do begin
if idx = AxisIndex then
begin
SelectNode(node);
frame := TChartAxisFrame(node.Data);
frame.Page := APage;
exit;
end;
node := node.GetNextSibling;
inc(idx);
end;
end;
procedure TChartEditorForm.SelectFooter;
begin
SelectNode(FFooterNode);
end;
procedure TChartEditorForm.SelectLegend;
begin
SelectNode(FLegendNode);
end;
procedure TChartEditorForm.SelectNode(ANode: TTreeNode);
begin
Tree.Selected := ANode;
TreeSelectionChanged(nil);
end;
procedure TChartEditorForm.SelectSeries(ASeriesIndex: Integer);
var
idx: Integer;
node: TTreeNode;
begin
idx := 0;
node := FSeriesNode.GetFirstChild;
while (node <> nil) do
begin
if idx = ASeriesIndex then
begin
SelectNode(node);
exit;
end;
node := node.GetNextSibling;
inc(idx);
end;
end;
procedure TChartEditorForm.SelectTitle;
begin
SelectNode(FTitleNode);
end;
procedure TChartEditorForm.SeriesChangedHandler(Sender: TObject);
begin
UpdateImages;
end;
procedure TChartEditorForm.SetChart(AValue: TChart);
var
titleFrame: TChartTitleFootFrame;
legendFrame: TChartLegendFrame;
i: Integer;
begin
if FChart = AValue then
exit;
FChart := AValue;
// Save inital chart and series properties for restoring when Cancel is pressed.
if FSavedChartStream = nil then
begin
FSavedChartStream := TMemoryStream.Create;
SetLength(FSavedSeriesStreams, FChart.SeriesCount);
for i := 0 to FChart.SeriesCount-1 do
FSavedSeriesStreams[i] := TMemoryStream.Create;
end else
begin
FSavedChartStream.Clear;
for i := 0 to FChart.SeriesCount-1 do
FSavedSeriesStreams[i].Clear;
end;
SaveChartToStream;
titleFrame := TChartTitleFootFrame(FTitleNode.Data);
titleFrame.Prepare(FChart.Title);
titleFrame := TChartTitleFootFrame(FFooterNode.Data);
titleFrame.Prepare(FChart.Foot);
legendFrame := TChartLegendFrame(FLegendNode.Data);
legendFrame.Prepare(FChart.Legend);
PopulateAxes(FChart);
PopulateSeries(FChart);
FOKClicked := false;
end;
procedure TChartEditorForm.TreeDeletion(Sender: TObject; Node: TTreeNode);
var
pageIdx: Integer;
begin
if (Node.Data = nil) or (csDestroying in ComponentState) then
exit;
pageIdx := GetPageIndexOfNode(Node);
if pageIdx > -1 then
Notebook.Page[pageIdx].Free; // Page owns and destroys the frame
end;
procedure TChartEditorForm.TreeSelectionChanged(Sender: TObject);
var
pageIdx: Integer;
s: String;
begin
pageIdx := GetPageIndexOfNode(Tree.Selected);
if pageIdx > -1 then
begin
Notebook.PageIndex := pageIdx;
s := Tree.Selected.Text;
if Tree.Selected.Parent = FAxesNode then
Label1.Caption := 'Axis: ' + s
else if Tree.Selected.Parent = FSeriesNode then
Label1.Caption := 'Series: "' + s + '"'
else
Label1.Caption := s;
ChartImagesDM.ChartImages.GetBitmap(Tree.Selected.ImageIndex, Image1.Picture.Bitmap);
end;
end;
procedure TChartEditorForm.UpdateImages;
begin
ChartImagesDM.ChartImages.Chart := nil;
ChartImagesDM.ChartImages.Chart := FChart;
ChartImagesDM.ChartImages.GetBitmap(Tree.Selected.ImageIndex, Image1.Picture.Bitmap);
end;
end.

View File

@ -0,0 +1,55 @@
object ChartImagesDM: TChartImagesDM
OldCreateOrder = False
Height = 150
HorizontalOffset = 261
VerticalOffset = 130
Width = 322
object ChartImages: TChartImageList
Left = 128
Top = 32
Bitmap = {
4C7A0700000010000000100000002A0500000000000078DAED984B4C1B571486
3171058828C40147952221924516C9260BBAA91AB26015296CC8020950050836
B0804D8046516584A01405E882053B17D7049080A2F028CFF08A0B1410221106
63504885DF06FCC0F6D89EB9D37B8C87D8C61ECF98366A2BAEF46B66ECFB8DEF
EB3FE7C87171814D62E0A6484D62502A1D149BB8F077EF7E4B871357FE22BF7F
B1F9C7D6868686BE191919D91F1B1B537111F40526905F5D5DDD72BBDDDA7072
B95C41CFD0970FDFDADAEA282C2CA42412894BAD561BD9788220B472B9DC6636
9BF5F0BCB8B8785854544402373E3E7EACC78D8D9F9A9A3ACACFCFA7E0F70606
062CC0C23BB88C1FE6595656E65D5A5A3ADCDCDC345556567A5A5A5A1CA1F389
C4F7F7F75B9E3F7F4E30FD602E76BB5DC795DFDFDF37ECEEEE1A23AD231B3F3A
3ABA373D3DADE422E81BC8CFCCCC0827272753F80898CBF37B797EFF5FE7F732
7FF19D3F4DD302BE6B0F924AA589C0CB64B264BC971ABCA71F78E84FCCBC6078
1C0F3EB29DB750FFAB542AEDF0F0F0F75CF9B6B63627F623AAAFAF27565656CC
6CBC46A331ACAFAF9B9967E88F3D8CB02FD0C4C4844BA954B2F238D638737373
69EC5BE7C1C181A1B4B4945428142E8FC7A38F36FEBDBD3D63414101C21CDDD1
D181F07B5053539333743E91F8868606577777377AF2A48B4C4B6BA644A21FA8
1B379AA8D4D41F83049F2726D69FC05960789BCDA6ABAEAEF658AD56E3E3C772
FC1E355A5E76D26FDE3869B8E2B377A6CD4DDF1505F281E363F8EC6C92CEC840
345C150A2D5D5D2DF3E9D933193C9FF1A1E72733F327475797CACF533EFEED5B
8D8F63C4F0E1CEAF505837DCD5B543AC4DE9A8DF5F6D5370E5E725C9AFC09F7C
9D8DBCE22F69B8CECE7EA4F0EF2210DC7F0E5EB5ACA5D4935B145CF98E9F5F2C
A00558F762CDFFE9E98E9CA424EF0E3E930FB90AC7EFEB0C7FED9A7B352989A4
7A7B9777E7E7E7B7A329B87EA08557AEA06388645555A43D5AEE02C13B02F8A7
0201A280CFCC44EE70FD218FB2F0BFC5C7D32EE0535311A552790DA1FCE0E0A0
A5A4A4846C6F6F3F813A228417DFBA65EF03FEFD7BAFC1E1706B2D168B2E30F6
410D81E77CDCD9D969DBD8D83005F3717177EE58A5C0BB5CA74C7979B9A7B7B7
D70AF7B89FA5B6B696883CFE607E6D6DCD8C6396B7A2A2C203B107C60D9F71E5
81E9E9E9B142DDD1D8D8E8ACA9A921D8D7FF136F3098F479797994C9643A8B95
46A351CF959F9F5F386C6E6E76F2DBFFF3EB172B3F3BBBB0353737175510E302
F99414EF77090994666060F4512CFEF9E71B9D83F50A2B33CC77D79393BDCDB7
6F5B7F8E24ECEF15581F8180F60885D4515A9A73EAC103EB577E3E03BEE32391
8820FDEFF4D520FDFD235978EDB761FFC2A9AE8EB2DEBC89A8AC2C44BC7C495A
C6C7153BA1F52BEC69A4FDD66A09BD4EF7297F87EE7F349EDDFFE779BEFE0FE5
F9FA3F908FC5FF817C2CFE6778F07D2CFE67F88585D8FC1F6DFFB8F0E0692EDE
0FE77FF0329FDCF9F9FD7FCEF3F74E6B86D8C68F73BD3A3D9DC809FDFF804BEE
EFEB5BDE855AE1D4FFFCF7AFAA8AB2430CF1D70C422E7C60FE871AC11FCBA066
78CAC7FF757532874844FA6A0D7FCD30CAC7FF52E92FB6D7AFB78E80F7D70C62
BEFE877808FC69CEE2EFFF687C34FFB3F15CFCCFC673F17FB4F14753249EABFF
A14608E5F9F8076A04A815A06688FB97B48BC62F3EFE3F5FFFFF3DF19BABFF2F
F3FF7F33FFBF7BE73146E20707871FB2D58F20B11851F7EF234F7131E990CBFF
08FAFFF2EA55F73A9FFA352181448989E4077CFF08785CCF56B0D5CFA0F87804
790BE1BC654F4EF66C89C5AE62FCFC058F9C8D730D5DC4D4CC4CFB0B48C2044D
}
end
end

View File

@ -0,0 +1,30 @@
unit ceImages;
{$mode ObjFPC}{$H+}
interface
uses
Classes, SysUtils, TAChartImageList;
type
{ TChartImagesDM }
TChartImagesDM = class(TDataModule)
ChartImages: TChartImageList;
private
public
end;
var
ChartImagesDM: TChartImagesDM;
implementation
{$R *.lfm}
end.

View File

@ -5,8 +5,8 @@ unit ceLegendDlg;
interface
uses
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ButtonPanel,
ExtCtrls, Buttons, ColorBox, ComCtrls, Spin,
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ButtonPanel,
ExtCtrls, Buttons, ComCtrls,
TAGraph, TALegend,
ceLegendFrame;
@ -40,9 +40,6 @@ implementation
{$R *.lfm}
uses
ceUtils;
procedure TChartLegendEditor.FormCloseQuery(Sender: TObject; var CanClose: boolean);
begin
if not CanClose then exit;

View File

@ -6,10 +6,15 @@ object MainForm: TMainForm
Caption = 'MainForm'
ClientHeight = 346
ClientWidth = 613
Menu = MainMenu1
Menu = MainMenu
OnCreate = FormCreate
LCLVersion = '2.1.0.0'
object Chart1: TChart
AnchorSideLeft.Control = Owner
AnchorSideTop.Control = Owner
AnchorSideRight.Control = Owner
AnchorSideRight.Side = asrBottom
AnchorSideBottom.Control = Bevel1
Left = 0
Height = 290
Top = 0
@ -47,7 +52,7 @@ object MainForm: TMainForm
)
Title.Visible = True
Toolset = ChartToolset1
Align = alClient
Anchors = [akTop, akLeft, akRight, akBottom]
object Chart1LineSeries1: TLineSeries
Title = 'Line'
LinePen.Color = clBlue
@ -74,30 +79,33 @@ object MainForm: TMainForm
end
end
object Label1: TLabel
AnchorSideLeft.Control = Owner
AnchorSideBottom.Control = cbDoubleClick
Left = 6
Height = 15
Top = 300
Width = 601
Align = alBottom
Anchors = [akLeft, akRight]
Anchors = [akLeft, akRight, akBottom]
BorderSpacing.Around = 6
Caption = 'Click on a title, axis, label, grid, data point to open the corresponding editor.'
ParentColor = False
end
object Bevel1: TBevel
AnchorSideBottom.Control = Label1
Left = 0
Height = 4
Top = 290
Width = 613
Align = alBottom
Shape = bsBottomLine
end
object cbDoubleClick: TCheckBox
AnchorSideLeft.Control = Owner
AnchorSideBottom.Control = Owner
AnchorSideBottom.Side = asrBottom
Left = 6
Height = 19
Top = 321
Width = 607
Align = alBottom
Width = 177
Anchors = [akLeft, akBottom]
BorderSpacing.Left = 6
BorderSpacing.Bottom = 6
@ -105,6 +113,18 @@ object MainForm: TMainForm
OnChange = cbDoubleClickChange
TabOrder = 1
end
object cbUseAllInOneDialog: TCheckBox
AnchorSideLeft.Control = cbDoubleClick
AnchorSideLeft.Side = asrBottom
AnchorSideTop.Control = cbDoubleClick
Left = 207
Height = 19
Top = 321
Width = 140
BorderSpacing.Left = 24
Caption = 'Use "all-in-one" dialog'
TabOrder = 2
end
object ChartToolset1: TChartToolset
Left = 104
Top = 16
@ -125,10 +145,10 @@ object MainForm: TMainForm
OnClick = ChartToolset1AxisClickTool1Click
end
end
object MainMenu1: TMainMenu
Images = ChartImageList1
Left = 488
Top = 272
object MainMenu: TMainMenu
Images = ChartImagesDM.ChartImages
Left = 104
Top = 88
object mnuSettings: TMenuItem
Caption = 'Settings'
object mnuChartTitle: TMenuItem
@ -151,12 +171,12 @@ object MainForm: TMainForm
end
object mnuBottomAxis: TMenuItem
Caption = 'Bottom axis...'
ImageIndex = 3
ImageIndex = 6
OnClick = mnuBottomAxisClick
end
object mnuLeftAxis: TMenuItem
Caption = 'Left axis...'
ImageIndex = 4
ImageIndex = 3
OnClick = mnuLeftAxisClick
end
object MenuItem1: TMenuItem
@ -192,27 +212,4 @@ object MainForm: TMainForm
Left = 444
Top = 168
end
object ChartImageList1: TChartImageList
Left = 216
Top = 16
Bitmap = {
4C7A050000001000000010000000FF0100000000000078DAED95314B033114C7
E3A01404C1CDF1C06FE027C828752DDDC40387729FC0F570D1D14F213A58BA15
41217BB77E802238DDD44304C7675F7AEFFAEE9ABB26B9D20EADF227B934BFBC
7FDEE55E0040402671750FB602C615F84F58AD157CAFD7AB940DEF125F4A0949
92801E70DBBFE6E23806973FA500A48C738EC7C7B6AE8F08F27CDC96174218C7
6DFCD74DE1F1D334D5E27D62AB7CD5F1E88DF65BC59BFC2383C3367BE3F10783
B490639BBC228F71F09D226FFB2E39AF30A0F6AD9CFB7486E71E24B8F6F7E777
7F7EB7797E7DCE2CEFC38EDF5F4DF7EFF2FDE6DF8158FCFBD40FCEFBD40F1F9E
D70F57FF4B532AE2BBE49F54E65BA3B4A08BF1AF5634F983CB715A68713EF7CF
F9D1C3692EE439FB3849755B17FFE3EE0CA66F42B7C80F874368B7DBD0ED76F5
33AE413CD58F32FF7C73AE85B1283E72D4124FF58078D37E713EB1659E3CE033
E5EBA4F59E8BB3AFDFD35CFA3B60EF129F29DEF1E10BDC5E4F758B6CBFDF8728
8A740E3A9D8E157F74F0A4C5F74C1E54F263E469CF38877CA3C833722413EF2A
531DF151760EBD595213D6778DA6FEF7FCE678250368C487B37A13CAA5B92A10
902B14309F172C5A8C2BB2F1AC5FF435FB8D94B3015B83AD97ADE393278CEDCB
D6E5AFA9301DD915EBCDFAAC516645A8B436E97F6DBCFCDA1E8F79DB01BEAA4E
B8F0A6358837DD47556A7257AEABCEFE034F9AC8A1
}
end
end

View File

@ -21,15 +21,15 @@ type
Chart1AreaSeries1: TAreaSeries;
Chart1BarSeries1: TBarSeries;
Chart1LineSeries1: TLineSeries;
ChartImageList1: TChartImageList;
ChartToolset1: TChartToolset;
ChartToolset1AxisClickTool1: TAxisClickTool;
ChartToolset1DataPointClickTool1: TDataPointClickTool;
ChartToolset1LegendClickTool1: TLegendClickTool;
ChartToolset1TitleFootClickTool1: TTitleFootClickTool;
cbDoubleClick: TCheckBox;
cbUseAllInOneDialog: TCheckBox;
Label1: TLabel;
MainMenu1: TMainMenu;
MainMenu: TMainMenu;
MenuItem1: TMenuItem;
mnuSeries: TMenuItem;
mnuChartLegend: TMenuItem;
@ -58,6 +58,7 @@ type
procedure mnuChartTitleClick(Sender: TObject);
procedure mnuLeftAxisClick(Sender: TObject);
private
procedure ChartEditor(AChart: TChart);
procedure EditAxis(AAxis: TChartAxis; APage: TChartAxisEditorPage);
procedure EditLegend(ALegend: TChartLegend);
procedure EditSeries(ASeries: TBasicChartSeries);
@ -77,10 +78,23 @@ implementation
uses
TAChartUtils, TACustomSeries,
ceTitleFootDlg, ceLegendDlg, ceSeriesDlg, ceAxisDlg;
ceTitleFootDlg, ceLegendDlg, ceSeriesDlg, ceAxisDlg, ceChartEditor, ceImages;
{ TMainForm }
procedure TMainForm.ChartEditor(AChart: TChart);
var
F: TChartEditorForm;
begin
F := TChartEditorForm.Create(nil);
try
F.Chart := AChart;
F.ShowModal;
finally
F.Free;
end;
end;
procedure TMainForm.ChartToolset1TitleFootClickTool1Click(ASender: TChartTool;
ATitle: TChartTitle);
begin
@ -91,11 +105,18 @@ end;
procedure TMainForm.cbDoubleClickChange(Sender: TObject);
var
shift: TShiftState;
s: String;
begin
if cbDoubleClick.Checked then
shift := [ssLeft, ssDouble]
else
begin
shift := [ssLeft, ssDouble];
s := 'Double-click';
end else
begin
shift := [ssLeft];
s := 'Click';
end;
Label1.Caption := s + ' on a title, axis, label, grid, data point to open the corresponding editor.';
ChartToolset1DatapointClickTool1.Shift := shift;
ChartToolset1TitleFootClickTool1.Shift := shift;
@ -108,14 +129,14 @@ var
i: Integer;
item: TMenuItem;
begin
ChartImageList1.Chart := Chart1;
ChartImagesDM.ChartImages.Chart := Chart1;
for i := 0 to Chart1.SeriesCount-1 do begin
item := TMenuItem.Create(MainMenu1);
item := TMenuItem.Create(MainMenu);
item.Caption := TCustomChartSeries(Chart1.Series[i]).Title + '...';
item.OnClick := @MenuSeriesClick;
item.Tag := PtrInt(Chart1.Series[i]);
item.ImageIndex := ChartImageList1.FirstSeriesIndex + i;
item.ImageIndex := ChartImagesDM.ChartImages.FirstSeriesIndex + i;
mnuSeries.Add(item);
end;
end;
@ -162,13 +183,18 @@ procedure TMainForm.EditAxis(AAxis: TChartAxis; APage: TChartAxisEditorPage);
var
F: TChartAxisEditor;
begin
F := TChartAxisEditor.Create(nil);
try
F.Prepare(AAxis, 'Edit chart axis "%s"');
F.Page := APage;
F.ShowModal;
finally
F.Free;
if cbUseAllInOneDialog.Checked then
EditChartAxis(AAxis, APage)
else
begin
F := TChartAxisEditor.Create(nil);
try
F.Prepare(AAxis, 'Edit chart axis "%s"');
F.Page := APage;
F.ShowModal;
finally
F.Free;
end;
end;
end;
@ -176,12 +202,17 @@ procedure TMainForm.EditLegend(ALegend: TChartLegend);
var
F: TChartLegendEditor;
begin
F := TChartLegendEditor.Create(nil);
try
F.Prepare(ALegend, 'Edit chart legend');
F.ShowModal;
finally
F.Free;
if cbUseAllInOneDialog.Checked then
EditChartLegend(ALegend.GetOwner as TChart)
else
begin
F := TChartLegendEditor.Create(nil);
try
F.Prepare(ALegend, 'Edit chart legend');
F.ShowModal;
finally
F.Free;
end;
end;
end;
@ -189,12 +220,17 @@ procedure TMainForm.EditSeries(ASeries: TBasicChartSeries);
var
F: TChartSeriesEditor;
begin
F := TChartSeriesEditor.Create(nil);
try
F.Prepare(ASeries, 'Edit series "%s"');
F.ShowModal;
finally
F.Free;
if cbUseAllInOneDialog.Checked then
EditChartSeries(ASeries)
else
begin
F := TChartSeriesEditor.Create(nil);
try
F.Prepare(ASeries, 'Edit series "%s"');
F.ShowModal;
finally
F.Free;
end;
end;
end;
@ -203,14 +239,24 @@ var
F: TChartTitleFootEditor;
s: String;
begin
F := TChartTitleFootEditor.Create(nil);
try
s := 'Edit chart %s';
if ATitle = Chart1.Title then s := Format(s, ['title']) else s := Format(s, ['footer']);
F.Prepare(ATitle, s);
F.ShowModal;
finally
F.Free;
if cbUseAllInOneDialog.Checked then
begin
if ATitle = Chart1.Title then
EditChartTitle(ATitle.GetOwner as TChart)
else
if ATitle = Chart1.Foot then
EditChartFooter(ATitle.GetOwner as TChart);
end else
begin
F := TChartTitleFootEditor.Create(nil);
try
s := 'Edit chart %s';
if ATitle = Chart1.Title then s := Format(s, ['title']) else s := Format(s, ['footer']);
F.Prepare(ATitle, s);
F.ShowModal;
finally
F.Free;
end;
end;
end;

View File

@ -69,12 +69,14 @@ type
FAreaSeriesBrushFrame: TChartBrushFrame;
FAreaSeriesContourPenFrame: TChartPenFrame;
FAreaSeriesDropLinesPenFrame: TChartPenFrame;
FOnChanged: TNotifyEvent;
procedure ChangedHandler(Sender: TObject);
protected
function GetChart: TChart;
public
constructor Create(AOwner: TComponent); override;
procedure Prepare(ASeries: TBasicChartSeries);
property OnChanged: TNotifyEvent read FOnChanged write FOnChanged;
end;
@ -251,6 +253,7 @@ end;
procedure TChartSeriesFrame.ChangedHandler(Sender: TObject);
begin
GetChart.Invalidate;
if Assigned(FOnChanged) then FOnChanged(self);
end;
procedure TChartSeriesFrame.edMarksFormatEditingDone(Sender: TObject);

View File

@ -50,7 +50,7 @@ type
procedure UpdateControls;
protected
procedure CalculatePreferredSize(var PreferredWidth, PreferredHeight: integer;
WithThemeSpace: Boolean); override;
{%H-}WithThemeSpace: Boolean); override;
public
constructor Create(AOwner: TComponent); override;
procedure GetData(out AShape: TChartLabelShape; ABrush: TBrush;

View File

@ -6,7 +6,7 @@ interface
uses
Classes, SysUtils, Graphics,
Forms, Controls, Dialogs, StdCtrls, ButtonPanel, ExtCtrls, Buttons, ComCtrls,
Forms, Controls, Dialogs, ButtonPanel, ExtCtrls, Buttons, ComCtrls,
TAGraph, TATextElements,
ceTitleFootFrame;
@ -41,12 +41,12 @@ implementation
{$R *.lfm}
uses
TATypes,
ceUtils;
TATypes;
procedure TChartTitleFootEditor.FormActivate(Sender: TObject);
var
h, w: Integer;
h: Integer = 0;
w: Integer = 0;
begin
FTitleFootFrame.GetPreferredSize(w, h);
inc(h, FTitleFootFrame.BorderSpacing.Around * 2);

View File

@ -37,7 +37,7 @@ type
procedure ShapeChangedHandler(AShape: TChartLabelShape);
protected
procedure CalculatePreferredSize(var PreferredWidth, PreferredHeight: integer;
WithThemeSpace: Boolean); override;
{%H-}WithThemeSpace: Boolean); override;
function GetChart: TChart;
public
constructor Create(AOwner: TComponent); override;

View File

@ -150,9 +150,25 @@
<Filename Value="ceseriesframe.pas"/>
<IsPartOfProject Value="True"/>
<ComponentName Value="ChartSeriesFrame"/>
<HasResources Value="True"/>
<ResourceBaseClass Value="Frame"/>
<UnitName Value="ceSeriesFrame"/>
</Unit>
<Unit>
<Filename Value="cecharteditor.pas"/>
<IsPartOfProject Value="True"/>
<ComponentName Value="ChartEditorForm"/>
<HasResources Value="True"/>
<ResourceBaseClass Value="Form"/>
<UnitName Value="ceChartEditor"/>
</Unit>
<Unit>
<Filename Value="ceimages.pas"/>
<IsPartOfProject Value="True"/>
<ComponentName Value="ChartImagesDM"/>
<ResourceBaseClass Value="DataModule"/>
<UnitName Value="ceImages"/>
</Unit>
</Units>
</ProjectOptions>
<CompilerOptions>
@ -180,6 +196,9 @@
<VerifyObjMethodCallValidity Value="True"/>
</CodeGeneration>
<Linking>
<Debugging>
<TrashVariables Value="True"/>
</Debugging>
<Options>
<Win32>
<GraphicApplication Value="True"/>

View File

@ -8,7 +8,7 @@ uses
{$ENDIF}{$ENDIF}
Interfaces, // this includes the LCL widgetset
Forms, ceMain, ceSeriesDlg, cePointerFrame, ceTitleFootFrame, ceAxisFrame,
ceSeriesFrame;
ceSeriesFrame, ceChartEditor, ceImages;
{$R *.res}
@ -16,6 +16,7 @@ begin
RequireDerivedFormResource:=True;
Application.Scaled:=True;
Application.Initialize;
Application.CreateForm(TChartImagesDM, ChartImagesDM);
Application.CreateForm(TMainForm, MainForm);
Application.Run;
end.