unit MetaEditor;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, _BaseTemplate, ExtCtrls, VirtualTrees, StdCtrls, ComCtrls, Grids,
  MPHexEditor, Wrapgrid, VTHeaderPopup, Menus, _TreeElement;

type
  TForm_Meta = class(TForm_BaseTemplate)
    VST: TVirtualStringTree;
    splitter: TSplitter;
    rightPages: TPageControl;
    tab_hex: TTabSheet;
    tab_meta: TTabSheet;
    panel_hex_actions: TPanel;
    hex: TMPHexEditor;
    splitter_hex_1: TSplitter;
    value_viewer: TWrapGrid;
    splitter_hex_2: TSplitter;
    structviewer: TVirtualStringTree;
    value_viewer_context: TPopupMenu;
    value_viewer_context_copy: TMenuItem;
    value_viewer_context_copyasdec: TMenuItem;
    value_viewer_context_copyasfloat: TMenuItem;
    value_viewer_context_copyasbitset: TMenuItem;
    value_viewer_context_copyasstring: TMenuItem;
    value_viewer_context_copyashex: TMenuItem;
    VTHPopup: TVTHeaderPopupMenu;
    btn_export: TButton;
    btn_import: TButton;
    vst_popup: TPopupMenu;
    vst_newRoot: TMenuItem;
    vst_setRoot: TMenuItem;
    procedure FormCreate(Sender: TObject);
    procedure VSTInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode;
      var ChildCount: Cardinal);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure VSTFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode;
      Column: TColumnIndex);
    procedure VSTFocusChanging(Sender: TBaseVirtualTree; OldNode,
      NewNode: PVirtualNode; OldColumn, NewColumn: TColumnIndex;
      var Allowed: Boolean);
    procedure VSTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
      Column: TColumnIndex; TextType: TVSTTextType; var CellText: WideString);
    procedure VSTPaintText(Sender: TBaseVirtualTree;
      const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
      TextType: TVSTTextType);
    procedure VSTGetPopupMenu(Sender: TBaseVirtualTree; Node: PVirtualNode;
      Column: TColumnIndex; const P: TPoint; var AskParent: Boolean;
      var PopupMenu: TPopupMenu);
    procedure vst_setRootClick(Sender: TObject);
    procedure vst_newRootClick(Sender: TObject);
    procedure VSTGetHint(Sender: TBaseVirtualTree; Node: PVirtualNode;
      Column: TColumnIndex; var LineBreakStyle: TVTTooltipLineBreakStyle;
      var HintText: WideString);
  private
    root: TTreeElement;
    procedure NewCon(ID: Integer);
  public
    procedure SetRoot(TreeElem: TTreeElement);
  end;


implementation
{$R *.dfm}
uses _MetaManager, _MetaTypes, ConnectionManager, Data, _FileTypes, Main, 
  TypeDefs;

type
  PNodeData = ^TNodeData;

  TNodeData = record
    Field: TTreeElement;
  end;

function AddVSTEntry(AVST: TCustomVirtualStringTree; ANode: PVirtualNode;
  ARecord: TNodeData): PVirtualNode;
var
  Data: PNodeData;
begin
  Result := AVST.AddChild(ANode);
  Data   := AVST.GetNodeData(Result);
  AVST.ValidateNode(Result, False);
  Data^ := ARecord;
end;


procedure TForm_Meta.NewCon(ID: Integer);
begin
  if ID >= 0 then
    SetRoot(ConManager.Connection[FConnectionID].MetaData.Root);
//SetRoot(ConManager.Connection[FConnectionID].MetaData.FileById[454]);
end;


procedure TForm_Meta.SetRoot(TreeElem: TTreeElement);
var
  i: Integer;
  data: TNodeData;
  node: PVirtualNode;
begin
  if FConnectionID <> TreeElem.ConnectionID then
    SelectConnection(TreeElem.ConnectionID);
  root := TreeElem;
  VST.Clear;
  VST.BeginUpdate;
  for i := 0 to root.ChildCount - 1 do
  begin
    data.Field := root.Child[i];
    node := AddVSTEntry(VST, nil, data);
    if data.Field.ChildCount > 0 then
      VST.HasChildren[node] := True;
  end;
  VST.EndUpdate;
end;

procedure TForm_Meta.VSTInitChildren(Sender: TBaseVirtualTree;
  Node: PVirtualNode; var ChildCount: Cardinal);
var
  data: PNodeData;
  newdata: TNodeData;
  newnode: PVirtualNode;
  i: Integer;
begin
  data := Sender.GetNodeData(node);

  if data.Field.ChildCount > 0 then
  begin
    for i := 0 to data.Field.ChildCount - 1 do
    begin
      newdata.Field := data.Field.Child[i];
      newnode := AddVSTEntry(TCustomVirtualStringTree(Sender), Node, newdata);
      if newdata.Field.ChildCount > 0 then
        Sender.HasChildren[newnode] := True;
    end;
  end;
  ChildCount := Sender.ChildCount[Node];
end;



procedure TForm_Meta.VSTFocusChanged(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Column: TColumnIndex);
var
  data: PNodeData;
  ffile: TFile;
//*******************************************************************
  fs: TFileStream;
//*******************************************************************
begin
  data := Sender.GetNodeData(Node);
  ffile := nil;
  if data.Field is TFile then
    ffile := TFile(data.Field);
  if data.Field is _MetaTypes.TDatLink then
    if Assigned(_MetaTypes.TDatLink(data.Field).TargetFile) then
      ffile := TFile(_MetaTypes.TDatLink(data.Field).TargetFile);
  if Assigned(ffile) then
  begin
    if Assigned(ffile.Editor) then
    begin
      ffile.Editor.Align := alClient;
      tab_meta.InsertControl(ffile.Editor);
      ffile.Opened := True;
    end;
