Minor slot hover performance improvements

Skip repaint on cursor moving the hover window
Cache reference to the slot interaction types and "nothing" slot image
Dispose of slot sprites when updating with a new one
If scrolling box/group, auto-update hover with the newly displayed slot's content instead of hiding
This commit is contained in:
Kurt 2026-03-19 17:25:06 -05:00
parent 56ba92b68b
commit 0e097b1fc6
10 changed files with 81 additions and 23 deletions

View File

@ -26,14 +26,14 @@ public sealed class SpriteBuilder5668s : SpriteBuilder
protected override Bitmap Unknown => Resources.b_unknown;
protected override Bitmap GetEggSprite(ushort species) => species == (int)Species.Manaphy ? Resources.b_490_e : Resources.b_egg;
public override Bitmap Hover => Resources.slotHover68;
public override Bitmap View => Resources.slotView68;
public override Bitmap Set => Resources.slotSet68;
public override Bitmap Delete => Resources.slotDel68;
public override Bitmap Transparent => Resources.slotTrans68;
public override Bitmap Hover { get; } = Resources.slotHover68;
public override Bitmap View { get; } = Resources.slotView68;
public override Bitmap Set { get; } = Resources.slotSet68;
public override Bitmap Delete { get; } = Resources.slotDel68;
public override Bitmap Transparent { get; } = Resources.slotTrans68;
public override Bitmap Drag => Resources.slotDrag68;
public override Bitmap UnknownItem => Resources.bitem_unk;
public override Bitmap None => Resources.b_0;
public override Bitmap None { get; } = Resources.b_0;
public override Bitmap ItemTM => Resources.bitem_tm;
public override Bitmap ItemTR => Resources.bitem_tr;
public override Bitmap ShadowLugia => Resources.b_249x;

View File

@ -26,14 +26,14 @@ public sealed class SpriteBuilder5668a : SpriteBuilder
protected override Bitmap Unknown => Resources.b_unknown;
protected override Bitmap GetEggSprite(ushort species) => species == (int)Species.Manaphy ? Resources.a_490_e : Resources.a_egg;
public override Bitmap Hover => Resources.slotHover68;
public override Bitmap View => Resources.slotView68;
public override Bitmap Set => Resources.slotSet68;
public override Bitmap Delete => Resources.slotDel68;
public override Bitmap Transparent => Resources.slotTrans68;
public override Bitmap Hover { get; } = Resources.slotHover68;
public override Bitmap View { get; } = Resources.slotView68;
public override Bitmap Set { get; } = Resources.slotSet68;
public override Bitmap Delete { get; } = Resources.slotDel68;
public override Bitmap Transparent { get; } = Resources.slotTrans68;
public override Bitmap Drag => Resources.slotDrag68;
public override Bitmap UnknownItem => Resources.bitem_unk;
public override Bitmap None => Resources.b_0;
public override Bitmap None { get; } = Resources.b_0;
public override Bitmap ItemTM => Resources.aitem_tm;
public override Bitmap ItemTR => Resources.bitem_tr;
public override Bitmap ShadowLugia => Resources.b_249x;

View File

@ -26,14 +26,14 @@ public sealed class SpriteBuilder5668c : SpriteBuilder
protected override Bitmap Unknown => Resources.b_unknown;
protected override Bitmap GetEggSprite(ushort species) => species == (int)Species.Manaphy ? Resources.b_490_e : Resources.b_egg;
public override Bitmap Hover => Resources.slotHover68;
public override Bitmap View => Resources.slotView68;
public override Bitmap Set => Resources.slotSet68;
public override Bitmap Delete => Resources.slotDel68;
public override Bitmap Transparent => Resources.slotTrans68;
public override Bitmap Hover { get; } = Resources.slotHover68;
public override Bitmap View { get; } = Resources.slotView68;
public override Bitmap Set { get; } = Resources.slotSet68;
public override Bitmap Delete { get; } = Resources.slotDel68;
public override Bitmap Transparent { get; } = Resources.slotTrans68;
public override Bitmap Drag => Resources.slotDrag68;
public override Bitmap UnknownItem => Resources.bitem_unk;
public override Bitmap None => Resources.b_0;
public override Bitmap None { get; } = Resources.b_0;
public override Bitmap ItemTM => Resources.bitem_tm;
public override Bitmap ItemTR => Resources.bitem_tr;
public override Bitmap ShadowLugia => Resources.b_249x;

View File

@ -104,6 +104,8 @@ private void InitializeEvents()
if (menu.mnuVSD.Visible)
return;
Box.CurrentBox = e.Delta > 1 ? Box.Editor.MoveLeft() : Box.Editor.MoveRight();
if (Box.M is { } m)
m.MouseRestart(); // should always trigger if properly connected
};
GB_Daycare.Click += (_, _) => SwitchDaycare();

View File

