unit FormItem;

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ItemList,
  ExtCtrls, ColorBox, Spin, Generics.Collections, FormEx;

type

  { TFormItem }

  TFormItem = class(TFormEx)
    ButtonOk: TButton;
    ButtonCancel: TButton;
    ScrollBox1: TScrollBox;
    procedure ButtonOkClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    FItem: TItem;
    DataControls: TObjectList<TControl>;
    DataLabels: TObjectList<TLabel>;
    procedure ControlChangeExecute(Sender: TObject);
    procedure SetItem(AValue: TItem);
    procedure LoadData(Item: TItem); virtual;
    procedure SaveData(Item: TItem); virtual;
    procedure InitControls;
  public
    procedure UpdateInterface;
    property Item: TItem read FItem write SetItem;
  end;


implementation

{$R *.lfm}

{ TFormItem }

procedure TFormItem.ButtonOkClick(Sender: TObject);
begin
  SaveData(Item);
end;

procedure TFormItem.FormCreate(Sender: TObject);
begin
  DataControls := TObjectList<TControl>.Create;
  DataLabels := TObjectList<TLabel>.Create;
end;

procedure TFormItem.FormDestroy(Sender: TObject);
begin
  FreeAndNil(DataLabels);
  FreeAndNil(DataControls);
end;

procedure TFormItem.ControlChangeExecute(Sender: TObject);
begin
  UpdateInterface;
end;

procedure TFormItem.SetItem(AValue: TItem);
begin
  if FItem = AValue then Exit;
  FItem := AValue;
  if Assigned(FItem) then begin
    InitControls;
    LoadData(Item);
    Caption := Item.GetClassName;
  end else begin
    DataControls.Clear;
  end;
end;

procedure TFormItem.LoadData(Item: TItem);
var
  Fields: TItemFields;
  I: Integer;
  J: Integer;
  Control: TControl;
  ReferenceList: TBaseItemList;
  ReferenceItem: TItem;
begin
  Fields := Item.GetFields;
  for I := 0 to Fields.Count - 1 do
  with Fields[I] do begin
    Control := DataControls[I];
    if DataType = dtInteger then TSpinEdit(Control).Value := Item.GetValueInteger(Index)
    else if DataType = dtString then TEdit(Control).Text := Item.GetValueString(Index)
    else if DataType = dtColor then TColorBox(Control).Selected := Item.GetValueColor(Index)
    else if DataType = dtBoolean then TCheckBox(Control).Checked := Item.GetValueBoolean(Index)
    else if DataType = dtEnumeration then begin
      TComboBox(Control).Items.BeginUpdate;
      try
        TComboBox(Control).Items.Clear;
        for J := 0 to EnumStates.Count - 1 do
          TComboBox(Control).Items.Add(EnumStates[J]);
        TComboBox(Control).ItemIndex := Integer(Item.GetValueEnumeration(Index));
      finally
        TComboBox(Control).Items.EndUpdate;
      end;
    end
    else if DataType = dtReference then begin
      TComboBox(Control).Items.BeginUpdate;
      try
        TComboBox(Control).Items.Clear;
        ReferenceList := Item.GetReferenceList(Index);
        if Assigned(ReferenceList) then
          for J := 0 to ReferenceList.Count - 1 do
            TComboBox(Control).Items.AddObject(TItem(ReferenceList[J]).Name, ReferenceList[J]);
        ReferenceItem := TItem(Item.GetValueReference(Index));
        TComboBox(Control).ItemIndex := TComboBox(Control).Items.IndexOfObject(ReferenceItem);
      finally
        TComboBox(Control).Items.EndUpdate;
      end;
    end
    else raise Exception.Create(Format(SUnsupportedDataType, [DataTypeStr[DataType]]));
  end;
  Fields.Free;
  UpdateInterface;
end;

procedure TFormItem.SaveData(Item: TItem);
var
  Fields: TItemFields;
  I: Integer;
  Control: TControl;
