Merge p10-w1-t2-drop-action-buttons: remove dead action_buttons module
This commit is contained in:
+3
-5
@@ -2,8 +2,7 @@
|
||||
// action_bar — the REAPER-free, LICE-free layout + hit-test math behind the bank_panel's
|
||||
// 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
|
||||
// bar of clusters, each button carrying 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
|
||||
@@ -19,14 +18,13 @@
|
||||
// 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 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.
|
||||
// DAW. Mirror of mode_switch / prune_button.
|
||||
//
|
||||
// NAME NOTE (brief §name-collision): ButtonRect / ButtonStripRect / ActionButtonRect /
|
||||
// SegmentRect / CellRect / FooterRect / KitButtonBox are already owned in this namespace, so
|
||||
// this module's types are ActionBarRect / ActionBarSlot / ActionCluster — grep-checked free
|
||||
// before minting. They are a distinct concept (a task-grouped multi-cluster bar with text
|
||||
// sub-rects) from the flat action_buttons strip, so the separate names are correct, not merely
|
||||
// non-colliding.
|
||||
// sub-rects), so the separate names are correct, not merely non-colliding.
|
||||
//
|
||||
// SCOPE: the destructive PRUNE button is NOT in this bar — it stays set-apart in the footer,
|
||||
// warn-marked, owned by prune_button (L2 keeps prune deliberately away from the frequent
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
// action_buttons — pure implementation. See action_buttons.h. NO REAPER / SWELL / vendor.
|
||||
|
||||
#include "action_buttons.h"
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace reasampler {
|
||||
|
||||
namespace {
|
||||
|
||||
// The left edge of button i when `count` buttons share a strip of the given x-origin and
|
||||
// width. Boundary i is x + (i * width) / count, so button i spans [edge(i), edge(i+1)).
|
||||
// Every boundary derives from the same formula, so consecutive buttons share an exact
|
||||
// edge (no gap, no overlap) and edge(count) == x + width precisely. count assumed >= 1.
|
||||
int buttonEdge(int x, int width, int i, int count) {
|
||||
return x + (i * width) / count;
|
||||
}
|
||||
|
||||
// True for an ASCII space or tab (the whitespace the SDK binding string might carry).
|
||||
bool isBlankChar(char c) { return c == ' ' || c == '\t'; }
|
||||
|
||||
// The trimmed [first, last) view of `s` with leading/trailing blanks removed. Returns
|
||||
// an empty range when `s` is all blanks.
|
||||
std::string trimBlanks(const std::string& s) {
|
||||
std::size_t b = 0;
|
||||
std::size_t e = s.size();
|
||||
while (b < e && isBlankChar(s[b])) ++b;
|
||||
while (e > b && isBlankChar(s[e - 1])) --e;
|
||||
return s.substr(b, e - b);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ButtonFit computeButtonFit(const ButtonStripRect& strip, int buttonCount,
|
||||
int minButtonWidth) {
|
||||
ButtonFit fit;
|
||||
if (buttonCount <= 0 || strip.width <= 0 || minButtonWidth <= 0) return fit;
|
||||
|
||||
int fits = strip.width / minButtonWidth; // how many min-width buttons the strip holds
|
||||
if (fits > buttonCount) fits = buttonCount;
|
||||
if (fits < 0) fits = 0;
|
||||
|
||||
fit.visibleCount = fits;
|
||||
fit.hiddenCount = buttonCount - fits;
|
||||
return fit;
|
||||
}
|
||||
|
||||
std::vector<ActionButtonRect> computeButtonRects(const ButtonStripRect& strip, int buttonCount,
|
||||
int minButtonWidth) {
|
||||
std::vector<ActionButtonRect> rects;
|
||||
const ButtonFit fit = computeButtonFit(strip, buttonCount, minButtonWidth);
|
||||
const int n = fit.visibleCount;
|
||||
if (n <= 0) return rects;
|
||||
|
||||
rects.reserve(static_cast<std::size_t>(n));
|
||||
for (int i = 0; i < n; ++i) {
|
||||
const int left = buttonEdge(strip.x, strip.width, i, n);
|
||||
const int right = buttonEdge(strip.x, strip.width, i + 1, n);
|
||||
ActionButtonRect r;
|
||||
r.index = i;
|
||||
r.x = left;
|
||||
r.y = strip.y;
|
||||
r.width = right - left; // absorbs rounding; visible buttons abut and fill the strip
|
||||
r.height = strip.height;
|
||||
rects.push_back(r);
|
||||
}
|
||||
return rects;
|
||||
}
|
||||
|
||||
int hitTestButton(int px, int py, const ButtonStripRect& strip, int buttonCount,
|
||||
int minButtonWidth) {
|
||||
if (strip.height <= 0) return -1;
|
||||
// Reject anything outside the strip band first (half-open bounds match the rects).
|
||||
if (px < strip.x || px >= strip.x + strip.width ||
|
||||
py < strip.y || py >= strip.y + strip.height)
|
||||
return -1;
|
||||
|
||||
const ButtonFit fit = computeButtonFit(strip, buttonCount, minButtonWidth);
|
||||
const int n = fit.visibleCount;
|
||||
if (n <= 0) return -1;
|
||||
|
||||
// Inside the band: find the visible button whose [edge(i), edge(i+1)) contains px.
|
||||
// A point past the last visible button's right edge (narrow-panel overflow dead-zone)
|
||||
// falls through to -1.
|
||||
for (int i = 0; i < n; ++i) {
|
||||
const int left = buttonEdge(strip.x, strip.width, i, n);
|
||||
const int right = buttonEdge(strip.x, strip.width, i + 1, n);
|
||||
if (px >= left && px < right) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string formatButtonLabel(const std::string& name, const std::string& rawBinding) {
|
||||
const std::string binding = trimBlanks(rawBinding);
|
||||
if (binding.empty()) {
|
||||
return name + " (" + kUnboundMarker + ")";
|
||||
}
|
||||
|
||||
std::string shown = binding;
|
||||
if (static_cast<int>(shown.size()) > kMaxBindingChars) {
|
||||
// Keep the leading portion and mark the truncation with a single-width "~".
|
||||
shown = shown.substr(0, static_cast<std::size_t>(kMaxBindingChars - 1)) + "~";
|
||||
}
|
||||
return name + " " + shown;
|
||||
}
|
||||
|
||||
} // namespace reasampler
|
||||
@@ -1,125 +0,0 @@
|
||||
#pragma once
|
||||
// action_buttons — the REAPER-free layout + label-format math behind the bank_panel's
|
||||
// action-trigger button strip (Milestone 11). A row of LICE-drawn buttons in the docked
|
||||
// panel fires the capture / insert / provenance actions THROUGH the existing command-id
|
||||
// contract (the shell resolves each button's command id at runtime via NamedCommandLookup
|
||||
// and dispatches with Main_OnCommand — this module never touches REAPER), and each button
|
||||
// surfaces the action's current key binding as a reminder label.
|
||||
//
|
||||
// What is NOT DAW-bound lives here so it is unit-tested outside the DAW (CLAUDE.md
|
||||
// §load-bearing split), and it is two mirror-of-mode_switch concerns in one pure module:
|
||||
//
|
||||
// 1. Button-strip layout + hit-test. Unlike the mode switch (which tiles N EQUAL
|
||||
// segments at any width), the button strip must degrade gracefully on a narrow
|
||||
// panel: buttons never shrink below a minimum readable width — instead only as many
|
||||
// as fit are laid out (equally sharing the strip) and the rest are reported hidden.
|
||||
// That is the "overflow handling for narrow panels — no clipped garbage" requirement.
|
||||
// 2. Label-text formatting: (action name + the SDK's binding string) -> the label drawn
|
||||
// on a button, with the unbound / empty / blank cases degraded to an explicit marker
|
||||
// and an over-long binding truncated so it never blows the button's text budget.
|
||||
//
|
||||
// PURE MODULE: NO REAPER types, NO SWELL, NO vendor/ includes. Standard library only.
|
||||
// Builds and unit-tests without REAPER. Mirror of mode_switch / tab_strip.
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace reasampler {
|
||||
|
||||
// The strip the buttons are drawn into, top-left origin (SWELL/LICE convention).
|
||||
// (x, y) is the top-left corner; width/height are the strip extents. The panel reserves
|
||||
// this as a fixed-height band (its own judgment where — above the tail footer).
|
||||
struct ButtonStripRect {
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
|
||||
bool operator==(const ButtonStripRect& o) const {
|
||||
return x == o.x && y == o.y && width == o.width && height == o.height;
|
||||
}
|
||||
};
|
||||
|
||||
// One button's pixel rectangle within the strip, top-left origin, plus the index of the
|
||||
// action it drives in the caller's list (button order). The shell draws the button here,
|
||||
// labels it, and — on a hit at this index — resolves that action's command id and fires.
|
||||
// Only VISIBLE buttons get a rect (a button that does not fit the strip is omitted, never
|
||||
// returned with a clipped/zero width), so every returned rect is fully drawable.
|
||||
struct ActionButtonRect {
|
||||
int index = 0;
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
|
||||
bool operator==(const ActionButtonRect& o) const {
|
||||
return index == o.index && x == o.x && y == o.y &&
|
||||
width == o.width && height == o.height;
|
||||
}
|
||||
};
|
||||
|
||||
// How many of `buttonCount` buttons fit `strip` at a minimum button width of
|
||||
// `minButtonWidth`. This is the overflow decision, split from the rect tiling so the
|
||||
// shell can size an "overflow" affordance / count without re-deriving it. Clamps to
|
||||
// [0, buttonCount]; a non-positive strip width or minButtonWidth yields 0. When all fit,
|
||||
// visibleCount == buttonCount and hiddenCount == 0.
|
||||
struct ButtonFit {
|
||||
int visibleCount = 0; // buttons that fit (and will be laid out)
|
||||
int hiddenCount = 0; // buttonCount - visibleCount (the overflow)
|
||||
};
|
||||
|
||||
ButtonFit computeButtonFit(const ButtonStripRect& strip, int buttonCount,
|
||||
int minButtonWidth);
|
||||
|
||||
// Tiles the VISIBLE buttons (per computeButtonFit) left-to-right across `strip`, sharing
|
||||
// its full width EQUALLY (exact tiling, rounding absorbed at boundaries so buttons abut
|
||||
// with no gap/overlap and the last visible button reaches strip.x + strip.width — the
|
||||
// same boundary discipline as mode_switch). Buttons never render narrower than
|
||||
// minButtonWidth: when not all fit, the visible ones each get width >= minButtonWidth by
|
||||
// construction (fewer buttons over the same strip). Returns exactly visibleCount rects in
|
||||
// button-index order (indices 0..visibleCount-1). buttonCount <= 0, non-positive strip
|
||||
// width, or non-positive minButtonWidth -> empty.
|
||||
std::vector<ActionButtonRect> computeButtonRects(const ButtonStripRect& strip, int buttonCount,
|
||||
int minButtonWidth);
|
||||
|
||||
// Hit-tests a point (SWELL/LICE top-left client coords) against the strip laid out for
|
||||
// `buttonCount` buttons at `minButtonWidth`. Returns the index of the button containing
|
||||
// the point, or -1 for a miss: outside the strip band entirely, or in the strip band but
|
||||
// past the last visible button (the overflow dead-zone on a narrow panel — a harmless
|
||||
// no-op the shell ignores). Half-open bounds [x, x+width) x [y, y+height) match
|
||||
// computeButtonRects so no pixel is double-claimed and the hit maps to the button drawn
|
||||
// there.
|
||||
int hitTestButton(int px, int py, const ButtonStripRect& strip, int buttonCount,
|
||||
int minButtonWidth);
|
||||
|
||||
// --- Label formatting ---------------------------------------------------------
|
||||
//
|
||||
// The SDK's kbd_getTextFromCmd returns the binding text for a command in the main
|
||||
// section (e.g. "Ctrl+Shift+C"), or an empty / whitespace-only / null string when the
|
||||
// action is unbound. The shell reads that raw string; this function turns
|
||||
// (short action name + raw binding) into the label drawn on the button, with every
|
||||
// degenerate binding collapsed to ONE explicit unbound marker so an unbound button reads
|
||||
// clearly rather than showing a stray separator or a blank tail.
|
||||
|
||||
// The marker appended when an action has no key binding. An em-dash-free ASCII marker so
|
||||
// it renders in any SWELL font; the label reads e.g. "Capture Item (unbound)".
|
||||
inline constexpr const char* kUnboundMarker = "unbound";
|
||||
|
||||
// Max characters of the binding string kept in the label. A pathological binding (a long
|
||||
// multi-chord custom binding) is truncated with a trailing ellipsis so it never overruns
|
||||
// the button's text budget; DrawText's own DT_END_ELLIPSIS is a per-pixel backstop, but
|
||||
// bounding the string here keeps the label deterministic and testable.
|
||||
inline constexpr int kMaxBindingChars = 24;
|
||||
|
||||
// Formats a button label from the action's short name and the raw SDK binding string.
|
||||
// * Bound: "<name> <binding>" (two spaces separate name and binding).
|
||||
// * Unbound: "<name> (unbound)" when `rawBinding` is empty, or contains only
|
||||
// whitespace (spaces/tabs), or is otherwise blank — all collapse to the
|
||||
// single marker.
|
||||
// * A binding longer than kMaxBindingChars is truncated to kMaxBindingChars-1 chars
|
||||
// plus a "~" ellipsis (kept ASCII, single-width) so the whole label stays bounded.
|
||||
// Leading/trailing whitespace on a non-blank binding is trimmed before formatting.
|
||||
// `name` is passed through verbatim (already short — the shell supplies a terse label).
|
||||
std::string formatButtonLabel(const std::string& name, const std::string& rawBinding);
|
||||
|
||||
} // namespace reasampler
|
||||
@@ -2,8 +2,8 @@
|
||||
// component_geometry — the REAPER-free, LICE-free geometry + hit-test math for the shared
|
||||
// drawing kit's generic components (Phase L, L1): a button box, a slider's track/handle,
|
||||
// and a list row. These are the kit-level primitives that DON'T already have a pure owner:
|
||||
// bank_grid / mode_switch / tab_strip / action_buttons / prune_button stay the source of
|
||||
// truth for the surfaces THEY own; this module carries only the new, reusable component
|
||||
// bank_grid / mode_switch / tab_strip / prune_button stay the source of truth for the
|
||||
// surfaces THEY own; this module carries only the new, reusable component
|
||||
// shapes the kit's drawButton / drawSlider / drawListRow draw against.
|
||||
//
|
||||
// Why pure (CLAUDE.md §load-bearing split, DS-1 caution): even where the draw shell reuses
|
||||
@@ -47,8 +47,8 @@ bool hitTestBox(int px, int py, const KitBox& box);
|
||||
//
|
||||
// A button drawn inside a host cell, inset by a uniform padding so it reads as a raised
|
||||
// control rather than a full-bleed fill (the kit's drawButton draws the micro-gradient
|
||||
// surface inside this box). Distinct from prune_button/action_buttons, which own their
|
||||
// OWN placement within their strips — this is the generic "given a cell, where's the
|
||||
// surface inside this box). Distinct from prune_button, which owns its OWN placement
|
||||
// within its strip — this is the generic "given a cell, where's the
|
||||
// button" helper for new kit consumers.
|
||||
struct KitButtonBox {
|
||||
KitBox box;
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
// drag_out_win — never by relocating or copying bytes here).
|
||||
//
|
||||
// PURE MODULE: NO REAPER types, NO SWELL, NO OS/OLE, NO vendor/ includes. Standard library
|
||||
// only. Builds and unit-tests without REAPER. Mirror of action_buttons / mode_switch.
|
||||
// only. Builds and unit-tests without REAPER. Mirror of mode_switch.
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
Reference in New Issue
Block a user