mirror of
https://github.com/SourMesen/Mesen2.git
synced 2025-04-02 10:21:44 -04:00
Watch: Added missing context menu actions
This commit is contained in:
parent
cb15f9a122
commit
41ac7a3ba4
9 changed files with 238 additions and 25 deletions
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ namespace Mesen.Debugger.Utilities
|
|||
}
|
||||
}
|
||||
} else {
|
||||
focusParent.RemoveHandler(InputElement.KeyDownEvent, handler!);
|
||||
elem.RemoveHandler(InputElement.KeyDownEvent, handler!);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 _),
|
||||
|
|
|
@ -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>
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue