Debugger: Tilemap viewer - Added view in memory viewer option

+ Fixed right-click working out-of-bounds due to scroll overlay
+ Give hex viewer focus when opening the window
This commit is contained in:
Sour 2022-01-25 20:02:34 -05:00
parent d06f132b7b
commit ea9c8fad96
12 changed files with 86 additions and 22 deletions

View file

@ -118,7 +118,7 @@ namespace Mesen.Debugger.Controls
private double RowWidth => LetterSize.Width * (3 * BytesPerRow - 1);
private double StringViewMargin => 20;
private double ColumnHeaderHeight => LetterSize.Height + 5;
private int VisibleRows => (int)((Bounds.Height - ColumnHeaderHeight) / RowHeight) - 1;
private int VisibleRows => Math.Max(0, (int)((Bounds.Height - ColumnHeaderHeight) / RowHeight) - 1);
private string HexFormat => "X2";
private int _cursorPosition = 0;
@ -136,11 +136,20 @@ namespace Mesen.Debugger.Controls
SelectedRowColumnColorProperty, HeaderBackgroundProperty, HeaderForegroundProperty, HeaderHighlightProperty,
IsFocusedProperty
);
FontFamilyProperty.Changed.AddClassHandler<HexEditor>((x, e) => {
x.InitFontAndLetterSize();
});
FontSizeProperty.Changed.AddClassHandler<HexEditor>((x, e) => {
x.InitFontAndLetterSize();
});
}
public HexEditor()
{
Focusable = true;
InitFontAndLetterSize();
}
protected override void OnPointerEnter(PointerEventArgs e)
@ -178,7 +187,7 @@ namespace Mesen.Debugger.Controls
}
}
private void SetCursorPosition(int pos, bool keepNibble = false)
public void SetCursorPosition(int pos, bool keepNibble = false, bool scrollToTop = false)
{
this.SelectionStart = Math.Min(Math.Max(0, pos), this.DataProvider.Length - 1);
this.SelectionLength = 0;
@ -188,7 +197,7 @@ namespace Mesen.Debugger.Controls
_lastNibble = false;
}
ScrollIntoView(_cursorPosition);
ScrollIntoView(_cursorPosition, scrollToTop);
}
private void ChangeSelectionLength(int offset)
@ -426,14 +435,14 @@ namespace Mesen.Debugger.Controls
return null;
}
private void ScrollIntoView(int byteIndex)
private void ScrollIntoView(int byteIndex, bool scrollToTop = false)
{
int topRow = TopRow;
if(byteIndex < 0) {
topRow = 0;
} else if(byteIndex >= DataProvider.Length) {
topRow = (DataProvider.Length / BytesPerRow) - VisibleRows;
} else if(byteIndex < TopRow * BytesPerRow) {
} else if(byteIndex < TopRow * BytesPerRow || scrollToTop) {
//scroll up
topRow = byteIndex / BytesPerRow;
} else if(byteIndex > (TopRow + VisibleRows) * BytesPerRow) {
@ -544,9 +553,6 @@ namespace Mesen.Debugger.Controls
context.DrawRectangle(ColorHelper.GetBrush(Colors.White), null, new Rect(Bounds.Size));
//Init font and letter size
InitFontAndLetterSize();
//Draw column headers
DrawColumnHeaders(context);
using var columnHeaderTranslation = context.PushPostTransform(Matrix.CreateTranslation(0, this.ColumnHeaderHeight));

View file

@ -159,6 +159,9 @@ namespace Mesen.Debugger.Controls
public PictureViewer()
{
Focusable = true;
VerticalAlignment = VerticalAlignment.Top;
HorizontalAlignment = HorizontalAlignment.Left;
ClipToBounds = true;
}
private void OnSourceInvalidated(object? sender, EventArgs e)

View file

@ -289,5 +289,8 @@ namespace Mesen.Debugger.Utilities
[IconFile("VerticalLayout")]
ViewInTileViewer,
[IconFile("CheatCode")]
ViewInMemoryViewer,
}
}

View file

@ -14,7 +14,7 @@ namespace Mesen.Debugger.Utilities
private static ConcurrentDictionary<Window, bool> _openedWindows = new();
private static object _windowNotifLock = new();
public static void OpenDebugWindow<T>(Func<T> createWindow) where T : Window
public static T OpenDebugWindow<T>(Func<T> createWindow) where T : Window
{
if(Interlocked.Increment(ref _debugWindowCounter) == 1) {
//Opened a debug window and nothing else was opened, load the saved workspace
@ -29,6 +29,17 @@ namespace Mesen.Debugger.Utilities
};
_openedWindows.TryAdd(wnd, true);
wnd.Show();
return wnd;
}
public static T GetOrOpenDebugWindow<T>(Func<T> createWindow) where T : Window
{
foreach(Window wnd in _openedWindows.Keys) {
if(wnd is T) {
return (T)wnd;
}
}
return OpenDebugWindow<T>(createWindow);
}
private static void CloseDebugWindow(Window wnd)

View file