//*******************************************************************
//    fs := TFileStream.Create('C:\Spiele\Oni\GameDataFolder\tests\'+IntToStr(ffile.FileInfo.ID)+'_recreated.hex', fmCreate);
//    ffile.ReCreateFile(fs);
//    fs.Free;
//*******************************************************************
  end;
end;


procedure TForm_Meta.VSTFocusChanging(Sender: TBaseVirtualTree; OldNode,
  NewNode: PVirtualNode; OldColumn, NewColumn: TColumnIndex;
  var Allowed: Boolean);
var
  data: PNodeData;
  i: Integer;
begin
  data := Sender.GetNodeData(NewNode);
  if data.Field is TFile then
  begin
    if Assigned(TFile(data.Field).Editor) then
      Allowed := not TFile(data.Field).Opened
    else
      Allowed := True;
  end;
  if Allowed and Assigned(OldNode) then
  begin
    data := Sender.GetNodeData(OldNode);
    if data.Field is TFile then
    begin
      if TFile(data.Field).Opened then
      begin
        if tab_meta.ControlCount > 0 then
          for i := 0 to tab_meta.ControlCount - 1 do
            tab_meta.RemoveControl(tab_meta.Controls[i]);
        TFile(data.Field).Opened := False;
      end;
    end;
  end;
end;


procedure TForm_Meta.VSTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
  Column: TColumnIndex; TextType: TVSTTextType; var CellText: WideString);
var
  Data: PNodeData;
begin
  Data     := Sender.GetNodeData(Node);
  CellText := '';
  if TextType = ttNormal then
  begin
    case Column of
      0: CellText := Data.Field.Caption;
      1: CellText := data.Field.VType;
      2:
        begin
          if Data.Field is TDataField then
            CellText := TDataField(Data.Field).ValueAsString;
        end;
    end;
  end;
end;


procedure TForm_Meta.VSTPaintText(Sender: TBaseVirtualTree;
  const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
  TextType: TVSTTextType);
var
  Data: PNodeData;
begin
  Data     := Sender.GetNodeData(Node);
  if TextType = ttNormal then
  begin
    case Column of
      0:
        begin
          if Data.Field is TFile then
          begin
            if Length(TFile(Data.Field).FileInfo.Name) = 0 then
              TargetCanvas.Font.Color := $C06060;
            if TFile(Data.Field).FileInfo.Size = 0 then
              TargetCanvas.Font.Color := $2020A0;
          end;
        end;
    end;
  end;
end;



procedure TForm_Meta.VSTGetHint(Sender: TBaseVirtualTree; Node: PVirtualNode;
  Column: TColumnIndex; var LineBreakStyle: TVTTooltipLineBreakStyle;
  var HintText: WideString);
var
  data: PNodeData;
  CellText: WideString;

  i: Integer;
  links: TStrings;
begin
  inherited;
  if Assigned(Node) then
  begin
    VSTGetText(Sender, Node, Column, ttNormal, CellText);
    if Length(CellText) > 0 then
    begin
      data := Sender.GetNodeData(Node);
      if data.Field is TDataField then
      begin
        case Column of
          0,1: HintText := TDataField(data.Field).Description;
          2: HintText := '';
        end;
      end;
      if (data.Field is _MetaTypes.TDatLink) and (Column = 2) then
      begin
        links := nil;
        links := ConManager.Connection[FConnectionID].GetFilesList(_MetaTypes.TDatLink(data.Field).PosExts, '', False, ST_NameAsc);
        HintText := IntToStr(links.Count);
        for i := 0 to Min(links.Count - 1, 99) do
        begin
          if (i mod 5) = 0 then
            HintText := HintText + #13+#10;
          HintText := HintText + links.Strings[i] + '       ';
        end;
      end;
    end;
  end
  else
    HintText := '';
end;

procedure TForm_Meta.VSTGetPopupMenu(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Column: TColumnIndex; const P: TPoint;
  var AskParent: Boolean; var PopupMenu: TPopupMenu);
var
  data: PNodeData;
begin
  inherited;
  AskParent := False;
  if Assigned(Node) then
  begin
    Sender.Selected[Node] := True;
    Sender.FocusedNode := Node;
    data := Sender.GetNodeData(Node);
    if Column = 0 then
    begin
      if TTreeElement(data.Field).ChildCount > 0 then
        PopupMenu := vst_popup
      else
        PopupMenu := nil;
    end;
  end;
end;

procedure TForm_Meta.vst_newRootClick(Sender: TObject);
var
  data: PNodeData;
  form: TForm_BaseTemplate;
begin
  inherited;
  data := VST.GetNodeData(VST.FocusedNode);
  form := nil;
  form := Form_Main.open_child('meta');
  if form is TForm_Meta then
    TForm_Meta(form).SetRoot(data.Field);
end;

procedure TForm_Meta.vst_setRootClick(Sender: TObject);
var
  data: PNodeData;
begin
  inherited;
  data := VST.GetNodeData(VST.FocusedNode);
  SetRoot(data.Field);
end;

procedure TForm_Meta.FormClose(Sender: TObject; var Action: TCloseAction);
begin
//  Meta.Free;
  inherited;
end;

procedure TForm_Meta.FormCreate(Sender: TObject);
begin
  inherited;
  OnNewConnection := NewCon;

  VST.NodeDataSize := SizeOf(TNodeData);
  VST.Font.Charset := AppSettings.CharSet;
  VST.Clear;

  UpdateConList;
end;

end.
