From 8ca57b9593ae4db54e7baf6eed648257eafbb76d Mon Sep 17 00:00:00 2001 From: e Date: Wed, 19 Jun 2024 17:06:30 -0300 Subject: [PATCH 1/3] Editor: add local variables to watch panel automatically This change assumes local variables are usually meaningful in the context of the function being debugged. The user can still add and remove variables to watch, for meaningful global variables. --- Editor/AGS.Editor/AGSEditor.cs | 1 + Editor/AGS.Editor/GUI/GUIController.cs | 12 ++++ Editor/AGS.Editor/GUI/WatchVariablesPanel.cs | 72 +++++++++++++++++++- Editor/AGS.Editor/Panes/ScriptEditorBase.cs | 2 +- 4 files changed, 85 insertions(+), 2 deletions(-) diff --git a/Editor/AGS.Editor/AGSEditor.cs b/Editor/AGS.Editor/AGSEditor.cs index 7dd1ba5d77..bc9fead8a3 100644 --- a/Editor/AGS.Editor/AGSEditor.cs +++ b/Editor/AGS.Editor/AGSEditor.cs @@ -408,6 +408,7 @@ private void _debugger_BreakAtLocation(DebugCallStack callStack) Factory.GUIController.HideOutputPanel(); Factory.GUIController.ShowCallStack(callStack); Factory.GUIController.ZoomToFile(callStack.Lines[0].ScriptName, callStack.Lines[0].LineNumber, true, callStack.ErrorMessage); + Factory.GUIController.SetAutoLocalVariables(callStack); Factory.GUIController.NotifyWatchVariables(); } diff --git a/Editor/AGS.Editor/GUI/GUIController.cs b/Editor/AGS.Editor/GUI/GUIController.cs index fef74917e3..f0bb632ceb 100644 --- a/Editor/AGS.Editor/GUI/GUIController.cs +++ b/Editor/AGS.Editor/GUI/GUIController.cs @@ -51,6 +51,7 @@ public class GUIController : IGUIController private delegate void ShowCallStackDelegate(DebugCallStack callStack); private delegate void ShowFindSymbolResultsDelegate(List results); private delegate void NotifyWatchVariablesDelegate(); + private delegate void NotifySetAutoLocalVariables(DebugCallStack callStack); private frmMain _mainForm; private LogPanel _pnlEngineLog; @@ -515,6 +516,17 @@ public void PrintEngineLog(string message, LogGroup group, LogLevel level) _pnlEngineLog?.WriteLogMessage(message, group, level); } + public void SetAutoLocalVariables(DebugCallStack callStack) + { + if (_mainForm.pnlWatchVariables.InvokeRequired) + { + _mainForm.pnlWatchVariables.Invoke(new NotifySetAutoLocalVariables(SetAutoLocalVariables), callStack); + return; + } + + _mainForm.pnlWatchVariables.SetAutoLocalVariables(callStack); + } + public void NotifyWatchVariables() { if (_mainForm.pnlWatchVariables.InvokeRequired) diff --git a/Editor/AGS.Editor/GUI/WatchVariablesPanel.cs b/Editor/AGS.Editor/GUI/WatchVariablesPanel.cs index c065408126..8029354aa8 100644 --- a/Editor/AGS.Editor/GUI/WatchVariablesPanel.cs +++ b/Editor/AGS.Editor/GUI/WatchVariablesPanel.cs @@ -1,4 +1,5 @@ -using System; +using AGS.Types; +using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; @@ -264,6 +265,75 @@ private void UpdateSingleWatch(ListViewItem item) } } + private int PerceivedBrightness(Color c) + { + return (int)Math.Sqrt( + c.R * c.R * .299 + + c.G * c.G * .587 + + c.B * c.B * .114); + } + + public void SetAutoLocalVariables(DebugCallStack callStack) + { + if (!AGSEditor.Instance.Debugger.IsActive) + return; + + string scriptName = callStack.Lines[0].ScriptName; + int lineNumber = callStack.Lines[0].LineNumber; + ScintillaWrapper scintilla = Factory.GUIController.GetScriptEditorControl(scriptName, true) as ScintillaWrapper; + if (scintilla == null) + return; + + if (scintilla.CurrentLine != lineNumber) + { + scintilla.GoToLine(lineNumber); + } + + List varnames = scintilla.GetListOfLocalVariablesForCurrentPosition(false) + .Select(v => v.VariableName).Distinct().ToList(); + + listView1.BeginUpdate(); + foreach (ListViewItem itm in listView1.Items) + { + if(itm.Tag as string == "autolocal") + { + itm.Remove(); + } + } + + + lock (_updateItemLock) + { + for (int i = _itemsToUpdate.Count - 1; i >= 0; i--) + { + ListViewItem itm = _itemsToUpdate[i]; + if (itm.Tag as string == "autolocal") + { + _itemsToUpdate.RemoveAt(i); + } + } + + Color c = Color.Empty; + foreach (var v in varnames) + { + var itm = CreateItem(v); + itm.Tag = "autolocal"; + itm = listView1.Items.Insert(0, itm); + + if (c.IsEmpty) + { + int brightness = PerceivedBrightness(itm.ForeColor); + c = brightness > 128 ? Color.LightBlue : Color.DarkBlue; + } + itm.ForeColor = c; + + _itemsToUpdate.Add(itm); + } + } + listView1.EndUpdate(); + _updateItemTimer.Start(); + } + public void UpdateAllWatches() { if (!AGSEditor.Instance.Debugger.IsActive) diff --git a/Editor/AGS.Editor/Panes/ScriptEditorBase.cs b/Editor/AGS.Editor/Panes/ScriptEditorBase.cs index 9248e3bcd6..c8b5a32c23 100644 --- a/Editor/AGS.Editor/Panes/ScriptEditorBase.cs +++ b/Editor/AGS.Editor/Panes/ScriptEditorBase.cs @@ -97,7 +97,7 @@ protected IScript Script /// /// Lets for a child class to assign an actual Scintilla control. /// - protected ScintillaWrapper Scintilla + public ScintillaWrapper Scintilla { get { return _scintilla; } set From 99b268eccffe2e9207adf560fe8e0ff3cb12e878 Mon Sep 17 00:00:00 2001 From: e Date: Wed, 19 Jun 2024 20:19:05 -0300 Subject: [PATCH 2/3] Editor: avoid blinking in Watch Variables already added --- Editor/AGS.Editor/GUI/WatchVariablesPanel.cs | 41 ++++++++++---------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/Editor/AGS.Editor/GUI/WatchVariablesPanel.cs b/Editor/AGS.Editor/GUI/WatchVariablesPanel.cs index 8029354aa8..daca8374b0 100644 --- a/Editor/AGS.Editor/GUI/WatchVariablesPanel.cs +++ b/Editor/AGS.Editor/GUI/WatchVariablesPanel.cs @@ -293,43 +293,44 @@ public void SetAutoLocalVariables(DebugCallStack callStack) .Select(v => v.VariableName).Distinct().ToList(); listView1.BeginUpdate(); + + // We will avoid blinking of all "autolocal" by removing the ones not in varnames + // so we can keep the ones that already were added in a previous cycle + // later we will add ONLY the ones that weren't already added + // We also need to keep sync in the items to update. foreach (ListViewItem itm in listView1.Items) { - if(itm.Tag as string == "autolocal") + if (itm.Tag as string == "autolocal" && !varnames.Contains(itm.Text)) { itm.Remove(); } } - lock (_updateItemLock) { - for (int i = _itemsToUpdate.Count - 1; i >= 0; i--) - { - ListViewItem itm = _itemsToUpdate[i]; - if (itm.Tag as string == "autolocal") - { - _itemsToUpdate.RemoveAt(i); - } - } + _itemsToUpdate.RemoveAll(itm => itm.Tag as string == "autolocal" && !varnames.Contains(itm.Text)); Color c = Color.Empty; foreach (var v in varnames) { - var itm = CreateItem(v); - itm.Tag = "autolocal"; - itm = listView1.Items.Insert(0, itm); - - if (c.IsEmpty) + if (!listView1.Items.Cast().Any(itm => itm.Text == v && itm.Tag as string == "autolocal")) { - int brightness = PerceivedBrightness(itm.ForeColor); - c = brightness > 128 ? Color.LightBlue : Color.DarkBlue; - } - itm.ForeColor = c; + var itm = CreateItem(v); + itm.Tag = "autolocal"; + listView1.Items.Insert(0, itm); + + if (c == Color.Empty) + { + int brightness = PerceivedBrightness(itm.ForeColor); + c = brightness > 128 ? Color.LightBlue : Color.DarkBlue; + } + itm.ForeColor = c; - _itemsToUpdate.Add(itm); + _itemsToUpdate.Add(itm); + } } } + listView1.EndUpdate(); _updateItemTimer.Start(); } From c0a8775bf95ddf4975732e7138c19f74c87b2c05 Mon Sep 17 00:00:00 2001 From: e Date: Wed, 3 Jul 2024 20:05:30 -0300 Subject: [PATCH 3/3] Editor: simple add to watch pane implementation --- Editor/AGS.Editor/GUI/GUIController.cs | 8 ++++++ Editor/AGS.Editor/GUI/WatchVariablesPanel.cs | 8 ++++++ Editor/AGS.Editor/Panes/ScriptEditorBase.cs | 27 +++++++++++++++++--- 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/Editor/AGS.Editor/GUI/GUIController.cs b/Editor/AGS.Editor/GUI/GUIController.cs index f0bb632ceb..1db9af861a 100644 --- a/Editor/AGS.Editor/GUI/GUIController.cs +++ b/Editor/AGS.Editor/GUI/GUIController.cs @@ -487,6 +487,14 @@ public void HideFindSymbolResults() _mainForm.pnlFindResults.Hide(); } + public void AddVariableToWatchPanel(string var_name) + { + _mainForm.pnlWatchVariables.AddVariableToWatchList(var_name); + if (_mainForm.pnlWatchVariables.IsHidden) + return; + _mainForm.pnlWatchVariables.Show(); + } + public void ShowWatchVariablesPanel(bool ifEnabled) { if (ifEnabled && _mainForm.pnlWatchVariables.IsHidden) diff --git a/Editor/AGS.Editor/GUI/WatchVariablesPanel.cs b/Editor/AGS.Editor/GUI/WatchVariablesPanel.cs index daca8374b0..73d6424246 100644 --- a/Editor/AGS.Editor/GUI/WatchVariablesPanel.cs +++ b/Editor/AGS.Editor/GUI/WatchVariablesPanel.cs @@ -385,6 +385,14 @@ private void listView1_MouseUp(object sender, MouseEventArgs e) } } + public void AddVariableToWatchList(string var_name) + { + ListViewItem item = listView1.Items.Add(CreateItem(var_name)); + lock (_updateItemLock) + _itemsToUpdate.Add(item); + _updateItemTimer.Start(); + } + private void addToolStripMenuItem_Click(object sender, EventArgs e) { ListViewItem item; diff --git a/Editor/AGS.Editor/Panes/ScriptEditorBase.cs b/Editor/AGS.Editor/Panes/ScriptEditorBase.cs index c8b5a32c23..7c72c6c2ef 100644 --- a/Editor/AGS.Editor/Panes/ScriptEditorBase.cs +++ b/Editor/AGS.Editor/Panes/ScriptEditorBase.cs @@ -34,6 +34,7 @@ public class ScriptEditorBase : EditorContentPanel private const string GO_TO_DEFINITION_COMMAND = "ScriptGoToDefiniton"; private const string FIND_ALL_USAGES_COMMAND = "ScriptFindAllUsages"; private const string GO_TO_SPRITE_COMMAND = "ScriptGoToSprite"; + private const string ADD_TO_WATCH_PANE_COMMAND = "ScriptAddToWatch"; protected AGSEditor _agsEditor; // Loaded script reference, is assigned by the child class. @@ -54,6 +55,7 @@ public class ScriptEditorBase : EditorContentPanel _menuCmdCopy, _menuCmdPaste, _menuCmdGoToDefinition, + _menuCmdAddToWatchPane, _menuCmdFindAllUsages, _menuCmdGoToSprite; @@ -163,6 +165,8 @@ private void InitEditorMenus() _menuCmdGoToDefinition = new MenuCommand(GO_TO_DEFINITION_COMMAND, "Go to Definition", Keys.F12); _menuCmdGoToDefinition.Enabled = false; + _menuCmdAddToWatchPane = new MenuCommand(ADD_TO_WATCH_PANE_COMMAND, "Add to Watch", null); + _menuCmdAddToWatchPane.Enabled = false; _menuCmdFindAllUsages = new MenuCommand(FIND_ALL_USAGES_COMMAND, "Find All Usages", Keys.Shift | Keys.F12); _menuCmdFindAllUsages.Enabled = false; _menuCmdGoToSprite = new MenuCommand(GO_TO_SPRITE_COMMAND, "Go to Sprite", Keys.Shift | Keys.F7); @@ -170,6 +174,7 @@ private void InitEditorMenus() _extraMenu.Commands.Add(MenuCommand.Separator); _extraMenu.Commands.Add(_menuCmdGoToDefinition); + _extraMenu.Commands.Add(_menuCmdAddToWatchPane); _extraMenu.Commands.Add(_menuCmdFindAllUsages); _extraMenu.Commands.Add(_menuCmdGoToSprite); @@ -246,7 +251,11 @@ protected override void OnCommandClick(string command) } else if (IsContextCommand(command)) { - if (command == GO_TO_DEFINITION_COMMAND || + if (command == ADD_TO_WATCH_PANE_COMMAND) + { + Factory.GUIController.AddVariableToWatchPanel(_goToDefinition); + } + else if (command == GO_TO_DEFINITION_COMMAND || command == FIND_ALL_USAGES_COMMAND) { string[] structAndMember = _goToDefinition.Split('.'); @@ -340,6 +349,7 @@ protected virtual void UpdateUICommands() (_menuCmdUndo.Enabled != canUndo) || (_menuCmdRedo.Enabled != canRedo) || (_menuCmdGoToDefinition.Enabled != canGoToDefinition) || + (_menuCmdAddToWatchPane.Enabled != canGoToDefinition) || (_menuCmdFindAllUsages.Enabled != canGoToDefinition) || (_menuCmdGoToSprite.Enabled != canGoToSprite); @@ -350,7 +360,9 @@ protected virtual void UpdateUICommands() _menuCmdPaste.Enabled = canPaste; _menuCmdUndo.Enabled = canUndo; _menuCmdRedo.Enabled = canRedo; - _menuCmdGoToDefinition.Enabled = _menuCmdFindAllUsages.Enabled = canGoToDefinition; + _menuCmdGoToDefinition.Enabled = canGoToDefinition; + _menuCmdAddToWatchPane.Enabled = canGoToDefinition; + _menuCmdFindAllUsages.Enabled = canGoToDefinition; _menuCmdGoToSprite.Enabled = canGoToSprite; Factory.ToolBarManager.RefreshCurrentPane(); @@ -365,7 +377,10 @@ protected static bool IsStandardEditCommand(string c) protected static bool IsContextCommand(string c) { - return (c == GO_TO_DEFINITION_COMMAND) || (c == FIND_ALL_USAGES_COMMAND) || (c == GO_TO_SPRITE_COMMAND); + return (c == GO_TO_DEFINITION_COMMAND) || + (c == FIND_ALL_USAGES_COMMAND) || + (c == GO_TO_SPRITE_COMMAND) || + (c == ADD_TO_WATCH_PANE_COMMAND); } protected void UpdateScriptDocumentContext(int clickedPositionInDocument) @@ -421,12 +436,18 @@ private void scintilla_ConstructContextMenu(ContextMenuStrip menuStrip, int clic UpdateScriptDocumentContext(clickedPositionInDocument); string typeName = _goToDefinition != null ? (" of " + _goToDefinition) : string.Empty; + string varName = _goToDefinition != null ? (_goToDefinition + " to Watch Panel") : string.Empty; menuItem = new ToolStripMenuItem(_menuCmdGoToDefinition.Name + typeName, null, onClick, GO_TO_DEFINITION_COMMAND); menuItem.ShortcutKeys = _menuCmdGoToDefinition.ShortcutKey; menuItem.Enabled = (_goToDefinition != null); menuStrip.Items.Add(menuItem); + menuItem = new ToolStripMenuItem("Add " + varName, null, onClick, ADD_TO_WATCH_PANE_COMMAND); + menuItem.ShortcutKeys = _menuCmdAddToWatchPane.ShortcutKey; + menuItem.Enabled = (_goToDefinition != null); + menuStrip.Items.Add(menuItem); + menuItem = new ToolStripMenuItem(_menuCmdFindAllUsages.Name + typeName, null, onClick, FIND_ALL_USAGES_COMMAND); menuItem.ShortcutKeys = _menuCmdFindAllUsages.ShortcutKey; menuItem.Enabled = (_goToDefinition != null);