Watch: Added missing context menu actions

This commit is contained in:
Sour 2021-12-23 13:34:55 -05:00
parent cb15f9a122
commit 41ac7a3ba4
9 changed files with 238 additions and 25 deletions

View file

@ -35,13 +35,15 @@ namespace Mesen.Debugger.Utilities
IconFileAttribute? attr = ActionType.GetAttribute<IconFileAttribute>();
if(!string.IsNullOrEmpty(attr?.Icon)) {
return ImageUtilities.FromAsset(attr.Icon);
} else if(IsSelected?.Invoke() == true) {
return ImageUtilities.FromAsset("Assets/MenuItemChecked.png");
}
return null;
}
}
List<ContextMenuAction>? _subActions;
public List<ContextMenuAction>? SubActions
List<object>? _subActions;
public List<object>? SubActions
{
get => _subActions;
set
@ -50,9 +52,11 @@ namespace Mesen.Debugger.Utilities
if(_subActions != null) {
IsEnabled = () => {
foreach(ContextMenuAction subAction in _subActions) {
if(subAction.IsEnabled == null || subAction.IsEnabled()) {
return true;
foreach(object subAction in _subActions) {
if(subAction is ContextMenuAction act) {
if(act.IsEnabled == null || act.IsEnabled()) {
return true;
}
}
}
return false;
@ -63,6 +67,7 @@ namespace Mesen.Debugger.Utilities
public Func<string>? HintText { get; set; }
public Func<bool>? IsEnabled { get; set; }
public Func<bool>? IsSelected { get; set; }
public Func<DbgShortKeys>? Shortcut { get; set; }
public string ShortcutText => Shortcut?.Invoke().ToString() ?? "";
@ -141,6 +146,29 @@ namespace Mesen.Debugger.Utilities
MoveUp,
[IconFile("MoveDown")]
MoveDown
MoveDown,
WatchDecimalDisplay,
WatchHexDisplay,
WatchBinaryDisplay,
RowDisplayFormat,
RowFormatBinary,
RowFormatHex8Bits,
RowFormatHex16Bits,
RowFormatHex24Bits,
RowFormatSigned8Bits,
RowFormatSigned16Bits,
RowFormatSigned24Bits,
RowFormatUnsigned,
[IconFile("Close")]
ClearFormat,
[IconFile("Import")]
Import,
[IconFile("Export")]
Export
}
}

View file

@ -64,7 +64,7 @@ namespace Mesen.Debugger.Utilities
}
}
} else {
focusParent.RemoveHandler(InputElement.KeyDownEvent, handler!);
elem.RemoveHandler(InputElement.KeyDownEvent, handler!);
}
}
};

View file