@ -18,6 +18,7 @@ public sealed class SlotChangeManager(SAVEditor se) : IDisposable
{
public readonly SAVEditor SE = se;
public readonly SlotTrackerImage LastSlot = new();
public PictureBox? Hovered { get; private set; }
public readonly DragManager Drag = new();
public SaveDataEditor<PictureBox> Env { get; set; } = null!;
@ -34,15 +35,28 @@ public void MouseEnter(object? sender, EventArgs e)
{
if (sender is not PictureBox pb)
return;
MouseRestart(pb);
}
public void MouseRestart()
{
if (Hovered is { } pb)
MouseRestart(pb);
}
private void MouseRestart(PictureBox pb)
{
bool dataPresent = pb.Image is not null;
if (dataPresent)
Hover.Start(pb, LastSlot);
Hovered = pb;
pb.Cursor = dataPresent ? Cursors.Hand : Cursors.Default;
}
public void MouseLeave(object? sender, EventArgs e)
{
Hover.Stop();
Hovered = null;
}
public void MouseClick(object? sender, MouseEventArgs e)

View File

@ -447,4 +447,30 @@ protected override CreateParams CreateParams
private readonly record struct RenderMoveLine(string Text, Image? Icon, Color Color);
private readonly record struct RenderTextLine(string Text, Color Color, int TopPadding, int BottomPadding);
/// <summary>
/// Moves the form to the specified screen coordinates without resizing or changing its z-order.
/// </summary>
/// <remarks>
/// This method updates the form's position using the Win32 SetWindowPos API with flags that minimize redraws and prevent activation or z-order changes.
/// Use this method when you need to reposition the form efficiently without affecting its size or focus.
/// </remarks>
/// <param name="x">The new horizontal position, in pixels, of the form's upper-left corner relative to the screen.</param>
/// <param name="y">The new vertical position, in pixels, of the form's upper-left corner relative to the screen.</param>
public void MoveForm(int x, int y)
{
const uint SWP_NOSIZE = 0x0001;
const uint SWP_NOZORDER = 0x0004;
const uint SWP_NOREDRAW = 0x0008;
const uint SWP_NOACTIVATE = 0x0010;
const uint SWP_NOSENDCHANGING = 0x0400;
const uint SWP_ASYNCWINDOWPOS = 0x4000;
const uint flags = SWP_NOZORDER | SWP_NOSIZE | SWP_NOREDRAW | SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_ASYNCWINDOWPOS;
SetWindowPos(Handle, 0, x, y, 0, 0, flags);
return;
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern bool SetWindowPos(nint hWnd, nint hWndInsertAfter, int x, int y, int cx, int cy, uint uFlags);
}
}

View File

@ -14,9 +14,9 @@ public static class SlotUtil
/// <summary>
/// Gets the background image for a slot based on the provided <see cref="type"/>.
/// </summary>
public static Bitmap GetTouchTypeBackground(SlotTouchType type) => type switch
public static Bitmap? GetTouchTypeBackground(SlotTouchType type) => type switch
{
SlotTouchType.None => SpriteUtil.Spriter.Transparent,
SlotTouchType.None => null,
SlotTouchType.Get => SpriteUtil.Spriter.View,
SlotTouchType.Set => SpriteUtil.Spriter.Set,
SlotTouchType.Delete => SpriteUtil.Spriter.Delete,
@ -42,6 +42,9 @@ public static class SlotUtil
/// </summary>
public static void UpdateSlot(PictureBox pb, ISlotInfo info, PKM pk, SaveFile sav, SlotVisibilityType flags, SlotTouchType t = SlotTouchType.None)
{
pb.Image?.Dispose();
pb.BackgroundImage?.Dispose();
pb.BackgroundImage = GetTouchTypeBackground(t);
if (pk.Species == 0) // Nothing in slot
{

View File

@ -103,7 +103,7 @@ public void UpdatePreviewPosition(Point location)
var cLoc = Cursor.Position;
var shift = Settings.PreviewCursorShift;
cLoc.Offset(shift);
Previewer.Location = cLoc;
Previewer.MoveForm(cLoc.X, cLoc.Y);
}
public void Show(Control pb, IEncounterInfo enc)

View File

@ -54,6 +54,7 @@ public SAV_BoxViewer(SAVEditor p, SlotChangeManager m, int box)
if (parent.menu.mnuVSD.Visible)
return;
Box.CurrentBox = e.Delta > 1 ? Box.Editor.MoveLeft() : Box.Editor.MoveRight();
m.MouseRestart();
};
var mnu = parent.SlotPictureBoxes[0].ContextMenuStrip;

View File

@ -15,6 +15,8 @@ public sealed partial class SAV_GroupViewer : Form
private readonly IReadOnlyList<SlotGroup> Groups;
private readonly SummaryPreviewer Preview = new();
private PictureBox? Hover;
public int CurrentGroup { get; set; } = -1;
public SAV_GroupViewer(SaveFile sav, IPKMView view, IReadOnlyList<SlotGroup> groups)
@ -28,7 +30,12 @@ public SAV_GroupViewer(SaveFile sav, IPKMView view, IReadOnlyList<SlotGroup> gro
Regenerate(count);
CenterToParent();
MouseWheel += (_, e) => CurrentGroup = e.Delta > 1 ? MoveLeft() : MoveRight();
MouseWheel += (_, e) =>
{
CurrentGroup = e.Delta > 1 ? MoveLeft() : MoveRight();
if (Hover is { } pb)
HoverSlot(pb);
};
var names = groups.Select(z => $"{z.GroupName}").ToArray();
CB_BoxSelect.Items.AddRange(names);
@ -48,7 +55,11 @@ public SAV_GroupViewer(SaveFile sav, IPKMView view, IReadOnlyList<SlotGroup> gro
pb.ContextMenuStrip = mnu;
pb.MouseMove += (_, args) => Preview.UpdatePreviewPosition(args.Location);
pb.MouseEnter += (_, _) => HoverSlot(pb);
pb.MouseLeave += (_, _) => Preview.Clear();
pb.MouseLeave += (_, _) =>
{
Preview.Clear();
Hover = null;
};
}
FormClosing += (_, _) => Preview.Clear();
}
@ -59,6 +70,7 @@ private void HoverSlot(PictureBox pb)
var index = Box.Entries.IndexOf(pb);
var slot = group.Slots[index];
Preview.Show(pb, slot, group.Type);
Hover = pb;
}
private void OmniClick(object sender, EventArgs e)