diff --git a/.gitattributes b/.gitattributes index 5fddd5244c..9db779789a 100644 --- a/.gitattributes +++ b/.gitattributes @@ -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 diff --git a/components/tachart/demo/charteditor/ceaxisdlg.pas b/components/tachart/demo/charteditor/ceaxisdlg.pas index 142ed44d90..50537b7070 100644 --- a/components/tachart/demo/charteditor/ceaxisdlg.pas +++ b/components/tachart/demo/charteditor/ceaxisdlg.pas @@ -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 diff --git a/components/tachart/demo/charteditor/cecharteditor.lfm b/components/tachart/demo/charteditor/cecharteditor.lfm new file mode 100644 index 0000000000..4711fa6c11 --- /dev/null +++ b/components/tachart/demo/charteditor/cecharteditor.lfm @@ -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 diff --git a/components/tachart/demo/charteditor/cecharteditor.pas b/components/tachart/demo/charteditor/cecharteditor.pas new file mode 100644 index 0000000000..35b045d621 --- /dev/null +++ b/components/tachart/demo/charteditor/cecharteditor.pas @@ -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. + diff --git a/components/tachart/demo/charteditor/ceimages.lfm b/components/tachart/demo/charteditor/ceimages.lfm new file mode 100644 index 0000000000..e68ca3e1fb --- /dev/null +++ b/components/tachart/demo/charteditor/ceimages.lfm @@ -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 diff --git a/components/tachart/demo/charteditor/ceimages.pas b/components/tachart/demo/charteditor/ceimages.pas new file mode 100644 index 0000000000..4cdeb6a1d8 --- /dev/null +++ b/components/tachart/demo/charteditor/ceimages.pas @@ -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. + diff --git a/components/tachart/demo/charteditor/celegenddlg.pas b/components/tachart/demo/charteditor/celegenddlg.pas index 2846b47c03..d7049bdcb4 100644 --- a/components/tachart/demo/charteditor/celegenddlg.pas +++ b/components/tachart/demo/charteditor/celegenddlg.pas @@ -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; diff --git a/components/tachart/demo/charteditor/cemain.lfm b/components/tachart/demo/charteditor/cemain.lfm index de766dd19e..83220dda4f 100644 --- a/components/tachart/demo/charteditor/cemain.lfm +++ b/components/tachart/demo/charteditor/cemain.lfm @@ -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 diff --git a/components/tachart/demo/charteditor/cemain.pas b/components/tachart/demo/charteditor/cemain.pas index 361be1fd7d..d8f66d1591 100644 --- a/components/tachart/demo/charteditor/cemain.pas +++ b/components/tachart/demo/charteditor/cemain.pas @@ -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; diff --git a/components/tachart/demo/charteditor/ceseriesframe.pas b/components/tachart/demo/charteditor/ceseriesframe.pas index 9505743285..7b8c43d267 100644 --- a/components/tachart/demo/charteditor/ceseriesframe.pas +++ b/components/tachart/demo/charteditor/ceseriesframe.pas @@ -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); diff --git a/components/tachart/demo/charteditor/ceshapebrushpenmarginsframe.pas b/components/tachart/demo/charteditor/ceshapebrushpenmarginsframe.pas index accb6b3edb..d5ecb43a46 100644 --- a/components/tachart/demo/charteditor/ceshapebrushpenmarginsframe.pas +++ b/components/tachart/demo/charteditor/ceshapebrushpenmarginsframe.pas @@ -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; diff --git a/components/tachart/demo/charteditor/cetitlefootdlg.pas b/components/tachart/demo/charteditor/cetitlefootdlg.pas index 24b2ce7472..ae71c47dd4 100644 --- a/components/tachart/demo/charteditor/cetitlefootdlg.pas +++ b/components/tachart/demo/charteditor/cetitlefootdlg.pas @@ -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); diff --git a/components/tachart/demo/charteditor/cetitlefootframe.pas b/components/tachart/demo/charteditor/cetitlefootframe.pas index 7ab7e49946..94d82385d5 100644 --- a/components/tachart/demo/charteditor/cetitlefootframe.pas +++ b/components/tachart/demo/charteditor/cetitlefootframe.pas @@ -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; diff --git a/components/tachart/demo/charteditor/charteditordemo.lpi b/components/tachart/demo/charteditor/charteditordemo.lpi index 7ad1ff6c28..3d8bc4350a 100644 --- a/components/tachart/demo/charteditor/charteditordemo.lpi +++ b/components/tachart/demo/charteditor/charteditordemo.lpi @@ -150,9 +150,25 @@ + + + + + + + + + + + + + + + + @@ -180,6 +196,9 @@ + + + diff --git a/components/tachart/demo/charteditor/charteditordemo.lpr b/components/tachart/demo/charteditor/charteditordemo.lpr index 1ee278eef4..a9e9f5de8c 100644 --- a/components/tachart/demo/charteditor/charteditordemo.lpr +++ b/components/tachart/demo/charteditor/charteditordemo.lpr @@ -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.