@ -15,7 +15,7 @@ namespace Mesen.Debugger.ViewModels
[Reactive] public List<WatchValueInfo> WatchEntries { get; private set; } = new List<WatchValueInfo>();
[Reactive] public int SelectedIndex { get; set; } = 0;
private WatchManager _manager;
public WatchManager Manager { get; }
public WatchListViewModel() : this(CpuType.Cpu) { }
@ -23,41 +23,47 @@ namespace Mesen.Debugger.ViewModels
{
Id = "WatchList";
Title = "Watch";
_manager = WatchManager.GetWatchManager(cpuType);
_manager.WatchChanged += WatchListViewModel_WatchChanged;
Manager = WatchManager.GetWatchManager(cpuType);
Manager.WatchChanged += WatchListViewModel_WatchChanged;
UpdateWatch();
}
public void UpdateWatch()
{
WatchEntries = _manager.GetWatchContent(WatchEntries);
int selection = SelectedIndex;
WatchEntries = Manager.GetWatchContent(WatchEntries);
if(selection < WatchEntries.Count) {
SelectedIndex = selection;
} else {
SelectedIndex = WatchEntries.Count - 1;
}
}
public void EditWatch(int index, string expression)
{
_manager.UpdateWatch(index, expression);
Manager.UpdateWatch(index, expression);
}
public void MoveUp(int index)
{
List<string> entries = _manager.WatchEntries;
List<string> entries = Manager.WatchEntries;
if(index > 0 && index < entries.Count) {
string currentEntry = entries[index];
string entryAbove = entries[index - 1];
_manager.UpdateWatch(index - 1, currentEntry);
_manager.UpdateWatch(index, entryAbove);
Manager.UpdateWatch(index - 1, currentEntry);
Manager.UpdateWatch(index, entryAbove);
SelectedIndex = index - 1;
}
}
public void MoveDown(int index)
{
List<string> entries = _manager.WatchEntries;
List<string> entries = Manager.WatchEntries;
if(index < entries.Count - 1) {
string currentEntry = entries[index];
string entryBelow = entries[index + 1];
_manager.UpdateWatch(index + 1, currentEntry);
_manager.UpdateWatch(index, entryBelow);
Manager.UpdateWatch(index + 1, currentEntry);
Manager.UpdateWatch(index, entryBelow);
SelectedIndex = index + 1;
}
}
@ -67,10 +73,24 @@ namespace Mesen.Debugger.ViewModels
UpdateWatch();
}
private int[] GetIndexes(List<WatchValueInfo> items)
{
return items.Select(x => WatchEntries.IndexOf(x)).ToArray();
}
internal void DeleteWatch(List<WatchValueInfo> items)
{
int[] indexes = items.Select(x => WatchEntries.IndexOf(x)).ToArray();
_manager.RemoveWatch(indexes);
Manager.RemoveWatch(GetIndexes(items));
}
internal void SetSelectionFormat(WatchFormatStyle format, int byteLength, List<WatchValueInfo> items)
{
Manager.SetSelectionFormat(format, byteLength, GetIndexes(items));
}
internal void ClearSelectionFormat(List<WatchValueInfo> items)
{
Manager.ClearSelectionFormat(GetIndexes(items));
}
}
}

View file

@ -29,10 +29,12 @@
CellEditEnded="OnCellEditEnded"
KeyDown="OnGridKeyDown"
SelectedIndex="{CompiledBinding SelectedIndex}"
CanUserSortColumns="False"
CanUserReorderColumns="False"
IsReadOnly="False"
>
<DataGrid.Columns>
<DataGridTextColumn Header="Watch" Binding="{Binding Expression}" Width="1*" CanUserResize="True" />
<DataGridTextColumn Header="Name" Binding="{Binding Expression}" Width="1*" CanUserResize="True" />
<DataGridTextColumn
CellStyleClasses="watchValue"
Header="Value"

View file

