{*********************************************}
{  TeeChart Charting Library for FireMonkey   }
{  Copyright (c) 2012-2020 by Steema Software }
{  All Rights Reserved                        }
{*********************************************}
unit FMXTee.Editor.Series.Map;
{$I TeeDefs.inc}

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,

  {$IFDEF D17}
  System.Rtti,
  {$ENDIF}

  FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs, FMXTee.Chart.ListBox,

  {$IFNDEF UPTOXE3}
  FMX.StdCtrls,
  {$ENDIF}

  {$IFNDEF UPTOXE7}
  FMX.SpinBox, FMX.Controls.Presentation, FMX.EditBox,
  {$ENDIF}

  FMX.TabControl, FMXTee.Series.Map, FMX.Edit, FMX.ListBox, FMX.Colors,
  FMX.Layouts, FMX.Grid, FMXTee.Chart.Grid,
  FMXTee.Editor.Stroke, FMXTee.Editor.Brush;

type
  TMapSeriesEditor = class(TForm)
    TabControlMap: TTabControl;
    TabGlobal: TTabItem;
    TabShadow: TTabItem;
    TabEmboss: TTabItem;
    CBTransparent: TCheckBox;
    BBorder: TButton;
    BBrush: TButton;
    UDMapTransp: TSpinBox;
    LTransp: TLabel;
    UDPointSize: TSpinBox;
    LPointSize: TLabel;
    TabShapes: TTabItem;
    PanelShapes: TPanel;
    PanelShapeButtons: TPanel;
    PanelShapesLeft: TPanel;
    TabControlShape: TTabControl;
    SplitterShapes: TSplitter;
    TabValues: TTabItem;
    TabFormat: TTabItem;
    TabPoints: TTabItem;
    EText: TEdit;
    EditZ: TEdit;
    LShapeText: TLabel;
    LShapeZ: TLabel;
    LShapeIndex: TLabel;
    ShapeIndex: TLabel;
    CBColor: TComboColorBox;
    LColor: TLabel;
    CBGlobalPen: TCheckBox;
    CBGlobalBrush: TCheckBox;
    CBDefaultColor: TCheckBox;
    CBClosed: TCheckBox;
    CBVisible: TCheckBox;
    UDTransp: TSpinBox;
    LFormatTransp: TLabel;
    SBAdd: TButton;
    SBDelete: TButton;
    TabGrid3D: TTabItem;
    LBShapes: TChartListBox;
    LabelCode: TLabel;
    ECode: TEdit;
    TabBorder: TTabItem;
    TabPattern: TTabItem;
    TabMarks: TTabItem;
    GBMapMarks: TGroupBox;
    CBMarksText: TComboBox;
    CBMarksAutoSize: TCheckBox;
    CBMarksUpper: TCheckBox;
    CBMarksCentroids: TCheckBox;
    CBAutoColor: TCheckBox;
    TabLegend: TTabItem;
    GBLegend: TGroupBox;
    CBLegendZero: TCheckBox;
    CBLegendEmpty: TCheckBox;
    CBLegendSort: TComboBox;
    LSortBy: TLabel;
    CBLegendInverted: TCheckBox;
    LLegendStyle: TLabel;
    CBLegendStyle: TComboBox;
    procedure FormActivate(Sender: TObject);
    procedure CBTransparentChange(Sender: TObject);
    procedure BBorderClick(Sender: TObject);
    procedure BBrushClick(Sender: TObject);
    procedure UDMapTranspChange(Sender: TObject);
    procedure UDPointSizeChange(Sender: TObject);
    procedure ETextChange(Sender: TObject);
    procedure EditZChange(Sender: TObject);
    procedure LBShapesClick(Sender: TObject);
    procedure CBColorChange(Sender: TObject);
    procedure TabControlMapChange(Sender: TObject);
    procedure CBGlobalPenChange(Sender: TObject);
    procedure CBGlobalBrushChange(Sender: TObject);
    procedure SBDeleteClick(Sender: TObject);
    procedure SBAddClick(Sender: TObject);
    procedure CBDefaultColorChange(Sender: TObject);
    procedure CBClosedChange(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure CBVisibleChange(Sender: TObject);
    procedure UDTranspChange(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure LBShapesChangeCheck(Sender: TObject);
    procedure ECodeChange(Sender: TObject);
    procedure TabControlShapeChange(Sender: TObject);
    procedure CBMarksTextChange(Sender: TObject);
    procedure CBMarksAutoSizeChange(Sender: TObject);
    procedure CBMarksUpperChange(Sender: TObject);
    procedure CBMarksCentroidsChange(Sender: TObject);
    procedure CBAutoColorChange(Sender: TObject);
    procedure CBLegendZeroChange(Sender: TObject);
    procedure CBLegendEmptyChange(Sender: TObject);
    procedure CBLegendSortChange(Sender: TObject);
    procedure CBLegendInvertedChange(Sender: TObject);
    procedure CBLegendStyleChange(Sender: TObject);
  private
    { Private declarations }
    ChangingColor,
    ChangingText : Boolean;
    Grid3DForm : TCustomForm;
    FChartGrid : TChartGrid;
    IReady     : Boolean;
    IShapeBorder : TStrokeEditor;
    IShapeBrush  : TBrushEditor;

    procedure CheckDefaultColor;
    Procedure EnableTabs;
    procedure FillShapes;
    Function SelectedShape:TTeePolygon;
    procedure ChartGridSetEditText(Sender: TObject; const ACol,
      ARow: Integer; const Value: {$IFDEF D17}TValue{$ELSE}Variant{$ENDIF});
  protected
    Map : TMapSeries;
    DirtyList : Boolean;
  public
    { Public declarations }
    InitialShape : TObject;
  end;

implementation

{$R *.fmx}

uses
  FMXTee.Editor.Gradient,
  FMXTee.Editor.Shadow, FMXTee.Editor.Series.Grid, FMXTee.Procs, FMXTee.Engine;

procedure TMapSeriesEditor.CBAutoColorChange(Sender: TObject);
begin
  Map.MapMarks.AutoTextColor:=CBAutoColor.IsChecked;
end;

procedure TMapSeriesEditor.CBClosedChange(Sender: TObject);
begin
  if SelectedShape<>nil then
    SelectedShape.Closed:=CBClosed.IsChecked;
end;

procedure TMapSeriesEditor.CBColorChange(Sender: TObject);
begin
  CheckDefaultColor;
  LBShapes.Repaint;
end;

procedure TMapSeriesEditor.CBDefaultColorChange(Sender: TObject);
begin
  if (SelectedShape<>nil) and not ChangingColor then
  begin
    SelectedShape.Color:=clTeeColor;
    LBShapes.Repaint;
  end;
end;

procedure TMapSeriesEditor.CBGlobalBrushChange(Sender: TObject);
begin
  if SelectedShape<>nil then
    SelectedShape.ParentBrush:=CBGlobalBrush.IsChecked;
end;

procedure TMapSeriesEditor.CBGlobalPenChange(Sender: TObject);
begin
  if SelectedShape<>nil then
    SelectedShape.ParentPen:=CBGlobalPen.IsChecked;
end;

procedure TMapSeriesEditor.CBLegendEmptyChange(Sender: TObject);
begin
  Map.MapLegend.IncludeUnNamed:=CBLegendEmpty.IsChecked;
end;

procedure TMapSeriesEditor.CBLegendInvertedChange(Sender: TObject);
begin
  Map.MapLegend.Sort.Inverted:=CBLegendInverted.IsChecked;
end;

procedure TMapSeriesEditor.CBLegendSortChange(Sender: TObject);
begin
  Map.MapLegend.Sort.By:=TMapLegendSortBy(CBLegendSort.ItemIndex);
end;

procedure TMapSeriesEditor.CBLegendStyleChange(Sender: TObject);
begin
  Map.MapLegend.Style:=TMapLegendStyle(CBLegendStyle.ItemIndex);
end;

procedure TMapSeriesEditor.CBLegendZeroChange(Sender: TObject);
begin
  Map.MapLegend.IncludeZero:=CBLegendZero.IsChecked;
end;

procedure TMapSeriesEditor.CBMarksAutoSizeChange(Sender: TObject);
begin
  Map.MapMarks.AutoSize:=CBMarksAutoSize.IsChecked;
end;

procedure TMapSeriesEditor.CBMarksCentroidsChange(Sender: TObject);
begin
  Map.MapMarks.Centroid:=CBMarksCentroids.IsChecked;
end;

procedure TMapSeriesEditor.CBMarksTextChange(Sender: TObject);
begin
  if Assigned(Map) then
     Map.MapMarks.TextStyle:=TMapMarksText(CBMarksText.ItemIndex);
end;

procedure TMapSeriesEditor.CBMarksUpperChange(Sender: TObject);
begin
  Map.MapMarks.UpperCase:=CBMarksUpper.IsChecked;
end;

procedure TMapSeriesEditor.CBTransparentChange(Sender: TObject);
begin
  if Assigned(Map) then
    Map.Transparent:=CBTransparent.IsChecked;
end;

procedure TMapSeriesEditor.CBVisibleChange(Sender: TObject);
begin
  if SelectedShape<>nil then
  begin
    SelectedShape.Points.Visible:=CBVisible.IsChecked;

    LBShapes.SelectedSeries.Visible:=CBVisible.IsChecked;

    if LBShapes.Selected.IsChecked<>CBVisible.IsChecked then
       LBShapes.Selected.IsChecked:=CBVisible.IsChecked;

    LBShapes.Repaint;
  end;
end;

procedure TMapSeriesEditor.LBShapesChangeCheck(Sender: TObject);
begin
  LBShapes.ItemIndex:=(Sender as TListBoxItem).Index;
  LBShapes.SelectRange((Sender as TListBoxItem),(Sender as TListBoxItem));

  SelectedShape.Points.Visible:=(Sender as TListBoxItem).IsChecked;

  LBShapesClick(LBShapes);
  LBShapes.Repaint;
end;

procedure TMapSeriesEditor.LBShapesClick(Sender: TObject);
begin
  EnableTabs;

  if SelectedShape<>nil then
  begin
    With SelectedShape do
    begin
      ShapeIndex.Text:=IntToStr(Index);

      CBColor.Color:=SelectedShape.Color;
      CBGlobalPen.IsChecked:=ParentPen;
      CheckDefaultColor;
      CBGlobalBrush.IsChecked:=ParentBrush;

      ChangingText:=True;
      try
        EText.Text:=Text;
        ECode.Text:=Code;
        EditZ.Text:=FloatToStr(Z);
      finally
        ChangingText:=False;
      end;

      CBClosed.IsChecked:=Closed;
      CBVisible.IsChecked:=Points.Visible;
      UDTransp.Value:=Transparency;

      FChartGrid.Series:=Points;

      if Assigned(IShapeBorder) then
         IShapeBorder.RefreshPen(Pen);

      if Assigned(IShapeBrush) then
         IShapeBrush.RefreshBrush(Brush);
    end;

    SBDelete.Enabled:=True;

  end
  else
  begin
    ShapeIndex.Text:='';
    ChangingText:=True;
    EText.Text:='';
    ECode.Text:='';
    EditZ.Text:='0';
    ChangingText:=False;
  end;
end;

procedure TMapSeriesEditor.BBrushClick(Sender: TObject);
begin
  if Assigned (Map) then
    TBrushEditor.Edit(Self, Map.Brush)
end;

procedure TMapSeriesEditor.BBorderClick(Sender: TObject);
begin
  if Assigned(Map) then
    TStrokeEditor.Edit(Self, Map.Pen);
end;

type
  TSeriesAccess=class(TChartSeries);

procedure TMapSeriesEditor.CheckDefaultColor;
var tmp : TAlphaColor;
begin
  ChangingColor:=True;

  tmp:=TSeriesAccess(SelectedShape.ParentSeries).InternalColor(SelectedShape.Index);

  CBDefaultColor.IsChecked:=tmp=clTeeColor;
  ChangingColor:=False;

  CBDefaultColor.Enabled:=not CBDefaultColor.IsChecked;
end;

procedure TMapSeriesEditor.FormActivate(Sender: TObject);
begin
  if CBLegendSort.Items.Count=0 then
  begin
    CBLegendSort.Items.Add('Text');
    CBLegendSort.Items.Add('Value');
    CBLegendSort.Items.Add('None');
  end;

  if CBMarksText.Items.Count=0 then
  begin
    CBMarksText.Items.Add('Labels');
    CBMarksText.Items.Add('Codes');
    CBMarksText.Items.Add('Both');
  end;

  if CBLegendStyle.Items.Count=0 then
  begin
    CBLegendStyle.Items.Add('Colors');
    CBLegendStyle.Items.Add('Texts');
    CBLegendStyle.Items.Add('Groups');
  end;

  if not Assigned(Map) then
  begin
    Map:=TMapSeries(TagObject);

    if Assigned(Map) then
    begin
      ChangingText:=False;
      UDMapTransp.Value:=Map.Transparency;
      CBTransparent.IsChecked:=Map.Transparent;
      UDPointSize.Value:=Map.PointSize;

      CBMarksText.ItemIndex:=Ord(Map.MapMarks.TextStyle);

      CBMarksAutoSize.IsChecked:=Map.MapMarks.AutoSize;
      CBMarksUpper.IsChecked:=Map.MapMarks.UpperCase;
      CBMarksCentroids.IsChecked:=Map.MapMarks.Centroid;
      CBAutoColor.IsChecked:=Map.MapMarks.AutoTextColor;

      if not Assigned(FChartGrid) then
      begin
        FChartGrid:=TChartGrid.Create(Self);
        FChartGrid.Align:=TAlignLayout.{$IFDEF D20}Client{$ELSE}alClient{$ENDIF};
        FChartGrid.OnSetEditText:=ChartGridSetEditText;
        TabPoints.AddObject(FChartGrid);
      end;

      TGrid3DSeriesEditor.CreateEmbedd(Self,Map,TabGrid3D);
      TShadowEditor.InsertForm(Map.Shadow,TabShadow);
      TShadowEditor.InsertForm(Map.Emboss,TabEmboss);

      CBLegendStyle.ItemIndex:=Ord(Map.MapLegend.Style);
      CBLegendZero.IsChecked:=Map.MapLegend.IncludeZero;
      CBLegendEmpty.IsChecked:=Map.MapLegend.IncludeUnNamed;
      CBLegendSort.ItemIndex:=Ord(Map.MapLegend.Sort.By);
      CBLegendInverted.IsChecked:=Map.MapLegend.Sort.Inverted;
    end;

    TabControlMap.ActiveTab:=TabGlobal;
    FChartGrid.ShowFields:=False;
    EnableTabs;

    //ChartGridNavigator1.Buttons[nbInsert].Visible:=True;
    //ChartGridNavigator1.Buttons[nbDelete].Visible:=True;

    TabControlShape.ActiveTab:=TabFormat;

    if Assigned(Map) and (Map.Shapes.Count>0) then
    begin
      FillShapes; // 7.07

      if Assigned(InitialShape) then
      begin
        TabControlMap.ActiveTab:=TabShapes;
        TabControlMapChange(Self);
        LBShapes.ItemIndex:=LBShapes.Items.IndexOfObject(InitialShape);
      end
      else
         LBShapes.ItemIndex:=0;

      LBShapesClick(Self);
    end;

    TabControlMap.ActiveTab:=TabGlobal;
    TabControlShape.ActiveTab:=TabValues;
  end;
end;

procedure TMapSeriesEditor.FormCreate(Sender: TObject);
begin
  IReady:=True;
  InitialShape:=nil;
end;

procedure TMapSeriesEditor.FormDestroy(Sender: TObject);
begin
  FreeAndNil(Grid3DForm);
end;

procedure TMapSeriesEditor.ECodeChange(Sender: TObject);
var tmp : String;
begin
  if not ChangingText then
  begin
    tmp:=SelectedShape.Code;

    if tmp<>ECode.Text then
       SelectedShape.Code:=ECode.Text;
  end;
end;

procedure TMapSeriesEditor.EditZChange(Sender: TObject);
var tmp : Double;
begin
  if IReady and (not ChangingText) then
  begin
    tmp:=StrToFloat(EditZ.Text);
    if SelectedShape.Z<>tmp then
    begin
      SelectedShape.Z:=tmp;
      Map.Repaint;
    end;
  end;
end;

procedure TMapSeriesEditor.EnableTabs;

  procedure EnableControls(Tab:TTabItem; Value:Boolean);
  var t : Integer;
  begin
    for t:=0 to Tab. ChildrenCount-1 do
      if Tab.Children[t] is TControl then
         (Tab.Children[t] as TControl).Enabled:=Value;
  end;

var tmp : Boolean;
begin
  tmp:=Assigned(Map) and (Map.Shapes.Count>0) and (SelectedShape<>nil);

  EnableControls(TabValues,tmp);
  EnableControls(TabFormat,tmp);
  EnableControls(TabPoints,tmp);
end;

procedure TMapSeriesEditor.SBAddClick(Sender: TObject);
begin
  with Map.Shapes.Add do { 5.02 }
       Text:=IntToStr(Map.Count);

  FillShapes;

  with LBShapes do
  begin
    ItemIndex:=Items.Count-1;
    SelectRange(ListItems[ItemIndex],ListItems[ItemIndex]);
    SetFocus;
  end;

  LBShapesClick(Self);
  EnableTabs;
end;

procedure TMapSeriesEditor.SBDeleteClick(Sender: TObject);
var tmpLast : Boolean;
    tmp     : Integer;
begin
  tmp:=LBShapes.ItemIndex;
  tmpLast:=LBShapes.ItemIndex=LBShapes.Items.Count-1;
  Map.Delete(LBShapes.ItemIndex);
  SBDelete.Enabled:=Map.Shapes.Count>0;

  FillShapes;

  if Map.Shapes.Count>0 then
  begin
    if tmpLast then tmp:=LBShapes.Items.Count-1;
  end
  else tmp:=-1;

  with LBShapes do
  begin
    ItemIndex:=tmp;
    if tmp>=0 then
       SelectRange(ListItems[tmp],ListItems[tmp]);
  end;

  LBShapesClick(Self);
  EnableTabs;
end;

function TMapSeriesEditor.SelectedShape: TTeePolygon;
begin
  if LBShapes.ItemIndex>=0 then
     result:=Map.Shapes[LBShapes.ItemIndex]
  else
     result:=nil;
end;

procedure TMapSeriesEditor.TabControlMapChange(Sender: TObject);
begin
  if Assigned(Map) and
     ((LBShapes.Items.Count<>Map.Shapes.Count) or DirtyList) then
  begin
    FillShapes;
    LBShapesClick(Self);
  end;
end;

procedure TMapSeriesEditor.TabControlShapeChange(Sender: TObject);
begin
  if (TabControlShape.ActiveTab=TabBorder) and (not Assigned(IShapeBorder)) then
     IShapeBorder:=TStrokeEditor.InsertForm(SelectedShape.Pen,TabBorder)
  else
  if (TabControlShape.ActiveTab=TabPattern) and (not Assigned(IShapeBrush)) then
     IShapeBrush:=TBrushEditor.InsertForm(SelectedShape.Brush,TabPattern);
end;

procedure TMapSeriesEditor.ETextChange(Sender: TObject);
var tmp : String;
begin
  if not ChangingText then
  begin
    tmp:=SelectedShape.Text;
    if tmp<>EText.Text then
    begin
      SelectedShape.Text:=EText.Text;
      With LBShapes do Items[ItemIndex]:=SelectedShape.Text;
    end;
  end;
end;

Procedure TMapSeriesEditor.FillShapes;
var t : Integer;
    tmp : TListBoxItem;
begin
  With LBShapes do
  begin
    Items.BeginUpdate;
    try
      Clear;
      for t:=0 to Map.Shapes.Count-1 do
      begin
        tmp:=TListBoxItem.Create(Owner);
        tmp.Text:=Map.Labels[t];
        if tmp.Text='' then
          tmp.Text:=IntToStr(t);
        tmp.Data:=Map.Shapes[t].Points;
        tmp.IsChecked:=Map.Shapes[t].Points.Visible;
        AddObject(tmp);
      end;
    finally
      Items.EndUpdate;
    end;
  end;

  DirtyList:=False;
end;

procedure TMapSeriesEditor.ChartGridSetEditText(Sender: TObject; const ACol,
  ARow: Integer; const Value: {$IFDEF D17}TValue{$ELSE}Variant{$ENDIF});
begin
  if Assigned(Map) then
    Map.Repaint;
end;

procedure TMapSeriesEditor.UDMapTranspChange(Sender: TObject);
begin
  if Assigned(Map) then
    Map.Transparency:=Round(UDMapTransp.Value);
end;

procedure TMapSeriesEditor.UDPointSizeChange(Sender: TObject);
begin
  if Assigned(Map) then
    Map.PointSize:=Round(UDPointSize.Value);
end;

procedure TMapSeriesEditor.UDTranspChange(Sender: TObject);
begin
  if SelectedShape<>nil then
     SelectedShape.Transparency:=Round(UDTransp.Value);
end;

initialization
  RegisterSeriesEditor(TMapSeriesEditor);
end.