begin
  Fields := Item.GetFields;
  for I := 0 to Fields.Count - 1 do
  with Fields[I] do begin
    Control := DataControls[I];
    if DataType = dtInteger then Item.SetValueInteger(Index, TSpinEdit(Control).Value)
    else if DataType = dtString then Item.SetValueString(Index, TEdit(Control).Text)
    else if DataType = dtColor then Item.SetValueColor(Index, TColorBox(Control).Selected)
    else if DataType = dtBoolean then Item.SetValueBoolean(Index, TCheckBox(Control).Checked)
    else if DataType = dtEnumeration then Item.SetValueEnumeration(Index, TUndefinedEnum(TComboBox(Control).ItemIndex))
    else if DataType = dtReference then begin
      if TComboBox(Control).ItemIndex <> -1 then
        Item.SetValueReference(Index, TItem(TComboBox(Control).Items.Objects[TComboBox(Control).ItemIndex]))
        else Item.SetValueReference(Index, nil);
    end
    else raise Exception.Create(Format(SUnsupportedDataType, [DataTypeStr[DataType]]));
  end;
  Fields.Free;
end;

procedure TFormItem.InitControls;
var
  NewControl: TControl;
  NewLabel: TLabel;
  Fields: TItemFields;
  I: Integer;
  Y: Integer;
begin
  DataControls.Clear;
  DataLabels.Clear;
  Y := Scale96ToScreen(8);
  Fields := Item.GetFields;
  for I := 0 to Fields.Count - 1 do
  with Fields[I] do begin
    NewLabel := TLabel.Create(ScrollBox1);
    NewLabel.Left := Scale96ToScreen(8);
    NewLabel.Top := Y;
    NewLabel.Parent := ScrollBox1;
    NewLabel.Caption := Name + ':';
    NewLabel.Visible := True;
    DataLabels.Add(NewLabel);

    if DataType = dtInteger then begin
      NewControl := TSpinEdit.Create(nil);
      NewControl.Width := Scale96ToScreen(100);
      TSpinEdit(NewControl).MaxValue := High(Integer);
    end else
    if DataType = dtString then begin
      NewControl := TEdit.Create(nil);
      NewControl.Width := Scale96ToScreen(200);
    end else
    if DataType = dtColor then begin
      NewControl := TColorBox.Create(nil);
      NewControl.Width := Scale96ToScreen(200);
      TColorBox(NewControl).Style := [cbStandardColors, cbExtendedColors,
        cbCustomColor, cbPrettyNames];
    end else
    if DataType = dtEnumeration then begin
      NewControl := TComboBox.Create(nil);
      NewControl.Width := Scale96ToScreen(200);
      TComboBox(NewControl).Style := csDropDownList;
      TComboBox(NewControl).OnChange := ControlChangeExecute;
    end else
    if DataType = dtReference then begin
      NewControl := TComboBox.Create(nil);
      NewControl.Width := Scale96ToScreen(200);
      TComboBox(NewControl).Style := csDropDownList;
    end else
    if DataType = dtBoolean then begin
      NewControl := TCheckBox.Create(nil);
    end else
      raise Exception.Create(Format(SUnsupportedDataType, [DataTypeStr[DataType]]));
    NewControl.Left := Scale96ToScreen(150);
    NewControl.Top := Y;
    NewControl.Parent := ScrollBox1;
    TFormEx.Translator.TranslateComponent(NewControl);
    TFormEx.ThemeManager.ApplyTheme(NewControl);
    NewControl.Visible := True;
    DataControls.Add(NewControl);
    Y := Y + Scale96ToScreen(30);
  end;
  Fields.Free;
end;

procedure TFormItem.UpdateInterface;
var
  I: Integer;
  Fields: TItemFields;
  Condition: Boolean;
begin
  Fields := Item.GetFields;
  try
    for I := 0 to Fields.Count - 1 do
    with Fields[I] do begin
      if VisibleIfIndex > 0 then begin
        if Fields[VisibleIfIndex].DataType = dtEnumeration then begin
          Condition := TComboBox(DataControls[VisibleIfIndex]).ItemIndex > 0;
        end else Condition := False;
      end;
      DataControls[I].Visible := (VisibleIfIndex = 0) or ((VisibleIfIndex > 0) and Condition);
      DataLabels[I].Visible := DataControls[I].Visible;
    end;
  finally
    Fields.Free;
  end;
end;

end.

