L6 toolbar polish: single-row faces, Cancel RT -> overflow, Re-capture between groups
Button faces now show only the short label (keybinding moved to hover tooltip as "name — binding"). Cancel RT joins the overflow menu alongside Capture RT. Re-capture sits between the capture and placement clusters. Toolbar heights 40->28.
This commit is contained in:
+6
-19
@@ -16,28 +16,15 @@ int totalButtons(const std::vector<ClusterSpec>& clusters) {
|
||||
return n;
|
||||
}
|
||||
|
||||
// Fills a slot's label / binding sub-rects from its box per the spec. The binding is the
|
||||
// bottom `bindingHeight` micro strip; the label is the remainder above it, both inset
|
||||
// horizontally so text clears the button edge. A button shorter than minSplitHeight is not
|
||||
// split: bindingBox stays empty and the label fills the interior (the shell draws only the
|
||||
// label — graceful, no clipped micro row).
|
||||
void fillTextRects(ActionBarSlot& s, const ActionBarSpec& spec) {
|
||||
// Fills a slot's label rect from its box. The label spans the full button height — a single-row
|
||||
// short label (L6: keybinding sub-row removed from the face; binding is in the hover tooltip).
|
||||
// Insets horizontally so text clears the button edge.
|
||||
void fillTextRects(ActionBarSlot& s, const ActionBarSpec& /*spec*/) {
|
||||
const int hpad = 4; // horizontal text inset inside the button
|
||||
const int innerX = s.x + hpad;
|
||||
const int innerW = s.width - 2 * hpad;
|
||||
if (innerW <= 0) return; // too narrow for text; leave sub-rects empty
|
||||
|
||||
if (s.height >= spec.minSplitHeight && spec.bindingHeight > 0 &&
|
||||
s.height - spec.bindingHeight > 0) {
|
||||
const int bindH = spec.bindingHeight;
|
||||
const int labelH = s.height - bindH;
|
||||
s.labelX = innerX; s.labelY = s.y; s.labelW = innerW; s.labelH = labelH;
|
||||
s.bindX = innerX; s.bindY = s.y + labelH; s.bindW = innerW; s.bindH = bindH;
|
||||
} else {
|
||||
// Too short to split — label fills the interior; no binding row.
|
||||
s.labelX = innerX; s.labelY = s.y; s.labelW = innerW; s.labelH = s.height;
|
||||
s.bindX = s.bindY = s.bindW = s.bindH = 0;
|
||||
}
|
||||
if (innerW <= 0) return; // too narrow for text; leave label rect empty
|
||||
s.labelX = innerX; s.labelY = s.y; s.labelW = innerW; s.labelH = s.height;
|
||||
}
|
||||
|
||||
// Tiles the first `visible` buttons into slots, cluster by cluster, left to right. This is the
|
||||
|
||||
+20
-30
@@ -1,12 +1,13 @@
|
||||
#pragma once
|
||||
// action_bar — the REAPER-free, LICE-free layout + hit-test math behind the bank_panel's
|
||||
// TASK-GROUPED toolbars (Phase L, L2 + L4). L2's dock-panel layout redesign (DS-3: a thorough
|
||||
// layout, not a re-skin) groups the action-trigger button inventory BY TASK — a compact bar of
|
||||
// clusters instead of one flat equal-tiled strip (the M11 action_buttons row this supersedes
|
||||
// for the panel's action inventory). Each button carries a label sub-rect and a keybinding-help
|
||||
// MICRO sub-rect ("icon+label, keybinding as a micro sub-label" — the L2 contract), and the bar
|
||||
// degrades gracefully on a narrow panel by dropping WHOLE trailing buttons (never clipping) so
|
||||
// the frequent leading cluster survives.
|
||||
// TASK-GROUPED toolbars (Phase L, L2 + L4 + L6). L2's dock-panel layout redesign (DS-3: a
|
||||
// thorough layout, not a re-skin) groups the action-trigger button inventory BY TASK — a compact
|
||||
// bar of clusters instead of one flat equal-tiled strip (the M11 action_buttons row this
|
||||
// supersedes for the panel's action inventory). Each button carries a label sub-rect spanning
|
||||
// its full height — a single-row short label (L6: the keybinding sub-row was on the button face
|
||||
// through L5; L6 moves it to the hover tooltip instead). The bar degrades gracefully on a narrow
|
||||
// panel by dropping WHOLE trailing buttons (never clipping) so the frequent leading cluster
|
||||
// survives.
|
||||
//
|
||||
// L4 re-homes the inventory across TWO toolbars, BOTH driven by this one module: a TOP toolbar
|
||||
// (Capture + Placement — the two acts the tool exists for) and a BOTTOM toolbar (the Design-View
|
||||
@@ -17,8 +18,8 @@
|
||||
// Why pure (CLAUDE.md §load-bearing split, DS-1 caution): the panel shell owns the SWELL
|
||||
// window, the L1-kit draws, and the NamedCommandLookup/Main_OnCommand dispatch — all
|
||||
// DAW-verified. What is NOT DAW-bound — how the clusters tile the bar, where each button and
|
||||
// its two text sub-rects sit, and which button a click hits — lives HERE, unit-tested outside
|
||||
// the DAW. Mirror of mode_switch / action_buttons / prune_button.
|
||||
// its label sub-rect sit, and which button a click hits — lives HERE, unit-tested outside the
|
||||
// DAW. Mirror of mode_switch / action_buttons / prune_button.
|
||||
//
|
||||
// NAME NOTE (brief §name-collision): ButtonRect / ButtonStripRect / ActionButtonRect /
|
||||
// SegmentRect / CellRect / FooterRect / KitButtonBox are already owned in this namespace, so
|
||||
@@ -74,10 +75,9 @@ struct ActionBarRect {
|
||||
// position in the caller's flat action list (the caller supplies actions in cluster order, so
|
||||
// index also selects the action to fire on a hit). `cluster` is the task group it was laid out
|
||||
// under (surfaced so a test can assert the grouping is structural, and the shell can tint a
|
||||
// cluster). `box` is the whole button rect; `labelBox` and `bindingBox` split it into the
|
||||
// action-name row (top) and the keybinding MICRO row (bottom) so the shell draws each with the
|
||||
// matching kit font. Only VISIBLE buttons get a slot — a button that does not fit is omitted,
|
||||
// never returned clipped, so every slot is fully drawable.
|
||||
// cluster). `box` is the whole button rect; `labelBox` is the text area inset horizontally so
|
||||
// text clears the button edge. Only VISIBLE buttons get a slot — a button that does not fit is
|
||||
// omitted, never returned clipped, so every slot is fully drawable.
|
||||
struct ActionBarSlot {
|
||||
int index = 0;
|
||||
ActionCluster cluster = ActionCluster::Capture;
|
||||
@@ -85,22 +85,16 @@ struct ActionBarSlot {
|
||||
int y = 0;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
// Text sub-rects (absolute, top-left origin), both inside `box`. bindingBox is the bottom
|
||||
// micro strip; labelBox is the remainder above it. When the button is too short to split
|
||||
// (height < a minimum), bindingBox is empty (width/height 0) and labelBox is the whole
|
||||
// interior — the shell then draws only the label (graceful, no clipped micro row).
|
||||
// Label rect (absolute, top-left origin), inside `box`. The label spans the full button
|
||||
// height — a single-row short label only (L6: keybinding sub-row removed from the face;
|
||||
// binding is surfaced in the hover tooltip instead).
|
||||
int labelX = 0, labelY = 0, labelW = 0, labelH = 0;
|
||||
int bindX = 0, bindY = 0, bindW = 0, bindH = 0;
|
||||
|
||||
bool bindingEmpty() const { return bindW <= 0 || bindH <= 0; }
|
||||
|
||||
bool operator==(const ActionBarSlot& o) const {
|
||||
return index == o.index && cluster == o.cluster &&
|
||||
x == o.x && y == o.y && width == o.width && height == o.height &&
|
||||
labelX == o.labelX && labelY == o.labelY &&
|
||||
labelW == o.labelW && labelH == o.labelH &&
|
||||
bindX == o.bindX && bindY == o.bindY &&
|
||||
bindW == o.bindW && bindH == o.bindH;
|
||||
labelW == o.labelW && labelH == o.labelH;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -124,16 +118,12 @@ struct ClusterSpec {
|
||||
// task grouping reads visually; the 8px-grid density decision).
|
||||
// * sidePad — left/right inset from the bar edges to the first/last button.
|
||||
// * verticalInset — top/bottom gap inside the bar (buttons read as raised, not full-bleed).
|
||||
// * bindingHeight — height of the keybinding MICRO sub-row at the button's bottom.
|
||||
// * minSplitHeight— a button shorter than this is not split (bindingBox empty; label fills).
|
||||
struct ActionBarSpec {
|
||||
int buttonWidth = 108;
|
||||
int buttonGap = 4;
|
||||
int clusterGap = 16;
|
||||
int sidePad = 8;
|
||||
int verticalInset = 3;
|
||||
int bindingHeight = 11;
|
||||
int minSplitHeight = 30;
|
||||
};
|
||||
|
||||
// How many buttons (from the front, cluster by cluster) fit the bar at `spec.buttonWidth`.
|
||||
@@ -152,9 +142,9 @@ BarFit computeBarFit(const ActionBarRect& bar, const std::vector<ClusterSpec>& c
|
||||
// Lays out the VISIBLE buttons (per computeBarFit) left-to-right in cluster order: buttons
|
||||
// pack at buttonWidth with buttonGap inside a cluster and clusterGap between clusters, starting
|
||||
// at bar.x + sidePad. Each slot carries its flat action index, its cluster, its box, and the
|
||||
// label / keybinding sub-rects. Empty clusters emit no gap. Returns exactly visibleCount slots
|
||||
// in ascending index order. A degenerate bar (width/height <= 0), an empty cluster list, or a
|
||||
// non-positive buttonWidth yields empty.
|
||||
// label sub-rect (full-height single row). Empty clusters emit no gap. Returns exactly
|
||||
// visibleCount slots in ascending index order. A degenerate bar (width/height <= 0), an empty
|
||||
// cluster list, or a non-positive buttonWidth yields empty.
|
||||
std::vector<ActionBarSlot> computeBarSlots(const ActionBarRect& bar,
|
||||
const std::vector<ClusterSpec>& clusters,
|
||||
const ActionBarSpec& spec);
|
||||
|
||||
+47
-54
@@ -47,7 +47,6 @@
|
||||
#include <vector>
|
||||
|
||||
#include "action_bar.h" // pure TASK-GROUPED action-bar layout + hit-test (L2)
|
||||
#include "action_buttons.h" // pure label format (formatButtonLabel) — reused by the L2 bar (M11)
|
||||
#include "actions.h" // persistBankOp — shared undo-block wrapper (R-B panel path)
|
||||
#include "drag_out.h" // pure gesture-boundary decision + path-list assembly (M11)
|
||||
#include "drag_out_win.h" // OLE / SWELL drag-out initiation seam (M11)
|
||||
@@ -162,8 +161,8 @@ constexpr int kFooterHeight = 30;
|
||||
// * kBottomToolbarHeight — the BOTTOM toolbar (Design-View tag/switch verbs) directly above
|
||||
// the footer (L4 §2). This is the L2 action-bar band, repurposed.
|
||||
// The kBarSpec metrics the bars consume live near the draw below; only heights live here.
|
||||
constexpr int kTopToolbarHeight = 40; // taller — hosts the label + keybinding micro sub-row
|
||||
constexpr int kBottomToolbarHeight = 40; // same shape (label + keybinding sub-row)
|
||||
constexpr int kTopToolbarHeight = 28; // single-row label face (L6: keybinding sub-row removed)
|
||||
constexpr int kBottomToolbarHeight = 28; // same shape — both bars consistent
|
||||
|
||||
// --- Tooltip (Phase L, L5) ----------------------------------------------------
|
||||
// The custom hover-delay tooltip's timing + approximate text metrics. The delay matches the
|
||||
@@ -793,13 +792,14 @@ struct ActionBarRow {
|
||||
// for the top bar (its actions are unconditional triggers).
|
||||
};
|
||||
|
||||
// The TOP toolbar inventory (L5 refinement 1): the FREQUENT acts only — Capture (item / track)
|
||||
// then Placement (insert / insert-conform) then Maintenance (re-capture / cancel RT). The three
|
||||
// RARE capture variants (Batch Items / Batch Razor / Capture RT) are re-homed OFF the visible
|
||||
// bar into the far-right "⋯" overflow menu (overflowMenuRows) — same registered actions, same
|
||||
// command-id contract, just a different home. Capture scopes come from captureActionTable()
|
||||
// (render_settings, pure); the rest are the registered M11/M10/M8 commands. Built once per
|
||||
// draw/click. Each row carries its full (prefix-stripped) action name for the hover tooltip.
|
||||
// The TOP toolbar inventory (L6 refinement): the FREQUENT acts only — Capture (item / track)
|
||||
// then Re-capture (Maintenance, set between the two capture verbs and the placement verbs) then
|
||||
// Placement (insert / insert-conform). The FOUR RARE variants (Batch Items / Batch Razor /
|
||||
// Capture RT / Cancel RT) are ALL in the far-right "⋯" overflow menu (overflowMenuRows) —
|
||||
// same registered actions, same command-id contract, just a different home. Capture scopes come
|
||||
// from captureActionTable() (render_settings, pure); the rest are the registered M11/M10/M8
|
||||
// commands. Built once per draw/click. Each row carries its full (prefix-stripped) action name
|
||||
// for the hover tooltip.
|
||||
std::vector<ActionBarRow> topBarRows() {
|
||||
std::vector<ActionBarRow> rows;
|
||||
// Capture cluster — the primary gesture, leftmost. Face is a terse "Capture Item/Track";
|
||||
@@ -811,26 +811,26 @@ std::vector<ActionBarRow> topBarRows() {
|
||||
rows.push_back({def.commandSuffix, label, def.descriptionPhrase,
|
||||
ActionCluster::Capture, true});
|
||||
}
|
||||
// Maintenance cluster — Re-capture from source (M10), placed BETWEEN the capture group and
|
||||
// the placement group so its position reads "refine the last capture before placing it".
|
||||
// Cancel RT lives in the overflow menu (both realtime verbs share that home — L6).
|
||||
rows.push_back({"RECAPTURE_FROM_SOURCE", "Re-capture",
|
||||
"re-capture from source", ActionCluster::Maintenance, true});
|
||||
// Placement cluster — the second act (still a distinct on-demand act; no auto-insert).
|
||||
rows.push_back({"INSERT_SELECTED", "Insert",
|
||||
"insert selected sample at edit cursor", ActionCluster::Placement, true});
|
||||
rows.push_back({"INSERT_SELECTED_CONFORM", "Insert Conform",
|
||||
"insert selected sample at edit cursor (conform to tempo)",
|
||||
ActionCluster::Placement, true});
|
||||
// Maintenance cluster — rarer upkeep: re-capture from source (M10) and cancel an
|
||||
// in-flight realtime capture (M8). Capture-adjacent, so they live in the top toolbar.
|
||||
rows.push_back({"RECAPTURE_FROM_SOURCE", "Re-capture",
|
||||
"re-capture from source", ActionCluster::Maintenance, true});
|
||||
rows.push_back({"CANCEL_REALTIME_CAPTURE", "Cancel RT",
|
||||
"cancel realtime capture", ActionCluster::Maintenance, true});
|
||||
return rows;
|
||||
}
|
||||
|
||||
// The TOP-toolbar OVERFLOW menu inventory (L5 refinement 1): the three rare capture variants,
|
||||
// pulled off the visible bar into the far-right "⋯" menu button's popup. Each fires the SAME
|
||||
// existing registered command id via the SAME NamedCommandLookup/Main_OnCommand contract — no
|
||||
// action changes. The fullName is the popup entry text (the terse shortLabel is unused for menu
|
||||
// items; the popup has room for the full name). Order matches the L4 capture-cluster order.
|
||||
// The TOP-toolbar OVERFLOW menu inventory (L6): four items pulled off the visible bar into the
|
||||
// far-right "⋯" menu button's popup — the three rare batch/realtime capture variants plus
|
||||
// Cancel RT (both realtime verbs share the menu home). Each fires the SAME existing registered
|
||||
// command id via the SAME NamedCommandLookup/Main_OnCommand contract — no action changes. The
|
||||
// fullName is the popup entry text (the terse shortLabel is unused for menu items; the popup has
|
||||
// room for the full name). Batch entries first, then the two realtime verbs.
|
||||
std::vector<ActionBarRow> overflowMenuRows() {
|
||||
return {
|
||||
{"CAPTURE_BATCH_ITEMS", "Batch Items",
|
||||
@@ -839,6 +839,8 @@ std::vector<ActionBarRow> overflowMenuRows() {
|
||||
"batch capture razor areas (one per area)", ActionCluster::Capture, true},
|
||||
{"CAPTURE_TRACK_REALTIME", "Capture RT",
|
||||
"capture selected track (realtime)", ActionCluster::Capture, true},
|
||||
{"CANCEL_REALTIME_CAPTURE", "Cancel RT",
|
||||
"cancel realtime capture", ActionCluster::Maintenance, true},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -886,8 +888,9 @@ std::vector<ActionBarRow> bottomBarRows() {
|
||||
// The cluster button-count specs for a given row set, in the row list's cluster order (so the
|
||||
// pure action_bar's flat index lines up with the row list). Handles all five cluster kinds;
|
||||
// empty clusters contribute a 0-count spec (action_bar skips them, emitting no gap). The spec
|
||||
// order follows each toolbar's fixed layout order (top: Capture, Placement, Maintenance;
|
||||
// bottom: Tagging, Switching).
|
||||
// order follows each toolbar's fixed layout order (top: Capture, Maintenance, Placement —
|
||||
// Re-capture sits between the two capture verbs and the placement verbs; bottom: Tagging,
|
||||
// Switching). The bottom bar's Maintenance count is 0, so the order change is transparent there.
|
||||
std::vector<ClusterSpec> actionBarClusters(const std::vector<ActionBarRow>& rows) {
|
||||
int nCap = 0, nPlace = 0, nMaint = 0, nTag = 0, nSwitch = 0;
|
||||
for (const ActionBarRow& r : rows) {
|
||||
@@ -901,8 +904,8 @@ std::vector<ClusterSpec> actionBarClusters(const std::vector<ActionBarRow>& rows
|
||||
}
|
||||
return {
|
||||
{ActionCluster::Capture, nCap},
|
||||
{ActionCluster::Placement, nPlace},
|
||||
{ActionCluster::Maintenance, nMaint},
|
||||
{ActionCluster::Placement, nPlace},
|
||||
{ActionCluster::Tagging, nTag},
|
||||
{ActionCluster::Switching, nSwitch},
|
||||
};
|
||||
@@ -910,11 +913,10 @@ std::vector<ClusterSpec> actionBarClusters(const std::vector<ActionBarRow>& rows
|
||||
|
||||
// The toolbar layout spec (the panel's 8px-grid density decision). One source of truth shared
|
||||
// by both toolbars' draw and hit-test (identical button shape top and bottom). L5 refinement 5:
|
||||
// clusterGap widened 16 -> 24 (a 6:1 inter/intra ratio) so semantic groups read AS groups — the
|
||||
// gap between clusters is visibly larger than the gap between buttons within a cluster.
|
||||
// clusterGap widened 16 -> 24 (a 6:1 inter/intra ratio) so semantic groups read AS groups. L6:
|
||||
// bindingHeight / minSplitHeight removed — buttons are single-row label-only faces now.
|
||||
const ActionBarSpec kBarSpec{/*buttonWidth=*/108, /*buttonGap=*/4, /*clusterGap=*/24,
|
||||
/*sidePad=*/8, /*verticalInset=*/3, /*bindingHeight=*/11,
|
||||
/*minSplitHeight=*/30};
|
||||
/*sidePad=*/8, /*verticalInset=*/3};
|
||||
|
||||
// The BOTTOM toolbar band: a fixed-height band directly above the footer (below the split
|
||||
// body). Degenerate (height 0) when the client is too short to host it above the footer.
|
||||
@@ -950,12 +952,13 @@ std::string barBindingText(int cmd) {
|
||||
}
|
||||
|
||||
// Draws one task-grouped toolbar through the L1 kit: a bg/panel band, then each visible button
|
||||
// as a kit drawButton (rest/hover/disabled) with the action NAME on the label row and the key
|
||||
// binding (or "unbound") on the Micro sub-row. Overflow drops WHOLE trailing buttons (the pure
|
||||
// layout returns only the buttons that fit), so nothing is drawn clipped. `hoverKind` selects
|
||||
// which HoverKind this bar's buttons use (TopBarButton / BottomBarButton) so the two toolbars'
|
||||
// hover states never cross. `topDivider` draws a hairline at the band's top edge (the bottom
|
||||
// toolbar's elevation over the split body); the top toolbar draws it at its bottom edge instead.
|
||||
// as a kit drawButton (rest/hover/disabled) with the action short label on the single-row face.
|
||||
// Overflow drops WHOLE trailing buttons (the pure layout returns only the buttons that fit), so
|
||||
// nothing is drawn clipped. `hoverKind` selects which HoverKind this bar's buttons use
|
||||
// (TopBarButton / BottomBarButton) so the two toolbars' hover states never cross. `topDivider`
|
||||
// draws a hairline at the band's top edge (the bottom toolbar's elevation over the split body);
|
||||
// the top toolbar draws it at its bottom edge instead. Key binding help is in the hover tooltip
|
||||
// (L6), not on the button face — the face shows only shortLabel.
|
||||
void drawToolbar(LICE_IBitmap* bmp, const ActionBarRect& bar,
|
||||
const std::vector<ActionBarRow>& rows, HoverKind hoverKind, bool topDivider) {
|
||||
if (bar.height <= 0 || bar.width <= 0) return;
|
||||
@@ -983,8 +986,8 @@ void drawToolbar(LICE_IBitmap* bmp, const ActionBarRect& bar,
|
||||
state = InteractionState::Hover;
|
||||
|
||||
// The button surface (drawButton draws the micro-gradient + rounded border + honors
|
||||
// the state). The label is drawn separately below so the binding sub-row can use the
|
||||
// Micro font, so pass no label to drawButton.
|
||||
// the state). The label is drawn separately so the text role tracks the state correctly;
|
||||
// pass no label to drawButton.
|
||||
const KitButtonBox box{KitBox{s.x, s.y, s.width, s.height}};
|
||||
drawButton(bmp, box, /*label=*/nullptr, state, /*warn=*/false);
|
||||
|
||||
@@ -992,19 +995,6 @@ void drawToolbar(LICE_IBitmap* bmp, const ActionBarRect& bar,
|
||||
(state == InteractionState::Disabled) ? Role::TextDim : Role::TextPrimary;
|
||||
const KitBox labelBox{s.labelX, s.labelY, s.labelW, s.labelH};
|
||||
kitText(bmp, labelBox, row.shortLabel.c_str(), Font::Label, textRole, Align::Center);
|
||||
|
||||
if (!s.bindingEmpty()) {
|
||||
// The keybinding help sub-label, dim + Micro. formatButtonLabel's blank/unbound
|
||||
// collapse is reused so an unbound action reads "(unbound)" cleanly; here we want
|
||||
// just the binding token (name is already on the label row), so format the binding
|
||||
// alone and strip the leading name-less case.
|
||||
const std::string binding = barBindingText(cmd);
|
||||
const std::string sub = formatButtonLabel("", binding); // "" + " (unbound)" / " <bind>"
|
||||
std::size_t start = sub.find_first_not_of(' ');
|
||||
const std::string shown = (start == std::string::npos) ? sub : sub.substr(start);
|
||||
const KitBox bindBox{s.bindX, s.bindY, s.bindW, s.bindH};
|
||||
kitText(bmp, bindBox, shown.c_str(), Font::Micro, Role::TextDim, Align::Center);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1098,11 +1088,14 @@ bool currentTooltip(int w, int h, std::string& textOut, int& ax, int& ay, int& a
|
||||
|
||||
// The full name is stored already prefix-free, but strip defensively in case a source ever
|
||||
// carries the "ReaSampler:" display prefix (the tooltip must never show it — L5 refinement 2).
|
||||
// Intentionally distinct sources: the tooltip reads the registered phrase (fullName) while the
|
||||
// keybinding sub-row in drawToolbar reads the live binding via kbd_getTextFromCmd. Do not
|
||||
// unify them — each serves a different purpose and has a different lifetime.
|
||||
textOut = stripActionPrefix(rows[static_cast<std::size_t>(hv.index)].fullName,
|
||||
actionDisplayPrefix());
|
||||
// L6: the keybinding sub-row was removed from the button face, so the tooltip now carries
|
||||
// both the name AND the binding (when bound) — e.g. "capture selected item — F5". When the
|
||||
// action is unbound the tooltip shows only the name (no "(unbound)" noise in the tooltip).
|
||||
const std::string phrase = stripActionPrefix(rows[static_cast<std::size_t>(hv.index)].fullName,
|
||||
actionDisplayPrefix());
|
||||
const int cmd = resolveBarCommandId(rows[static_cast<std::size_t>(hv.index)]);
|
||||
const std::string binding = barBindingText(cmd);
|
||||
textOut = binding.empty() ? phrase : phrase + " \xe2\x80\x94 " + binding; // " — " (em dash, UTF-8)
|
||||
ax = slot->x; ay = slot->y; aw = slot->width; ah = slot->height;
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user