L7: capture-order slot model, card metadata overlay, tertiary-border selection
Add gap-preserving per-bank SlotMap (reorder + Alt-replace mutators, JSON round-trip, insertion-order migration) to bank_book; stamp captureTimeSig on Sample; pure card_meta formatters + card_drag gesture/slot module; card metadata overlay + purple selection border in the panel. Shell drop/cursor wiring deferred. Fixes: removeSample syncs SlotMap; card_drag gap-probe coordinate.
This commit is contained in:
+48
-15
@@ -54,6 +54,7 @@
|
||||
#include "bank_book.h"
|
||||
#include "bank_grid.h"
|
||||
#include "bank_model.h"
|
||||
#include "card_meta.h" // L7 decorative overlay formatters: bars.beats + s.ms (pure)
|
||||
#include "capture_paths.h"
|
||||
#include "component_geometry.h" // KitBox — the kit text()'s draw box (L1)
|
||||
#include "draw_kit.h" // kit text() over cached AA fonts — retires GDI DrawText (L1)
|
||||
@@ -455,35 +456,64 @@ const Envelope& thumbnailFor(const Sample& sample, int width,
|
||||
|
||||
// --- Drawing: thumbnails (unchanged from M5) ----------------------------------
|
||||
|
||||
// Draws the L7 decorative metadata overlay on a card: bars.beats.subdivisions bottom-LEFT
|
||||
// (musical, from the capture-time tempo + meter stamp) and seconds.milliseconds bottom-RIGHT
|
||||
// (wall-clock). Decorative + non-interactive (no hit-test, no hover). Drawn in the kit's
|
||||
// Micro / ValueMono classes in text/dim, subordinate to the waveform. A blank musical
|
||||
// read-out (unstamped meter / unknown tempo) simply omits the bottom-left string.
|
||||
void drawCardMeta(LICE_IBitmap* bmp, const CellRect& rect, const Sample& s) {
|
||||
MusicalLength ml;
|
||||
ml.lengthSeconds = s.lengthSeconds;
|
||||
ml.tempoBpm = s.captureTempo;
|
||||
ml.timeSigNum = s.captureTimeSigNum;
|
||||
ml.timeSigDenom = s.captureTimeSigDenom;
|
||||
const std::string bars = formatBarsBeats(ml); // "" when unstamped/no-tempo
|
||||
const std::string secs = formatSecondsMs(s.lengthSeconds);
|
||||
|
||||
// A short strip along the card's bottom edge. Left/right halves; text/dim so the
|
||||
// waveform stays the centerpiece. Micro on the left (musical), ValueMono on the right
|
||||
// (tabular numbers that must not jitter).
|
||||
const int stripH = 12;
|
||||
const int pad = 3;
|
||||
const int y = rect.y + rect.height - stripH;
|
||||
if (!bars.empty()) {
|
||||
const KitBox left{rect.x + pad, y, rect.width / 2 - pad, stripH};
|
||||
text(bmp, left, bars.c_str(), Font::Micro, Role::TextDim, Align::Left);
|
||||
}
|
||||
const KitBox right{rect.x + rect.width / 2, y, rect.width / 2 - pad, stripH};
|
||||
text(bmp, right, secs.c_str(), Font::ValueMono, Role::TextDim, Align::Right);
|
||||
}
|
||||
|
||||
void drawThumbnail(LICE_IBitmap* bmp, const CellRect& rect, const Envelope& env,
|
||||
bool selected, bool focused, bool hovered) {
|
||||
// Cell surface through the kit: Active (accent) when selected, else hover-or-rest bg/cell.
|
||||
// The grid is the centerpiece (bones preserved) — the surface picks up the L2 palette +
|
||||
// micro-gradient while the waveform plot below stays the panel's own draw.
|
||||
bool selected, bool focused, bool hovered, const Sample* sample) {
|
||||
// Cell surface through the kit (L7 selection restyle): a selected card draws the NORMAL
|
||||
// cell surface (Rest, or Hover when hovered) — NOT the inverted accent-fill. Selection is
|
||||
// marked purely by an accent/tertiary (pastel purple) border below; hover stays a fill-
|
||||
// state change orthogonal to that border, so a hovered selected card still reads selected.
|
||||
const KitBox cell{rect.x, rect.y, rect.width, rect.height};
|
||||
const InteractionState state = selected ? InteractionState::Active
|
||||
: (hovered ? InteractionState::Hover
|
||||
: InteractionState::Rest);
|
||||
const InteractionState state = hovered ? InteractionState::Hover : InteractionState::Rest;
|
||||
fillSurface(bmp, cell, Role::BgCell, state);
|
||||
|
||||
// Border: accent when selected, else hairline. A focus ring is a distinct text/primary
|
||||
// double-line (the kit's focus convention) so focus reads even on a selected cell.
|
||||
const KitColor border = selected ? roleColor(Role::AccentPrimary) : roleColor(Role::LineHairline);
|
||||
// Border (L7): accent/TERTIARY purple when selected (the sole selection signal), else
|
||||
// hairline. Focus is a distinct text/primary inner ring so a focused-AND-selected card
|
||||
// reads BOTH — the purple outer border + the inner focus ring — kept visually separate.
|
||||
const KitColor border = selected ? roleColor(Role::AccentTertiary) : roleColor(Role::LineHairline);
|
||||
LICE_DrawRect(bmp, rect.x, rect.y, rect.width, rect.height, toLice(border), 1.0f, 0);
|
||||
if (focused) {
|
||||
const LICE_pixel ring = toLice(roleColor(Role::TextPrimary));
|
||||
LICE_DrawRect(bmp, rect.x + 1, rect.y + 1, rect.width - 2, rect.height - 2, ring, 1.0f, 0);
|
||||
}
|
||||
|
||||
// Waveform plot (peaks invariant: min<=max). The wave uses the accent role except on a
|
||||
// selected cell (whose fill is already the accent) — there it draws in bg/base for contrast.
|
||||
// Waveform plot (peaks invariant: min<=max). The wave keeps its NORMAL accent color in
|
||||
// every state (L7 dropped the inverted bg/base wave on the selected cell — the cell fill
|
||||
// is no longer inverted, so no contrast swap is needed).
|
||||
const LICE_pixel midCol = toLice(roleColor(Role::LineHairline));
|
||||
const LICE_pixel waveCol =
|
||||
toLice(selected ? roleColor(Role::BgBase) : roleColor(Role::AccentPrimary));
|
||||
const LICE_pixel waveCol = toLice(roleColor(Role::AccentPrimary));
|
||||
|
||||
if (env.empty()) {
|
||||
const int midY = rect.y + rect.height / 2;
|
||||
LICE_Line(bmp, rect.x + 2, midY, rect.x + rect.width - 2, midY, midCol, 1.0f, 0, false);
|
||||
if (sample) drawCardMeta(bmp, rect, *sample); // L7 overlay even on an empty envelope
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -513,6 +543,9 @@ void drawThumbnail(LICE_IBitmap* bmp, const CellRect& rect, const Envelope& env,
|
||||
LICE_Line(bmp, x, yMin, x, yMax, waveCol, 1.0f, 0, false);
|
||||
}
|
||||
}
|
||||
|
||||
// L7 decorative metadata overlay, drawn last so it sits over the waveform.
|
||||
if (sample) drawCardMeta(bmp, rect, *sample);
|
||||
}
|
||||
|
||||
// --- Kit draw adapters (Phase L) ----------------------------------------------
|
||||
@@ -1266,7 +1299,7 @@ void drawRegionGrid(LICE_IBitmap* bmp, const RECT& region, bool isBanks,
|
||||
// Grid-cell hover is intentionally not tracked: the cell already carries selection +
|
||||
// focus chrome (the centerpiece's "bones"); a third transient hover state on every
|
||||
// cell would add repaint churn + visual noise. Hover lights the chrome/buttons/tabs.
|
||||
drawThumbnail(bmp, rect, env, selected, focused, /*hovered=*/false);
|
||||
drawThumbnail(bmp, rect, env, selected, focused, /*hovered=*/false, &samples[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user