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, Template, RawEdit, BinEdit, Extractor, Preview, TxmpReplace; 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); function open_child(window_context: String; connection, fileid: Integer): TForm_ToolTemplate; 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 procedure DefaultHandler(var Message); override; end; var Form_Main: TForm_Main; implementation uses LevelDB; {$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_ToolTemplate; begin Result := True; if MDITab.MDIChildCount > 0 then begin for i := 0 to MDITab.MDIChildCount - 1 do begin if MDITab.MDIChildren[i] is TForm_ToolTemplate then begin toolform := TForm_ToolTemplate(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_ToolTemplate; begin pt.X := X; pt.Y := Y; tabIndex := MDITab.GetTabAtPos(pt); hint := ''; if tabIndex >= 0 then begin if MDITab.MDIChildren[tabIndex] is TForm_ToolTemplate then begin tool := TForm_ToolTemplate(MDITab.MDIChildren[tabIndex]); if tool.ConnectionID > -1 then hint := 'Connection: ' + ExtractFileName(ConManager.Connection[tool.ConnectionID].FileName) + #13+#10 else hint := 'Connection: none' + #13+#10; if tool.SelectedFile.ID > -1 then hint := hint + 'Selected File: ' + FormatNumber(tool.SelectedFile.ID, 5, '0') + '-' + tool.SelectedFile.Name + '.' + tool.SelectedFile.Extension else hint := hint + 'Selected File: none'; 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_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_ToolTemplate then TForm_ToolTemplate(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 // ShowMessage('Not yet usable'); 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 // ShowMessage('Not yet usable'); 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', -1, -1); end; procedure TForm_Main.menu_bineditClick(Sender: TObject); begin open_child('binedit', -1, -1); end; procedure TForm_Main.menu_raweditClick(Sender: TObject); begin open_child('rawedit', -1, -1); end; procedure TForm_Main.menu_txmpreplaceClick(Sender: TObject); begin open_child('txmpreplace', -1, -1); end; procedure TForm_Main.menu_extractorClick(Sender: TObject); begin open_child('extractor', -1, -1); end; procedure TForm_Main.menu_metaClick(Sender: TObject); begin ShowMessage('TBD'); end; procedure TForm_Main.menu_filecompareClick(Sender: TObject); begin open_child('compare', -1, -1); 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 // name := TTBItem(Sender).Caption; 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_ToolTemplate; type TTemplate = class of TForm_ToolTemplate; TTool = record name: String; icon: Integer; caption: String; classt: TTemplate; end; const Tools: array[0..4] 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) ); var toolform: TForm_ToolTemplate; 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 then toolform.SelectFileID(connection, fileid); end; Result := toolform; end; end; end.