#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 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