From 1db54108ac6c38c5530edbd22c5c9ca17b277deb Mon Sep 17 00:00:00 2001
From: James Groom <OSSYoshiRulz+GitHub@gmail.com>
Date: Fri, 5 Apr 2024 00:14:21 +0000
Subject: [PATCH] Wire up `ScreenshotForm` for the quickslot buttons in the
 status bar

---
 .../savestates/SavestateFile.cs               | 10 +++++
 src/BizHawk.Client.EmuHawk/MainForm.Events.cs | 37 +++++++++++++++++++
 src/BizHawk.Client.EmuHawk/MainForm.cs        | 17 +++++++++
 3 files changed, 64 insertions(+)

diff --git a/src/BizHawk.Client.Common/savestates/SavestateFile.cs b/src/BizHawk.Client.Common/savestates/SavestateFile.cs
index 36643397bf..d277d8d104 100644
--- a/src/BizHawk.Client.Common/savestates/SavestateFile.cs
+++ b/src/BizHawk.Client.Common/savestates/SavestateFile.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
 using System.IO;
 using System.Linq;
 
+using BizHawk.Bizware.BizwareGL;
 using BizHawk.Common;
 using BizHawk.Emulation.Common;
 
@@ -13,6 +14,15 @@ namespace BizHawk.Client.Common
 	/// </summary>
 	public class SavestateFile
 	{
+		public static BitmapBuffer/*?*/ GetFrameBufferFrom(string path)
+		{
+			using var bl = ZipStateLoader.LoadAndDetect(path);
+			if (bl is null) return null;
+			IVideoProvider/*?*/ vp = null;
+			bl.GetLump(BinaryStateLump.Framebuffer, abort: false, br => QuickBmpFile.LoadAuto(br.BaseStream, out vp));
+			return vp is null ? null : new(width: vp.BufferWidth, height: vp.BufferHeight, vp.GetVideoBuffer());
+		}
+
 		private readonly IEmulator _emulator;
 		private readonly IStatable _statable;
 		private readonly IVideoProvider _videoProvider;
diff --git a/src/BizHawk.Client.EmuHawk/MainForm.Events.cs b/src/BizHawk.Client.EmuHawk/MainForm.Events.cs
index e2fd81db5d..af71ec51f9 100644
--- a/src/BizHawk.Client.EmuHawk/MainForm.Events.cs
+++ b/src/BizHawk.Client.EmuHawk/MainForm.Events.cs
@@ -2472,6 +2472,43 @@ namespace BizHawk.Client.EmuHawk
 			}
 		}
 
+		private readonly ScreenshotForm _screenshotTooltip = new();
+
+		private void SlotStatusButtons_MouseEnter(object/*?*/ sender, EventArgs e)
+		{
+			var slot = 10;
+			if (sender == Slot1StatusButton) slot = 1;
+			else if (sender == Slot2StatusButton) slot = 2;
+			else if (sender == Slot3StatusButton) slot = 3;
+			else if (sender == Slot4StatusButton) slot = 4;
+			else if (sender == Slot5StatusButton) slot = 5;
+			else if (sender == Slot6StatusButton) slot = 6;
+			else if (sender == Slot7StatusButton) slot = 7;
+			else if (sender == Slot8StatusButton) slot = 8;
+			else if (sender == Slot9StatusButton) slot = 9;
+			//TODO just put the slot number in Control.Tag already
+			if (!(HasSlot(slot) && ReadScreenshotFromSavestate(slot: slot) is {} bb))
+			{
+				_screenshotTooltip.FadeOut();
+				return;
+			}
+			var width = bb.Width;
+			var height = bb.Height;
+			var location = PointToScreen(MainStatusBar.Location);
+			location.Offset(((e as MouseEventArgs)?.X ?? 50) - width/2, -height);
+			_screenshotTooltip.UpdateValues(
+				bb,
+				captionText: string.Empty,
+				location,
+				width: width,
+				height: height,
+				Graphics.FromHwnd(Handle).MeasureString);
+			_screenshotTooltip.FadeIn();
+		}
+
+		private void SlotStatusButtons_MouseLeave(object/*?*/ sender, EventArgs e)
+			=> _screenshotTooltip.FadeOut();
+
 		private void SlotStatusButtons_MouseUp(object sender, MouseEventArgs e)
 		{
 			var slot = 10;
diff --git a/src/BizHawk.Client.EmuHawk/MainForm.cs b/src/BizHawk.Client.EmuHawk/MainForm.cs
index 87eae0f4a7..da46f59d2b 100644
--- a/src/BizHawk.Client.EmuHawk/MainForm.cs
+++ b/src/BizHawk.Client.EmuHawk/MainForm.cs
@@ -195,6 +195,18 @@ namespace BizHawk.Client.EmuHawk
 			SetStatusBar();
 			_stateSlots.Update(Emulator, MovieSession.Movie, SaveStatePrefix());
 
+			var quickslotButtons = new[]
+			{
+				Slot1StatusButton, Slot2StatusButton, Slot3StatusButton, Slot4StatusButton, Slot5StatusButton,
+				Slot6StatusButton, Slot7StatusButton, Slot8StatusButton, Slot9StatusButton, Slot0StatusButton,
+			};
+			for (var i = 0; i < quickslotButtons.Length; i++)
+			{
+				ref var button = ref quickslotButtons[i];
+				button.MouseEnter += SlotStatusButtons_MouseEnter;
+				button.MouseLeave += SlotStatusButtons_MouseLeave;
+			}
+
 			// New version notification
 			UpdateChecker.CheckComplete += (s2, e2) =>
 			{
@@ -4235,6 +4247,11 @@ namespace BizHawk.Client.EmuHawk
 			return int.Parse(slot.Substring(slot.Length - 1, 1));
 		}
 
+		public BitmapBuffer/*?*/ ReadScreenshotFromSavestate(int slot)
+			=> Emulator.HasSavestates()
+				? SavestateFile.GetFrameBufferFrom($"{SaveStatePrefix()}.QuickSave{slot % 10}.State")
+				: null;
+
 		public bool LoadState(string path, string userFriendlyStateName, bool suppressOSD = false) // Move to client.common
 		{
 			if (!Emulator.HasSavestates()) return false;