L5: dock-panel button refinements — overflow menu, tooltips, opposite-mode tag buttons

Top-bar rare-capture variants move to a right-anchored More popup; short faces gain
hover-delay full-name tooltips (prefix stripped); bottom bar becomes four opposite-mode
Item/Track tag buttons + Show Both (Toggle/Activates dropped); wider cluster gaps. New
pure overflow_menu/mode_enable/tooltip modules, CTest-covered. Same actions, same contract.
This commit is contained in:
2026-07-26 23:56:49 -04:00
parent 0c7b871d8d
commit 7cd0771e45
11 changed files with 1025 additions and 53 deletions
+62
View File
@@ -0,0 +1,62 @@
#pragma once
// tooltip — the REAPER-free layout math + text helper behind the bank_panel's custom hover-delay
// tooltip (Phase L, L5, refinement 2). Button FACES stay short (the terse shortLabel); hovering a
// button for a short delay pops a small tooltip carrying the FULL action name with the
// "ReaSampler:" display prefix stripped. The tooltip is a custom LICE-kit draw (NOT the native
// Win32 / SWELL tooltip control) — chosen so it is uniform across platforms and consistent with
// the L1 kit (brief §tooltip mechanism). The DAW-bound parts (the hover timer, the LICE overlay
// draw, the kbd/action-name query) live in the shell; what is NOT DAW-bound — WHERE the tooltip
// box sits relative to its anchor button within the panel client, and stripping the display
// prefix — lives here, unit-tested outside the DAW. Mirror of prune_button / component_geometry.
//
// PURE MODULE: NO REAPER types, NO SWELL, NO LICE, NO vendor/ includes. Standard library only.
#include <string>
namespace reasampler {
// The tooltip's box (top-left origin, SWELL/LICE convention). A zero-area rect means "do not
// draw" (degenerate inputs); the caller checks empty() before drawing.
struct TooltipBox {
int x = 0;
int y = 0;
int width = 0;
int height = 0;
bool empty() const { return width <= 0 || height <= 0; }
bool operator==(const TooltipBox& o) const {
return x == o.x && y == o.y && width == o.width && height == o.height;
}
};
// Placement inputs, in pixels.
// * gap — vertical gap between the anchor button and the tooltip box.
// * padX/padY — horizontal / vertical text padding inside the box.
// * margin — minimum clearance kept from the client edges when clamping.
struct TooltipSpec {
int gap = 4;
int padX = 6;
int padY = 3;
int margin = 2;
};
// Strips the action DISPLAY PREFIX from a full action name for the tooltip face. The registered
// gaccel name is composed as `prefix + phrase` (prefix from actionDisplayPrefix(), e.g.
// "ReaSampler: "); the tooltip shows only the phrase. If `fullName` does not start with
// `prefix`, it is returned unchanged (defensive — a name from an unexpected source still shows).
// An empty prefix returns fullName unchanged.
std::string stripActionPrefix(const std::string& fullName, const std::string& prefix);
// Places a tooltip of pixel size (textW + 2*padX) x (textH + 2*padY) for the button rect
// (anchorX, anchorY, anchorW, anchorH), clamped inside the client rect (0,0,clientW,clientH).
// Preference: BELOW the anchor, horizontally centred on it. If it would clip the bottom edge,
// it flips ABOVE the anchor. It is then clamped horizontally (and vertically as a last resort)
// to stay within `margin` of the client edges. Returns an empty box when the text extent or the
// client is degenerate. `textW`/`textH` are the measured text extents (the shell measures with
// the kit font before calling).
TooltipBox computeTooltip(int anchorX, int anchorY, int anchorW, int anchorH,
int textW, int textH, int clientW, int clientH,
const TooltipSpec& spec);
} // namespace reasampler