@ -7,6 +7,7 @@ using Avalonia.Threading;
using Mesen.Config;
using Mesen.Debugger.Controls;
using Mesen.Debugger.Utilities;
using Mesen.Debugger.Windows;
using Mesen.Interop;
using Mesen.Utilities;
using Mesen.ViewModels;
@ -110,6 +111,17 @@ namespace Mesen.Debugger.ViewModels
});
DebugShortcutManager.CreateContextMenu(picViewer, new List<object>() {
new ContextMenuAction() {
ActionType = ActionType.ViewInMemoryViewer,
OnClick = () => {
DebugTilemapTileInfo? tile = GetSelectedTileInfo();
if(tile != null && tile.Value.TileMapAddress >= 0) {
MemoryToolsWindow wnd = DebugWindowManager.GetOrOpenDebugWindow(() => new MemoryToolsWindow(new MemoryToolsViewModel()));
wnd.SetCursorPosition(CpuType.GetVramMemoryType(), tile.Value.TileMapAddress);
wnd.Activate();
}
}
},
new ContextMenuAction() {
ActionType = ActionType.ViewInTileViewer,
IsEnabled = () => false,
@ -168,6 +180,16 @@ namespace Mesen.Debugger.ViewModels
}
}
private DebugTilemapTileInfo? GetSelectedTileInfo()
{
if(SelectionRect.IsEmpty || _ppuState == null || _prevVram == null) {
return null;
} else {
PixelPoint p =PixelPoint.FromPoint(SelectionRect.TopLeft, 1);
return DebugApi.GetTilemapTileInfo((uint)p.X, (uint)p.Y, CpuType, GetOptions(SelectedTab), _prevVram, _ppuState);
}
}
private void UpdatePreviewPanel()
{
if(SelectionRect.IsEmpty) {

View file

@ -64,8 +64,6 @@
<Border BorderBrush="Gray" BorderThickness="1">
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" AllowAutoHide="False">
<dc:PictureViewer
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
x:Name="picViewer"
Source="{CompiledBinding ViewerBitmap}"
Zoom="{CompiledBinding Config.ImageScale}"

View file

@ -44,6 +44,14 @@ namespace Mesen.Debugger.Windows
_editor.ByteUpdated += editor_ByteUpdated;
}
public void SetCursorPosition(MemoryType memType, int address)
{
if(_model.AvailableMemoryTypes.Contains(memType)) {
_model.Config.MemoryType = memType;
_editor.SetCursorPosition(address, scrollToTop: true);
}
}
protected override void OnClosing(CancelEventArgs e)
{
base.OnClosing(e);
@ -57,6 +65,7 @@ namespace Mesen.Debugger.Windows
{
base.OnOpened(e);
InitializeActions();
_editor.Focus();
}
private void InitializeComponent()

View file

@ -113,8 +113,6 @@
AllowAutoHide="False"
>
<dc:PictureViewer
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
x:Name="picViewer"
Source="{CompiledBinding ViewerBitmap}"
Zoom="{CompiledBinding Config.ImageScale}"

View file

@ -111,8 +111,6 @@
AllowAutoHide="False"
>
<dc:PictureViewer
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
x:Name="picViewer"
Source="{CompiledBinding ViewerBitmap}"
Zoom="{CompiledBinding Config.ImageScale}"

View file

@ -95,8 +95,6 @@
AllowAutoHide="False"
>
<dc:PictureViewer
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
x:Name="picViewer"
Source="{CompiledBinding ViewerBitmap}"
Zoom="{CompiledBinding Config.ImageScale}"

View file

@ -302,18 +302,35 @@ namespace Mesen.Interop
}
[DllImport(DllPath)] public static extern void ResetMemoryAccessCounts();
public static void GetMemoryAccessCounts(MemoryType type, ref AddressCounters[] counters)
public static void GetMemoryAccessCounts(MemoryType type, ref AddressCounters[] counts)
{
int size = DebugApi.GetMemorySize(type);
Array.Resize(ref counters, size);
DebugApi.GetMemoryAccessCountsWrapper(0, (uint)size, type, counters);
Array.Resize(ref counts, size);
GCHandle handle = GCHandle.Alloc(counts, GCHandleType.Pinned);
IntPtr ptr = handle.AddrOfPinnedObject();
DebugApi.GetMemoryAccessCountsWrapper(0, (uint)size, type, ptr);
handle.Free();
}
[DllImport(DllPath, EntryPoint = "GetMemoryAccessCounts")] private static extern void GetMemoryAccessCountsWrapper(UInt32 offset, UInt32 length, MemoryType type, [In,Out]AddressCounters[] counts);
public static AddressCounters[] GetMemoryAccessCounts(MemoryType type)
{
int size = DebugApi.GetMemorySize(type);
AddressCounters[] counts = new AddressCounters[size];
GetMemoryAccessCounts(type, ref counts);
return counts;
}
[DllImport(DllPath, EntryPoint = "GetMemoryAccessCounts")] private static extern void GetMemoryAccessCountsWrapper(UInt32 offset, UInt32 length, MemoryType type, IntPtr counts);
public static AddressCounters[] GetMemoryAccessCounts(UInt32 offset, UInt32 length, MemoryType type)
{
AddressCounters[] counts = new AddressCounters[length];
DebugApi.GetMemoryAccessCountsWrapper(offset, length, type, counts);
GCHandle handle = GCHandle.Alloc(counts, GCHandleType.Pinned);
IntPtr ptr = handle.AddrOfPinnedObject();
DebugApi.GetMemoryAccessCountsWrapper(offset, length, type, ptr);
handle.Free();
return counts;
}

View file

@ -1800,6 +1800,7 @@ x == [$150] || y == [10]
<Value ID="ExportToPng">Export to PNG</Value>
<Value ID="ViewInTileViewer">View in Tile Viewer</Value>
<Value ID="ViewInMemoryViewer">View in Memory Viewer</Value>
</Enum>
</Enums>
</Resources>