Simba/Projects/Simba/simbaunit.pas

3569 lines
104 KiB
Plaintext

{
This file is part of the Mufasa Macro Library (MML)
Copyright (c) 2009 by Raymond van Venetië and Merlijn Wajer
MML is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
MML is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with MML. If not, see <http://www.gnu.org/licenses/>.
See the file COPYING, included in this distribution,
for details about the copyright.
Simba: GUI for the Mufasa Macro Library
}
unit SimbaUnit;
{$undef EditButtons}
{$Undef ProcessMessages} //Define this for processmessages in ThreadSafeCall
{$mode objfpc}{$H+}
{$I Simba.inc}
interface
uses
{$IFDEF LINUX}cthreads, cmem,{$ENDIF}
Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
StdCtrls, Menus, ComCtrls, ExtCtrls, SynEdit, SynHighlighterPas,
MufasaTypes,
mmlpsthread, // Code to use the interpreters in threads.
synedittypes,
{$IFDEF MSWINDOWS} os_windows, windows,{$ENDIF} //For ColorPicker etc.
{$IFDEF LINUX} os_linux, {$ENDIF} //For ColorPicker etc.
colourpicker, windowselector, // We need these for the Colour Picker and Window Selector
framescript,
lcltype, ActnList,
SynExportHTML, SynEditKeyCmds, SynEditHighlighter,
SynEditMarkupHighAll, LMessages, Buttons,
mmisc, stringutil,mufasatypesutil, mufasabase,
about, framefunctionlist, ocr, updateform, Simbasettings,
{$IFDEF USE_EXTENSIONS}psextension, virtualextension, extensionmanager,{$ENDIF}
settingssandbox,
v_ideCodeParser, v_ideCodeInsight, CastaliaPasLexTypes, // Code completion units
CastaliaSimplePasPar, v_AutoCompleteForm, // Code completion units
PSDump,
settings, updater;
const
SimbaVersion = 971;
interp_PS = 0; //PascalScript
interp_RT = 1; //RUTIS
interp_CP = 2; //CPascal
{ Place the shortcuts here }
{$IFDEF LINUX}
shortcut_StartScript = '<Ctrl><Alt>R';
shortcut_StopScript = '<Ctrl><Alt>S';
shortcut_PickColour = '<Ctrl><Alt>P';
{$ELSE}
shortcut_StartScriptMod = MOD_CONTROL or MOD_ALT;
shortcut_StartScriptKey = VK_R;
shortcut_StopScriptMod = MOD_CONTROL or MOD_ALT;
shortcut_StopScriptKey = VK_S;
shortcut_PickColourMod = MOD_CONTROL or MOD_ALT;
shortcut_PickColourKey = VK_P;
{$ENDIF}
type
{ TMufasaTab }
TMufasaTab = class(Tobject)
private
PageCtrl : TPageControl;
public
TabSheet : TTabsheet;
ScriptFrame : TScriptFrame;
procedure Clear;//This will 'reset' the ScriptFrame
constructor Create(Page : TPageControl);
destructor Destroy; override;
end;
// Tab
{ TSimbaForm }
TSimbaForm = class(TForm)
ActionGoto: TAction;
ActionCPascal: TAction;
ActionRUTIS: TAction;
ActionPascalScript: TAction;
ActionExtensions: TAction;
ActionSaveDef: TAction;
ActionConsole: TAction;
ActionNormalSize: TAction;
ActionCompileScript: TAction;
ActionExit: TAction;
ActionReplace: TAction;
ActionFindNext: TAction;
ActionRedo: TAction;
ActionUndo: TAction;
ActionSelectAll: TAction;
ActionDelete: TAction;
ActionPaste: TAction;
ActionCopy: TAction;
ActionCut: TAction;
ActionFindStart: TAction;
ActionClearDebug: TAction;
ActionSaveAll: TAction;
ActionStopScript: TAction;
ActionSaveScript: TAction;
ActionSaveScriptAs: TAction;
ActionRunScript: TAction;
ActionPauseScript: TAction;
ActionNewScript: TAction;
ActionOpenScript: TAction;
ActionNewTab: TAction;
ActionCloseTab: TAction;
ActionTabLast: TAction;
ActionTabNext: TAction;
ActionList: TActionList;
CheckBoxMatchCase: TCheckBox;
frmFunctionList: TFunctionListFrame;
LabeledEditSearch: TLabeledEdit;
LazHighlighter: TSynPasSyn;
MainMenu: TMainMenu;
Memo1: TMemo;
MenuFile: TMenuItem;
MenuEdit: TMenuItem;
MenuHelp: TMenuItem;
MenuDivider7: TMenuItem;
MenuInterpreters: TMenuItem;
MenuItemReadOnlyTab: TMenuItem;
MenuItemGoto: TMenuItem;
MenuItemDivider50: TMenuItem;
MenuItemPascalScript: TMenuItem;
MenuItemCPascal: TMenuItem;
MenuItemRUTIS: TMenuItem;
MenuItemOpenPluginsFolder: TMenuItem;
MenuItemOpenIncludesFolder: TMenuItem;
MenuItemOpenScriptsFolder: TMenuItem;
MenuItemDivider11: TMenuItem;
MenuItemSaveDef: TMenuItem;
MenuItemBitmapConv: TMenuItem;
MenuItemExtensions: TMenuItem;
MenuItemSettingsButton: TMenuItem;
MenuItemDivider10: TMenuItem;
MenuTools: TMenuItem;
MenuItemOpenRecent: TMenuItem;
MenuItemCompile: TMenuItem;
MenuItemHandbook: TMenuItem;
MenuItemAbout: TMenuItem;
MenuItemReportBug: TMenuItem;
MenuItemExportHTML: TMenuItem;
MenuItemDivider9: TMenuItem;
MouseTimer: TTimer;
NewsTimer: TTimer;
FunctionListTimer: TTimer;
SCARHighlighter: TSynPasSyn;
TT_Console: TToolButton;
TT_Cut: TToolButton;
TT_Copy: TToolButton;
TT_Paste: TToolButton;
ToolButton9: TToolButton;
UpdateTimer: TTimer;
ToolButton3: TToolButton;
TT_Update: TToolButton;
UpdateMenuButton: TMenuItem;
MenuitemFillFunctionList: TMenuItem;
MenuItemFunctionList: TMenuItem;
MenuItemHide: TMenuItem;
MenuItemDebugImage: TMenuItem;
MenuItemMainExit: TMenuItem;
MenuItemDivider6: TMenuItem;
PopupItemReplace: TMenuItem;
MenuItemReplace: TMenuItem;
dlgReplace: TReplaceDialog;
MenuItemColourHistory: TMenuItem;
MenuView: TMenuItem;
MenuItemFindNext: TMenuItem;
PopupItemDelete: TMenuItem;
MenuItemDelete: TMenuItem;
MenuItemDivider5: TMenuItem;
MenuItemSelectAll: TMenuItem;
PopupItemSelectAll: TMenuItem;
PopupItemDivider2: TMenuItem;
PopupItemPaste: TMenuItem;
PopupItemCopy: TMenuItem;
PopupItemCut: TMenuItem;
PopupItemDivider1: TMenuItem;
PopupItemRedo: TMenuItem;
PopupItemUndo: TMenuItem;
PopupItemDivider3: TMenuItem;
PopupItemFind: TMenuItem;
MenuItemFind: TMenuItem;
MenuItemDivider4: TMenuItem;
MenuItemDivider3: TMenuItem;
MenuItemCopy: TMenuItem;
MenuItemSaveAll: TMenuItem;
MenuItemTabCloseOthers: TMenuItem;
MenuItemTabAdd: TMenuItem;
MenuItemTabClose: TMenuItem;
MenuItemCloseTabs: TMenuItem;
MenuItemCloseTab: TMenuItem;
MenuItemNewTab: TMenuItem;
MenuItemDivider2: TMenuItem;
MenuItemDivider: TMenuItem;
PageControl1: TPageControl;
ScriptPopup: TPopupMenu;
SearchPanel: TPanel;
ScriptPanel: TPanel;
SpeedButtonSearch: TSpeedButton;
SplitterFunctionList: TSplitter;
TabPopup: TPopupMenu;
TB_SaveAll: TToolButton;
DebugTimer: TTimer;
TrayDivider: TMenuItem;
TrayPlay: TMenuItem;
TrayStop: TMenuItem;
TrayPause: TMenuItem;
MenuItemPause: TMenuItem;
MenuItemStop: TMenuItem;
MenuItemShow: TMenuItem;
MenuItemExit: TMenuItem;
MenuItemCut: TMenuItem;
MenuItemPaste: TMenuItem;
MenuItemNew: TMenuItem;
MenuItemSaveAs: TMenuItem;
MenuItemOpen: TMenuItem;
MenuItemRedo: TMenuItem;
MenuItemUndo: TMenuItem;
MenuItemSave: TMenuItem;
Mufasa_Image_List: TImageList;
MenuItemScript: TMenuItem;
MenuItemRun: TMenuItem;
PanelMemo: TPanel;
SplitterMemoSynedit: TSplitter;
TrayPopup: TPopupMenu;
StatusBar: TStatusBar;
ToolBar1: TToolBar;
TB_Run: TToolButton;
TB_Pause: TToolButton;
TB_Stop: TToolButton;
ToolButton1: TToolButton;
TB_ReloadPlugins: TToolButton;
TB_Tray: TToolButton;
TB_NewTab: TToolButton;
TB_CloseTab: TToolButton;
TB_New: TToolButton;
ToolButton2: TToolButton;
TB_Open: TToolButton;
TB_Save: TToolButton;
ToolButton4: TToolButton;
TB_ClearDebug: TToolButton;
TB_PickColour: TToolButton;
TB_SelectClient: TToolButton;
ToolButton8: TToolButton;
MTrayIcon: TTrayIcon;
procedure ActionClearDebugExecute(Sender: TObject);
procedure ActionCloseTabExecute(Sender: TObject);
procedure ActionCompileScriptExecute(Sender: TObject);
procedure ActionConsoleExecute(Sender: TObject);
procedure ActionCopyExecute(Sender: TObject);
procedure ActionCPascalExecute(Sender: TObject);
procedure ActionCutExecute(Sender: TObject);
procedure ActionDeleteExecute(Sender: TObject);
procedure ActionExitExecute(Sender: TObject);
procedure ActionExtensionsExecute(Sender: TObject);
procedure ActionExtensionsUpdate(Sender: TObject);
procedure ActionFindNextExecute(Sender: TObject);
procedure ActionFindstartExecute(Sender: TObject);
procedure ActionGotoExecute(Sender: TObject);
procedure ActionNewExecute(Sender: TObject);
procedure ActionNewTabExecute(Sender: TObject);
procedure ActionNormalSizeExecute(Sender: TObject);
procedure ActionOpenExecute(Sender: TObject);
procedure ActionPascalScriptExecute(Sender: TObject);
procedure ActionPasteExecute(Sender: TObject);
procedure ActionPauseExecute(Sender: TObject);
procedure ActionRedoExecute(Sender: TObject);
procedure ActionReplaceExecute(Sender: TObject);
procedure ActionRunExecute(Sender: TObject);
procedure ActionRUTISExecute(Sender: TObject);
procedure ActionSaveAllExecute(Sender: TObject);
procedure ActionSaveAsExecute(Sender: TObject);
procedure ActionSaveDefExecute(Sender: TObject);
procedure ActionSaveExecute(Sender: TObject);
procedure ActionSelectAllExecute(Sender: TObject);
procedure ActionStopExecute(Sender: TObject);
procedure ActionTabLastExecute(Sender: TObject);
procedure ActionTabNextExecute(Sender: TObject);
procedure ActionUndoExecute(Sender: TObject);
procedure ChangeMouseStatus(Sender: TObject);
procedure CheckBoxMatchCaseClick(Sender: TObject);
procedure CloseFindPanel;
procedure doOnHide(Sender: TObject);
procedure editSearchListExit(Sender: TObject);
procedure editSearchListKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
procedure editSearchListKeyPress(Sender: TObject; var Key: char);
procedure FormDropFiles(Sender: TObject; const FileNames: array of String);
procedure FunctionListChange(Sender: TObject; Node: TTreeNode);
procedure FunctionListEnter(Sender: TObject);
procedure FunctionListExit(Sender: TObject);
procedure FunctionListTimerTimer(Sender: TObject);
procedure MenuItemReadOnlyTabClick(Sender: TObject);
procedure MenuItemBitmapConvClick(Sender: TObject);
procedure MenuItemHandbookClick(Sender: TObject);
procedure MenuItemColourHistoryClick(Sender: TObject);
procedure dlgReplaceFind(Sender: TObject);
procedure dlgReplaceReplace(Sender: TObject);
procedure EditSearchChange(Sender: TObject);
procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormShortCuts(var Msg: TLMKey; var Handled: Boolean);
procedure LabeledEditSearchEnter(Sender: TObject);
procedure LabeledEditSearchExit(Sender: TObject);
procedure LabeledEditSearchKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
procedure LabeledEditSearchKeyPress(Sender: TObject; var Key: char);
procedure MenuEditClick(Sender: TObject);
procedure MenuItemAboutClick(Sender: TObject);
procedure MenuItemCloseTabsClick(Sender: TObject);
procedure MenuItemDebugImageClick(Sender: TObject);
procedure MenuItemExportHTMLClick(Sender: TObject);
procedure MenuitemFillFunctionListClick(Sender: TObject);
procedure MenuItemHideClick(Sender: TObject);
procedure MenuItemOpenIncludesFolderClick(Sender: TObject);
procedure MenuItemOpenPluginsFolderClick(Sender: TObject);
procedure MenuItemOpenScriptsFolderClick(Sender: TObject);
procedure MenuItemReportBugClick(Sender: TObject);
procedure MenuItemSettingsButtonClick(Sender: TObject);
procedure MenuItemShowClick(Sender: TObject);
procedure MenuItemTabCloseClick(Sender: TObject);
procedure MenuItemTabCloseOthersClick(Sender: TObject);
procedure MenuItemFunctionListClick(Sender: TObject);
procedure MTrayIconClick(Sender: TObject);
procedure NewsTimerTimer(Sender: TObject);
procedure OnLinePSScript(Sender: TObject);
procedure ButtonPickClick(Sender: TObject);
procedure ButtonSelectorDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure PageControl1Change(Sender: TObject);
procedure ButtonTrayClick(Sender: TObject);
procedure PageControl1Changing(Sender: TObject; var AllowChange: Boolean);
procedure PageControl1ContextPopup(Sender: TObject; MousePos: TPoint;
var Handled: Boolean);
procedure PageControl1DragDrop(Sender, Source: TObject; X, Y: Integer);
procedure PageControl1DragOver(Sender, Source: TObject; X, Y: Integer;
State: TDragState; var Accept: Boolean);
procedure PageControl1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure PageControl1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure PickerPick(Sender: TObject; const Colour, colourx,
coloury: integer);
procedure PopupItemFindClick(Sender: TObject);
procedure ProcessDebugStream(Sender: TObject);
procedure RecentFileItemsClick(Sender: TObject);
procedure ScriptPanelDockDrop(Sender: TObject; Source: TDragDockObject; X,
Y: Integer);
procedure ScriptPanelDockOver(Sender: TObject; Source: TDragDockObject; X,
Y: Integer; State: TDragState; var Accept: Boolean);
procedure ScriptPopupPopup(Sender: TObject);
procedure SpeedButtonSearchClick(Sender: TObject);
procedure SplitterFunctionListCanResize(Sender: TObject; var NewSize: Integer;
var Accept: Boolean);
procedure TB_ReloadPluginsClick(Sender: TObject);
procedure ThreadOpenConnectionEvent(Sender: TObject; var url: string;
var Continue: boolean);
procedure ThreadOpenFileEvent(Sender: TObject; var Filename: string;
var Continue: boolean);
procedure ThreadWriteFileEvent(Sender: TObject; var Filename: string;
var Continue: boolean);
procedure ScriptStartEvent(Sender: TObject; var Script : string; var Continue : boolean);
procedure TrayPopupPopup(Sender: TObject);
procedure TT_UpdateClick(Sender: TObject);
procedure UpdateMenuButtonClick(Sender: TObject);
procedure UpdateTimerCheck(Sender: TObject);
procedure OnCCMessage(Sender: TObject; const Typ: TMessageEventType; const Msg: string; X, Y: Integer);
procedure OnCompleteCode(Str: string);
function OnCCFindInclude(Sender: TObject; var FileName: string): Boolean;
function OnCCLoadLibrary(Sender: TObject; var LibName: string; out ci: TCodeInsight): Boolean;
private
PopupTab : integer;
RecentFileItems : array of TMenuItem;
RecentFiles : TStringList;
FirstRun : boolean;//Only show the warnings the first run (path not existing one's)
SearchStart : TPoint;
LastTab : integer;
UpdatingFonts : boolean;
OpenConnectionData : TOpenConnectionData;
OpenFileData : TOpenFileData;
WriteFileData : TWriteFileData;
ScriptStartData : TScriptStartData;
procedure UpdateInterpreter;
procedure HandleConnectionData;
procedure HandleOpenFileData;
procedure HandleWriteFileData;
procedure HandleScriptStartData;
function GetInterpreter: Integer;
function GetDefScriptPath: string;
function GetScriptPath : string;
{$IFDEF USE_EXTENSIONS}function GetExtPath: string;{$ENDIF}
function GetFontPath: String;
function GetHighlighter: TSynCustomHighlighter;
function GetIncludePath: String;
function GetPluginPath: string;
function GetScriptState: TScriptState;
function GetShowParamHintAuto: boolean;
function GetShowCodeCompletionAuto: Boolean;
function GetSimbaNews: String;
procedure SetDefScriptPath(const AValue: string);
{$IFDEF USE_EXTENSIONS}procedure SetExtPath(const AValue: string);{$ENDIF}
procedure SetFontPath(const AValue: String);
procedure SetIncludePath(const AValue: String);
procedure SetInterpreter(const AValue: Integer);
procedure SetPluginPath(const AValue: string);
procedure SetScriptPath(const AValue: string);
procedure SetShowParamHintAuto(const AValue: boolean);
procedure SetShowCodeCompletionAuto(const AValue: boolean);
procedure SetScriptState(const State: TScriptState);
function CreateSetting(const Key, Value : string) : string;
procedure SetSetting(const key,Value : string; save : boolean = false);
function SettingExists(const key : string) : boolean;
procedure FontUpdate;
public
DebugStream: String;
SearchString : string;
CurrScript : TScriptFrame; //The current scriptframe
CurrTab : TMufasaTab; //The current TMufasaTab
CodeCompletionForm: TAutoCompletePopup;
CodeCompletionStart: TPoint;
ParamHint : TParamHint;
Tabs : TList;
Manager: TIOManager;
OCR_Fonts: TMOCR;
Picker: TMColorPicker;
Selector: TMWindowSelector;
OnScriptStart : TScriptStartEvent;
FormCallBackData : TCallBackData;
{$ifdef mswindows}
ConsoleVisible : boolean;
procedure ShowConsole( ShowIt : boolean);
{$endif}
procedure FormCallBack;
function LoadSettingDef(const Key, Def : string) : string;
procedure FunctionListShown( ShowIt : boolean);
property ScriptState : TScriptState read GetScriptState write SetScriptState;
procedure SafeCallThread;
procedure UpdateTitle;
function OpenScript : boolean;
function LoadScriptFile(filename : string; AlwaysOpenInNewTab : boolean = false; CheckOtherTabs : boolean = true) : boolean;
function SaveCurrentScript : boolean;
function SaveCurrentScriptAs : boolean;
function SaveCurrentScriptAsDefault : boolean;
function CanExitOrOpen : boolean;
function ClearScript : boolean;
procedure RunScript;
procedure PauseScript;
procedure StopScript;
procedure AddTab;
procedure StopCodeCompletion;
function FindTab(filename : string) : integer;
function DeleteTab( TabIndex : integer; CloseLast : boolean; Silent : boolean = false) : boolean;
procedure ClearTab( TabIndex : integer);
procedure CloseTabs(Exclude: integer = -1; Silent : boolean = false); //-1 for no exclusion
procedure SetEditActions;
procedure DoSearch(Next : boolean; HighlightAll : boolean);
procedure RefreshTab;//Refreshes all the form items that depend on the Script (Panels, title etc.)
procedure RefreshTabSender(sender : PtrInt);
procedure CreateDefaultEnvironment;
procedure LoadFormSettings;
procedure SaveFormSettings;
procedure LoadExtensions;
procedure AddRecentFile(const filename : string);
procedure InitializeTMThread(out Thread : TMThread);
procedure HandleParameters;
procedure OnSaveScript(const Filename : string);
property Interpreter : Integer read GetInterpreter write SetInterpreter;
property ShowParamHintAuto : boolean read GetShowParamHintAuto write SetShowParamHintAuto;
property ShowCodeCompletionAuto: Boolean read GetShowCodeCompletionAuto write SetShowCodeCompletionAuto;
property IncludePath : String read GetIncludePath write SetIncludePath;
property FontPath : String read GetFontPath write SetFontPath;
property PluginPath : string read GetPluginPath write SetPluginPath;
{$IFDEF USE_EXTENSIONS}property ExtPath : string read GetExtPath write SetExtPath;{$ENDIF}
property ScriptDir : string read GetScriptPath write SetScriptPath;
property DefScriptPath : string read GetDefScriptPath write SetDefScriptPath;
property CurrHighlighter : TSynCustomHighlighter read GetHighlighter;
function DefaultScript : string;
end;
procedure ClearDebug;
procedure formWriteln( S : String);
procedure formWritelnEx( S : String);
function GetMethodName( Decl : string; PlusNextChar : boolean) : string;
const
WindowTitle = 'Simba - %s';//Title, where %s = the place of the filename.
Panel_State = 0;
Panel_Coords = 1;
Panel_ScriptName = 2;
Panel_ScriptPath = 3;
Panel_General = 3;
Image_Stop = 7;
Image_Terminate = 19;
var
SimbaForm: TSimbaForm;
MainDir : string;
{$ifdef MSWindows}
PrevWndProc : WNDPROC;
{$endif}
CurrentSyncInfo : TSyncInfo;//We need this for SafeCallThread
implementation
uses
lclintf,
syncobjs, // for the critical sections / mutexes
debugimage,
files,
InterfaceBase,
bitmapconv,
bitmaps,
{$IFDEF USE_EXTENSIONS}extensionmanagergui,{$ENDIF}
colourhistory,
math
{$IFDEF LINUX_HOTKEYS}
,keybinder
{$ENDIF}
;
{ Console handler }
{$IFDEF MSWINDOWS}
function ConsoleHandler( eventType : DWord) : WINBOOL;stdcall;
begin
TThread.Synchronize(nil,@SimbaForm.Close);
Result := true;
end;
{$ENDIF}
{Global Hotkey Binding }
{$IFDEF MSWINDOWS}
{ Used for global callbacks on WINDOWS }
function WndCallback(Ahwnd: HWND; uMsg: UINT; wParam: WParam;
lParam: LParam): LRESULT stdcall;
begin
if uMsg = WM_HOTKEY then //Found an hotkey!
begin
if (lo(lParam) = shortcut_StartScriptMod) and (hi(lParam) =shortcut_StartScriptKey) then
SimbaForm.ActionRunScript.Execute;
if (lo(lParam) = shortcut_StopScriptMod) and (hi(lParam) =shortcut_StopScriptKey) then
SimbaForm.ActionStopScript.Execute;
if (lo(lParam) = shortcut_PickColourMod) and (hi(lParam) =shortcut_PickColourKey) then
SimbaForm.ButtonPickClick(nil);
Result := 0;
end else
Result := Windows.CallWindowProc(PrevWndProc,Ahwnd, uMsg, WParam, LParam);
end;
procedure Bind_Windows_Keys;
begin
PrevWndProc := Windows.WNDPROC(GetWindowLong(SimbaForm.handle,GWL_WNDPROC));
SetWindowLong(SimbaForm.Handle,GWL_WNDPROC,PtrInt(@WndCallback));
if not RegisterHotkey(SimbaForm.Handle,0,shortcut_StartScriptMod,shortcut_StartScriptKey) then
mDebugLn('Unable to register start script global hotkey');
if not RegisterHotkey(SimbaForm.Handle,1,shortcut_StopScriptMod,shortcut_StopScriptKey) then
mDebugLn('Unable to register stop script global hotkey');
if not RegisterHotkey(SimbaForm.Handle,2,shortcut_PickColourMod,shortcut_PickColourKey) then
mDebugLn('Unable to register pick colour global hotkey');
end;
procedure Unbind_Windows_Keys;
var
i : integer;
begin
for i := 0 to 2 do
if not UnRegisterHotkey(SimbaForm.Handle,i) then
mDebugLn('Unable to unregister '+ inttostr(i) + ' global hotkey');
end;
{$ELSE}
{$IFDEF LINUX_HOTKEYS}
{$WARNING This will probably not work if people don't have libkeybinder installed. Perhaps ship it with Simba? }
{ Used for global callbacks on LINUX }
procedure keybinder_callback(keystring: PChar; user_data: PtrUInt); cdecl;
begin
writeln('Keystring: ' + keystring);
if keystring = shortcut_StartScript then
SimbaForm.ActionRunScript.Execute
else if keystring = shortcut_StopScript then
SimbaForm.ActionStopScript.Execute
else if keystring = shortcut_PickColour then
SimbaForm.ButtonPickClick(nil)
else
writeln('Unknown keystring: ', keystring)
end;
{ XXX, TODO: Pressing the stop shortcut twice (quickly) may crash Simba. }
procedure Bind_Linux_Keys;
begin
keybinder_init(); { Initialise keybinder }
{ Bind keys }
if not keybinder_bind(PChar(shortcut_StartScript), @keybinder_callback, PtrUInt(0)) then
mDebugLn('Unable to register '+ shortcut_StartScript + ' as global hotkey');
if not keybinder_bind(PChar(shortcut_StopScript), @keybinder_callback, PtrUInt(0)) then
mDebugLn('Unable to register '+ shortcut_StopScript + ' as global hotkey');
if not keybinder_bind(PChar(shortcut_PickColour), @keybinder_callback, PtrUInt(0)) then
mDebugLn('Unable to register '+ shortcut_PickColour + ' as global hotkey');
end;
procedure Unbind_Linux_Keys;
begin
keybinder_unbind(PChar(shortcut_StartScript), @keybinder_callback, PtrUInt(0));
keybinder_unbind(PChar(shortcut_StopScript), @keybinder_callback, PtrUInt(0));
keybinder_unbind(PChar(shortcut_PickColour), @keybinder_callback, PtrUInt(0));
end;
{$ENDIF}
{$ENDIF}
var
DebugCriticalSection: syncobjs.TCriticalSection;
procedure TSimbaForm.OnCCMessage(Sender: TObject; const Typ: TMessageEventType; const Msg: string; X, Y: Integer);
begin
if (Typ = meNotSupported) then
Exit;
if (Sender is TmwSimplePasPar) then
if (TmwSimplePasPar(Sender).Lexer.TokenID = tok_DONE) then
Exit;
mDebugLn('ERROR: '+Format('%d:%d %s', [Y + 1, X, Msg])+' in '+TCodeInsight(Sender).FileName);
end;
procedure TSimbaForm.OnCompleteCode(Str: string);
var
sp, ep: Integer;
s: string;
begin
if (Str <> '') then
begin
s := WordAtCaret(CurrScript.SynEdit, sp, ep);
if (s <> '') then
begin
CurrScript.SynEdit.SelStart := CurrScript.SynEdit.SelStart + (sp - CurrScript.SynEdit.CaretX);
CurrScript.SynEdit.SelEnd := CurrScript.SynEdit.SelStart + (ep - CurrScript.SynEdit.CaretX) + 1;
CurrScript.SynEdit.SelText := Str;
end
else
CurrScript.SynEdit.InsertTextAtCaret(Str);
end;
end;
function TSimbaForm.OnCCFindInclude(Sender: TObject; var FileName: string): Boolean;
var
Temp : string;
begin
Temp := FindFile(filename,[MainDir+DS,IncludePath]);
if temp <> '' then
begin;
filename := temp;
result := true;
end else
result := false;
end;
function TSimbaForm.OnCCLoadLibrary(Sender: TObject; var LibName: string; out ci: TCodeInsight): Boolean;
var
i, Index: Integer;
b: TStringList;
ms: TMemoryStream;
begin
try
Index := PluginsGlob.LoadPlugin(LibName);
except
Result := false;
Index := -1;
end;
if (Index < 0) then
Exit(False)
else
begin
b := TStringList.Create;
try
ms := TMemoryStream.Create;
with PluginsGlob.MPlugins[Index] do
for i := 0 to MethodLen - 1 do
b.Add(Methods[i].FuncStr + 'forward;');
ci := TCodeInsight.Create;
with ci do
begin
OnMessage := @SimbaForm.OnCCMessage;
b.SaveToStream(ms);
FileName := LibName;
Run(ms, nil, -1, True);
end;
finally
b.Free;
end;
end;
end;
procedure TSimbaForm.UpdateInterpreter;
begin
ActionPascalScript.Checked:= false;
ActionRUTIS.Checked:= false;
ActionCPascal.Checked:= false;
case Interpreter of
interp_PS: ActionPascalScript.Checked:= True;
interp_CP: ActionCPascal.Checked:= True;
interp_RT: ActionRUTIS.Checked:= true;
end;
end;
procedure TSimbaForm.HandleConnectionData;
{$IFDEF USE_EXTENSIONS}
var
Args : TVariantArray;
begin
SetLength(Args,2);
Args[0] := OpenConnectionData.URL^;
Args[1] := OpenConnectionData.Continue^;
try
ExtManager.HandleHook(EventHooks[SExt_onOpenConnection].HookName,Args);
OpenConnectionData.URL^ := Args[0];
OpenConnectionData.Continue^ := Args[1];
except
on e : Exception do
mDebugLn('ERROR in HandleConnectiondata: ' + e.message);
end;
{$ELSE}
begin
{$ENDIF}
end;
function TSimbaForm.GetInterpreter: Integer;
begin
result := StrToIntDef(LoadSettingDef('Settings/Interpreter/Type','0'),0);
if (result < 0) or (result > 2) then
begin
SetInterpreter(0);
result := 0;
end;
end;
function TSimbaForm.GetDefScriptPath: string;
begin
result :=LoadSettingDef('Settings/SourceEditor/DefScriptPath', ExpandFileName(MainDir+DS+'default.simba'));
end;
function TSimbaForm.GetScriptPath: string;
begin
result :=IncludeTrailingPathDelimiter(LoadSettingDef('Settings/Scripts/Path', ExpandFileName(MainDir+DS+'Scripts' + DS)));
end;
procedure TSimbaForm.HandleOpenFileData;
{$IFDEF USE_EXTENSIONS}
var
Args : TVariantArray;
begin
SetLength(Args,2);
Args[0] := OpenFileData.FileName^;
Args[1] := OpenFileData.Continue^;
try
ExtManager.HandleHook(EventHooks[SExt_onOpenFile].HookName,Args);
OpenFileData.FileName^ := Args[0];
OpenFileData.Continue^ := Args[1];
except
on e : Exception do
mDebugLn('ERROR in HandleOpenFileData: ' + e.message);
end;
{$ELSE}
begin
{$ENDIF}
end;
procedure TSimbaForm.HandleWriteFileData;
{$IFDEF USE_EXTENSIONS}
var
Args : TVariantArray;
begin
SetLength(Args,2);
Args[0] := WriteFileData.FileName^;
Args[1] := WriteFileData.Continue^;
try
ExtManager.HandleHook(EventHooks[SExt_onWriteFile].HookName,Args);
WriteFileData.FileName^ := Args[0];
WriteFileData.Continue^ := Args[1];
except
on e : Exception do
mDebugLn('ERROR in HandleWriteFileData: ' + e.message);
end;
{$ELSE}
begin
{$ENDIF}
end;
procedure TSimbaForm.HandleScriptStartData;
{$IFDEF USE_EXTENSIONS}
var
Args : TVariantArray;
begin
SetLength(Args,2);
Args[0] := ScriptStartData.Script^;
Args[1] := ScriptStartData.Continue^;
try
ExtManager.HandleHook(EventHooks[SExt_onScriptStart].HookName,Args);
ScriptStartData.Script^ := Args[0];
ScriptStartData.Continue^ := Args[1];
except
on e : Exception do
mDebugLn('ERROR in HandleScriptStartData: ' + e.message);
end;
{$ELSE}
begin
{$ENDIF}
end;
procedure TSimbaForm.ProcessDebugStream(Sender: TObject);
begin
if length(DebugStream) = 0 then
Exit;
// cut off 1 newline char
DebugCriticalSection.Enter;
try
setlength(DebugStream, length(DebugStream) - 1);
Memo1.Lines.Add(DebugStream);
SetLength(DebugStream, 0);
finally
DebugCriticalSection.Leave;
end;
end;
procedure TSimbaForm.RecentFileItemsClick(Sender: TObject);
var
i : integer;
begin
for i := 0 to high(RecentFileItems) do
if RecentFileItems[i] = sender then
begin;
LoadScriptFile(RecentFiles[RecentFiles.Count - 1 -i]);//Inverse order
exit;
end;
end;
procedure TSimbaForm.ScriptPanelDockDrop(Sender: TObject; Source: TDragDockObject;
X, Y: Integer);
begin
if(X <= (ScriptPanel.Width div 2))then
begin
frmFunctionList.Align := alLeft;
PageControl1.Align := alRight;
SplitterFunctionList.ResizeAnchor := akLeft;
SplitterFunctionList.Align := alLeft;
SplitterFunctionList.Left := frmFunctionList.Left + frmFunctionList.Width;
end else begin
frmFunctionList.Align := alRight;
PageControl1.Align := alLeft;
SplitterFunctionList.ResizeAnchor := akRight;
SplitterFunctionList.Align := alRight;
SplitterFunctionList.Left := frmFunctionList.Left;
end;
PageControl1.Width := ScriptPanel.Width - (Source.DockRect.Right - Source.DockRect.Left);
frmFunctionList.Width := ScriptPanel.Width - PageControl1.Width;
PageControl1.Align := alClient;
SplitterFunctionList.Show;
end;
procedure TSimbaForm.ScriptPanelDockOver(Sender: TObject; Source: TDragDockObject; //is there a better way to do all of this?
X, Y: Integer; State: TDragState; var Accept: Boolean);
var
P: TPoint;
begin
Accept := frmFunctionList.DragKind = dkDock;
if(Accept)then
begin
P := ScriptPanel.ClientToScreen(Classes.Point(0, 0));
if(X <= (ScriptPanel.Width div 2))then
Source.DockRect := Classes.Rect(P.x, P.y, min(P.x + frmFunctionList.Width, P.x + (ScriptPanel.Width div 2)), P.y + ScriptPanel.Height)
else
Source.DockRect := Classes.Rect(max(P.x + ScriptPanel.Width - frmFunctionList.Width, P.x + (ScriptPanel.Width div 2)), P.y, P.x + ScriptPanel.Width, P.y + ScriptPanel.Height);
end;
end;
procedure TSimbaForm.ScriptPopupPopup(Sender: TObject);
begin
SetEditActions;
end;
procedure TSimbaForm.SpeedButtonSearchClick(Sender: TObject);
begin
CloseFindPanel;
end;
procedure TSimbaForm.SplitterFunctionListCanResize(Sender: TObject; var NewSize: Integer;
var Accept: Boolean);
begin
if(NewSize > ScriptPanel.Width div 2)then
NewSize := ScriptPanel.Width div 2;
end;
procedure TSimbaForm.TB_ReloadPluginsClick(Sender: TObject);
begin
// PluginsGlob.FreePlugins;
end;
procedure TSimbaForm.ThreadOpenConnectionEvent(Sender: TObject; var url: string;var Continue: boolean);
begin
OpenConnectionData.Sender := Sender;
OpenConnectionData.URL:= @URL;
OpenConnectionData.Continue:= @Continue;
TThread.Synchronize(nil,@HandleConnectionData);
end;
procedure TSimbaForm.ThreadOpenFileEvent(Sender: TObject; var Filename: string;
var Continue: boolean);
begin
OpenFileData.Sender := Sender;
OpenFileData.FileName:= @FileName;
OpenFileData.Continue:= @Continue;
TThread.Synchronize(nil,@HandleOpenFileData);
end;
procedure TSimbaForm.ThreadWriteFileEvent(Sender: TObject; var Filename: string;
var Continue: boolean);
begin
WriteFileData.Sender := Sender;
WriteFileData.FileName:= @FileName;
WriteFileData.Continue:= @Continue;
TThread.Synchronize(nil,@HandleWriteFileData);
end;
procedure TSimbaForm.TrayPopupPopup(Sender: TObject);
begin
{ XXX: What's up with this? }
MenuItemHide.enabled:= SimbaForm.Visible;
{$ifdef MSWindows}
MenuItemShow.Enabled:= not SimbaForm.Visible;
if SimbaForm.Visible then
if SimbaForm.CanFocus then
SimbaForm.SetFocus;
{$endif}
end;
procedure TSimbaForm.TT_UpdateClick(Sender: TObject);
begin
SimbaUpdateForm.ShowModal;
TT_Update.Visible:=False;
end;
procedure TSimbaForm.UpdateTimerCheck(Sender: TObject);
var
chk: String;
time:integer;
LatestVersion : integer;
begin
UpdateTimer.Interval:= MaxInt;
FontUpdate;
chk := LowerCase(LoadSettingDef('Settings/Updater/CheckForUpdates','True'));
if chk <> 'true' then
Exit;
LatestVersion:= SimbaUpdateForm.GetLatestSimbaVersion;
if LatestVersion > SimbaVersion then
begin;
TT_Update.Visible:=True;
formWritelnEx('A new update of Simba is available!');
formWritelnEx(format('Current version is %d. Latest version is %d',[SimbaVersion,LatestVersion]));
end else
begin
mDebugLn(format('Current Simba version: %d',[SimbaVersion]));
mDebugLn('Latest Simba Version: ' + IntToStr(LatestVersion));
end;
time := StrToIntDef(LoadSettingDef('Settings/Updater/CheckEveryXMinutes','30'),30);
UpdateTimer.Interval:= time {mins} * 60 {secs} * 1000 {ms};//Every half hour
end;
procedure TSimbaForm.UpdateMenuButtonClick(Sender: TObject);
begin
if SimbaUpdateForm.CanUpdate then
SimbaUpdateForm.ShowModal
else
ShowMessage('No Updates Available!');
end;
{ Clear te debug memo }
procedure ClearDebug;
begin
{$IFNDEF MSWINDOWS} { First write everything we can, then clear }
SimbaForm.ProcessDebugStream(nil);
{$ENDIF}
TThread.Synchronize(nil,@SimbaForm.Memo1.Clear);
end;
procedure formWriteln( S : String);
begin
mDebugLn('formWriteln: ' + s);
{$ifdef MSWindows}
//Ha, we cán acces the debugmemo
SimbaForm.Memo1.Lines.Add(s);
{$else}
DebugCriticalSection.Enter;
try
s := s + MEOL;
SimbaForm.DebugStream:= SimbaForm.DebugStream + s;
finally
DebugCriticalSection.Leave;
end;
{$endif}
end;
//{$ENDIF}
procedure TSimbaForm.RunScript;
begin
if CurrThread <> nil then
exit;
with CurrScript do
begin
if ScriptState = ss_Paused then
begin;
ScriptThread.Resume;
ScriptState := ss_Running;
Exit;
end else
if ScriptState <> ss_None then
begin;
FormWritelnEx('The script hasn''t stopped yet, so we cannot start a new one.');
exit;
end;
InitializeTMThread(scriptthread);
ScriptThread.CompileOnly:= false;
ScriptThread.OnTerminate:=@ScriptThreadTerminate;
ScriptState:= ss_Running;
FirstRun := false;
//Lets run it!
ScriptThread.Resume;
end;
end;
procedure TSimbaForm.PauseScript;
begin
with CurrScript do
begin;
if ScriptState = ss_Running then
begin;
{$ifdef MSWindows}
ScriptThread.Suspended:= True;
ScriptState:= ss_Paused;
{$else}
mDebugLn('Linux does not yet support suspending threads.');
{$endif}
end else if ScriptState = ss_Paused then
begin;
ScriptThread.Resume;
ScriptState := ss_Running;
end;
end;
end;
procedure TSimbaForm.StopScript;
begin
with CurrScript do
begin;
case ScriptState of
ss_Stopping:
begin //Terminate the thread the tough way.
mDebugLn('Terminating the Scriptthread');
mDebugLn('Exit code terminate: ' +inttostr(KillThread(ScriptThread.Handle)));
WaitForThreadTerminate(ScriptThread.Handle, 0);
ScriptThread.Free;
ScriptState := ss_None;
end;
ss_Running:
begin
ScriptThread.Terminate;
ScriptState := ss_Stopping;
end;
ss_Paused:
begin
ScriptThread.Resume;
ScriptThread.Terminate;
ScriptState:= ss_Stopping;
end;
end;
end;
end;
{ Tab management }
procedure TSimbaForm.AddTab;
var
Tab : TMufasaTab;
begin;
Tab := TMufasaTab.Create(Self.PageControl1);
Tabs.Add(Tab);
Tab.TabSheet.ImageIndex:= 8;
// Tab.TabSheet.OnContextPopup:= @TabPopup;
PageControl1.TabIndex:= Tabs.Count - 1;
RefreshTab;
if tabs.count > 1 then
begin;
TB_SaveAll.Enabled:= True;
MenuItemSaveAll.Enabled:= True;
end;
end;
function TSimbaForm.DeleteTab(TabIndex: integer; CloseLast : boolean; Silent : boolean = false) : boolean;
var
Tab : TMufasaTab;
OldIndex : integer;//So that we can switch back, if needed.
begin
if not Silent then
begin;
OldIndex := PageControl1.TabIndex;
if TabIndex = OldIndex then
begin;
if lowercase(LoadSettingDef('Settings/Tabs/OpenNextOnClose','False')) = 'false' then
OldIndex := LastTab //We are closing the 'current' tab, lets go back in history
else
OldIndex := Min(Tabs.Count - 1,OldIndex + 1);
end;
PageControl1.TabIndex:= TabIndex;
end;
//ScriptFrame now is now correct ;-D
result := CanExitOrOpen;
if not result then
exit;
Tab := TMufasaTab(Tabs[TabIndex]);
if (Tabs.Count = 1) and (not CloseLast) then
Tab.Clear
else
begin;
Tab.Free;
Tabs.Delete(TabIndex);
if not Silent then
begin;
if OldIndex > TabIndex then
PageControl1.TabIndex := OldIndex - 1
else if OldIndex < TabIndex then
PageControl1.TabIndex := OldIndex;
end;
end;
if tabs.count <= 1 then
begin;
TB_SaveAll.Enabled:= false;
MenuItemSaveAll.Enabled:= false;
end;
if not silent then
RefreshTab;
end;
procedure TSimbaForm.ClearTab(TabIndex: integer);
begin
TMufasaTab(Tabs[TabIndex]).Clear;
end;
procedure TSimbaForm.CloseTabs(Exclude: integer = -1; Silent : boolean = false);
var
I : integer;
begin
for i := tabs.count - 1 downto 0 do
if i <> exclude then
if not DeleteTab(i,false,silent) then
exit;
end;
procedure TSimbaForm.SetEditActions;
procedure EditActions(Undo,Redo,Cut,Copy,Paste,Delete : boolean);
begin;
ActionUndo.Enabled:= Undo;
ActionRedo.Enabled:= Redo;
ActionCut.Enabled:= Cut;
ActionCopy.Enabled:= Copy;
ActionPaste.Enabled:= Paste;
ActionDelete.Enabled:= Delete;
{$ifdef UpdateEditButtons}
TT_Cut.Enabled:= Cut;
TT_Paste.Enabled:=Paste;
TT_Copy.enabled := Copy;
{$endif}
end;
var
S: String;
B: Boolean;
begin
if CurrScript.SynEdit.Focused or ScriptPopup.HandleAllocated then
begin
with CurrScript.SynEdit do
begin
EditActions(CanUndo,CanRedo,SelText <> '',SelText <> '',CanPaste,SelText <> '');
// B:= SelText <> '';
B := SelAvail;
PopupItemFind.Enabled:= B;
PopupItemReplace.Enabled:= B;
if(B)then
begin
s := SelText;
if(Length(S) > 13)then
S:= Format('"%s"', [Copy(S, 1, 10) + '...'])
else
S:= Format('"%s"', [S]);
PopupItemFind.Caption:= 'Find next: ' + S;
PopupItemReplace.Caption:= 'Replace: ' + S;
end;
end
end
else if Memo1.Focused then
with Memo1 do
EditActions(CanUndo,False,SelText <>'',SelText <> '',True,SelText <> '')
else
EditActions(false,false,false,false,false,false);
end;
procedure TSimbaForm.DoSearch(Next: boolean; HighlightAll : boolean);
var
Res : integer;
CurrPos : TPoint;
SearchOptions : TSynSearchOptions;
begin
SearchOptions:= [];
if CheckBoxMatchCase.Checked then
SearchOptions := [ssoMatchCase];
if SearchString = '' then
begin
res := -1;
CurrScript.Synedit.SetHighlightSearch('',[]);
// CurrScript.SynEdit.SelectionMode:=
// CurrScript.SynEdit.CaretXY := CurrScript.SynEdit.CaretXY;
CurrScript.SynEdit.LogicalCaretXY := SearchStart;
end
else
begin
mDebugLn('Searching: ' + SearchString);
if next then
CurrPos := CurrScript.SynEdit.LogicalCaretXY
else
CurrPos := SearchStart;
Res := CurrScript.SynEdit.SearchReplaceEx(SearchString,'',SearchOptions,CurrPos);
if res = 0 then
begin
res := CurrScript.SynEdit.SearchReplaceEx(SearchString,'',SearchOptions,Classes.Point(0,0));
if res > 0 then
begin;
mDebugLn('End of document reached');
SearchStart.x := 0;
SearchStart.Y := CurrScript.SynEdit.LogicalCaretXY.y;
end;
end;
end;
if res = 0 then
begin;
LabeledEditSearch.Color := 6711039;
LabeledEditSearch.Font.Color:= clWhite;
CurrScript.Synedit.SetHighlightSearch('',[]);
CurrScript.SynEdit.LogicalCaretXY := SearchStart;
end
else
begin
LabeledEditSearch.Color:= clWindow;
LabeledEditSearch.Font.Color:= clWindowText;
with CurrScript.SynEdit do
begin
HighlightAllColor.Background:= clYellow;
if HighlightAll then
SetHighlightSearch(SearchString,[])
else
SetHighlightSearch('',[]);
end;
end;
end;
procedure TSimbaForm.RefreshTab;
var
Tab : TMufasaTab;
Script : TScriptFrame;
NewTab : integer;
begin
if tabs.Count < 1 then
begin;
mDebugLn('Cannot refresh tab, since there are no tabs.');
exit;
end;
NewTab := PageControl1.TabIndex;
if NewTab < 0 then exit;
Tab := TMufasaTab(Tabs[Newtab]);
Script := Tab.ScriptFrame;
Self.CurrScript := Script;
Self.CurrTab := Tab;
SetScriptState(Tab.ScriptFrame.FScriptState);//To set the buttons right
if Self.Showing then
if Tab.TabSheet.TabIndex = Self.PageControl1.TabIndex then
if CurrScript.SynEdit.CanFocus then
CurrScript.SynEdit.SetFocus; // XXX: This is never called
StopCodeCompletion;//To set the highlighting back to normal;
frmFunctionList.LoadScriptTree(CurrScript.SynEdit.Text);
with CurrScript.SynEdit do
begin
SetHighlightSearch('',[]);
UseIncrementalColor:= false;
MarkupByClass[TSynEditMarkupHighlightAllCaret].TempEnable;
Invalidate;
end;
LabeledEditSearch.SelLength:= 0;
LabeledEditSearch.Color:= clWindow;
LabeledEditSearch.Font.Color:= clWindowText;
//Set tha edit buttons right
SetEditActions;
end;
procedure TSimbaForm.RefreshTabSender(sender: PtrInt);
begin
RefreshTab;
end;
{ Settings related code }
{ Creates default settings }
procedure TSimbaForm.CreateDefaultEnvironment;
var
PluginsPath,extensionsPath : string;
begin
CreateSetting('Settings/Updater/CheckForUpdates','True');
CreateSetting('Settings/Updater/CheckEveryXMinutes','30');
CreateSetting('Settings/Interpreter/Type', '0');
CreateSetting('Settings/Fonts/LoadOnStartUp', 'True');
CreateSetting('Settings/Fonts/Version','-1');
CreateSetting('Settings/Tabs/OpenNextOnClose','False');
CreateSetting('Settings/Tabs/OpenScriptInNewTab','True');
CreateSetting('Settings/Tabs/CheckTabsBeforeOpen','True');
CreateSetting('Settings/ColourPicker/ShowHistoryOnPick', 'True');
CreateSetting('Settings/General/MaxRecentFiles','10');
CreateSetting('Settings/MainForm/NormalSize','739:555');
CreateSetting('Settings/FunctionList/ShowOnStart','True');
CreateSetting('Settings/CodeHints/ShowAutomatically','True');
CreateSetting('Settings/CodeCompletion/ShowAutomatically','True');
CreateSetting('Settings/SourceEditor/LazColors','True');
{$IFDEF USE_EXTENSIONS}CreateSetting('Settings/Extensions/FileExtension','sex');{$ENDIF}
CreateSetting('Settings/Updater/RemoteLink',SimbaURL + 'Simba'{$IFDEF WINDOWS} +'.exe'{$ENDIF});
CreateSetting('Settings/Updater/RemoteVersionLink',SimbaURL + 'Version');
CreateSetting('Settings/Fonts/VersionLink', FontURL + 'Version');
CreateSetting('Settings/Fonts/UpdateLink', FontURL + 'Fonts.tar.bz2');
CreateSetting('Settings/News/URL', 'http://simba.villavu.com/bin/news');
{Creates the paths and returns the path}
PluginsPath := CreateSetting('Settings/Plugins/Path', ExpandFileName(MainDir+ DS+ 'Plugins' + DS));
{$IFDEF USE_EXTENSIONS}
extensionsPath := CreateSetting('Settings/Extensions/Path',ExpandFileName(MainDir +DS + 'Extensions' + DS));
CreateSetting('Extensions/ExtensionCount','0');
{$ENDIF}
CreateSetting('LastConfig/MainForm/Position','');
CreateSetting('LastConfig/MainForm/State','Normal');
{$ifdef MSWindows}
CreateSetting('LastConfig/Console/Visible','False');
ShowConsole(False);
{$endif}
CreateSetting('Settings/Tray/AlwaysVisible', 'True');
if not DirectoryExists(IncludePath) then
CreateDir(IncludePath);
if not DirectoryExists(FontPath) then
CreateDir(FontPath);
if not DirectoryExists(PluginsPath) then
CreateDir(PluginsPath);
{$IFDEF USE_EXTENSIONS}
if not DirectoryExists(extensionsPath) then
CreateDir(extensionsPath);
if not DirectoryExists(ExtPath) then
CreateDir(ExtPath);
{$ENDIF}
if not DirectoryExists(ScriptDir) then
CreateDir(ScriptDir);
SettingsForm.SettingsTreeView.Items.GetFirstNode.Expand(false);
SettingsForm.SaveCurrent;
LoadFormSettings;
UpdateTimer.Interval:=25;
end;
{ Load settings }
procedure TSimbaForm.LoadFormSettings;
var
str,str2 : string;
Data : TStringArray;
i,ii : integer;
begin
self.BeginFormUpdate;
str := LoadSettingDef('LastConfig/MainForm/Position','');
if str <> '' then
begin;
Data := Explode(':',str);
if length(Data) <> 4 then
Exit;
Self.Left:= StrToIntDef(Data[0],Self.Left);
Self.Top:= StrToIntDef(Data[1],self.top);
Self.Width:= StrToIntDef(Data[2],self.width);
Self.Height:= StrToIntDef(Data[3],self.height);
end;
str := lowercase(LoadSettingDef('LastConfig/MainForm/State','Normal'));
if str = 'maximized' then
self.windowstate := wsMaximized
else
// if str = 'normal' then
Self.WindowState := wsNormal;
if SettingExists('LastConfig/MainForm/RecentFiles/Count') then
begin;
ii := StrToIntDef(LoadSettingDef('LastConfig/MainForm/RecentFiles/Count','-1'),-1);
for i := 0 to ii do
begin
str := LoadSettingDef('LastConfig/MainForm/RecentFiles/File' + inttostr(I),'');
if str <> '' then
AddRecentFile(str);
end;
end;
str := LowerCase(LoadSettingDef('Settings/FunctionList/ShowOnStart','True'));
str2 := lowercase(LoadSettingDef('LastConfig/MainForm/FunctionListShown',''));
if (str = 'true') or (str2 = 'true') then
FunctionListShown(True)
else
FunctionListShown(false);
{$ifdef MSWindows}
str := LowerCase(LoadSettingDef('LastConfig/Console/Visible','True'));
if str = 'true' then
ShowConsole(True)
else
ShowConsole(false);
{$endif}
if Lowercase(LoadSettingDef('Settings/Tray/AlwaysVisible', 'True')) <> 'true' then
begin
MTrayIcon.Hide;
writeln('Hiding tray.');
end;
UpdateInterpreter;
self.EndFormUpdate;
end;
{ Save Settings }
procedure TSimbaForm.SaveFormSettings;
var
Data : TStringArray;
path : string;
i : integer;
begin
with SettingsForm.Settings do
begin
if Self.WindowState = wsMaximized then
SetSetting('LastConfig/MainForm/State','maximized')
else
begin; //Only save the form position if its not maximized.
SetSetting('LastConfig/MainForm/State','normal');
Data := ConvArr([inttostr(Self.left),inttostr(self.top),inttostr(self.width),inttostr(self.height)]);
SetSetting('LastConfig/MainForm/Position', Implode(':',Data ));
end;
DeleteKey('LastConfig/MainForm/RecentFiles');
if RecentFiles.Count > 0 then
begin
SetSetting('LastConfig/MainForm/RecentFiles/Count',inttostr(RecentFiles.Count));
SetLength(data,RecentFiles.Count);
for i := 0 to RecentFiles.Count - 1 do
SetSetting('LastConfig/MainForm/RecentFiles/File'+inttostr(i),RecentFiles[i]);
end;
if MenuItemFunctionList.Checked then
SetSetting('LastConfig/MainForm/FunctionListShown','True')
else
SetSetting('LastConfig/MainForm/FunctionListShown','False');
{$ifdef MSWindows}
if ConsoleVisible then
SetSetting('LastConfig/Console/Visible','True')
else
SetSetting('LastConfig/Console/Visible','False');
{$endif}
{$IFDEF USE_EXTENSIONS}
SetSetting('Extensions/ExtensionCount',inttostr(ExtManager.Extensions.Count));
for i := 0 to ExtManager.Extensions.Count-1 do
begin;
path :='Extensions/Extension' + inttostr(I);
SetSetting(Path + '/Path',TVirtualSimbaExtension(ExtManager.Extensions[i]).Filename);
SetSetting(Path + '/Enabled',BoolToStr(TVirtualSimbaExtension(ExtManager.Extensions[i]).Enabled,True));
end;
{$ENDIF}
SaveToXML(SimbaSettingsFile);
end;
end;
procedure TSimbaForm.LoadExtensions;
{$IFDEF USE_EXTENSIONS}
var
extCount : integer;
function LoadExtension(Number : integer) : boolean;
var
Path : string;
ExtPath : string;
ExtEnabled : boolean;
begin;
result := false;
if (number < 0) or (number >= extCount) then
exit;
path := 'Extensions/Extension' + inttostr(number);
if SettingExists(Path) = false then
exit;
ExtPath := LoadSettingDef(Path + '/Path','');
if ExtPath = '' then
exit;
ExtEnabled := StrToBoolDef(LoadSettingDef(Path + '/Enabled','false'),false);
if ExtManager.LoadPSExtension(ExtPath,ExtEnabled) = false then
exit;
Result := true;
end;
procedure DeleteExtension(number : integer);
var
i : integer;
path : string;
begin;
path := 'Extensions/Extension';
SettingsForm.Settings.DeleteKey(path + inttostr(number));
for i := number + 1 to extCount - 1 do
SettingsForm.Settings.RenameKey(path + inttostr(i),'Extension' + inttostr(i-1));
SetSetting('Extensions/ExtensionCount',inttostr(extCount - 1),true);
dec(extCount);
end;
var
str,str2 : string;
i : integer;
begin
extCount := StrToIntDef(LoadSettingDef('Extensions/ExtensionCount/','0'),0);
for i := 0 to extCount - 1 do
while (i < extCount) and not LoadExtension(i) do
DeleteExtension(i);
SetSetting('Extensions/ExtensionCount',inttostr(extCount));
str := LoadSettingDef('Settings/Extensions/Path',ExpandFileName(MainDir +DS + 'Extensions' + DS));
str2 := LoadSettingDef('Settings/Extensions/FileExtension','sex');
ExtManager.LoadPSExtensionsDir(str,str2);
{$ELSE}
begin
{$ENDIF}
end;
procedure TSimbaForm.AddRecentFile(const filename: string);
var
MaxRecentFiles : integer;
Len,i : integer;
begin
MaxRecentFiles:= StrToIntDef(LoadSettingDef('Settings/General/MaxRecentFiles','10'),10);
i := RecentFiles.IndexOf(filename);
if i <> -1 then
RecentFiles.Delete(i);
if RecentFiles.Count = MaxRecentFiles then
RecentFiles.Delete(0);
RecentFiles.Add(filename);
Len := RecentFiles.Count;
if len <> length(RecentFileItems) then //Not reached maximum yet, add those files!
begin
SetLength(RecentFileItems,len);
RecentFileItems[len-1] := TMenuItem.Create(MenuItemOpenRecent);
RecentFileItems[len-1].OnClick:=@RecentFileItemsClick;
MenuItemOpenRecent.Add(RecentFileItems[len-1]);
end;
for i := 0 to len - 1 do
RecentFileItems[len - 1-i].Caption:= ExtractFileName(RecentFiles[i]);
end;
{ Loads/Creates the required stuff for a script thread. }
procedure TSimbaForm.InitializeTMThread(out Thread: TMThread);
var
AppPath : string;
ScriptPath : string;
Script : string;
Se: TMMLSettingsSandbox;
loadFontsOnScriptStart: boolean;
Continue : boolean;
begin
if (CurrScript.ScriptFile <> '') and CurrScript.GetReadOnly() then
begin
formWriteln('Reloading read only script');
CurrScript.ReloadScript;
end;
Script := CurrScript.SynEdit.Lines.Text;
if Assigned(OnScriptStart) then
begin
Continue := True;
OnScriptStart(Self,script,continue);
if not Continue then
exit;
end;
AppPath:= MainDir + DS;
CurrScript.ScriptErrorLine:= -1;
CurrentSyncInfo.SyncMethod:= @Self.SafeCallThread;
try
case Interpreter of
interp_PS : Thread := TPSThread.Create(true,@CurrentSyncInfo,PluginPath);
// XXX: Rutis needs to be completely removed from Simba if it's not defined.
// XXX: Not just print a message that it's not supported now.
interp_RT : {$IFDEF USE_RUTIS}Thread := TRTThread.Create(true,@CurrentSyncInfo,PluginPath){$ELSE}formWriteln('RUTIS NOT SUPPORTED') {$ENDIF};
interp_CP : Thread := TCPThread.Create(true,@CurrentSyncInfo,PluginPath);
end;
except
mDebugLn('Failed to initialise the interpreter');
Exit;
end;
{$IFNDEF TERMINALWRITELN}
Thread.SetDebug(@formWriteln);
{$ENDIF}
Thread.SetScript(Script);
Thread.ErrorData:= @CurrScript.ErrorData;
Thread.OnError:= @CurrScript.HandleErrorData;
FormCallBackData.FormCallBack:= @self.FormCallBack;
Thread.CallBackData:=@FormCallBackData;
if CurrScript.ScriptFile <> '' then
ScriptPath := IncludeTrailingPathDelimiter(ExtractFileDir(CurrScript.ScriptFile));
if DirectoryExists(PluginPath) then
PluginsGlob.AddPath(PluginPath);
if not DirectoryExists(IncludePath) then
if FirstRun then
FormWritelnEx('Warning: The include directory specified in the Settings isn''t valid.');
if not DirectoryExists(fontPath) then
if FirstRun then
FormWritelnEx('Warning: The font directory specified in the Settings isn''t valid. Can''t load fonts now');
Thread.SetPaths(ScriptPath,AppPath,Includepath,PluginPath,fontPath);
if selector.haspicked then
Thread.Client.IOManager.SetTarget(Selector.LastPick);
loadFontsOnScriptStart := (lowercase(LoadSettingDef('Settings/Fonts/LoadOnStartUp', 'True')) = 'true');
if (loadFontsOnScriptStart) then
begin
if ((not (Assigned(OCR_Fonts))) and DirectoryExists(fontPath)) then
begin
OCR_Fonts := TMOCR.Create(Thread.Client);
OCR_Fonts.InitTOCR(fontPath);
end;
if (Assigned(OCR_Fonts)) then
Thread.Client.MOCR.Fonts := OCR_Fonts.Fonts;
end;
{
We pass the entire settings to the script; it will then create a Sandbox
for settings that are exported to the script. This way we can access all
the settings from the PSThread, and scripts can only access limited
resources. Hopefully this won't cause any form / thread related problems?
(Settings doesn't use the Settings form, iirc)
Well, it was like this previously as well, we just passed a sandbox to it
directly, but the sandbox still called Settings.
}
Thread.SetSettings(SettingsForm.Settings, SimbaSettingsFile);
Thread.OpenConnectionEvent:=@ThreadOpenConnectionEvent;
Thread.WriteFileEvent:=@ThreadWriteFileEvent;
Thread.OpenFileEvent:=@ThreadOpenFileEvent;
end;
procedure TSimbaForm.HandleParameters;
var
DoRun : Boolean;
ErrorMsg : string;
begin
DoRun := false;
// paramcount = 1 means we got only one parameter. We assume this to be a file.
// and try to open it accordingly
if (Paramcount = 1) and not (Application.HasOption('open')) then
begin
writeln('Opening file: ' + ParamStr(1));
if FileExistsUTF8(ParamStrUTF8(1)) then
LoadScriptFile(ParamStrUTF8(1));
end else
// we have more parameters. Check for specific options. (-r -o, --run --open)
begin
ErrorMsg:=Application.CheckOptions('ro:',['run', 'open:']);
if ErrorMsg <> '' then
begin
mDebugLn('ERROR IN COMMAND LINE ARGS: ' + ErrorMSG)
end else
begin
if Application.HasOption('o','open') then
begin
writeln('Opening file: ' + Application.GetOptionValue('o','open'));
LoadScriptFile(Application.GetOptionValue('o','open'));
DoRun:= Application.HasOption('r','run');
end else
// no valid options
begin
writeln('No valid command line args are passed');
end;
end;
end;
if DoRun then
Self.RunScript;
end;
procedure TSimbaForm.OnSaveScript(const Filename: string);
begin
with CurrScript do
begin
ScriptFile:= SetDirSeparators(Filename);
ScriptName:= ExtractFileNameOnly(ScriptFile);
mDebugLn('Script name will be: ' + ScriptName);
FormWritelnEx('Successfully saved: ' + ScriptFile);
StartText:= SynEdit.Lines.Text;
ScriptChanged := false;
SynEdit.MarkTextAsSaved;
CurrTab.TabSheet.Caption:= ScriptName;
Self.AddRecentFile(ScriptFile);
UpdateTitle;
end;
end;
function TSimbaForm.DefaultScript: string;
var
x : TStringList;
begin
result := '';
case Interpreter of
interp_PS : begin
if FileExistsUTF8(SimbaForm.DefScriptPath) then
begin
x := TStringList.Create;
try
x.LoadFromFile(SimbaForm.DefScriptPath);
except
mDebugLn('Couldn''t load default script file.');
end;
Result := x.Text;
end else
result := 'program new;'+LineEnding + 'begin'+LineEnding+'end.' + LineEnding;
end;
interp_RT : result := 'program untitled;' + LineEnding + lineEnding + 'interface' + LineEnding + LineEnding +
'implementation' + LineEnding + LineEnding + 'begin' + LineEnding + 'end.' + LineEnding;
end;
end;
procedure TSimbaForm.ActionTabLastExecute(Sender: TObject);
var
CurrIndex : integer;
begin
CurrIndex := PageControl1.TabIndex;
if CurrIndex = 0 then
CurrIndex := Tabs.count - 1
else
Dec(CurrIndex);
PageControl1.TabIndex:= CurrIndex;
end;
procedure TSimbaForm.ActionCloseTabExecute(Sender: TObject);
begin
if(PageControl1.PageCount > 1) then
begin
if Sender is TTabSheet then
Self.DeleteTab(TTabSheet(Sender).TabIndex,false)
else
Self.DeleteTab(PageControl1.TabIndex,false)
end
else
Self.ClearScript; //DeleteTab would take care of this already, but yeah, it's neater this way.
end;
procedure TSimbaForm.ActionCompileScriptExecute(Sender: TObject);
var
TempThread : TMThread;
begin
InitializeTMThread(TempThread);
TempThread.CompileOnly:= true;
TempThread.Resume;
end;
procedure TSimbaForm.ActionConsoleExecute(Sender: TObject);
begin
{$ifdef mswindows}
ShowConsole(not ConsoleVisible);
{$endif}
end;
procedure TSimbaForm.ActionCopyExecute(Sender: TObject);
begin
if CurrScript.SynEdit.Focused or ScriptPopup.HandleAllocated then
CurrScript.SynEdit.CopyToClipboard
else if Memo1.Focused then
Memo1.CopyToClipboard;
end;
procedure TSimbaForm.ActionCPascalExecute(Sender: TObject);
begin
Interpreter:= interp_CP;
end;
procedure TSimbaForm.ActionCutExecute(Sender: TObject);
begin
if CurrScript.SynEdit.Focused or ScriptPopup.HandleAllocated then
CurrScript.SynEdit.CutToClipboard
else if Memo1.Focused then
Memo1.CutToClipboard;
end;
procedure TSimbaForm.ActionDeleteExecute(Sender: TObject);
begin
if CurrScript.SynEdit.Focused or ScriptPopup.HandleAllocated then
CurrScript.SynEdit.ClearSelection
else if Memo1.Focused then
Memo1.ClearSelection;
end;
procedure TSimbaForm.ActionExitExecute(Sender: TObject);
begin
Self.Close;
end;
procedure TSimbaForm.ActionExtensionsExecute(Sender: TObject);
begin
{$IFDEF USE_EXTENSIONS}
if not ExtensionsForm.Showing then
ExtensionsForm.Show
else
ExtensionsForm.Hide;
{$ENDIF}
end;
procedure TSimbaForm.ActionExtensionsUpdate(Sender: TObject);
begin
{$IFDEF USE_EXTENSIONS}TAction(Sender).Checked := ExtensionsForm.Showing;{$ENDIF}
end;
procedure TSimbaForm.ActionFindNextExecute(Sender: TObject);
begin
DoSearch(true, false);
end;
procedure TSimbaForm.ActionFindstartExecute(Sender: TObject);
begin
if frmFunctionList.Focused or frmFunctionList.FunctionList.Focused or frmFunctionList.editSearchList.Focused then
begin
if frmFunctionList.editSearchList.CanFocus then
frmFunctionList.editSearchList.SetFocus;
end else
begin
SearchPanel.Visible:= true;
if LabeledEditSearch.CanFocus then
LabeledEditSearch.SetFocus;
end;
end;
procedure TSimbaForm.ActionGotoExecute(Sender: TObject);
var
Value : string;
P : TPoint;
begin
Value := '';
if InputQuery('Goto line','Goto line:',Value) then
begin
P.x := 1;
P.y := StrToIntDef(Value,-1);
if p.y < 1 then p.y :=1;
CurrScript.SynEdit.CaretXY := p;
CurrScript.SynEdit.TopLine:= max(P.y - (CurrScript.SynEdit.LinesInWindow div 2),1);
end;
end;
procedure TSimbaForm.ActionClearDebugExecute(Sender: TObject);
begin
Memo1.Clear;
end;
procedure TSimbaForm.ActionNewExecute(Sender: TObject);
begin
//Self.ClearScript;
Self.AddTab;
end;
procedure TSimbaForm.ActionNewTabExecute(Sender: TObject);
begin
Self.AddTab;
end;
procedure TSimbaForm.ActionNormalSizeExecute(Sender: TObject);
var
SizeStr : string;
Data : TStringArray;
begin
SizeStr := LoadSettingDef('Settings/MainForm/NormalSize','739:555');
Data := Explode(':',SizeStr);
if length(Data) = 2 then
begin
Self.Width:= StrToIntDef(Data[0],739);
Self.Height:= StrToIntDef(Data[1],555);
end else
begin;
self.width := 739;
self.height := 555;
end;
end;
procedure TSimbaForm.ActionOpenExecute(Sender: TObject);
begin
Self.OpenScript;
end;
procedure TSimbaForm.ActionPascalScriptExecute(Sender: TObject);
begin
Interpreter:= interp_PS;
end;
procedure TSimbaForm.ActionPasteExecute(Sender: TObject);
begin
if CurrScript.SynEdit.Focused or ScriptPopup.HandleAllocated then
CurrScript.SynEdit.PasteFromClipboard
else if Memo1.Focused then
Memo1.PasteFromClipboard
else if LabeledEditSearch.Focused then
LabeledEditSearch.PasteFromClipboard
else if frmFunctionList.editSearchList.Focused then
frmFunctionList.editSearchList.PasteFromClipboard;
end;
procedure TSimbaForm.ActionPauseExecute(Sender: TObject);
begin
Self.PauseScript;
end;
procedure TSimbaForm.ActionRedoExecute(Sender: TObject);
begin
if CurrScript.SynEdit.Focused or ScriptPopup.HandleAllocated then
CurrScript.Redo
else if Memo1.Focused then
Memo1.Undo; //?
end;
procedure TSimbaForm.ActionReplaceExecute(Sender: TObject);
begin
if(ScriptPopup.HandleAllocated)then
dlgReplace.FindText:= CurrScript.SynEdit.SelText;
dlgReplace.Execute;
end;
procedure TSimbaForm.ActionRunExecute(Sender: TObject);
begin
Self.RunScript;
end;
procedure TSimbaForm.ActionRUTISExecute(Sender: TObject);
begin
{$IFDEF USE_RUTIS}
Interpreter:= interp_RT;
{$ENDIF}
end;
procedure TSimbaForm.ActionSaveAllExecute(Sender: TObject);
var
i : integer;
OldIndex : integer;
begin
OldIndex := PageControl1.TabIndex;
for i := 0 to Tabs.Count - 1 do
begin;
PageControl1.TabIndex:= i;
SaveCurrentScript;
end;
PageControl1.TabIndex:= oldindex;
end;
procedure TSimbaForm.ActionSaveAsExecute(Sender: TObject);
begin
Self.SaveCurrentScriptAs;
end;
procedure TSimbaForm.ActionSaveDefExecute(Sender: TObject);
begin
Self.SaveCurrentScriptAsDefault;
end;
procedure TSimbaForm.ActionSaveExecute(Sender: TObject);
begin
Self.SaveCurrentScript;
end;
procedure TSimbaForm.ActionSelectAllExecute(Sender: TObject);
begin
if CurrScript.SynEdit.Focused or ScriptPopup.HandleAllocated then
CurrScript.SynEdit.SelectAll
else if Memo1.Focused then
Memo1.SelectAll
else if LabeledEditSearch.Focused then
LabeledEditSearch.SelectAll;
end;
procedure TSimbaForm.ActionStopExecute(Sender: TObject);
begin
Self.StopScript;
end;
procedure TSimbaForm.ActionTabNextExecute(Sender: TObject);
var
CurrIndex : integer;
begin
CurrIndex := PageControl1.TabIndex;
if CurrIndex = Tabs.count - 1 then
CurrIndex := 0
else
Inc(CurrIndex);
PageControl1.TabIndex:= CurrIndex;
end;
procedure TSimbaForm.ActionUndoExecute(Sender: TObject);
begin
if CurrScript.SynEdit.Focused or ScriptPopup.HandleAllocated then
CurrScript.Undo
else if Memo1.Focused then
Memo1.Undo;
end;
procedure TSimbaForm.ChangeMouseStatus(Sender: TObject);
var
x, y: Integer;
begin
if Self.Manager.TargetValid = false then
self.Manager.SetDesktop;
Self.Manager.GetMousePos(x, y);
if self.Manager.ReceivedError() then
begin
FormWritelnEx('Our window no longer exists -> Resetting to desktop');
self.Manager.SetDesktop;
self.Manager.ResetError;
end;
StatusBar.Panels[Panel_Coords].Text := Format('(%d, %d)', [x, y]);
end;
procedure TSimbaForm.CheckBoxMatchCaseClick(Sender: TObject);
begin
RefreshTab;
CurrScript.SynEdit.MarkupByClass[TSynEditMarkupHighlightAllCaret].TempDisable;
SearchString := LabeledEditSearch.Text;
DoSearch(false, true);
CurrScript.SynEdit.UseIncrementalColor:= true;
LabeledEditSearch.SetFocus;
end;
procedure TSimbaForm.CloseFindPanel;
begin
SearchPanel.Visible:= false;
if CurrScript.SynEdit.CanFocus then
CurrScript.SynEdit.SetFocus;
end;
{
If we are being sent to the background; then minimize other active windows as
well.
}
procedure TSimbaForm.doOnHide(Sender: TObject);
begin
if (not (csDestroying in ComponentState)) and (DebugImgForm <> nil) and DebugImgForm.Showing then
DebugImgForm.Hide;
end;
procedure TSimbaForm.StopCodeCompletion;
begin
CodeCompletionForm.Hide;
if frmFunctionList.InCodeCompletion then
with CurrScript,frmFunctionList do
begin;
editSearchList.Color:= clWhite;
if FilterTree.Focused then
begin;
mDebugLn('This is currently not supported');
SynEdit.Lines[CompletionCaret.y - 1] := CompletionStart;
SynEdit.LogicalCaretXY:= Classes.point(CompletionCaret.x,CompletionCaret.y);
SynEdit.SelEnd:= SynEdit.SelStart;
end;
InCodeCompletion:= false;
SynEdit.SelectedColor.Style:= [];
SynEdit.SelectedColor.Foreground:= clHighlightText;
SynEdit.SelectedColor.Background:= clHighlight;
Synedit.MarkupByClass[TSynEditMarkupHighlightAllCaret].TempEnable;
end;
end;
function TSimbaForm.FindTab(filename: string): integer;
var
i : integer;
begin
FileName := SetDirSeparators(filename);
for i := 0 to SimbaForm.Tabs.Count - 1 do
{$ifdef MSWindows} //Case insensitive
if lowercase(TMufasaTab(Tabs[i]).ScriptFrame.ScriptFile) = lowercase(filename) then
{$else}
if TMufasaTab(Tabs[i]).ScriptFrame.ScriptFile = filename then
{$endif}
exit(i);
result := -1;
end;
procedure TSimbaForm.editSearchListExit(Sender: TObject);
begin
frmFunctionList.editSearchList.Color := clWhite;
StopCodeCompletion;
end;
procedure TSimbaForm.editSearchListKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if key = vk_up then
begin
frmFunctionList.Find(True,true);
key := 0;
end else
if key = vk_down then
begin
frmFunctionList.Find(true);
key := 0;
end;
end;
procedure TSimbaForm.editSearchListKeyPress(Sender: TObject; var Key: char);
var
linetext : string;
begin
if key = #13 then//enter
begin;
key := #0;
frmFunctionList.Find(True);
end else
if frmFunctionList.InCodeCompletion then
begin;
if key = #27 then//esc -> C'est error!
begin
key := #0;
StopCodeCompletion;
CurrScript.SynEdit.Lines[frmFunctionList.CompletionCaret.y - 1] := frmFunctionList.CompletionStart;
CurrScript.SynEdit.LogicalCaretXY:= Classes.point(frmFunctionList.CompletionCaret.x,frmFunctionList.CompletionCaret.y);
CurrScript.SynEdit.SelEnd:= CurrScript.SynEdit.SelStart;
CurrScript.SynEdit.SetFocus;
end else
if key in [' ',',','.','(',')'] then //on on these chars we will insert the function!
begin;
StopCodeCompletion;
linetext := CurrScript.SynEdit.Lines[frmFunctionList.CompletionCaret.y - 1];
while (frmFunctionList.CompletionCaret.x <= length(linetext)) and (linetext[frmFunctionList.CompletionCaret.x] in ['a'..'z','A'..'Z','0'..'9','_']) do
inc(frmFunctionList.CompletionCaret.x);
CurrScript.SynEdit.LogicalCaretXY:= frmFunctionList.CompletionCaret;
CurrScript.SynEdit.SelStart:= CurrScript.SynEdit.SelEnd;
CurrScript.SynEdit.ExecuteCommand(ecChar,key,nil);
CurrScript.SynEdit.SetFocus;
key := #0;
end;
end;
end;
procedure TSimbaForm.FormDropFiles(Sender: TObject; const FileNames: array of String
);
var
i : integer;
begin
if (length(FileNames) = 1) then
begin
LoadScriptFile(FileNames[0]); //One file saves us some work
exit;
end;
if (length(FileNames) > 5) then //> 5 seems nice to me, cant imagine you want to open that many scripts on a regular base
case MessageDlg('Are you sure you want to open '+inttostr(length(filenames))+
' scripts?', mtConfirmation, mbYesNo, 0) of
IDNO: exit;
end;
{$IfDef WINDOWS}
//Fix for the really old Windows kernel bug which probably will never be fixed
for i := 1 to high(filenames) do
LoadScriptFile(FileNames[i],true);
LoadScriptFile(FileNames[0],true);
{$Else} //in this case its tolerable as Windows is the only OS with this bug
for i := 0 to high(filenames) do
LoadScriptFile(FileNames[i],true);
{$EndIf};
end;
procedure TSimbaForm.FunctionListChange(Sender: TObject; Node: TTreeNode);
var
MethodInfo : TMethodInfo;
begin
if node = nil then
exit;
if Node.level = 0 then
StatusBar.Panels[Panel_General].Text := 'Section: ' + Node.Text;
if (Node.Level > 0) and (Node.Data <> nil) then
begin
MethodInfo := PMethodInfo(node.Data)^;
StatusBar.Panels[Panel_General].Text := MethodInfo.MethodStr;
end;
end;
procedure TSimbaForm.FunctionListEnter(Sender: TObject);
begin
frmFunctionList.LoadScriptTree(CurrScript.SynEdit.Text);
end;
procedure TSimbaForm.FunctionListExit(Sender: TObject);
begin
// StatusBar.Panels[2].Text:= '';
end;
procedure TSimbaForm.FunctionListTimerTimer(Sender: TObject);
begin
if Self.Visible and (CurrScript <> nil) then
frmFunctionList.LoadScriptTree(CurrScript.SynEdit.Text);
end;
procedure TSimbaForm.MenuItemBitmapConvClick(Sender: TObject);
begin
BitmapConvForm.Show;
end;
procedure TSimbaForm.MenuItemHandbookClick(Sender: TObject);
begin
OpenURL('http://docs.villavu.com/simba/');
end;
procedure TSimbaForm.MenuItemColourHistoryClick(Sender: TObject);
begin
MenuItemColourHistory.Checked := not ColourHistoryForm.Visible;
if MenuItemColourHistory.Checked then
ColourHistoryForm.Show
else
ColourHistoryForm.Hide;
end;
procedure TSimbaForm.dlgReplaceFind(Sender: TObject);
begin
SearchString := dlgReplace.FindText;
DoSearch(True, False);
end;
procedure TSimbaForm.dlgReplaceReplace(Sender: TObject);
var
SOptions: TSynSearchOptions;
P: TPoint;
Y: Boolean;
Btns: TMsgDlgButtons;
procedure Replace;
begin
CurrScript.SynEdit.SearchReplaceEx(dlgReplace.FindText, dlgReplace.ReplaceText, SOptions + [ssoReplace], P);
end;
begin
Y:= False;
SOptions:= [];
if(frMatchCase in dlgReplace.Options)then SOptions:= [ssoMatchCase];
if(frWholeWord in dlgReplace.Options)then SOptions+= [ssoWholeWord];
with CurrScript.SynEdit do
begin
Btns:= [mbYes, mbNo];
if(frReplaceAll in dlgReplace.Options)then Btns+= [mbYesToAll];
if(frEntireScope in dlgReplace.Options)then P:= Classes.Point(0, 0) else P:= CaretXY;
while SearchReplaceEx(dlgReplace.FindText, '', SOptions, P) > 0 do
begin
if(Y)then
Replace
else case MessageDlg('Replace', Format('Do you want to replace "%s" with "%s"?', [dlgReplace.FindText, dlgReplace.ReplaceText]), mtConfirmation, Btns, 0) of
mrYes: Replace;
mrYesToAll: begin
Replace;
Y:= True;
end;
end;
if(not(frReplaceAll in dlgReplace.Options))then exit;
P:= CaretXY;
end;
end;
end;
procedure TSimbaForm.EditSearchChange(Sender: TObject);
begin
SearchString :=LabeledEditSearch.Text;
DoSearch(false, true);
end;
procedure TSimbaForm.FormClose(Sender: TObject; var CloseAction: TCloseAction);
var
i : integer;
begin
Self.SaveFormSettings;
for i := Tabs.Count - 1 downto 0 do
if not DeleteTab(i,true) then
begin;
CloseAction := caNone;
exit;
end;
FunctionListTimer.Enabled:= false;
CloseAction := caFree;
{$IFDEF USE_EXTENSIONS}FreeAndNil(ExtManager);{$ENDIF}
end;
procedure CCFillCore;
var
t: TMThread;
a: TPSScriptExtension;
b: TStringList;
ms: TMemoryStream;
buf : TCodeInsight;
begin
if SimbaForm.UpdatingFonts then
begin
mDebugLn('Updating the fonts, thus waiting a bit till we init the OCR.');
while SimbaForm.UpdatingFonts do
begin
if GetCurrentThreadId = MainThreadID then
Application.ProcessMessages;
sleep(25);
end;
end;
SimbaForm.InitializeTMThread(t);
KillThread(t.ThreadID); { XXX: Why do we kill the thread again ? }
if (t is TPSThread) then
try
a := TPSScriptExtension.Create(SimbaForm);
b := TStringList.Create;
ms := TMemoryStream.Create;
try
with TPSThread(t).PSScript do
begin
a.OnCompile := OnCompile;
a.OnCompImport := OnCompImport;
a.OnExecImport := OnExecImport;
a.Defines.Assign(Defines);
end;
a.GetValueDefs(b);
CoreDefines.AddStrings(a.Defines);
buf := TCodeInsight.Create;
with buf do
begin
OnMessage := @SimbaForm.OnCCMessage;
b.SaveToStream(ms);
Run(ms, nil, -1, True);
FileName := '"PSCORE"';
end;
SetLength(CoreBuffer, 1);
CoreBuffer[0] := buf;
finally
b.Free;
a.Free;
end;
finally
//KillThread(t.ThreadID);
t.Free;
end;
end;
procedure TSimbaForm.FormCreate(Sender: TObject);
var
FillThread : TProcThread;
begin
self.BeginFormUpdate;
Randomize;
DecimalSeparator := '.';
MainDir:= ExtractFileDir(Application.ExeName);
RecentFiles := TStringList.Create;
SimbaSettingsFile := MainDir + DS + 'settings.xml';
//AutoCompletionStart := Point(-1, -1);
CodeCompletionForm := TAutoCompletePopup.Create(Self);
CodeCompletionForm.InsertProc := @OnCompleteCode;
ParamHint := TParamHint.Create(self);
{$IFDEF MSWindows}
ConsoleVisible := True;
{ Bind CTRL+ALT+S to Script stop }
Bind_Windows_Keys();
{$ELSE}
TT_Console.Visible:= False;
{ Bind CTRL+ALT+S to Script stop }
{$IFDEF LINUX_HOTKEYS}
Bind_Linux_Keys();
{$ENDIF}
{$ENDIF}
InitmDebug; { Perhaps we need to place this before our mDebugLines?? }
Self.OnScriptStart:= @ScriptStartEvent;
FillThread := TProcThread.Create;
FillThread.FreeOnTerminate:= True;
FillThread.NormalProc:= @CCFillCore;
UpdateTimer.OnTimer:= @UpdateTimerCheck;
Application.CreateForm(TSimbaUpdateForm, SimbaUpdateForm);
{$IFDEF USE_EXTENSIONS}Application.CreateForm(TExtensionsForm, ExtensionsForm);{$ENDIF}
if FileExistsUTF8(SimbaSettingsFile) then
begin
Application.CreateForm(TSettingsForm,SettingsForm);
Self.LoadFormSettings;
end else
begin
Application.CreateForm(TSettingsForm,SettingsForm);
Self.CreateDefaultEnvironment;
FillThread.StartWait:= 250;
end;
//Show close buttons @ tabs
PageControl1.Options:=PageControl1.Options+[nboShowCloseButtons];
PageControl1.OnCloseTabClicked:=ActionCloseTab.OnExecute;
Tabs := TList.Create;
AddTab;//Give it alteast 1 tab ;-).
Manager := TIOManager.Create; //No need to load plugins for the Global manager
Picker := TMColorPicker.Create(Manager);
Picker.OnPick:=@PickerPick;
Selector := TMWindowSelector.Create(Manager);
{ For writeln }
SetLength(DebugStream, 0);
DebugCriticalSection := syncobjs.TCriticalSection.Create;
{$ifdef mswindows} { The Debug timer checks for new stuff to print }
DebugTimer.Enabled:= false;
{$endif}
Application.QueueAsyncCall(@RefreshTabSender,0);
{$ifdef mswindows} { Only windows can't remove files if they are in use }
if FileExists(Application.ExeName+'_old_') then
begin
mDebugLn('We still have an out-dated exe file in the dir. Lets remove!');
mDebugLn(format('Successfully deleted the file? %s',[BoolToStr(DeleteFile(PChar(Application.ExeName + '_old_')),true)]));
end;
SetConsoleCtrlHandler(@ConsoleHandler,true);
{$endif}
frmFunctionList.OnEndDock:= @frmFunctionList.FrameEndDock;
FirstRun := True;//Our next run is the first run.
HandleParameters; { Handle command line parameters }
TT_Update.Visible:= false;
//Fill the codeinsight buffer
FillThread.Resume;
//Load the extensions
{$IFDEF USE_EXTENSIONS}LoadExtensions;{$ENDIF}
UpdateTitle;
{$IFNDEF USE_RUTIS}
MenuItemRUTIS.Enabled:=False;
{$ENDIF}
{$IFDEF USE_EXTENSIONS}ActionExtensions.Visible := True;{$ENDIF}
self.EndFormUpdate;
if SettingsForm.Oops then
formWriteln('WARNING: No permissions to write to settings.xml!');
end;
procedure TSimbaForm.FormDestroy(Sender: TObject);
var
i : integer;
begin
{ Free the tabs }
for i := Tabs.Count - 1 downto 0 do
TMufasaTab(Tabs[i]).Free;
for i := 0 to high(RecentFileItems) do
RecentFileItems[i].Free;
{$IFDEF USE_EXTENSIONS}
if ExtManager <> nil then
FreeAndNil(extmanager);
{$ENDIF}
Tabs.Free;
{ Free MML Core stuff }
Selector.Free;
Picker.Free;
Manager.Free;
{ Free the plugins }
PluginsGlob.Free;
{ Free Fonts }
if (Assigned(OCR_Fonts)) then
OCR_Fonts.Free;
SetLength(DebugStream, 0);
DebugCriticalSection.Free;
RecentFiles.Free;
ParamHint.Free;
{$ifdef MSWindows}
Unbind_Windows_Keys;
{$else}
{$IFDEF LINUX_HOTKEYS}
Unbind_Linux_Keys;
{$ENDIF}
{$endif}
end;
procedure TSimbaForm.FormShortCuts(var Msg: TLMKey; var Handled: Boolean);
begin
SetEditActions;
Handled := ActionList.IsShortCut(Msg);
end;
procedure TSimbaForm.LabeledEditSearchEnter(Sender: TObject);
begin
SearchStart := CurrScript.SynEdit.LogicalCaretXY;
with CurrScript.SynEdit do
begin
UseIncrementalColor:= true;
MarkupByClass[TSynEditMarkupHighlightAllCaret].TempDisable
end;
end;
procedure TSimbaForm.LabeledEditSearchExit(Sender: TObject);
begin
if not CheckBoxMatchCase.MouseEntered then
RefreshTab;
end;
procedure TSimbaForm.LabeledEditSearchKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if (ssCtrl in Shift) and (key = vk_f) then
begin;
LabeledEditSearch.SelectAll;
end else
if key = VK_ESCAPE then
begin
CloseFindPanel;
key := 0;
end;
end;
procedure TSimbaForm.LabeledEditSearchKeyPress(Sender: TObject; var Key: char);
begin
if key = #13 then
begin;
SearchString:= LabeledEditSearch.Text;
DoSearch(true, true);
key := #0;
// LabeledEditSearch.SelStart:= Length(LabeledEditSearch.Text);
end;
end;
procedure TSimbaForm.MenuEditClick(Sender: TObject);
begin
SetEditActions;
end;
procedure TSimbaForm.MenuItemAboutClick(Sender: TObject);
begin
AboutForm.ShowModal;
end;
procedure TSimbaForm.MenuItemCloseTabsClick(Sender: TObject);
begin
Self.CloseTabs;
end;
procedure TSimbaForm.MenuItemDebugImageClick(Sender: TObject);
begin
MenuItemDebugImage.Checked := not DebugImgForm.Visible;
if MenuItemDebugImage.Checked then
DebugImgForm.Show
else
DebugImgForm.Hide;
end;
procedure TSimbaForm.MenuItemExportHTMLClick(Sender: TObject);
var
SynExporterHTML : TSynExporterHTML;
begin;
SynExporterHTML := TSynExporterHTML.Create(nil);
SynExporterHTML.Highlighter := CurrHighlighter;
SynExporterHTML.ExportAsText:= True;
with TSaveDialog.Create(nil) do
try
Filter:= 'HTML Files (*.html;*.htm)|*.html;*.htm|All files(*.*)|*.*';
Options:= [ofOverwritePrompt,ofEnableSizing];
DefaultExt:= 'html';
if Execute then
begin
if CurrScript.ScriptName <> '' then
SynExporterHTML.Title:= 'Simba - ' + CurrScript.ScriptName
else
SynExporterHTML.Title:= 'Simba - Untitled';
SynExporterHTML.ExportAll(CurrScript.SynEdit.Lines);
SynExporterHTML.SaveToFile(FileName);
end;
finally
free;
SynExporterHTML.Free;
end;
end;
procedure formWritelnEx(S: String);
begin
SimbaForm.Memo1.Lines.Add(s);
end;
function GetMethodName( Decl : string; PlusNextChar : boolean) : string;
var
I : integer;
ii : integer;
begin;
I := pos(' ',Decl) + 1;
for ii := i to Length(decl) do
begin;
if (Decl[ii] = '(') or (Decl[ii] = ';') then
begin;
if PlusNextChar then
result := result + decl[ii];
exit;
end;
if (Decl[ii] = ' ') or (Decl[ii] = ':') then
begin;
if PlusNextChar then
result := result + ' ';
exit;
end;
result := result + decl[ii];
end;
//We made it out of the loop.. This is a method without ';' we might wanne add that!
if PlusNextChar then
result := result + ';';
end;
procedure TSimbaForm.MenuitemFillFunctionListClick(Sender: TObject);
var
Methods : TExpMethodArr;
LastSection : string;
Sections : TStringList;
Nodes : array of TTreeNode;
i : integer;
Index : integer;
TempNode : TTreeNode;
Temp2Node : TTreeNode;
Tree : TTreeView;
begin
SetLength(nodes,0);
frmFunctionList.FunctionList.BeginUpdate;
if frmFunctionList.FunctionList.Items.Count = 0 then
begin;
Methods := TMThread.GetExportedMethods;
Tree := frmFunctionList.FunctionList;
Tree.Items.Clear;
Sections := TStringList.Create;
LastSection := '';
frmFunctionList.ScriptNode := Tree.Items.Add(nil,'Script');
frmFunctionList.IncludesNode := Tree.Items.Add(nil,'Includes');
for i := 0 to high(Methods) do
begin;
if Methods[i].Section <> LastSection then
begin;
LastSection := Methods[i].Section;
Index := Sections.IndexOf(LastSection);
if Index <> -1 then
TempNode := Nodes[index]
else
begin
TempNode := Tree.Items.Add(nil,LastSection);
Sections.Add(LastSection);
setlength(nodes,length(nodes)+1);
nodes[high(nodes)] := tempNode;
end;
end;
Temp2Node := Tree.Items.AddChild(Tempnode,GetMethodName(Methods[i].FuncDecl,false));
Temp2Node.Data := GetMem(SizeOf(TMethodInfo));
FillChar(PMethodInfo(Temp2Node.Data)^,SizeOf(TMethodInfo),0);
with PMethodInfo(Temp2Node.Data)^ do
begin
MethodStr:= strnew(PChar(Methods[i].FuncDecl));
BeginPos:= -1;
end;
end;
Sections.free;
end;
frmFunctionList.FunctionList.EndUpdate;
if CurrScript <> nil then
frmFunctionList.LoadScriptTree(CurrScript.SynEdit.Text);
end;
procedure TSimbaForm.MenuItemHideClick(Sender: TObject);
begin
if Self.Visible = false then
MenuItemShowClick(sender)
else
Self.Hide;
end;
procedure TSimbaForm.MenuItemOpenIncludesFolderClick(Sender: TObject);
begin
OpenDocument(Self.IncludePath);
end;
procedure TSimbaForm.MenuItemOpenPluginsFolderClick(Sender: TObject);
begin
OpenDocument(Self.PluginPath);
end;
procedure TSimbaForm.MenuItemOpenScriptsFolderClick(Sender: TObject);
begin
OpenDocument(Self.ScriptDir);
end;
procedure TSimbaForm.MenuItemReportBugClick(Sender: TObject);
begin
OpenURL('http://bugs.villavu.com/mantis/bug_report_page.php');
end;
procedure TSimbaForm.MenuItemSettingsButtonClick(Sender: TObject);
begin
SettingsForm.ShowModal;
end;
procedure TSimbaForm.MenuItemShowClick(Sender: TObject);
begin
Self.Show;
Self.WindowState := wsNormal;
end;
procedure TSimbaForm.MenuItemTabCloseClick(Sender: TObject);
begin
DeleteTab(PopupTab,false);
end;
procedure TSimbaForm.MenuItemTabCloseOthersClick(Sender: TObject);
begin
CloseTabs(PopupTab);
end;
procedure TSimbaForm.MenuItemReadOnlyTabClick(Sender: TObject);
var
Tab: TMufasaTab;
begin
Tab := TMufasaTab(Tabs[PopupTab]);
Tab.ScriptFrame.SetReadOnly(not Tab.ScriptFrame.GetReadOnly());
MenuItemReadOnlyTab.Checked := not Tab.ScriptFrame.GetReadOnly();
end;
procedure TSimbaForm.MenuItemFunctionListClick(Sender: TObject);
begin
FunctionListShown(not MenuItemFunctionList.Checked);
end;
procedure TSimbaForm.MTrayIconClick(Sender: TObject);
begin
self.Show;
if Lowercase(LoadSettingDef('Settings/Tray/AlwaysVisible', 'True')) <> 'true' then
MTrayIcon.Hide;
if Self.CanFocus then
self.SetFocus;
end;
function TSimbaForm.GetSimbaNews: String;
var
t: TDownloadThread;
begin
t := TDownloadThread.Create(LoadSettingDef('Settings/News/URL', 'http://Simba.villavu.com/bin/news'),
@Result);
t.Resume;
while not t.done do
begin
Application.ProcessMessages;
Sleep(50);
end;
end;
procedure TSimbaForm.SetDefScriptPath(const AValue: string);
begin
SetSetting('Settings/SourceEditor/DefScriptPath',AValue,True);
end;
{$IFDEF USE_EXTENSIONS}
procedure TSimbaForm.SetExtPath(const AValue: string);
begin
SetSetting('Settings/Extensions/Path',AValue,true);
end;
{$ENDIF}
procedure TSimbaForm.NewsTimerTimer(Sender: TObject);
var
s: String;
News : TStringList; {Need it for correct EOL stuff}
begin
NewsTimer.Enabled:=False;
s := GetSimbaNews;
News := TStringList.Create;
News.Text:= s;
Memo1.Lines.AddStrings(News);
Memo1.Lines.add('');
News.free;
end;
procedure TSimbaForm.OnLinePSScript(Sender: TObject);
begin
{$IFDEF ProcessMessages}
Application.ProcessMessages; //Don't think that this is neccesary though
{$ENDIF}
end;
procedure TSimbaForm.ButtonPickClick(Sender: TObject);
var
c, x, y: Integer;
cobj: TColourPickerObject;
begin
if Picker.Picking then
begin
formWriteln('Error: Already picking a colour');
exit;
end;
Picker.Pick(c, x, y);
cobj := TColourPickerObject.Create(c, Classes.Point(x,y), '');
{ TODO: This should be no problem if the form is hidden? }
if lowercase(LoadSettingDef('Settings/ColourPicker/AddToHistoryOnPick', 'True')) = 'true' then
ColourHistoryForm.AddColObj(cobj, true);
if lowercase(LoadSettingDef('Settings/ColourPicker/ShowHistoryOnPick', 'True')) = 'true' then
ColourHistoryForm.Show;
FormWritelnEx('Picked colour: ' + inttostr(c) + ' at (' + inttostr(x) + ', ' + inttostr(y) + ')');
end;
procedure TSimbaForm.ButtonSelectorDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
Manager.SetTarget(Selector.Drag);
FormWritelnEx('New window: ' + IntToStr(Selector.LastPick));
end;
procedure TSimbaForm.PageControl1Change(Sender: TObject);
begin
RefreshTab();
UpdateTitle;
end;
procedure TSimbaForm.ButtonTrayClick(Sender: TObject);
begin
MTrayIcon.Show;
self.hide;
end;
procedure TSimbaForm.PageControl1Changing(Sender: TObject; var AllowChange: Boolean
);
begin
LastTab:= PageControl1.TabIndex;
end;
procedure TSimbaForm.PageControl1ContextPopup(Sender: TObject; MousePos: TPoint;
var Handled: Boolean);
begin
PopupTab := PageControl1.TabIndexAtClientPos(MousePos);
if PopupTab = -1 then
begin
mDebugLn('We couldn''t find which tab you clicked on, closing the popup');
Handled := true;
end else
begin
MenuItemReadOnlyTab.Checked := TMufasaTab(Tabs[PopupTab]).ScriptFrame.GetReadOnly();
end;
end;
procedure TSimbaForm.PageControl1DragDrop(Sender, Source: TObject; X, Y: Integer);
var
NewPos : integer;
OldPos : integer;
begin
if sender <> PageControl1 then
exit;
NewPos := PageControl1.TabIndexAtClientPos(Classes.Point(x,y));
OldPos := PageControl1.TabIndex;
if (NewPos <> OldPos) and (NewPos <> -1) then
begin;
Tabs.Move(OldPos,NewPos);
PageControl1.Pages[OldPos].PageIndex := NewPos;
end;
end;
procedure TSimbaForm.PageControl1DragOver(Sender, Source: TObject; X, Y: Integer;
State: TDragState; var Accept: Boolean);
var
Pos: Integer;
begin
Pos := PageControl1.TabIndexAtClientPos(Classes.Point(x,y));
Accept := (Pos <> PageControl1.TabIndex) and (Pos <> -1);
end;
procedure TSimbaForm.PageControl1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if(Button = mbLeft)then
begin
{$ifdef linux}
PageControl1.TabIndex := PageControl1.TabIndexAtClientPos(Point(x,y));
{$endif}
PageControl1.BeginDrag(false, 10);
end;
end;
procedure TSimbaForm.PageControl1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if(Button = mbMiddle) and (not(PageControl1.Dragging))then
if(PageControl1.TabIndexAtClientPos(Classes.Point(x,y)) <> -1)then
DeleteTab(PageControl1.TabIndexAtClientPos(Classes.Point(x,y)), False);
end;
procedure TSimbaForm.PickerPick(Sender: TObject; const Colour, colourx,
coloury: integer);
{$IFDEF USE_EXTENSIONS}
var
Args : TVariantArray;
begin
SetLength(args,3);
Args[0] := Colour;
Args[1] := Colourx;
Args[2] := Coloury;
ExtManager.HandleHook(EventHooks[SExt_OnColourPick].HookName,Args);
{$ELSE}
begin
{$ENDIF}
end;
procedure TSimbaForm.PopupItemFindClick(Sender: TObject);
begin
SearchString := CurrScript.SynEdit.SelText;
ActionFindNextExecute(ScriptPopup);
end;
function TSimbaForm.GetScriptState: TScriptState;
begin
result := CurrScript.FScriptState;
end;
function TSimbaForm.GetShowParamHintAuto: boolean;
begin
Result := LowerCase(LoadSettingDef('Settings/CodeHints/ShowAutomatically','True')) = 'true';
end;
function TSimbaForm.GetShowCodeCompletionAuto: boolean;
begin
Result := LowerCase(LoadSettingDef('Settings/CodeCompletion/ShowAutomatically','True')) = 'true';
end;
procedure TSimbaForm.SetFontPath(const AValue: String);
begin
SetSetting('Settings/Fonts/Path',AValue,true);
end;
function TSimbaForm.GetFontPath: String;
begin
Result := IncludeTrailingPathDelimiter(LoadSettingDef('Settings/Fonts/Path', ExpandFileName(MainDir+DS+'Fonts' + DS)));
end;
{$IFDEF USE_EXTENSIONS}
function TSimbaForm.GetExtPath: string;
begin
Result := IncludeTrailingPathDelimiter(LoadSettingDef('Settings/Extensions/Path', ExpandFileName(MainDir+DS+'Extensions' + DS)));
end;
{$ENDIF}
function TSimbaForm.GetHighlighter: TSynCustomHighlighter;
begin
if lowercase(LoadSettingDef('Settings/SourceEditor/LazColors','True')) = 'true' then
result := LazHighlighter
else
result := SCARHighlighter;
end;
function TSimbaForm.GetIncludePath: String;
begin
Result := IncludeTrailingPathDelimiter(LoadSettingDef('Settings/Includes/Path', ExpandFileName(MainDir+DS+'Includes' + DS)));
end;
function TSimbaForm.GetPluginPath: string;
begin
Result := IncludeTrailingPathDelimiter(LoadSettingDef('Settings/Plugins/Path', ExpandFileName(MainDir+DS+'Plugins' + DS)));
end;
procedure TSimbaForm.SetIncludePath(const AValue: String);
begin
SetSetting('Settings/Includes/Path',AValue,true);
end;
procedure TSimbaForm.SetInterpreter(const AValue: Integer);
var
UpdateCurrScript: Boolean;
begin
UpdateCurrScript := false;
if (CurrScript <> nil) then
with CurrScript.Synedit do
if (Lines.text = DefaultScript) and not(CanUndo or CanRedo) then
UpdateCurrScript := true;
SetSetting('Settings/Interpreter/Type',Inttostr(AValue),true);
UpdateInterpreter;
if UpdateCurrScript then
CurrScript.SynEdit.Lines.text := DefaultScript;
end;
procedure TSimbaForm.SetPluginPath(const AValue: string);
begin
SetSetting('Settings/Plugins/Path',AValue,true);
end;
procedure TSimbaForm.SetScriptPath(const AValue: string);
begin
SetSetting('Settings/Scripts/Path',AValue,True);
end;
procedure TSimbaForm.SetScriptState(const State: TScriptState);
begin
CurrScript.FScriptState:= State;
with Self.StatusBar.panels[Panel_State] do
case state of
ss_Running : begin Text := 'Running'; TB_Run.Enabled:= False; {$ifdef MSWindows}TB_Pause.Enabled:= True; {$endif}
TB_Stop.ImageIndex := Image_Stop; TB_Stop.Enabled:= True;
TrayPlay.Checked := True; TrayPlay.Enabled := False; {$ifdef MSWindows}TrayPause.Checked := false; TrayPause.Enabled := True;{$endif}
TrayStop.Enabled:= True; TrayStop.Checked:= False;
end;
ss_Paused : begin Text := 'Paused'; TB_Run.Enabled:= True; {$ifdef MSWindows}TB_Pause.Enabled:= True; {$endif}
TB_Stop.ImageIndex := Image_Stop; TB_Stop.Enabled:= True;
TrayPlay.Checked := false; TrayPlay.Enabled := True; {$ifdef MSWindows}TrayPause.Checked := True; TrayPause.Enabled := True;{$endif}
TrayStop.Enabled:= True; TrayStop.Checked:= False;
end;
ss_Stopping: begin Text := 'Stopping';TB_Run.Enabled:= False; TB_Pause.Enabled:= False; TB_Stop.Enabled:= True;
TB_Stop.ImageIndex := Image_Terminate;
TrayPlay.Checked := False; TrayPlay.Enabled := False; {$ifdef MSWindows}TrayPause.Checked := false; TrayPause.Enabled := False;{$endif}
TrayStop.Enabled:= True; TrayStop.Checked:= True;
end;
ss_None : begin Text := 'Done'; TB_Run.Enabled:= True; TB_Pause.Enabled:= False; TB_Stop.Enabled:= False;
TB_Stop.ImageIndex := Image_Stop;
TrayPlay.Checked := false; TrayPlay.Enabled := True; {$ifdef MSWindows}TrayPause.Checked := false; TrayPause.Enabled := False;{$endif}
TrayStop.Enabled:= false; TrayStop.Checked:= False;
end;
end;
end;
function TSimbaForm.LoadSettingDef(const Key,Def: string): string;
begin
result := SettingsForm.Settings.GetKeyValueDefLoad(Key,def,SimbaSettingsFile);
end;
function TSimbaForm.CreateSetting(const Key,Value: string): string;
begin
result := SettingsForm.Settings.GetKeyValueDef(Key,value);
end;
procedure TSimbaForm.SetSetting(const key,Value: string; save : boolean);
begin
//Creates the setting if needed
SettingsForm.Settings.SetKeyValue(key,value);
if save then
SettingsForm.Settings.SaveToXML(SimbaSettingsFile);
end;
function TSimbaForm.SettingExists(const key: string): boolean;
begin
result :=SettingsForm.Settings.KeyExists(key);
end;
procedure TSimbaForm.FontUpdate;
procedure Idler;
begin
Application.ProcessMessages;
Sleep(25);
end;
var
CurrVersion : integer;
LatestVersion : integer;
FontDownload : TDownloadThread;
Stream : TStringStream;
UnTarrer : TUntarThread;
Fonts : string;
Decompress : TDecompressThread;
begin
if UpdatingFonts then
exit;
UpdatingFonts := True;
CurrVersion := StrToIntDef(LoadSettingDef('Settings/Fonts/Version','-1'),-1);
LatestVersion := SimbaUpdateForm.GetLatestFontVersion;
if LatestVersion > CurrVersion then
begin;
formWriteln(format('New fonts available. Current version: %d. Latest version: %d',[CurrVersion,LatestVersion]));
FontDownload := TDownloadThread.Create(LoadSettingDef('Settings/Fonts/UpdateLink',FontURL + 'Fonts.tar.bz2'),
@Fonts);
FontDownload.resume;
while FontDownload.Done = false do
Idler;
//Fontdownload is freed now
Stream := TStringStream.Create(Fonts);
try
Decompress := TDecompressThread.Create(Stream);
Decompress.Resume;
while Decompress.Finished = false do
Idler;
if Decompress.Result <> nil then
begin;
UnTarrer := TUntarThread.Create(Decompress.Result,FontPath,True);
UnTarrer.Resume;
while UnTarrer.Finished = false do
Idler;
if UnTarrer.Result then
begin;
FormWriteln('Succesfully installed the new fonts!');
SetSetting('Settings/Fonts/Version',IntToStr(LatestVersion),true);
if Assigned(self.OCR_Fonts) then
self.OCR_Fonts.Free;
FormWriteln('Freeing the current fonts. Creating new ones now');
Self.OCR_Fonts := TMOCR.Create(nil);
OCR_Fonts.InitTOCR(fontPath);
end;
UnTarrer.Free;
Decompress.Result.Free;
end;
Decompress.free;
finally
Stream.Free;
end;
end;
UpdatingFonts := False;
end;
procedure TSimbaForm.ScriptStartEvent(Sender: TObject; var Script: string;
var Continue: boolean);
begin
ScriptStartData.Sender:=Sender;
ScriptStartData.Script:= @Script;
ScriptStartData.Continue:= @Continue;
TThread.Synchronize(nil,@HandleScriptStartData);
end;
procedure TSimbaForm.SetShowParamHintAuto(const AValue: boolean);
begin
SetSetting('Settings/CodeHints/ShowAutomatically', Booltostr(AValue,true));
end;
procedure TSimbaForm.SetShowCodeCompletionAuto(const AValue: boolean);
begin
SetSetting('Settings/CodeCompletion/ShowAutomatically', Booltostr(AValue,true));
end;
{$ifdef mswindows}
function GetConsoleWindow: HWND; stdcall; external kernel32 name 'GetConsoleWindow';
procedure TSimbaForm.ShowConsole(ShowIt: boolean);
var
ProcessId : DWOrd;
begin
if ShowIt = ConsoleVisible then
Exit;
//Check if the console is ours (if it's not, do not hide it!!
GetWindowThreadProcessId(GetConsoleWindow,ProcessId);
if ProcessId = GetCurrentProcessId then
begin
if showit then
ShowWindow(GetConsoleWindow,SW_SHOWNA)
else
ShowWindow(GetConsoleWindow,sw_hide);
ConsoleVisible:= ShowIt;
end else
Writeln('You cannot hide the window, since its not created by Simba');
end;
{$endif}
procedure TSimbaForm.FormCallBack;
begin
with FormCallBackData do
case Cmd of
m_Status: StatusBar.Panels[Panel_General].Text:= PChar(data);
m_Disguise: begin Self.Caption:= Pchar(Data); Application.Title:= PChar(Data); end;
m_DisplayDebugImgWindow: DebugImgForm.ShowDebugImgForm(ppoint(data)^);
m_DrawBitmapDebugImg: DebugImgForm.DrawBitmap(TMufasaBitmap(data));
m_GetDebugBitmap : DebugImgForm.GetDebugImage(TMufasaBitmap(data));
m_ClearDebugImg : DebugImgForm.BlackDebugImage;
m_ClearDebug : Self.memo1.clear;
m_InputQuery : with PInputQueryData(data)^ do Res := InputQuery(ACaption,APrompt,Value);
m_ShowMessage : ShowMessage(PChar(data));
m_MessageBox : with PMessageBoxData(data)^ do res := Application.MessageBox(AText,ACaption,AFlags);
m_MessageDlg : with PMessageDlgData(data)^ do res := MessageDlg(ACaption,AMsg,ADlgType,AButtons,0);
end;
end;
procedure TSimbaForm.FunctionListShown(ShowIt: boolean);
begin
with MenuItemFunctionList, frmFunctionList do
begin
Checked := ShowIt;
if(Checked)then
begin
if FunctionList.Items.Count = 0 then
MenuitemFillFunctionListClick(nil);
FrameEndDock(frmFunctionList,frmFunctionList.Parent,0,0);//Set the label correctly
if(frmFunctionList.Parent is TPanel)then
begin
SplitterFunctionList.Show;
frmFunctionList.Show;
end else frmFunctionList.Parent.Show;
if Self.Visible then
if editSearchList.CanFocus then
editSearchList.SetFocus;
//Lets load up this Script tree!
if CurrScript <> nil then
frmFunctionList.LoadScriptTree(CurrScript.SynEdit.text);
end else begin
if(frmFunctionList.Parent is TPanel)then
frmFunctionList.Hide
else
frmFunctionList.Parent.Hide;
SplitterFunctionList.Hide;
end;
end;
end;
procedure TSimbaForm.SafeCallThread;
var
thread: TMThread;
LocalCopy : TSyncInfo;
begin
LocalCopy := CurrentSyncInfo;
mDebugLn('Executing : ' + LocalCopy.MethodName);
thread:= TMThread(LocalCopy.OldThread);
mmlpsthread.CurrThread:= thread;
try
if thread is TPSThread then
begin
with TPSThread(thread).PSScript do
begin
OnLine:=@OnLinePSScript;
LocalCopy.Res^:= Exec.RunProcPVar(LocalCopy.V^,Exec.GetProc(LocalCopy.MethodName));
Online := nil;
end;
end else
begin
raise Exception.Create('ThreadSafeCall not implemented on this client');
end;
finally
mmlpsthread.CurrThread:= nil;
end;
end;
procedure TSimbaForm.UpdateTitle;
begin
Application.Title:= PChar('Simba'); // XXX - Sure you want to do this for Disguise?
if CurrScript.ScriptChanged then
begin;
CurrTab.TabSheet.Caption:= CurrScript.ScriptName + '*';
Self.Caption := Format(WindowTitle,[CurrScript.ScriptName + '*']);
ActionSaveScript.Enabled:= True;
end else
begin;
ActionSaveScript.Enabled:= False;
CurrTab.TabSheet.Caption:= CurrScript.ScriptName;
Self.Caption := Format(WindowTitle,[CurrScript.ScriptName]);
end;
StatusBar.Panels[Panel_ScriptName].Text:= CurrScript.ScriptName;
StatusBar.Panels[Panel_ScriptPath].text:= CurrScript.ScriptFile;
end;
function TSimbaForm.OpenScript: boolean;
var
i: Integer;
OpenInNewTab : boolean;
begin
Result := False;
OpenInNewTab:= (LowerCase(LoadSettingDef('Settings/Tabs/OpenScriptInNewTab','True')) = 'true');
if not OpenInNewTab then
if CanExitOrOpen = false then
Exit;
with TOpenDialog.Create(nil) do
try
if (CurrScript.ScriptFile <> '') then
InitialDir := ExtractFileDir(CurrScript.ScriptFile)
else
InitialDir := ScriptDir;
Options := [ofAllowMultiSelect, ofExtensionDifferent, ofPathMustExist, ofFileMustExist, ofEnableSizing, ofViewDetail];
Filter:= 'Simba Files|*.simba;*.simb;*.cogat;*.mufa;*.txt' +
{$IFDEF USE_EXTENSIONS}';*.' + LoadSettingDef('Settings/Extensions/FileExtension', 'sex') + {$ENDIF}
'|Any files|*.*';
if Execute then
begin
Result := True;
for i := 0 to Files.Count - 1 do
if (not FileExistsUTF8(Files[i])) or (not LoadScriptFile(Files[i])) then
begin
Result := False;
Break;
end;
end;
finally
Free;
end;
if result then
UpdateTitle;
end;
function TSimbaForm.LoadScriptFile(filename: string; AlwaysOpenInNewTab: boolean; CheckOtherTabs : boolean
): boolean;
var
OpenInNewTab : boolean;
CheckTabsFirst : boolean;
Tab : integer;
begin
if AlwaysOpenInNewTab then
OpenInNewTab := true
else
OpenInNewTab:= (LowerCase(LoadSettingDef('Settings/Tabs/OpenScriptInNewTab','True')) = 'true');
if CheckOtherTabs then
CheckTabsFirst := True
else
CheckTabsFirst := (Lowercase(LoadSettingDef('Settings/Tabs/CheckTabsBeforeOpen','True')) = 'true');
if FileExistsUTF8(FileName) then
begin;
if CheckTabsFirst then
begin;
Tab := FindTab(filename);
if tab <> -1 then
begin
TMufasaTab(Tabs[tab]).ScriptFrame.MakeActiveScriptFrame;
exit(true);
end;
end;
if OpenInNewTab and (CurrScript.SynEdit.Text <> CurrScript.ScriptDefault) then //Add la tab!
self.addtab;
with CurrScript do
begin
filename := SetDirSeparators(filename);
SynEdit.Lines.LoadFromFile(filename);
StartText := SynEdit.Lines.text;
ScriptName:= ExtractFileNameOnly(filename);
mDebugLn('Script name will be: ' + ScriptName);
ScriptFile:= FileName;
ScriptChanged := false;
AddRecentFile(filename);
RefreshTab();
Result := True;
end;
end;
if Result then
UpdateTitle;
end;
function TSimbaForm.SaveCurrentScript: boolean;
begin
if CurrScript.GetReadOnly() then
begin
formWriteln('Script is in read-only/external editor mode. Not saving!');
exit(false);
end;
if not CurrScript.ScriptChanged then
begin
writeln('SaveScript - no changes.');
exit(false);
end;
with CurrScript do
begin
Result := (ScriptFile <> '');
if Result then
begin
try
SynEdit.Lines.SaveToFile(ScriptFile);
except
mDebugLn('Cannot save the file. Try specifying a different location.');
result := SaveCurrentScriptAs;
exit;
end;
OnSaveScript(scriptfile);
end
else
result := SaveCurrentScriptAs;
end;
end;
function TSimbaForm.SaveCurrentScriptAs: boolean;
var
ScriptFile : string;
begin
Result := false;
with TSaveDialog.Create(nil) do
try
if (CurrScript.ScriptFile <> '') then
InitialDir := ExtractFileDir(CurrScript.ScriptFile)
else
InitialDir := ScriptDir;
filter := 'Simba Files|*.simba;*.simb;*.cogat;*.mufa;*.txt' +
{$IFDEF USE_EXTENSIONS}';*.' + LoadSettingDef('Settings/Extensions/FileExtension','sex') + {$ENDIF}
'|Any files|*.*';
if Execute then
begin;
if ExtractFileExt(FileName) = '' then
begin;
ScriptFile := FileName + '.simba';
end else
ScriptFile := FileName;
CurrScript.SynEdit.Lines.SaveToFile(ScriptFile);
OnSaveScript(scriptfile);
end;
finally
free;
end;
end;
function TSimbaForm.SaveCurrentScriptAsDefault : boolean;
begin
with CurrScript do
begin
try
SynEdit.Lines.SaveToFile(DefScriptPath);
mDebugLn('Script saved as default.');
Result := True;
except
mDebugLn('Cannot save script as default.');
Result := False;
end;
end;
end;
function TSimbaForm.CanExitOrOpen: boolean;
begin;
Self.Enabled := False;//We HAVE to answer the popup
Result := True;
if ScriptState <> ss_None then
begin
if ScriptState <> ss_Stopping then
begin
result := False;
case MessageDlg('Script is still running', 'Do you want to stop the script?',
mtConfirmation, mbYesNoCancel, 0) of
mrYes: StopScript;
end;
end else
case MessageDlg('Script is stopping.', 'Do you want to terminate the script?',
mtConfirmation, mbYesNoCancel, 0) of
mrNo, mrCancel: Result := false;
mrYes: StopScript;
end;
end;
if Result and (CurrScript.StartText <> CurrScript.SynEdit.Lines.text) then
begin
case MessageDlg('Script has been modified.', 'Do you want to save the script?',
mtConfirmation, mbYesNoCancel, 0) of
mrCancel : Result := False;
mrYes : Result := SaveCurrentScript;
end;
end;
Self.Enabled := True;
if Self.CanFocus then
Self.SetFocus;
end;
function TSimbaForm.ClearScript: boolean;
begin
result := false;
if CanExitOrOpen then
begin;
result := true;
CurrTab.Clear;
RefreshTab();
end;
end;
{ TMufasaTab }
procedure TMufasaTab.Clear;
begin
ScriptFrame.Free;
ScriptFrame := TScriptFrame.Create(Tabsheet);
ScriptFrame.Parent := Tabsheet;
ScriptFrame.Align:= alClient;
end;
constructor TMufasaTab.Create(Page: TPageControl);
begin
inherited Create;
PageCtrl := Page;
Tabsheet := TTabSheet.Create(Page);
Tabsheet.PageControl := Page;
ScriptFrame := TScriptFrame.Create(Tabsheet);
ScriptFrame.Parent := Tabsheet;
ScriptFrame.Align := alClient;
end;
destructor TMufasaTab.Destroy;
begin
// ScriptFrame.Free;
TabSheet.Free;
inherited Destroy;
end;
initialization
{$R *.lfm}
end.