fix(ui): stop status-bar tooltips flashing on and off

The strip's built-in item tooltips open below the cursor. With the window
maximized the strip is at the bottom of the screen, so Windows pushes the
tooltip back over the cursor; the strip then sees a mouse leave, hides it,
re-shows it on the next hover, and it flickers. Show the tooltips above the
strip instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ajandClaude Opus 5.5 committed 2026-10-28 07:41:15 -04:00
1 parent 63915d6fb6
commit b65a9485c7
3 files changed
+99 -1

No files matched your search

+3
View File
@@ -21,7 +21,10 @@ namespace OpenNest.Forms
components.Dispose();
}
if (disposing)
{
updaterStatus?.Dispose();
statusStripToolTips?.Dispose();
}
base.Dispose(disposing);
}
+2 -1
View File
@@ -112,7 +112,7 @@ namespace OpenNest.Forms
Icon = Resources.app_icon;
statusStrip1.Items.Insert(statusStrip1.Items.IndexOf(materialStatusLabel) + 1, ledgerStatusLabel);
ledgerStatusLabel.Click += LedgerStatusLabel_Click;
statusStrip1.ShowItemToolTips = true; // The hold list lives in the ledger label's tooltip.
statusStripToolTips = new StatusStripToolTips(statusStrip1); // The hold list lives in the ledger label's tooltip.
statusBar = new MainStatusBar(statusLabel1, locationStatusLabel, selectionStatusLabel,
machineStatusLabel, materialStatusLabel, plateUtilStatusLabel, ledgerStatusLabel);
toolStrip1.Items.Add(CreateActionButton("btnCutPlanner", "Plan Cutting",
@@ -168,6 +168,7 @@ namespace OpenNest.Forms
}
private UpdaterStatus updaterStatus;
private StatusStripToolTips statusStripToolTips;
private void InitializeHelpMenu()
{
+94
View File
@@ -0,0 +1,94 @@
using System;
using System.Drawing;
using System.Windows.Forms;
namespace OpenNest.Forms
{
/// <summary>
/// Shows a status strip's item tooltips above the strip. The strip's own tooltips open
/// below the cursor; at the bottom of the screen Windows pushes them back over the
/// cursor, the strip sees a mouse leave and hides them, and they flash on and off.
/// </summary>
internal sealed class StatusStripToolTips : IDisposable
{
private const int Gap = 2;
private readonly ToolStrip strip;
private readonly ToolTip toolTip = new();
private readonly Timer hoverTimer = new() { Interval = SystemInformation.MouseHoverTime };
private ToolStripItem hoverItem;
private string shownText;
public StatusStripToolTips(ToolStrip strip)
{
this.strip = strip;
strip.ShowItemToolTips = false;
strip.MouseMove += Strip_MouseMove;
strip.MouseLeave += Strip_MouseLeave;
strip.MouseDown += Strip_MouseDown;
hoverTimer.Tick += HoverTimer_Tick;
}
public void Dispose()
{
hoverTimer.Dispose();
toolTip.Dispose();
}
private void Strip_MouseMove(object sender, MouseEventArgs e)
{
var item = strip.GetItemAt(e.Location);
if (item == hoverItem)
return;
Hide();
hoverItem = item;
if (!string.IsNullOrEmpty(item?.ToolTipText))
hoverTimer.Start();
}
private void Strip_MouseLeave(object sender, EventArgs e)
{
Hide();
hoverItem = null;
}
// The next move re-arms the hover, so a click that changes the text (a hold refresh) shows the new tip.
private void Strip_MouseDown(object sender, MouseEventArgs e)
{
Hide();
hoverItem = null;
}
private void HoverTimer_Tick(object sender, EventArgs e)
{
hoverTimer.Stop();
Show();
}
private void Show()
{
var text = hoverItem?.ToolTipText;
if (string.IsNullOrEmpty(text))
{
Hide();
return;
}
// The tooltip draws its text in the status font plus a few pixels of border and margin.
var height = TextRenderer.MeasureText(text, SystemFonts.StatusFont).Height + 10;
toolTip.Show(text, strip, hoverItem.Bounds.Left, -height - Gap);
shownText = text;
}
private void Hide()
{
hoverTimer.Stop();
if (shownText == null)
return;
toolTip.Hide(strip);
shownText = null;
}
}
}