Files
reasampler/src/core/ui/action_bar.h
T

82 lines
3.1 KiB
C++

#pragma once
#include "core/ui/rect.h"
// action_bar — layout + hit-test for the bank_panel's task-grouped toolbars: buttons cluster by
// task (Capture/Placement/Maintenance/Tagging/Switching); on a narrow panel, whole trailing
// buttons drop rather than shrink or clip. The destructive Prune button lives separately in
// prune_button, kept out of this cluster on purpose.
#include <vector>
namespace reasampler::ui {
// Task cluster a button belongs to. Cluster order is caller-supplied via ClusterSpec, not fixed
// here; a slot just carries which cluster it landed in.
enum class ActionCluster {
Capture,
Placement,
Maintenance,
Tagging,
Switching,
};
using ActionBarRect = Rect;
// One visible button's placement, top-left origin. `index` is its position in the caller's flat
// action list (cluster order), so index also selects the action to fire on a hit. Only buttons
// that fit get a slot — overflow is dropped whole, never clipped.
struct ActionBarSlot {
int index = 0;
ActionCluster cluster = ActionCluster::Capture;
int x = 0;
int y = 0;
int width = 0;
int height = 0;
// Label sub-rect, full button height, horizontally inset so text clears the edge.
int labelX = 0, labelY = 0, labelW = 0, labelH = 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;
}
};
// One cluster's button count, in the order the caller wants it drawn. count == 0 skips the
// cluster (no gap emitted). Flat action indices run cluster-by-cluster in this order.
struct ClusterSpec {
ActionCluster cluster = ActionCluster::Capture;
int count = 0;
};
// Layout inputs, in pixels; defaults are the bank_panel action-bar metrics.
struct ActionBarSpec {
int buttonWidth = 108;
int buttonGap = 4;
int clusterGap = 16;
int sidePad = 8;
int verticalInset = 3;
};
// How many buttons (from the front) fit at spec.buttonWidth. Split out so the shell can size an
// overflow affordance without re-deriving it. A bar too narrow for even one button yields 0.
struct BarFit {
int visibleCount = 0;
int hiddenCount = 0;
};
BarFit computeBarFit(const ActionBarRect& bar, const std::vector<ClusterSpec>& clusters,
const ActionBarSpec& spec);
// Lays out the visible buttons (per computeBarFit) left-to-right in cluster order.
std::vector<ActionBarSlot> computeBarSlots(const ActionBarRect& bar,
const std::vector<ClusterSpec>& clusters,
const ActionBarSpec& spec);
// Flat action index under (px, py), or -1 for a miss (outside the bar, in a gap, or past the
// last visible button). Gaps are real dead-zones here, not resolved to the nearest button.
int hitTestActionBar(int px, int py, const ActionBarRect& bar,
const std::vector<ClusterSpec>& clusters, const ActionBarSpec& spec);
} // namespace reasampler::ui