using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.IO; using System.Windows.Forms; using DSPRE.Resources; using DSPRE.ROMFiles; using ScintillaNET; using ScintillaNET.Utils; using System.Globalization; namespace DSPRE.Editors { public partial class ScriptEditor : UserControl { public bool scriptEditorIsReady { get; set; } = false; private Scintilla ScriptTextArea; private Scintilla FunctionTextArea; private Scintilla ActionTextArea; private SearchManager scriptSearchManager; private SearchManager functionSearchManager; private SearchManager actionSearchManager; private Scintilla currentScintillaEditor; private SearchManager currentSearchManager; private bool scriptsDirty = false; private bool functionsDirty = false; private bool actionsDirty = false; private string cmdKeyWords = ""; private string secondaryKeyWords = ""; private ScriptFile currentScriptFile; MainProgram _parent; /// /// the background color of the text area /// private readonly Color BACK_COLOR = Color.FromArgb(0x2A211C); /// /// default text color of the text area /// private readonly Color FORE_COLOR = Color.FromArgb(0xB7B7B7); /// /// change this to whatever margin you want the line numbers to show in /// private const int NUMBER_MARGIN = 1; /// /// change this to whatever margin you want the bookmarks/breakpoints to show in /// private const int BOOKMARK_MARGIN = 2; private const int BOOKMARK_MARKER = 2; /// /// change this to whatever margin you want the code folding tree (+/-) to show in /// private const int FOLDING_MARGIN = 3; /// /// set this true to show circular buttons for code folding (the [+] and [-] buttons on the margin) /// private const bool CODE_FOLDING_CIRCULAR = true; readonly Point initial_importScriptFileButton_location; readonly Point initial_exportScriptFileButton_location; readonly Point initial_addScriptFileButton_location; readonly Point initial_removeScriptFileButton_location; readonly Point initial_viewLevelScript_location; readonly Point new_importScriptFileButton_location; readonly Point new_exportScriptFileButton_location; readonly Point new_addScriptFileButton_location; readonly Point new_removeScriptFileButton_location; readonly Point new_viewLevelScript_location; public ScriptEditor() { InitializeComponent(); //initially, these buttons are off the canvas so they can be interacted with in the designer //they are then moved as needed initial_importScriptFileButton_location = importScriptFileButton.Location; initial_exportScriptFileButton_location = exportScriptFileButton.Location; initial_addScriptFileButton_location = addScriptFileButton.Location; initial_removeScriptFileButton_location = removeScriptFileButton.Location; initial_viewLevelScript_location = viewLevelScriptButton.Location; new_importScriptFileButton_location = new Point(164, 22); new_exportScriptFileButton_location = new Point(239, 22); new_addScriptFileButton_location = new Point(314, 22); new_removeScriptFileButton_location = new Point(314, 49); new_viewLevelScript_location = new Point(326, 37); importScriptFileButton.Enabled = false; exportScriptFileButton.Enabled = false; addScriptFileButton.Enabled = false; removeScriptFileButton.Enabled = false; viewLevelScriptButton.Enabled = false; } public void SetupScriptEditor(MainProgram parent, bool force = false) { if (scriptEditorIsReady && !force) { return; } scriptEditorIsReady = true; this._parent = parent; ScriptDatabase.InitializePokemonNames(); ScriptDatabase.InitializeItemNames(); ScriptDatabase.InitializeMoveNames(); ScriptDatabase.InitializeTrainerNames(); SetupScriptEditorTextAreas(); /* Extract essential NARCs sub-archives*/ Helpers.statusLabelMessage("Setting up Script Editor..."); Update(); DSUtils.TryUnpackNarcs(new List { RomInfo.DirNames.scripts }); //12 = scripts Narc Dir populate_selectScriptFileComboBox(0); UpdateScriptNumberCheckBox((NumberStyles)SettingsManager.Settings.scriptEditorFormatPreference); Helpers.statusLabelMessage(); } public void OpenScriptEditor(MainProgram parent, int scriptFileID) { SetupScriptEditor(parent); scriptEditorTabControl.SelectedIndex = 0; selectScriptFileComboBox.SelectedIndex = scriptFileID; EditorPanels.mainTabControl.SelectedTab = EditorPanels.scriptEditorTabPage; } private void SetupScriptEditorTextAreas() { //PREPARE SCRIPT EDITOR KEYWORDS cmdKeyWords = String.Join(" ", RomInfo.ScriptCommandNamesDict.Values) + " " + String.Join(" ", ScriptDatabase.movementsDictIDName.Values); cmdKeyWords += " " + cmdKeyWords.ToUpper() + " " + cmdKeyWords.ToLower(); secondaryKeyWords = String.Join(" ", RomInfo.ScriptComparisonOperatorsDict.Values) + " " + String.Join(" ", ScriptDatabase.specialOverworlds.Values) + " " + String.Join(" ", ScriptDatabase.overworldDirections.Values) + " " + String.Join(" ", ScriptDatabase.pokemonNames.Values) + " " + String.Join(" ", ScriptDatabase.itemNames.Values) + " " + String.Join(" ", ScriptDatabase.moveNames.Values) + " " + String.Join(" ", ScriptDatabase.soundNames.Values) + " " + String.Join(" ", ScriptDatabase.trainerNames.Values) + " " + ScriptFile.ContainerTypes.Script.ToString() + " " + ScriptFile.ContainerTypes.Function.ToString() + " " + ScriptFile.ContainerTypes.Action.ToString() + " " + Event.EventType.Overworld + " " + Overworld.MovementCodeKW; secondaryKeyWords += " " + secondaryKeyWords.ToUpper() + " " + secondaryKeyWords.ToLower(); // CREATE CONTROLS ScriptTextArea = new Scintilla(); scriptSearchManager = new SearchManager(EditorPanels.MainProgram, ScriptTextArea, panelFindScriptTextBox, PanelSearchScripts); scintillaScriptsPanel.Controls.Clear(); scintillaScriptsPanel.Controls.Add(ScriptTextArea); FunctionTextArea = new Scintilla(); functionSearchManager = new SearchManager(EditorPanels.MainProgram, FunctionTextArea, panelFindFunctionTextBox, PanelSearchFunctions); scintillaFunctionsPanel.Controls.Clear(); scintillaFunctionsPanel.Controls.Add(FunctionTextArea); ActionTextArea = new Scintilla(); actionSearchManager = new SearchManager(EditorPanels.MainProgram, ActionTextArea, panelFindActionTextBox, PanelSearchActions); scintillaActionsPanel.Controls.Clear(); scintillaActionsPanel.Controls.Add(ActionTextArea); currentScintillaEditor = ScriptTextArea; currentSearchManager = scriptSearchManager; // BASIC CONFIG ScriptTextArea.TextChanged += (OnTextChangedScript); FunctionTextArea.TextChanged += (OnTextChangedFunction); ActionTextArea.TextChanged += (OnTextChangedAction); // INITIAL VIEW CONFIG InitialViewConfig(ScriptTextArea); InitialViewConfig(FunctionTextArea); InitialViewConfig(ActionTextArea); InitSyntaxColoring(ScriptTextArea); InitSyntaxColoring(FunctionTextArea); InitSyntaxColoring(ActionTextArea); // NUMBER MARGIN InitNumberMargin(ScriptTextArea, ScriptTextArea_MarginClick); InitNumberMargin(FunctionTextArea, FunctionTextArea_MarginClick); InitNumberMargin(ActionTextArea, ActionTextArea_MarginClick); // BOOKMARK MARGIN InitBookmarkMargin(ScriptTextArea); InitBookmarkMargin(FunctionTextArea); InitBookmarkMargin(ActionTextArea); // CODE FOLDING MARGIN InitCodeFolding(ScriptTextArea); InitCodeFolding(FunctionTextArea); InitCodeFolding(ActionTextArea); // INIT HOTKEYS InitHotkeys(ScriptTextArea, scriptSearchManager); InitHotkeys(FunctionTextArea, functionSearchManager); InitHotkeys(ActionTextArea, actionSearchManager); // INIT TOOLTIPS DWELLING /* ScriptTextArea.MouseDwellTime = 300; ScriptTextArea.DwellEnd += TextArea_DwellEnd; ScriptTextArea.DwellStart += TextArea_DwellStart; FunctionTextArea.MouseDwellTime = 300; FunctionTextArea.DwellEnd += TextArea_DwellEnd; FunctionTextArea.DwellStart += TextArea_DwellStart; */ } private void populate_selectScriptFileComboBox(int selectedIndex = 0) { selectScriptFileComboBox.Items.Clear(); int scriptCount = Filesystem.GetScriptCount(); for (int i = 0; i < scriptCount; i++) { // ScriptFile currentScriptFile = new ScriptFile(i, true, true); // selectScriptFileComboBox.Items.Add(currentScriptFile); selectScriptFileComboBox.Items.Add($"Script File {i}"); } selectScriptFileComboBox.SelectedIndex = selectedIndex; } private void InitialViewConfig(Scintilla textArea) { textArea.Dock = DockStyle.Fill; textArea.WrapMode = WrapMode.Word; textArea.IndentationGuides = IndentView.LookBoth; textArea.CaretPeriod = 500; textArea.CaretForeColor = Color.White; textArea.SetSelectionBackColor(true, Color.FromArgb(0x114D9C)); textArea.WrapIndentMode = WrapIndentMode.Same; } private void InitSyntaxColoring(Scintilla textArea) { // Configure the default style textArea.StyleResetDefault(); textArea.Styles[Style.Default].Font = "Consolas"; textArea.Styles[Style.Default].Size = 12; textArea.Styles[Style.Default].BackColor = Color.FromArgb(0x212121); textArea.Styles[Style.Default].ForeColor = Color.FromArgb(0xFFFFFF); textArea.StyleClearAll(); // Configure the lexer styles textArea.Styles[Style.Python.Identifier].ForeColor = Color.FromArgb(0xD0DAE2); textArea.Styles[Style.Python.CommentLine].ForeColor = Color.FromArgb(0x40BF57); textArea.Styles[Style.Python.Number].ForeColor = Color.FromArgb(0xFFFF00); textArea.Styles[Style.Python.String].ForeColor = Color.FromArgb(0xFF00FF); textArea.Styles[Style.Python.Character].ForeColor = Color.FromArgb(0xE95454); textArea.Styles[Style.Python.Operator].ForeColor = Color.FromArgb(0xFFFF00); textArea.Styles[Style.Python.Word].ForeColor = Color.FromArgb(0x48A8EE); textArea.Styles[Style.Python.Word2].ForeColor = Color.FromArgb(0xF98906); textArea.Lexer = Lexer.Python; textArea.SetKeywords(0, cmdKeyWords); textArea.SetKeywords(1, secondaryKeyWords); } private void InitNumberMargin(Scintilla textArea, EventHandler textArea_MarginClick) { textArea.Styles[Style.LineNumber].BackColor = BACK_COLOR; textArea.Styles[Style.LineNumber].ForeColor = FORE_COLOR; textArea.Styles[Style.IndentGuide].ForeColor = FORE_COLOR; textArea.Styles[Style.IndentGuide].BackColor = BACK_COLOR; Margin nums = textArea.Margins[NUMBER_MARGIN]; nums.Type = MarginType.Number; nums.Sensitive = true; nums.Mask = 0; textArea.MarginClick += textArea_MarginClick; } private void InitBookmarkMargin(Scintilla textArea) { //TextArea.SetFoldMarginColor(true, IntToColor(BACK_COLOR)); Margin margin = textArea.Margins[BOOKMARK_MARGIN]; margin.Width = 20; margin.Sensitive = true; margin.Type = MarginType.Symbol; margin.Mask = (1 << BOOKMARK_MARKER); //margin.Cursor = MarginCursor.Arrow; Marker marker = textArea.Markers[BOOKMARK_MARKER]; marker.Symbol = MarkerSymbol.Circle; marker.SetBackColor(Color.FromArgb(0xFF003B)); marker.SetForeColor(Color.FromArgb(0x000000)); marker.SetAlpha(100); } private void InitCodeFolding(Scintilla textArea) { textArea.SetFoldMarginColor(true, BACK_COLOR); textArea.SetFoldMarginHighlightColor(true, BACK_COLOR); // Enable code folding textArea.SetProperty("fold", "1"); textArea.SetProperty("fold.compact", "1"); // Configure a margin to display folding symbols textArea.Margins[FOLDING_MARGIN].Type = MarginType.Symbol; textArea.Margins[FOLDING_MARGIN].Mask = Marker.MaskFolders; textArea.Margins[FOLDING_MARGIN].Sensitive = true; textArea.Margins[FOLDING_MARGIN].Width = 20; // Set colors for all folding markers for (int i = 25; i <= 31; i++) { textArea.Markers[i].SetForeColor(BACK_COLOR); // styles for [+] and [-] textArea.Markers[i].SetBackColor(FORE_COLOR); // styles for [+] and [-] } // Configure folding markers with respective symbols textArea.Markers[Marker.Folder].Symbol = CODE_FOLDING_CIRCULAR ? MarkerSymbol.CirclePlus : MarkerSymbol.BoxPlus; textArea.Markers[Marker.FolderOpen].Symbol = CODE_FOLDING_CIRCULAR ? MarkerSymbol.CircleMinus : MarkerSymbol.BoxMinus; textArea.Markers[Marker.FolderEnd].Symbol = CODE_FOLDING_CIRCULAR ? MarkerSymbol.CirclePlusConnected : MarkerSymbol.BoxPlusConnected; textArea.Markers[Marker.FolderMidTail].Symbol = MarkerSymbol.TCorner; textArea.Markers[Marker.FolderOpenMid].Symbol = CODE_FOLDING_CIRCULAR ? MarkerSymbol.CircleMinusConnected : MarkerSymbol.BoxMinusConnected; textArea.Markers[Marker.FolderSub].Symbol = MarkerSymbol.VLine; textArea.Markers[Marker.FolderTail].Symbol = MarkerSymbol.LCorner; // Enable automatic folding textArea.AutomaticFold = (AutomaticFold.Show | AutomaticFold.Click | AutomaticFold.Change); } private void InitHotkeys(Scintilla scintillaTb, SearchManager sm) { // register the hotkeys with the form HotKeyManager.AddHotKey(scintillaTb, sm.OpenSearch, Keys.F, true); HotKeyManager.AddHotKey(scintillaTb, () => Uppercase(scintillaTb), Keys.U, true); HotKeyManager.AddHotKey(scintillaTb, () => Lowercase(scintillaTb), Keys.L, true); HotKeyManager.AddHotKey(scintillaTb, () => ZoomIn(scintillaTb), Keys.Oemplus, true); HotKeyManager.AddHotKey(scintillaTb, () => ZoomOut(scintillaTb), Keys.OemMinus, true); HotKeyManager.AddHotKey(scintillaTb, () => ZoomDefault(scintillaTb), Keys.D0, true); HotKeyManager.AddHotKey(scintillaTb, sm.CloseSearch, Keys.Escape); // remove conflicting hotkeys from scintilla scintillaTb.ClearCmdKey(Keys.Control | Keys.F); scintillaTb.ClearCmdKey(Keys.Control | Keys.R); scintillaTb.ClearCmdKey(Keys.Control | Keys.H); scintillaTb.ClearCmdKey(Keys.Control | Keys.L); scintillaTb.ClearCmdKey(Keys.Control | Keys.U); } private void Uppercase(Scintilla textArea) { // save the selection int start = textArea.SelectionStart; int end = textArea.SelectionEnd; // modify the selected text textArea.ReplaceSelection(textArea.GetTextRange(start, end - start).ToUpper()); // preserve the original selection textArea.SetSelection(start, end); } private void Lowercase(Scintilla textArea) { // save the selection int start = textArea.SelectionStart; int end = textArea.SelectionEnd; // modify the selected text textArea.ReplaceSelection(textArea.GetTextRange(start, end - start).ToLower()); // preserve the original selection textArea.SetSelection(start, end); } private void ZoomIn(Scintilla textArea) { textArea.ZoomIn(); } private void ZoomOut(Scintilla textArea) { textArea.ZoomOut(); } private void ZoomDefault(Scintilla textArea) { textArea.Zoom = 0; } private void ScriptEditorSetClean() { Helpers.DisableHandlers(); scriptsTabPage.Text = ScriptFile.ContainerTypes.Script.ToString() + "s"; functionsTabPage.Text = ScriptFile.ContainerTypes.Function.ToString() + "s"; actionsTabPage.Text = ScriptFile.ContainerTypes.Action.ToString() + "s"; scriptsDirty = functionsDirty = actionsDirty = false; Helpers.EnableHandlers(); } private void OnTextChangedScript(object sender, EventArgs e) { ScriptTextArea.Margins[NUMBER_MARGIN].Width = ScriptTextArea.Lines.Count.ToString().Length * 13; scriptsDirty = true; scriptsTabPage.Text = ScriptFile.ContainerTypes.Script.ToString() + "s" + "*"; } private void OnTextChangedFunction(object sender, EventArgs e) { FunctionTextArea.Margins[NUMBER_MARGIN].Width = FunctionTextArea.Lines.Count.ToString().Length * 13; functionsDirty = true; functionsTabPage.Text = ScriptFile.ContainerTypes.Function.ToString() + "s" + "*"; } private void OnTextChangedAction(object sender, EventArgs e) { ActionTextArea.Margins[NUMBER_MARGIN].Width = ActionTextArea.Lines.Count.ToString().Length * 13; actionsDirty = true; actionsTabPage.Text = ScriptFile.ContainerTypes.Action.ToString() + "s" + "*"; } private void ScriptTextArea_MarginClick(object sender, MarginClickEventArgs e) { MarginClick(ScriptTextArea, e); } private void FunctionTextArea_MarginClick(object sender, MarginClickEventArgs e) { MarginClick(FunctionTextArea, e); } private void ActionTextArea_MarginClick(object sender, MarginClickEventArgs e) { MarginClick(ActionTextArea, e); } private void MarginClick(Scintilla textArea, MarginClickEventArgs e) { if (e.Margin == BOOKMARK_MARGIN) { // Do we have a marker for this line? const uint mask = (1 << BOOKMARK_MARKER); Line line = textArea.Lines[textArea.LineFromPosition(e.Position)]; if ((line.MarkerGet() & mask) > 0) { // Remove existing bookmark line.MarkerDelete(BOOKMARK_MARKER); } else { // Add bookmark line.MarkerAdd(BOOKMARK_MARKER); } } } private void selectScriptFileComboBox_SelectedIndexChanged(object sender, EventArgs e) { DisplayScript(); } public void UpdateScriptNumberCheckBox(NumberStyles toSet) { Helpers.DisableHandlers(); SettingsManager.Settings.scriptEditorFormatPreference = (int)toSet; switch ((NumberStyles)SettingsManager.Settings.scriptEditorFormatPreference) { case NumberStyles.None: scriptEditorNumberFormatNoPreference.Checked = true; break; case NumberStyles.HexNumber: scriptEditorNumberFormatHex.Checked = true; break; case NumberStyles.Integer: scriptEditorNumberFormatDecimal.Checked = true; break; } Console.WriteLine("changed style to " + SettingsManager.Settings.scriptEditorFormatPreference); Helpers.EnableHandlers(); } private void UpdateScriptNumberFormat(NumberStyles numberStyle) { if (Helpers.HandlersEnabled) { NumberStyles old = (NumberStyles)SettingsManager.Settings.scriptEditorFormatPreference; //Local Backup SettingsManager.Settings.scriptEditorFormatPreference = (int)numberStyle; if (!DisplayScript()) { UpdateScriptNumberCheckBox(old); //Restore old checkbox status! Script couldn't be redrawn } } } private void UpdateScriptNumberFormatNoPref(object sender, EventArgs e) { UpdateScriptNumberFormat(NumberStyles.None); } private void UpdateScriptNumberFormatDec(object sender, EventArgs e) { UpdateScriptNumberFormat(NumberStyles.Integer); } private void UpdateScriptNumberFormatHex(object sender, EventArgs e) { UpdateScriptNumberFormat(NumberStyles.HexNumber); } private bool DisplayScript() { Console.WriteLine("Script Reload has been requested"); /* clear controls */ if (Helpers.HandlersDisabled || selectScriptFileComboBox.SelectedItem == null) { return false; } if (scriptsDirty || functionsDirty || actionsDirty) { DialogResult d = MessageBox.Show("There are unsaved changes in this Script File.\nDo you wish to discard them?", "Unsaved work", MessageBoxButtons.YesNo, MessageBoxIcon.Warning); if (!d.Equals(DialogResult.Yes)) { Helpers.DisableHandlers(); // selectScriptFileComboBox.SelectedItem = currentScriptFile; selectScriptFileComboBox.SelectedIndex = (int)currentScriptFile.fileID; Helpers.EnableHandlers(); return false; } } Helpers.DisableHandlers(); ScriptFile lastScriptFile = currentScriptFile; // currentScriptFile = (ScriptFile)selectScriptFileComboBox.SelectedItem; currentScriptFile = new ScriptFile(selectScriptFileComboBox.SelectedIndex); // Load script file ScriptTextArea.ClearAll(); FunctionTextArea.ClearAll(); ActionTextArea.ClearAll(); scriptsNavListbox.Items.Clear(); functionsNavListbox.Items.Clear(); actionsNavListbox.Items.Clear(); //prevent buttons from flickering when the combobox selection changes bool typeChanged = true; if (lastScriptFile != null) { typeChanged = lastScriptFile.isLevelScript != currentScriptFile.isLevelScript; } if (typeChanged) { if (currentScriptFile.isLevelScript) { importScriptFileButton.Location = initial_importScriptFileButton_location; exportScriptFileButton.Location = initial_exportScriptFileButton_location; addScriptFileButton.Location = initial_addScriptFileButton_location; removeScriptFileButton.Location = initial_removeScriptFileButton_location; viewLevelScriptButton.Location = new_viewLevelScript_location; importScriptFileButton.Enabled = false; exportScriptFileButton.Enabled = false; addScriptFileButton.Enabled = false; removeScriptFileButton.Enabled = false; viewLevelScriptButton.Enabled = true; } else { importScriptFileButton.Location = new_importScriptFileButton_location; exportScriptFileButton.Location = new_exportScriptFileButton_location; addScriptFileButton.Location = new_addScriptFileButton_location; removeScriptFileButton.Location = new_removeScriptFileButton_location; viewLevelScriptButton.Location = initial_viewLevelScript_location; importScriptFileButton.Enabled = true; exportScriptFileButton.Enabled = true; addScriptFileButton.Enabled = true; removeScriptFileButton.Enabled = true; viewLevelScriptButton.Enabled = false; } } if (!currentScriptFile.isLevelScript) { displayScriptFile(ScriptFile.ContainerTypes.Script, currentScriptFile.allScripts, scriptsNavListbox, ScriptTextArea); displayScriptFile(ScriptFile.ContainerTypes.Function, currentScriptFile.allFunctions, functionsNavListbox, FunctionTextArea); displayScriptFileActions(ScriptFile.ContainerTypes.Action, currentScriptFile.allActions, actionsNavListbox, ActionTextArea); } ScriptEditorSetClean(); Helpers.statusLabelMessage(); Helpers.EnableHandlers(); return true; } static void displayScriptFile(ScriptFile.ContainerTypes containerType, List commandList, ListBox navListBox, Scintilla textArea) { string buffer = ""; /* Add commands */ for (int i = 0; i < commandList.Count; i++) { ScriptCommandContainer scriptCommandContainer = commandList[i]; /* Write header */ string header = containerType + " " + (i + 1); buffer += header + ':' + Environment.NewLine; navListBox.Items.Add(header); /* If current command is identical to another, print UseScript instead of commands */ if (scriptCommandContainer.usedScriptID < 0) { for (int j = 0; j < scriptCommandContainer.commands.Count; j++) { ScriptCommand command = scriptCommandContainer.commands[j]; if (!ScriptDatabase.endCodes.Contains(command.id)) { buffer += '\t'; } buffer += command.name + Environment.NewLine; } } else { buffer += '\t' + "UseScript_#" + scriptCommandContainer.usedScriptID + Environment.NewLine; } textArea.AppendText(buffer + Environment.NewLine); buffer = ""; } } static void displayScriptFileActions(ScriptFile.ContainerTypes containerType, List commandList, ListBox navListBox, Scintilla textArea) { /* Add movements */ string buffer = ""; for (int i = 0; i < commandList.Count; i++) { ScriptActionContainer currentCommand = commandList[i]; string header = containerType + " " + (i + 1); buffer += header + ':' + Environment.NewLine; navListBox.Items.Add(header); for (int j = 0; j < currentCommand.commands.Count; j++) { ScriptAction command = currentCommand.commands[j]; if (!ScriptDatabase.movementEndCodes.Contains(command.id)) { buffer += '\t'; } buffer += command.name + Environment.NewLine; } textArea.AppendText(buffer + Environment.NewLine); buffer = ""; } } private void scriptEditorZoomInButton_Click(object sender, EventArgs e) { ZoomIn(currentScintillaEditor); } private void scriptEditorZoomOutButton_Click(object sender, EventArgs e) { ZoomOut(currentScintillaEditor); } private void scriptEditorZoomResetButton_Click(object sender, EventArgs e) { ZoomDefault(currentScintillaEditor); } private void scriptEditorTabControl_TabIndexChanged(object sender, EventArgs e) { if (scriptEditorTabControl.SelectedTab == scriptsTabPage) { currentSearchManager = scriptSearchManager; currentScintillaEditor = ScriptTextArea; } else if (scriptEditorTabControl.SelectedTab == functionsTabPage) { currentSearchManager = functionSearchManager; currentScintillaEditor = FunctionTextArea; } else { //Actions currentSearchManager = actionSearchManager; currentScintillaEditor = ActionTextArea; } } private void removeScriptFileButton_Click(object sender, EventArgs e) { DialogResult d = MessageBox.Show("Are you sure you want to delete the last Script File?", "Confirm deletion", MessageBoxButtons.YesNo, MessageBoxIcon.Warning); if (d.Equals(DialogResult.Yes)) { /* Delete script file */ string path = Filesystem.GetScriptPath(selectScriptFileComboBox.Items.Count - 1); File.Delete(path); /* Check if currently selected file is the last one, and in that case select the one before it */ int lastIndex = selectScriptFileComboBox.Items.Count - 1; if (selectScriptFileComboBox.SelectedIndex == lastIndex) { selectScriptFileComboBox.SelectedIndex--; } /* Remove item from ComboBox */ selectScriptFileComboBox.Items.RemoveAt(lastIndex); } } private void addScriptFileButton_Click(object sender, EventArgs e) { /* Add new event file to event folder */ int fileID = selectScriptFileComboBox.Items.Count; ScriptFile scriptFile = new ScriptFile( scriptLines: new Scintilla { Text = "Script 1:\nEnd" }.Lines.ToStringsList(trim: true), functionLines: null, actionLines: null, fileID ); //check if ScriptFile instance was created successfully if (scriptFile.SaveToFileDefaultDir(fileID, showSuccessMessage: false)) { /* Update ComboBox and select new file */ selectScriptFileComboBox.Items.Add(scriptFile); selectScriptFileComboBox.SelectedItem = scriptFile; } } private void saveScriptFileButton_Click(object sender, EventArgs e) { /* Create new ScriptFile object using the values in the script editor */ int fileID = currentScriptFile.fileID; ScriptFile userEdited = new ScriptFile( scriptLines: ScriptTextArea.Lines.ToStringsList(trim: true), functionLines: FunctionTextArea.Lines.ToStringsList(trim: true), actionLines: ActionTextArea.Lines.ToStringsList(trim: true), fileID ); if (userEdited.hasNoScripts) { MessageBox.Show("This " + nameof(ScriptFile) + " couldn't be saved. A minimum of one script is required.", "Can't save", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } //check if ScriptFile instance was created successfully if (userEdited.SaveToFileDefaultDir(fileID)) { currentScriptFile = userEdited; ScriptEditorSetClean(); } } private void exportScriptFileButton_Click(object sender, EventArgs e) { currentScriptFile.SaveToFileExplorePath(currentScriptFile.ToString(), blindmode: true); } private void importScriptFileButton_Click(object sender, EventArgs e) { /* Prompt user to select .scr or .bin file */ OpenFileDialog of = new OpenFileDialog { Filter = "Script File (*.scr, *.bin)|*.scr;*.bin" }; if (of.ShowDialog(this) != DialogResult.OK) { return; } /* Update scriptFile object in memory */ int i = selectScriptFileComboBox.SelectedIndex; string path = Filesystem.GetScriptPath(i); File.Copy(of.FileName, path, true); populate_selectScriptFileComboBox(i); /* Refresh controls */ selectScriptFileComboBox_SelectedIndexChanged(null, null); /* Display success message */ MessageBox.Show("Scripts imported successfully!", "", MessageBoxButtons.OK, MessageBoxIcon.Information); } private void viewLevelScriptButton_Click(object sender, EventArgs e) { EditorPanels.levelScriptEditor.OpenLevelScriptEditor(this._parent, selectScriptFileComboBox.SelectedIndex); } private void locateCurrentScriptFile_Click(object sender, EventArgs e) { string path = Filesystem.GetScriptPath(selectScriptFileComboBox.SelectedIndex); Helpers.ExplorerSelect(path); } private void findNext(SearchManager searchManager) { searchManager.Find(true, false); scrollResultToTop(searchManager); } private void findPrev(SearchManager searchManager) { searchManager.Find(false, false); scrollResultToTop(searchManager); } private void findCurrent(SearchManager searchManager) { searchManager.Find(true, true); scrollResultToTop(searchManager); } private void TxtFindKeyDown(SearchManager searchManager, KeyEventArgs e) { if (HotKeyManager.IsHotkey(e, Keys.Enter)) { findNext(searchManager); } if (HotKeyManager.IsHotkey(e, Keys.Enter, true) || HotKeyManager.IsHotkey(e, Keys.Enter, false, true)) { findPrev(searchManager); } } private void BtnNextFindScript_Click(object sender, EventArgs e) { findNext(scriptSearchManager); } private void BtnPrevFindScript_Click(object sender, EventArgs e) { findPrev(scriptSearchManager); } private void panelFindScriptTextBox_TextChanged(object sender, EventArgs e) { findCurrent(scriptSearchManager); } private void scriptTxtFind_KeyDown(object sender, KeyEventArgs e) { TxtFindKeyDown(scriptSearchManager, e); } private void BtnCloseFindScript_Click(object sender, EventArgs e) { scriptSearchManager.CloseSearch(); } private void BtnNextFindFunc_Click(object sender, EventArgs e) { findNext(functionSearchManager); } private void BtnPrevFindFunc_Click(object sender, EventArgs e) { findNext(functionSearchManager); } private void panelFindFunctionTextBox_TextChanged(object sender, EventArgs e) { findNext(functionSearchManager); } private void functionTxtFind_KeyDown(object sender, KeyEventArgs e) { TxtFindKeyDown(functionSearchManager, e); } private void BtnCloseFindFunc_Click(object sender, EventArgs e) { functionSearchManager.CloseSearch(); } private void BtnNextFindActions_Click(object sender, EventArgs e) { findNext(actionSearchManager); } private void BtnPrevFindActions_Click(object sender, EventArgs e) { findNext(actionSearchManager); } private void panelFindActionTextBox_TextChanged(object sender, EventArgs e) { findNext(actionSearchManager); } private void actionTxtFind_KeyDown(object sender, KeyEventArgs e) { TxtFindKeyDown(actionSearchManager, e); } private void BtnCloseFindActions_Click(object sender, EventArgs e) { actionSearchManager.CloseSearch(); } void scrollResultToTop(SearchManager searchManager) { int resultStart = searchManager.textAreaScintilla.CurrentLine - ScriptEditorSearchResult.ResultsPadding; searchManager.textAreaScintilla.FirstVisibleLine = resultStart; } private void NavigatorGoTo(ListBox listBox, TabPage tabPage, SearchManager searchManager, ScriptFile.ContainerTypes containerType) { if (listBox.SelectedIndex < 0) { return; } scriptEditorTabControl.SelectedTab = tabPage; int commandNumber = listBox.SelectedIndex + 1; string CommandBlockOpen = $"{containerType} {commandNumber}:"; searchManager.Find(true, false, CommandBlockOpen); scrollResultToTop(searchManager); } private void scriptsNavListbox_SelectedIndexChanged(object sender, EventArgs e) { NavigatorGoTo((ListBox)sender, scriptsTabPage, scriptSearchManager, ScriptFile.ContainerTypes.Script); } private void functionsNavListbox_SelectedIndexChanged(object sender, EventArgs e) { NavigatorGoTo((ListBox)sender, functionsTabPage, functionSearchManager, ScriptFile.ContainerTypes.Function); } private void actionsNavListbox_SelectedIndexChanged(object sender, EventArgs e) { NavigatorGoTo((ListBox)sender, actionsTabPage, actionSearchManager, ScriptFile.ContainerTypes.Action); } private void openFindScriptEditorButton_Click(object sender, EventArgs e) { currentSearchManager.OpenSearch(); } private void ScriptEditorExpandButton_Click(object sender, EventArgs e) { currentScintillaEditor.FoldAll(FoldAction.Expand); } private void ScriptEditorCollapseButton_Click(object sender, EventArgs e) { currentScintillaEditor.FoldAll(FoldAction.Contract); } private void scriptEditorWordWrapCheckbox_CheckedChanged(object sender, EventArgs e) { ScriptTextArea.WrapMode = scriptEditorWordWrapCheckbox.Checked ? WrapMode.Word : WrapMode.None; FunctionTextArea.WrapMode = scriptEditorWordWrapCheckbox.Checked ? WrapMode.Word : WrapMode.None; ActionTextArea.WrapMode = scriptEditorWordWrapCheckbox.Checked ? WrapMode.Word : WrapMode.None; } private void viewWhiteSpacesButton_Click(object sender, EventArgs e) { ScriptTextArea.ViewWhitespace = scriptEditorWhitespacesCheckbox.Checked ? WhitespaceMode.VisibleAlways : WhitespaceMode.Invisible; FunctionTextArea.ViewWhitespace = scriptEditorWhitespacesCheckbox.Checked ? WhitespaceMode.VisibleAlways : WhitespaceMode.Invisible; ActionTextArea.ViewWhitespace = scriptEditorWhitespacesCheckbox.Checked ? WhitespaceMode.VisibleAlways : WhitespaceMode.Invisible; } private void searchInScriptsTextBox_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Enter) { searchInScriptsButton_Click(null, null); } } public List getScriptsToSearch() { List scriptsToSearch = new List(); if (searchOnlyCurrentScriptCheckBox.Checked) { this.UIThread(() => { searchProgressBar.Maximum = 1; }); int i = selectScriptFileComboBox.SelectedIndex; ScriptFile scriptFile = new ScriptFile(i); Console.WriteLine("Attempting to load script " + scriptFile.fileID); scriptsToSearch.Add(scriptFile); this.UIThread(() => { searchProgressBar.IncrementNoAnimation(); }); } else { this.UIThread(() => { searchProgressBar.Maximum = selectScriptFileComboBox.Items.Count; }); for (int i = 0; i < selectScriptFileComboBox.Items.Count; i++) { ScriptFile scriptFile = new ScriptFile(i); Console.WriteLine("Attempting to load script " + scriptFile.fileID); scriptsToSearch.Add(scriptFile); this.UIThread(() => { searchProgressBar.IncrementNoAnimation(); }); } } return scriptsToSearch; } private void searchInScriptsButton_Click(object sender, EventArgs e) { if (searchInScriptsTextBox.Text == "") { return; } BackgroundWorker bw = new BackgroundWorker(); bw.DoWork += (_sender, args) => { this.UIThread(() => { searchInScriptsResultListBox.Items.Clear(); searchProgressBar.Value = 0; }); List scriptsToSearch = getScriptsToSearch(); string searchString = searchInScriptsTextBox.Text; Func searchCriteriaCS = (string s) => s.IndexOf(searchString, StringComparison.InvariantCulture) >= 0; Func searchCriteriaCI = (string s) => s.IndexOf(searchString, StringComparison.InvariantCultureIgnoreCase) >= 0; Func searchCriteria = scriptSearchCaseSensitiveCheckBox.Checked ? searchCriteriaCS : searchCriteriaCI; List results = new List(); foreach (ScriptFile scriptFile in scriptsToSearch) { List scriptResults = SearchInScripts(scriptFile, scriptFile.allScripts, searchCriteria); List functionResults = SearchInScripts(scriptFile, scriptFile.allFunctions, searchCriteria); // List actionResults = SearchInScripts(scriptFile, scriptFile.allActions, searchCriteria); results.AddRange(scriptResults); results.AddRange(functionResults); // results.AddRange(actionResults); } this.UIThread(() => { searchInScriptsResultListBox.Items.AddRange(results.ToArray()); searchProgressBar.Value = 0; }); }; bw.RunWorkerAsync(); } private List SearchInScripts(ScriptFile scriptFile, List commandContainers, Func criteria) { List results = new List(); for (int j = 0; j < commandContainers.Count; j++) { if (commandContainers[j].commands is null) { continue; } ScriptCommandContainer scriptCommandContainer = commandContainers[j]; foreach (ScriptCommand scriptCommand in scriptCommandContainer.commands) { if (criteria(scriptCommand.name)) { results.Add(new ScriptEditorSearchResult(scriptFile, scriptCommandContainer.containerType, j + 1, scriptCommand)); } } } return results; } private void searchInScriptsResultListBox_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Enter) { goToSearchResult(); } } private void searchInScripts_GoToEntryResult(object sender, MouseEventArgs e) { goToSearchResult(); } private void goToSearchResult() { if (searchInScriptsResultListBox.SelectedItem == null) { return; } ScriptEditorSearchResult searchResult = (ScriptEditorSearchResult)searchInScriptsResultListBox.SelectedItem; ScriptFile scriptFile = searchResult.scriptFile; ScriptFile.ContainerTypes containerType = searchResult.containerType; selectScriptFileComboBox.SelectedIndex = scriptFile.fileID; if (containerType == ScriptFile.ContainerTypes.Script) { displaySearchResult(scriptsTabPage, scriptSearchManager, searchResult); } else if (containerType == ScriptFile.ContainerTypes.Function) { displaySearchResult(functionsTabPage, functionSearchManager, searchResult); } else if (containerType == ScriptFile.ContainerTypes.Action) { displaySearchResult(actionsTabPage, actionSearchManager, searchResult); } } private void displaySearchResult(TabPage tabPage, SearchManager searchManager, ScriptEditorSearchResult searchResult) { if (scriptEditorTabControl.SelectedTab != tabPage) { scriptEditorTabControl.SelectedTab = tabPage; } searchManager.Find(true, false, searchResult.CommandBlockOpen); int blockStart = searchManager.textAreaScintilla.CurrentLine - ScriptEditorSearchResult.ResultsPadding; searchManager.Find(true, false, searchResult.scriptCommand.name); int resultStart = searchManager.textAreaScintilla.CurrentLine - ScriptEditorSearchResult.ResultsPadding; if (scrollToBlockStartcheckBox.Checked) { searchManager.textAreaScintilla.FirstVisibleLine = blockStart; } else { searchManager.textAreaScintilla.FirstVisibleLine = resultStart; } } } public class ScriptEditorSearchResult { public readonly ScriptFile scriptFile; public readonly ScriptFile.ContainerTypes containerType; public readonly int commandNumber; public readonly ScriptCommand scriptCommand; public const int ResultsPadding = 1; public ScriptEditorSearchResult(ScriptFile scriptFile, ScriptFile.ContainerTypes containerType, int commandNumber, ScriptCommand scriptCommand) { this.scriptFile = scriptFile; this.containerType = containerType; this.commandNumber = commandNumber; this.scriptCommand = scriptCommand; } public string CommandBlockOpen { get { return $"{containerType} {commandNumber}:"; } } public override string ToString() { return $"File {scriptFile.fileID} - {CommandBlockOpen} {scriptCommand.name}"; } } }