unit Main;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, StrUtils, Clipbrd, ExtCtrls, ComCtrls, Menus, Grids,
  MPHexEditor, ToolWin, ImgList, Tabs,
  MDITab, TB2Item, TB2Dock, TB2Toolbar, TB2MDI, OneInst,
  Data, TypeDefs, ConnectionManager,
  Functions, Settings,
  RawEdit, BinEdit, Extractor, Preview, TxmpReplace,
  _BaseTemplate, _TemplateFile, _TemplateFileList;

type
  TForm_Main = class(TForm)
    saved:      TSaveDialog;
    opend:      TOpenDialog;
    statbar:    TStatusBar;
    MenuImages: TImageList;
    DockTop:    TTBDock;
    MainMenu:   TTBToolbar;
    menu_main:  TTBSubmenuItem;
    menu_loadfile: TTBItem;
    menu_sep1:  TTBSeparatorItem;
    menu_settings: TTBItem;
    menu_sep4:  TTBSeparatorItem;
    menu_exit:  TTBItem;
    menu_convert: TTBSubmenuItem;
    menu_createdb: TTBItem;
    menu_createlvl: TTBItem;
    menu_tools: TTBSubmenuItem;
    menu_preview: TTBItem;
    menu_binedit: TTBItem;
    menu_rawedit: TTBItem;
    menu_txmpreplace: TTBItem;
    menu_extractor: TTBItem;
    menu_filecompare: TTBItem;
    menu_levelstructedit: TTBItem;
    menu_view: TTBSubmenuItem;
    menu_windows_cascade: TTBItem;
    menu_windows_tile: TTBItem;
    menu_windows_closeall: TTBItem;
    menu_sep3:  TTBSeparatorItem;
    menu_windows_next: TTBItem;
    menu_windows_previous: TTBItem;
    menu_sep2:  TTBSeparatorItem;
    menu_About: TTBItem;
    Toolbar:    TTBToolbar;
    tbOpen:     TTBItem;
    DockLeft:   TTBDock;
    DockRight:  TTBDock;
    DockBottom: TTBDock;
    MDIToolbar: TTBToolbar;
    TBControlItem1: TTBControlItem;
    MDITab:     TMDITab;
    menu_toolbars: TTBSubmenuItem;
    menu_view_mdibar: TTBItem;
    menu_view_statusbar: TTBItem;
    menu_view_toolbar: TTBItem;
    tb_separator1: TTBSeparatorItem;
    tb_preview: TTBItem;
    tb_structure: TTBItem;
    tb_compare: TTBItem;
    tb_extractor: TTBItem;
    tb_txmpreplacer: TTBItem;
    tb_rawedit: TTBItem;
    tb_datedit: TTBItem;
    menu_windows_tilevert: TTBItem;
    tb_meta: TTBItem;
    menu_meta: TTBItem;
    TBSeparatorItem1: TTBSeparatorItem;
    tb_db2dat: TTBItem;
    tb_dat2db: TTBItem;
    menu_loaddb: TTBItem;
    tb_opendb: TTBItem;
    Images_Close: TImageList;
    menu_conns: TTBSubmenuItem;
    menu_windows: TTBSubmenuItem;
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormResize(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure ActivateTools(active: Boolean);
    procedure UpdateStatBar;
    procedure UpdateConLists;
    procedure LoadFile(typedb: Boolean);
    function TryCloseAll: Boolean;
    procedure MDITabDrawTab(Control: TCustomTabControl; TabIndex: Integer;
      const Rect: TRect; Active: Boolean);
    procedure MDITabMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure MDITabMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure ToolbarDockChanged(Sender: TObject);
    procedure CreateConnection(filename: String);
    function CheckConnectionCloseable(index: Integer): Boolean;

    procedure menu_loadfileClick(Sender: TObject);
    procedure menu_loaddbClick(Sender: TObject);
    procedure menu_settingsClick(Sender: TObject);
    procedure menu_exitClick(Sender: TObject);

    procedure menu_createlvlClick(Sender: TObject);
    procedure menu_createdbClick(Sender: TObject);

    procedure menu_bineditClick(Sender: TObject);
    procedure menu_filecompareClick(Sender: TObject);
    procedure menu_raweditClick(Sender: TObject);
    procedure menu_extractorClick(Sender: TObject);
    procedure menu_txmpreplaceClick(Sender: TObject);
    procedure menu_previewClick(Sender: TObject);
    procedure menu_metaClick(Sender: TObject);

    procedure menu_windows_cascadeClick(Sender: TObject);
    procedure menu_windows_tilevertClick(Sender: TObject);
    procedure menu_windows_tileClick(Sender: TObject);
    procedure menu_windows_closeallClick(Sender: TObject);
    procedure menu_windows_previousClick(Sender: TObject);
    procedure menu_windows_nextClick(Sender: TObject);
    procedure menu_conns_itemClick(Sender: TObject);
    procedure menu_windows_itemClick(Sender: TObject);
    procedure menu_view_mdibarClick(Sender: TObject);
    procedure menu_view_statusbarClick(Sender: TObject);
    procedure menu_view_toolbarClick(Sender: TObject);

    procedure menu_AboutClick(Sender: TObject);

    procedure WMCopyData(var Msg: TWMCopyData); message WM_COPYDATA;
  private
  public
    function open_child(window_context: String; Connection, FileID: Integer): TForm_BaseTemplate; overload;
    function open_child(window_context: String; Connection: Integer): TForm_BaseTemplate; overload;
    function open_child(window_context: String): TForm_BaseTemplate; overload;
    procedure DefaultHandler(var Message); override;
  end;

var
  Form_Main: TForm_Main;

implementation

uses
  LevelDB, MetaEditor;

{$R *.dfm}


procedure ShowOpenMsg(msg: TStatusMessages);
begin
  case msg of
    SM_AlreadyOpened:    ShowMessage('File already opened.');
    SM_FileNotFound:     ShowMessage('File not found.');
    SM_UnknownExtension: ShowMessage('Unknown extension.');
    SM_IncompatibleFile: ShowMessage('Incompatible file format.');
    SM_UnknownError:     ShowMessage('Unknown error.');
  end;
end;

procedure TForm_Main.CreateConnection(filename: String);
var
  RepMsg: TStatusMessages;
begin
  ConManager.OpenConnection(filename, RepMsg);
  ShowOpenMsg(RepMsg);
  if RepMsg = SM_OK then
  begin
    UpdateStatBar;
    UpdateConLists;
  end;
end;

function TForm_Main.CheckConnectionCloseable(index: Integer): Boolean;
var
  i: Integer;
  toolform: TForm_BaseTemplate;
begin
  Result := True;
  if MDITab.MDIChildCount > 0 then
  begin
    for i := 0 to MDITab.MDIChildCount - 1 do
    begin
      if MDITab.MDIChildren[i] is TForm_BaseTemplate then
      begin
        toolform := TForm_BaseTemplate(MDITab.MDIChildren[i]);
        if toolform.ConnectionID = ConManager.ConnectionByIndex[index].ConnectionID then
        begin
          if not toolform.Closeable then
          begin
            ShowMessage('Can not close toolwindow: ' + toolform.Caption);
            Result := False;
          end;
        end; 
      end;
    end;
  end;
end;


{ Eine zweite Instanz hat uns ihre Kommandozeilenparameter geschickt }
procedure TForm_Main.WMCopyData(var Msg: TWMCopyData);
var
  strings: TStringList;
begin
  if (Msg.CopyDataStruct.dwData = SecondInstMsgId) and (SecondInstMsgId <> 0) then
  begin
    Application.BringToFront;
    
    strings := TStringList.Create;
    strings.Text := ParamBlobToStr(Msg.CopyDataStruct.lpData);
    if strings.Count = 2 then
    begin
      if strings.Strings[0] = 'opf' then
      begin
        ShowMessage('Load OPF-File: ' + ParamStr(2));
      end
      else if (strings.Strings[0] = 'oldb') or (strings.Strings[0] = 'dat') then
      begin
        CreateConnection(strings.Strings[1]);
      end;
    end;
  end
  else
    inherited;
end;

{----------------------------------------------------------------------------}
{ Wir überschreiben den DefaultHandler, der alle Nachrichten zuerst bekommt, }
{ damit wir auf die Nachricht mit der ID SecondInstMsgId reagieren können.   }
{ (Dies ist notwendig, da wir jetzt noch nicht wissen welchen Wert           }
{  die ID haben wird, weswegen wir keine statische Message-Prozedure,        }
{  so wie bei WM_COPYDATA, schreiben können.)                                }
{----------------------------------------------------------------------------}
procedure TForm_Main.DefaultHandler(var Message);
begin
  if TMessage(Message).Msg = SecondInstMsgId then
    { Eine zweite Instanz hat uns nach dem Handle gefragt }
    { Es wird in die Message-Queue des Threads gepostet.  }
    PostThreadMessage(TMessage(Message).WParam, SecondInstMsgId, Handle, 0)
  else
    inherited;
end;



procedure TForm_Main.FormCreate(Sender: TObject);
begin
  Self.Caption := 'Oni Un/Packer ' + version;
  Self.FormResize(Self);

  ConManager.OnCoonnectionListChanged := UpdateConLists;

  if FileExists(ExtractFilepath(Application.EXEname) + '\oniunpacker.ini') then
  begin
    AssignFile(AppSettingsFile, ExtractFilepath(Application.EXEname) +
      '\oniunpacker.ini');
    Reset(AppSettingsFile);
    Read(AppSettingsFile, AppSettings);
    CloseFile(AppSettingsFile);
  end
  else
  begin
    ShowMessage('Warning!' + #13#10 +
                'It seems like this is the first time you OUP.' + #13#10 +
                'I do not take any responsibility for messed up data files' + #13+#10 +
                'Do not forget to make backup copies of your *.dat/*.raw/*.sep files!');
    AppSettings.DatPath        := ExtractFilepath(Application.EXEname);
    AppSettings.ExtractPath    := ExtractFilepath(Application.EXEname) + '\extract';
    AppSettings.CharSet        := DEFAULT_CHARSET;
    AppSettings.HideUnusedData := False;
  end;

  if MidStr(ParamStr(1), 1, 3) = 'opf' then
  begin
    ShowMessage('Load OPF-File: ' + ParamStr(2));
  end
  else if (MidStr(ParamStr(1), 1, 4) = 'oldb') or (MidStr(ParamStr(1), 1, 3) = 'dat') then
  begin
    CreateConnection(ParamStr(2));
  end;
  UpdateStatBar;
end;




procedure TForm_Main.FormResize(Sender: TObject);
begin
  statbar.Panels.Items[0].Width := Self.Width - 200;
  MDITab.Width := Self.Width - 20;
end;




procedure TForm_Main.MDITabDrawTab(Control: TCustomTabControl;
  TabIndex: Integer; const Rect: TRect; Active: Boolean);
var
  x, y: Integer;
  iconindex: Integer;
  caption: String;
begin
  iconindex := TMDITab(Control).Glyphs[TabIndex];
  caption := TMDITab(Control).Captions[TabIndex];
  if active then
  begin
    Control.Canvas.Font.Style := Control.Canvas.Font.Style + [fsItalic];
    y := Rect.Top + 1;
  end else
    y := Rect.Top;
  if iconindex >= 0 then
  begin
    TMDITab(Control).Images.Draw(Control.Canvas, Rect.Left + 4, y, iconindex);
    x := Rect.Left + 26;
  end else
    x := Rect.Left + 4;
  Control.Canvas.TextOut(x, y + 2, caption);
  if active then
    Images_Close.Draw(Control.Canvas, Rect.Right - 18, y, 0)
  else
    Images_Close.Draw(Control.Canvas, Rect.Right - 18, y, 1);
end;


procedure TForm_Main.MDITabMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
var
  pt: TPoint;
  tabIndex: Integer;
  hint: String;
  tool: TForm_BaseTemplate;
begin
  pt.X := X;
  pt.Y := Y;
  tabIndex := MDITab.GetTabAtPos(pt);
  hint := '';

  if tabIndex >= 0 then
  begin
    if MDITab.MDIChildren[tabIndex] is TForm_BaseTemplate then
    begin
      tool := TForm_BaseTemplate(MDITab.MDIChildren[tabIndex]);
      if tool.ConnectionID > -1 then
        hint := 'Connection: ' +
              ExtractFileName(ConManager.Connection[tool.ConnectionID].FileName)
      else
        hint := 'Connection: none';
      if tool is TForm_TemplateFile then
      begin
        if TForm_TemplateFile(tool).SelectedFile.ID > -1 then
          hint := hint + #13+#10 + 'Selected File: ' +
                FormatNumber(TForm_TemplateFile(tool).SelectedFile.ID, 5, '0') + '-' +
                TForm_TemplateFile(tool).SelectedFile.Name + '.' +
                TForm_TemplateFile(tool).SelectedFile.Extension
        else
          hint := hint + #13+#10 + 'Selected File: none';
      end;
    end
    else
      hint := 'Window: ' + MDITab.MDIChildren[tabIndex].Caption;
    if hint <> MDITab.Hint then
    begin
      MDITab.Hint := hint;
      MDITab.ShowHint := True;
    end;
  end
  else
  begin
    MDITab.ShowHint := False;
    MDITab.Hint := '';
  end;
end;

procedure TForm_Main.MDITabMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  pt: TPoint;
  tabIndex: Integer;
  tabRect: TRect;
  tabX, tabY, tabWidth: Integer;
begin
  pt.X := X;
  pt.Y := Y;
  tabIndex := MDITab.GetTabAtPos(pt);

//  if (Button = mbRight) and (tabIndex >= 0) then
//    MDITab.MDIChildren[tabIndex].Close;

  if (Button = mbLeft) and (tabIndex >= 0) then
  begin
    tabrect := MDITab.TabRect(tabIndex);
    tabX := X - tabrect.Left;
    tabY := Y - tabrect.Top;
    tabwidth := tabrect.Right - tabrect.Left;
    if (tabY >= 4) and (tabY <= 17) then
      if (tabX >= tabwidth - 19) and (tabX <= tabwidth - 7) then
        MDITab.MDIChildren[tabIndex].Close;
  end;
end;




procedure TForm_Main.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  AssignFile(AppSettingsFile, ExtractFilepath(Application.EXEname) + '\oniunpacker.ini');
  if FileExists(ExtractFilepath(Application.EXEname) + '\oniunpacker.ini') then
    Reset(AppSettingsFile)
  else
    Rewrite(AppSettingsFile);
  Write(AppSettingsFile, AppSettings);
  CloseFile(AppSettingsFile);
  Action := caFree;
end;



procedure TForm_Main.ActivateTools(active: Boolean);
begin
  menu_tools.Enabled := active;
  tb_preview.Enabled := active;
  tb_datedit.Enabled := active;
  tb_rawedit.Enabled := active;
  tb_txmpreplacer.Enabled := active;
  tb_extractor.Enabled := active;
  tb_meta.Enabled := active;
//  tb_compare.Enabled := active;
//  tb_structure.Enabled := active;
end;

procedure TForm_Main.UpdateStatBar;
begin
  if ConManager.Count > 0 then
  begin
    Self.Caption      := 'Oni Un/Packer ' + version;
    ActivateTools(True);
    statbar.Panels.Items[1].Text := 'Connections: ' + IntToStr(ConManager.Count);
  end
  else
  begin
    Self.Caption      := 'Oni Un/Packer ' + version;
    statbar.Panels.Items[0].Text := '';
    statbar.Panels.Items[1].Text := 'Connections: -';
    statbar.Panels.Items[2].Text := '';
    ActivateTools(False);
  end;
  menu_conns.Enabled := ConManager.Count > 0;
end;




procedure TForm_Main.ToolbarDockChanged(Sender: TObject);
var
  toolbar: TTBToolbar;
  position: TTBDockPosition;
  mode: TTBItemDisplayMode;
  i: Integer;
begin
  toolbar := TTBToolbar(Sender);
  if toolbar.Floating then
    mode := nbdmImageAndText
  else begin
    position := toolbar.CurrentDock.Position;
    if position in [dpLeft, dpRight] then
      mode := nbdmDefault
    else
      mode := nbdmImageAndText;
  end;
  for i := 0 to toolbar.Items.Count - 1 do
    toolbar.Items.Items[i].DisplayMode := mode;
end;

function TForm_Main.TryCloseAll: Boolean;
begin
  menu_windows_closeallClick(Self);
  Application.ProcessMessages;
  if MDITab.MDIChildCount = 0 then
    Result := True
  else
    Result := False;
end;


procedure TForm_Main.UpdateConLists;
var
  i: Integer;
  entry: TTBItem;
begin
  if MDITab.MDIChildCount > 0 then
    for i := 0 to MDITab.MDIChildCount - 1 do
      if MDITab.MDIChildren[i] is TForm_BaseTemplate then
        TForm_BaseTemplate(MDITab.MDIChildren[i]).UpdateConList;

  menu_conns.Clear;
  if ConManager.Count > 0 then
  begin
    for i := 0 to ConManager.Count - 1 do
    begin
      entry := TTBItem.Create(menu_conns);
      entry.Caption := ExtractFileName(ConManager.ConnectionByIndex[i].FileName);
      entry.Name := 'menu_conn_' + IntToStr(i);
      entry.OnClick := menu_conns_itemClick;
      menu_conns.Add(entry);
      entry := nil;
    end;
  end;
end;


procedure TForm_Main.LoadFile(typedb: Boolean);
var
  i: Integer;
begin
  opend.InitialDir := AppSettings.DatPath;
  opend.Filter     := 'Compatible level files|*.dat;*.oldb|Oni level (*.dat)|*.dat|OUP level database (*.oldb)|*.oldb|Any (*.*)|*';
  if typedb then
    opend.FilterIndex := 3
  else
    opend.FilterIndex := 2;
  if opend.Execute then
  begin
    if opend.Files.Count > 0 then
      for i := 0 to opend.Files.Count - 1 do
        CreateConnection(opend.Files.Strings[i]);
    AppSettings.DatPath := ExtractFilepath(opend.FileName);
  end;
  UpdateStatBar;
end;


 {#################################}
 {##### Main-Menu-Handlers    #####}
 {#################################}
procedure TForm_Main.menu_loaddbClick(Sender: TObject);
begin
  LoadFile(True);
end;

procedure TForm_Main.menu_loadfileClick(Sender: TObject);
begin
  LoadFile(False);
end;


procedure TForm_Main.menu_settingsClick(Sender: TObject);
begin
  Form_Settings.Visible := True;
  Self.Enabled   := False;
end;


procedure TForm_Main.menu_exitClick(Sender: TObject);
begin
  Self.Close;
end;


 {####################################}
 {##### Converters-Menu-Handlers #####}
 {####################################}
procedure TForm_Main.menu_createdbClick(Sender: TObject);
begin
  opend.Filter     := 'Oni-Dat-Files|*.dat';
  saved.Filter     := 'OUP-Level-DB (*.oldb)|*.oldb';
  saved.DefaultExt := 'oldb';
  if opend.Execute then
    if saved.Execute then
      Form_LevelDB.CreateDatabase(opend.FileName, saved.FileName);
end;


procedure TForm_Main.menu_createlvlClick(Sender: TObject);
begin
  opend.Filter     := 'OUP-Level-DB (*.oldb)|*.oldb';
  saved.Filter     := 'Oni-Dat-Files|*.dat';
  saved.DefaultExt := 'dat';
  if opend.Execute then
    if saved.Execute then
      Form_LevelDB.CreateLevel(opend.FileName, saved.FileName);
end;


 {#################################}
 {##### Tools-Menu-Handlers   #####}
 {#################################}
procedure TForm_Main.menu_previewClick(Sender: TObject);
begin
  open_child('preview');
end;

procedure TForm_Main.menu_bineditClick(Sender: TObject);
begin
  open_child('binedit');
end;

procedure TForm_Main.menu_raweditClick(Sender: TObject);
begin
  open_child('rawedit');
end;

procedure TForm_Main.menu_txmpreplaceClick(Sender: TObject);
begin
  open_child('txmpreplace');
end;

procedure TForm_Main.menu_extractorClick(Sender: TObject);
begin
  open_child('extractor');
end;

procedure TForm_Main.menu_metaClick(Sender: TObject);
begin
  open_child('meta');
end;

procedure TForm_Main.menu_filecompareClick(Sender: TObject);
begin
  open_child('compare');
end;


 {#################################}
 {#####   View-Menu-Handlers  #####}
 {#################################}
procedure TForm_Main.menu_windows_cascadeClick(Sender: TObject);
begin
  Self.Cascade;
end;

procedure TForm_Main.menu_windows_tilevertClick(Sender: TObject);
begin
  Self.TileMode := tbVertical;
  Self.Tile;
end;

procedure TForm_Main.menu_windows_tileClick(Sender: TObject);
begin
  Self.TileMode := tbHorizontal;
  Self.Tile;
end;

procedure TForm_Main.menu_windows_closeallClick(Sender: TObject);
begin
  MDITab.CloseAll;
end;

procedure TForm_Main.menu_windows_nextClick(Sender: TObject);
begin
  if MDIChildCount > 1 then
    if MDITab.TabIndex = MDITab.MDIChildCount - 1 then
      MDITab.MDIChildren[0].BringToFront
    else
      MDITab.MDIChildren[MDITab.TabIndex + 1].BringToFront;
end;

procedure TForm_Main.menu_windows_previousClick(Sender: TObject);
begin
  if MDIChildCount > 1 then
    if MDITab.TabIndex = 0 then
      MDITab.MDIChildren[MDITab.MDIChildCount - 1].BringToFront
    else
      MDITab.MDIChildren[MDITab.TabIndex - 1].BringToFront;
end;


 {##################################}
 {#####  Windows-Menu-Handlers #####}
 {##################################}
procedure TForm_Main.menu_windows_itemClick(Sender: TObject);
var
  name: String;
begin
  name := TTBItem(Sender).Name;
end;



 {######################################}
 {#####  Connections-Menu-Handlers #####}
 {######################################}
procedure TForm_Main.menu_conns_itemClick(Sender: TObject);
var
  name: String;
  index: Integer;
  RepMsg: TStatusMessages;
begin
  index := TTBItem(Sender).Parent.IndexOf(TTBItem(Sender));
  name := ExtractFileName(ConManager.ConnectionByIndex[index].FileName);
  if MessageBox(Handle, PChar('Do you really want to close data-connection to' +#13+#10+
        name + '?'), PChar('Close?'), MB_YESNO + MB_ICONQUESTION) = ID_YES then
  begin
    CheckConnectionCloseable(index);
    ConManager.CloseConnectionByIndex(index, RepMsg);
    ShowOpenMsg(RepMsg);
    UpdateConLists;
  end;
  UpdateStatBar;
end;


 {###################################}
 {#####  Toolbars-Menu-Handlers #####}
 {###################################}
procedure TForm_Main.menu_view_toolbarClick(Sender: TObject);
begin
  menu_view_toolbar.Checked := not menu_view_toolbar.Checked;
  Toolbar.Visible := menu_view_toolbar.Checked;
end;

procedure TForm_Main.menu_view_statusbarClick(Sender: TObject);
begin
  menu_view_statusbar.Checked := not menu_view_statusbar.Checked;
  statbar.Visible := menu_view_statusbar.Checked;
end;

procedure TForm_Main.menu_view_mdibarClick(Sender: TObject);
begin
  menu_view_mdibar.Checked := not menu_view_mdibar.Checked;
  mditoolbar.Visible := menu_view_mdibar.Checked;
end;



procedure TForm_Main.menu_AboutClick(Sender: TObject);
begin
  ShowMessage('Will be implemented later ;)');
end;





function TForm_Main.open_child(window_context: String; connection, fileid: Integer): TForm_BaseTemplate;
type
  TTemplate = class of TForm_BaseTemplate;
  TTool = record
      name: String;
      icon: Integer;
      caption: String;
      classt: TTemplate;
  end;
const
  Tools: array[0..5] of TTool = (
    (name: 'binedit';     icon: 5; caption: 'Binary .dat-Editor'; classt: TForm_BinEdit),
    (name: 'extractor';   icon: 8; caption: 'Extractor';          classt: TForm_Extractor),
    (name: 'preview';     icon: 4; caption: 'Preview-Window';     classt: TForm_Preview),
    (name: 'rawedit';     icon: 6; caption: 'Binary .raw-Editor'; classt: TForm_RawEdit),
    (name: 'txmpreplace'; icon: 7; caption: 'TXMP Replacer';      classt: TForm_TxmpReplace),
    (name: 'meta'; icon: 11; caption: 'MetaEditor'; classt: TForm_Meta)
  );
var
  toolform:    TForm_BaseTemplate;
  i:           Integer;
  tag:         Integer;
  iconindex:   Integer;
begin
  Result := nil;

  tag := 1;
  if MDIChildCount > 0 then
    for i := 0 to MDIChildCount - 1 do
      if MDIChildren[i].Tag >= tag then
        tag := MDIChildren[i].Tag + 1;

  iconindex := -1;

  toolform := nil;

  for i := 0 to High(Tools) do
    if Tools[i].name = window_context then
      Break;
  if i < Length(Tools) then
  begin
    toolform         := TTemplate(Tools[i].classt).Create(Self);
    toolform.Caption := Tools[i].caption + ' ' + IntToStr(tag) + '       ';
    iconindex        := Tools[i].icon;
  end else begin
    ShowMessage('WindowContext not found!');
  end;

  if Assigned(toolform) then
  begin
    toolform.Name    := window_context + IntToStr(tag);
    toolform.Tag     := tag;
    MDITab.AddTab(TForm(toolform), iconindex);
    toolform.Caption := AnsiReplaceStr(toolform.Caption, '       ', '');
    if Connection > -1 then
    begin
      toolform.SelectConnection(connection);
      if (FileID > -1) and (toolform is TForm_TemplateFile) then
        TForm_TemplateFile(toolform).SelectFileID(Connection, FileID);
    end;
    Result := toolform;
  end;
end;

function TForm_Main.open_child(window_context: String; Connection: Integer): TForm_BaseTemplate;
begin
  open_child(window_context, Connection, -1);
end;

function TForm_Main.open_child(window_context: String): TForm_BaseTemplate;
begin
  open_child(window_context, -1, -1);
end;

end.