@ -9,6 +9,7 @@ using Mesen.Debugger.Utilities;
using Mesen.Config;
using System;
using Mesen.Debugger.Controls;
using Mesen.Utilities;
namespace Mesen.Debugger.Views
{
@ -72,7 +73,104 @@ namespace Mesen.Debugger.Views
OnClick = () => {
_model!.MoveDown(grid.SelectedIndex);
}
}
},
new Separator(),
new ContextMenuAction() {
ActionType = ActionType.RowDisplayFormat,
SubActions = new() {
new ContextMenuAction() {
ActionType = ActionType.RowFormatBinary,
OnClick = () => _model!.SetSelectionFormat(WatchFormatStyle.Binary, 1, grid.SelectedItems.Cast<WatchValueInfo>().ToList())
},
new Separator(),
new ContextMenuAction() {
ActionType = ActionType.RowFormatHex8Bits,
OnClick = () => _model!.SetSelectionFormat(WatchFormatStyle.Hex, 1, grid.SelectedItems.Cast<WatchValueInfo>().ToList())
},
new ContextMenuAction() {
ActionType = ActionType.RowFormatHex16Bits,
OnClick = () => _model!.SetSelectionFormat(WatchFormatStyle.Hex, 2, grid.SelectedItems.Cast<WatchValueInfo>().ToList())
},
new ContextMenuAction() {
ActionType = ActionType.RowFormatHex24Bits,
OnClick = () => _model!.SetSelectionFormat(WatchFormatStyle.Hex, 3, grid.SelectedItems.Cast<WatchValueInfo>().ToList())
},
new Separator(),
new ContextMenuAction() {
ActionType = ActionType.RowFormatSigned8Bits,
OnClick = () => _model!.SetSelectionFormat(WatchFormatStyle.Signed, 1, grid.SelectedItems.Cast<WatchValueInfo>().ToList())
},
new ContextMenuAction() {
ActionType = ActionType.RowFormatSigned16Bits,
OnClick = () => _model!.SetSelectionFormat(WatchFormatStyle.Signed, 2, grid.SelectedItems.Cast<WatchValueInfo>().ToList())
},
new ContextMenuAction() {
ActionType = ActionType.RowFormatSigned24Bits,
OnClick = () => _model!.SetSelectionFormat(WatchFormatStyle.Signed, 3, grid.SelectedItems.Cast<WatchValueInfo>().ToList())
},
new Separator(),
new ContextMenuAction() {
ActionType = ActionType.RowFormatUnsigned,
OnClick = () => _model!.SetSelectionFormat(WatchFormatStyle.Unsigned, 1, grid.SelectedItems.Cast<WatchValueInfo>().ToList())
},
new Separator(),
new ContextMenuAction() {
ActionType = ActionType.ClearFormat,
OnClick = () => _model!.ClearSelectionFormat(grid.SelectedItems.Cast<WatchValueInfo>().ToList())
}
}
},
new Separator(),
new ContextMenuAction() {
ActionType = ActionType.WatchDecimalDisplay,
IsSelected = () => ConfigManager.Config.Debug.Debugger.WatchFormat == WatchFormatStyle.Unsigned,
OnClick = () => {
ConfigManager.Config.Debug.Debugger.WatchFormat = WatchFormatStyle.Unsigned;
}
},
new ContextMenuAction() {
ActionType = ActionType.WatchHexDisplay,
IsSelected = () => ConfigManager.Config.Debug.Debugger.WatchFormat == WatchFormatStyle.Hex,
OnClick = () => {
ConfigManager.Config.Debug.Debugger.WatchFormat = WatchFormatStyle.Hex;
}
},
new ContextMenuAction() {
ActionType = ActionType.WatchBinaryDisplay,
IsSelected = () => ConfigManager.Config.Debug.Debugger.WatchFormat == WatchFormatStyle.Binary,
OnClick = () => {
ConfigManager.Config.Debug.Debugger.WatchFormat = WatchFormatStyle.Binary;
}
},
new Separator(),
new ContextMenuAction() {
ActionType = ActionType.Import,
OnClick = async () => {
string? filename = await FileDialogHelper.OpenFile(null, VisualRoot, FileDialogHelper.WatchFileExt);
if(filename !=null) {
_model!.Manager.Import(filename);
}
}
},
new ContextMenuAction() {
ActionType = ActionType.Export,
OnClick = async () => {
string? filename = await FileDialogHelper.SaveFile(null, null, VisualRoot, FileDialogHelper.WatchFileExt);
if(filename != null) {
_model!.Manager.Export(filename);
}
}
},
});
}
@ -86,11 +184,16 @@ namespace Mesen.Debugger.Views
}
}
private static bool IsTextKey(Key key)
{
return key >= Key.A && key <= Key.Z || key >= Key.D0 && key <= Key.D9 || key >= Key.NumPad0 && key <= Key.Divide || key >= Key.OemSemicolon && key <= Key.Oem102;
}
private void OnGridKeyDown(object sender, KeyEventArgs e)
{
if(e.Key == Key.Escape) {
((DataGrid)sender).CancelEdit();
} else if(e.Key >= Key.A && e.Key <= Key.Z || e.Key >= Key.D0 && e.Key <= Key.D9) {
} else if(IsTextKey(e.Key)) {
((DataGrid)sender).CurrentColumn = ((DataGrid)sender).Columns[0];
((DataGrid)sender).BeginEdit();
}

View file

@ -9,7 +9,7 @@ using System.Text.RegularExpressions;
namespace Mesen.Debugger
{
class WatchManager
public class WatchManager
{
public static Regex FormatSuffixRegex = new Regex(@"^(.*),\s*([B|H|S|U])([\d]){0,1}$", RegexOptions.Compiled);
private static Regex _arrayWatchRegex = new Regex(@"\[((\$[0-9A-Fa-f]+)|(\d+)|([@_a-zA-Z0-9]+))\s*,\s*(\d+)\]", RegexOptions.Compiled);
@ -223,6 +223,47 @@ namespace Mesen.Debugger
{
File.WriteAllLines(filename, WatchEntries);
}
private string GetFormatString(WatchFormatStyle format, int byteLength)
{
string formatString = ", ";
switch(format) {
case WatchFormatStyle.Binary: formatString += "B"; break;
case WatchFormatStyle.Hex: formatString += "H"; break;
case WatchFormatStyle.Signed: formatString += "S"; break;
case WatchFormatStyle.Unsigned: formatString += "U"; break;
default: throw new Exception("Unsupported type");
}
if(byteLength > 1) {
formatString += byteLength.ToString();
}
return formatString;
}
internal void ClearSelectionFormat(int[] indexes)
{
SetSelectionFormat("", indexes);
}
public void SetSelectionFormat(WatchFormatStyle format, int byteLength, int[] indexes)
{
string formatString = GetFormatString(format, byteLength);
SetSelectionFormat(formatString, indexes);
}
private void SetSelectionFormat(string formatString, int[] indexes)
{
foreach(int i in indexes) {
if(i < _watchEntries.Count) {
Match match = WatchManager.FormatSuffixRegex.Match(_watchEntries[i]);
if(match.Success) {
UpdateWatch(i, match.Groups[1].Value + formatString);
} else {
UpdateWatch(i, _watchEntries[i] + formatString);
}
}
}
}
}
public class WatchValueInfo

View file

@ -223,7 +223,7 @@ namespace Mesen.Debugger.Windows
return new ContextMenuAction() {
ActionType = ActionType.MarkSelectionAs,
HintText = () => GetAddressRange(),
SubActions = new List<ContextMenuAction>() {
SubActions = new() {
new ContextMenuAction() {
ActionType = ActionType.MarkAsCode,
IsEnabled = () => GetMarkStartEnd(out _, out _),

View file

@ -1531,6 +1531,24 @@ x == [$150] || y == [10]
<Value ID="MarkAsCode">Code</Value>
<Value ID="MarkAsData">Data</Value>
<Value ID="MarkAsUnidentified">Unknown</Value>
<Value ID="WatchDecimalDisplay">Decimal Display</Value>
<Value ID="WatchHexDisplay">Hexadecimal Display</Value>
<Value ID="WatchBinaryDisplay">Binary Display</Value>
<Value ID="RowDisplayFormat">Row Display Format</Value>
<Value ID="RowFormatBinary">Binary</Value>
<Value ID="RowFormatHex8Bits">Hexadecimal (8-bit)</Value>
<Value ID="RowFormatHex16Bits">Hexadecimal (16-bit)</Value>
<Value ID="RowFormatHex24Bits">Hexadecimal (24-bit)</Value>
<Value ID="RowFormatSigned8Bits">Signed decimal (8-bit)</Value>
<Value ID="RowFormatSigned16Bits">Signed decimal (16-bit)</Value>
<Value ID="RowFormatSigned24Bits">Signed decimal (24-bit)</Value>
<Value ID="RowFormatUnsigned">Unsigned decimal</Value>
<Value ID="ClearFormat">Clear</Value>
<Value ID="Import">Import...</Value>
<Value ID="Export">Export...</Value>
</Enum>
</Enums>
</Resources>

View file

@ -20,6 +20,7 @@ namespace Mesen.Utilities
public static string AviExt = "avi";
public static string WaveExt = "wav";
public static string MesenSaveStateExt = "mss";
public static string WatchFileExt = "txt";
public static async Task<string?> OpenFile(string? initialFolder, IRenderRoot? parent, params string[] extensions)
{