Cut shell/panel comment bloat ~47% (comments only, zero code change)
This commit is contained in:
@@ -1,49 +1,35 @@
|
||||
// panel_render.cpp — the LICE draw seam of the docked bank panel (Q-W2 split of
|
||||
// bank_panel.cpp; M5 Wave A/B + Phase B4 + Phase L). Owns WM_PAINT's full paint:
|
||||
// the VERTICAL SPLIT (pool grid region on top, named-banks tab-page region below),
|
||||
// the region headers + tab strip, the two task-grouped toolbars + More button, the
|
||||
// footer (mode toggle + count + Tail + Prune), the hover-delay tooltip overlay, and
|
||||
// the per-card thumbnail/metadata draw — everything through the L1 kit by palette
|
||||
// role (draw_kit), double-buffered, BitBlt'd once.
|
||||
//
|
||||
// READ-ONLY: reads panel + session state; the input/drag seams mutate it. All rect
|
||||
// derivation comes from panel_layout (the single source both draw and hit-test use).
|
||||
//
|
||||
// Compiled into the reaper_reasampler MODULE. No REAPER API functions are called
|
||||
// here (LICE/Win32 only); REAPER SDK types arrive via panel_state.h.
|
||||
// panel_render.cpp — LICE draw seam of the docked bank panel. Owns WM_PAINT's full
|
||||
// paint: the vertical split, region headers + tab strip, the two toolbars + More
|
||||
// button, the footer, the tooltip overlay, and per-card thumbnail/metadata draw —
|
||||
// everything through the kit by palette role, double-buffered, BitBlt'd once.
|
||||
// Read-only: reads panel + session state; input/drag seams mutate it. All rect
|
||||
// derivation comes from panel_layout (the single source both draw and hit-test
|
||||
// use). No REAPER API functions are called here.
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "shell/panel/panel_state.h"
|
||||
|
||||
#include "shell/panel/draw_kit.h" // kit text()/fillSurface/drawButton/drawWaveform (L1)
|
||||
#include "shell/persist/session.h" // ReaSamplerSession — mode/view/tail reads
|
||||
#include "core/view/view_mode_model.h" // ViewModeModel / Mode — the footer toggle's model
|
||||
#include "shell/panel/draw_kit.h"
|
||||
#include "shell/persist/session.h"
|
||||
#include "core/view/view_mode_model.h"
|
||||
|
||||
namespace reasampler::panel {
|
||||
|
||||
namespace {
|
||||
|
||||
// --- Drawing: thumbnails (via the kit's shared drawWaveform since FA3) ---------
|
||||
|
||||
// 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.
|
||||
// Bars.beats.subdivisions bottom-left (musical), seconds.milliseconds bottom-right.
|
||||
// Decorative, non-interactive; a blank musical readout omits the 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 bars = formatBarsBeats(ml);
|
||||
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;
|
||||
@@ -57,17 +43,13 @@ void drawCardMeta(LICE_IBitmap* bmp, const CellRect& rect, const Sample& s) {
|
||||
|
||||
void drawThumbnail(LICE_IBitmap* bmp, const CellRect& rect, const Envelope& env,
|
||||
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.
|
||||
// Selected cards draw the normal cell surface, not an inverted fill — selection
|
||||
// is marked purely by the border below, kept orthogonal to hover state.
|
||||
const KitBox cell{rect.x, rect.y, rect.width, rect.height};
|
||||
const InteractionState state = hovered ? InteractionState::Hover : InteractionState::Rest;
|
||||
fillSurface(bmp, cell, Role::BgCell, state);
|
||||
|
||||
// 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.
|
||||
// Focus is a distinct inner ring so a focused-AND-selected card reads both.
|
||||
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) {
|
||||
@@ -75,44 +57,22 @@ void drawThumbnail(LICE_IBitmap* bmp, const CellRect& rect, const Envelope& env,
|
||||
LICE_DrawRect(bmp, rect.x + 1, rect.y + 1, rect.width - 2, rect.height - 2, ring, 1.0f, 0);
|
||||
}
|
||||
|
||||
// Waveform plot through the kit's shared primitive (FA3): the SAME per-pixel-column
|
||||
// min/max envelope draw the VST editor hero + browser cards use — one algorithm, one
|
||||
// look, everywhere. The oversampled env (see drawRegionGrid's binWidth) collapses per
|
||||
// column via peaks::columnMinMax inside the kit; an empty env draws just the midline.
|
||||
drawWaveform(bmp, cell, env);
|
||||
|
||||
// L7 decorative metadata overlay, drawn last so it sits over the waveform.
|
||||
if (sample) drawCardMeta(bmp, rect, *sample);
|
||||
}
|
||||
|
||||
// --- Kit draw adapters (Phase L) ----------------------------------------------
|
||||
//
|
||||
// All panel text draws through the kit's cached AA font (draw_kit::text), NOT raw GDI DrawText
|
||||
// (retired at L1). L2 re-roles every color through the pure `theme` module and draws surfaces
|
||||
// via the kit (fillSurface / drawButton). These thin adapters bridge the panel's RECT-based
|
||||
// geometry helpers to the kit's KitBox and give the panel a KitColor->LICE_pixel boundary for
|
||||
// the few raw borders it still draws over kit surfaces. The kit owns the font lifecycle
|
||||
// (kitFontsInit/Shutdown, wired at panel open/close below).
|
||||
|
||||
KitBox toKitBox(const RECT& r) {
|
||||
return KitBox{r.left, r.top, r.right - r.left, r.bottom - r.top};
|
||||
}
|
||||
|
||||
// KitColor -> LICE_pixel: all sites use the kit's toLice() from draw_kit.h — the single
|
||||
// conversion boundary the kit enforces. No local alias needed.
|
||||
|
||||
// L2 role/font-aware text: draws through the kit in a palette ROLE color and a chosen kit
|
||||
// Font (the action bar uses Micro for the keybinding sub-label, Label for the name, Title for
|
||||
// region headings). Takes a KitBox directly (the pure geometry the L2 modules return).
|
||||
void kitText(LICE_IBitmap* bmp, const KitBox& box, const char* txt,
|
||||
Font font, Role role, Align align) {
|
||||
text(bmp, box, txt, font, role, align);
|
||||
}
|
||||
|
||||
// The per-mode membership count that travels with the toggle (L4 §3): the number of leaves
|
||||
// tagged into the currently ACTIVE mode. A compact readout beside the toggle. 0 when no
|
||||
// session. (The Arrange default — untagged — is not counted; membership tracks tagged leaves.)
|
||||
// A display-only tally over the model's public membership map — no model semantics duplicated.
|
||||
// Number of leaves tagged into the currently active mode; 0 when no session. The
|
||||
// Arrange default (untagged) is not counted — membership tracks tagged leaves only.
|
||||
int activeModeMemberCount() {
|
||||
if (!g_panel.session) return 0;
|
||||
const ViewModeModel& view = g_panel.session->view();
|
||||
@@ -124,10 +84,9 @@ int activeModeMemberCount() {
|
||||
return n;
|
||||
}
|
||||
|
||||
// Draws the footer: the band + top divider, then the LEFT group (the narrow [Arrange|Design]
|
||||
// toggle drawn as mode_switch segments over footer_bar's toggle box, the per-mode count, and
|
||||
// the Tail BUTTON — L4 §4), the right-aligned version readout, and finally the Prune button
|
||||
// set apart at the far right (warn). READ-ONLY: reads session state; input handlers mutate it.
|
||||
// Draws the footer: band + top divider, LEFT group ([Arrange|Design] toggle, per-mode
|
||||
// count, Tail BUTTON), the version readout, and the Prune button at the far right.
|
||||
// READ-ONLY: reads session state; input handlers mutate it.
|
||||
void drawFooter(LICE_IBitmap* bmp, int w, int h) {
|
||||
const RECT f = panelFooter(w, h);
|
||||
if (f.top >= f.bottom) return;
|
||||
@@ -140,8 +99,7 @@ void drawFooter(LICE_IBitmap* bmp, int w, int h) {
|
||||
|
||||
const FooterBarLayout fb = footerBarLayoutFor(w, h);
|
||||
|
||||
// [Arrange|Design] toggle — drawn as N mode_switch segments inside footer_bar's toggle box
|
||||
// (the segment geometry stays owned by the pure mode_switch; footer_bar owns the box). The
|
||||
// [Arrange|Design] toggle — N mode_switch segments inside footer_bar's toggle box. The
|
||||
// active mode's segment carries the accent; others hover-or-rest bg/cell.
|
||||
if (!fb.toggle.empty() && g_panel.session) {
|
||||
const ViewModeModel& view = g_panel.session->view();
|
||||
@@ -166,8 +124,7 @@ void drawFooter(LICE_IBitmap* bmp, int w, int h) {
|
||||
}
|
||||
}
|
||||
|
||||
// Per-mode member count, a compact dim readout beside the toggle (L4 §3 — "the count
|
||||
// travels with the toggle"). Passive text, not a control.
|
||||
// Per-mode member count, a compact dim readout beside the toggle. Passive text, not a control.
|
||||
if (!fb.count.empty()) {
|
||||
const int members = activeModeMemberCount();
|
||||
const std::string countLabel =
|
||||
@@ -176,8 +133,8 @@ void drawFooter(LICE_IBitmap* bmp, int w, int h) {
|
||||
countLabel.c_str(), Font::Micro, Role::TextDim, Align::Center);
|
||||
}
|
||||
|
||||
// Tail BUTTON (L4 §4) — a real kit button with rest/hover states; its click cycles the
|
||||
// tail mode exactly as the old click-zone did. Label is the pure tailToggleLabel.
|
||||
// Tail BUTTON — a real kit button with rest/hover states; its click cycles the tail
|
||||
// mode. Label is the pure tailToggleLabel.
|
||||
if (!fb.tail.empty()) {
|
||||
const InteractionState state = hoverState(g_panel.hovered, HoverKind::TailButton, -1);
|
||||
const std::string label = tailToggleLabel(currentTail());
|
||||
@@ -185,17 +142,13 @@ void drawFooter(LICE_IBitmap* bmp, int w, int h) {
|
||||
drawButton(bmp, box, label.c_str(), state, /*warn=*/false);
|
||||
}
|
||||
|
||||
// Version/channel readout (Phase V, V3/V4), right-aligned, unobtrusive. appVersion()
|
||||
// renders the configured version string on stable and that string plus "-beta" on beta,
|
||||
// so a beta panel self-identifies. It sits inside the space footer_bar reserves at the
|
||||
// right (rightReserve) and clears the prune button (prune_button::rightInset). Dim,
|
||||
// passive identification (V3).
|
||||
// Version/channel readout. appVersion() renders the configured version string on
|
||||
// stable and that string plus "-beta" on beta, so a beta panel self-identifies.
|
||||
kitText(bmp, KitBox{f.left, f.top, (f.right - f.left) - 8, f.bottom - f.top},
|
||||
appVersion().c_str(), Font::Micro, Role::TextDim, Align::Right);
|
||||
|
||||
// Prune button — set apart at the far RIGHT (the ONLY warn-colored, byte-deleting control),
|
||||
// honoring hover. No-op when suppressed (footer too narrow). Order reads left (benign,
|
||||
// frequent) -> right (destructive, rare) per the L4 footer contract.
|
||||
// Prune button — the ONLY warn-colored, byte-deleting control. No-op when suppressed
|
||||
// (footer too narrow).
|
||||
const ButtonRect pb = pruneButtonRectFor(w, h);
|
||||
if (!pb.empty()) {
|
||||
const InteractionState state = hoverState(g_panel.hovered, HoverKind::PruneButton, -1);
|
||||
@@ -204,14 +157,12 @@ void drawFooter(LICE_IBitmap* bmp, int w, int h) {
|
||||
}
|
||||
}
|
||||
|
||||
// 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 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.
|
||||
// Draws one task-grouped toolbar through the kit. 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 so the two toolbars' hover
|
||||
// states never cross. `topDivider` draws the hairline at the band's top edge (bottom
|
||||
// toolbar) vs. bottom edge (top toolbar). Key binding help is in the hover tooltip, not
|
||||
// on the button face.
|
||||
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;
|
||||
@@ -230,17 +181,14 @@ void drawToolbar(LICE_IBitmap* bmp, const ActionBarRect& bar,
|
||||
const ActionBarRow& row = rows[static_cast<std::size_t>(s.index)];
|
||||
const int cmd = resolveBarCommandId(row);
|
||||
|
||||
// State: Disabled when the action is not registered on this channel OR the row is gated
|
||||
// off (L5 opposite-mode enablement — the tag buttons for the ACTIVE mode); else Hover
|
||||
// when hovered, else Rest. (The bar's actions are stateless triggers — no Active/Pressed.)
|
||||
// Disabled when unregistered on this channel or gated off (opposite-mode
|
||||
// enablement); else Hover when hovered, else Rest — these are stateless triggers.
|
||||
InteractionState state = InteractionState::Rest;
|
||||
if (cmd == 0 || !row.enabled) state = InteractionState::Disabled;
|
||||
else if (g_panel.hovered.kind == hoverKind && g_panel.hovered.index == s.index)
|
||||
state = InteractionState::Hover;
|
||||
|
||||
// The button surface (drawButton draws the micro-gradient + rounded border + honors
|
||||
// the state). The label is drawn separately so the text role tracks the state correctly;
|
||||
// pass no label to drawButton.
|
||||
// Label drawn separately (not passed to drawButton) so its text role tracks state.
|
||||
const KitButtonBox box{KitBox{s.x, s.y, s.width, s.height}};
|
||||
drawButton(bmp, box, /*label=*/nullptr, state, /*warn=*/false);
|
||||
|
||||
@@ -251,31 +199,22 @@ void drawToolbar(LICE_IBitmap* bmp, const ActionBarRect& bar,
|
||||
}
|
||||
}
|
||||
|
||||
// --- Top-toolbar overflow ("⋯" More) menu (L5 refinement 1) -------------------
|
||||
//
|
||||
// The three rare capture variants live only in this popup. The button is drawn kit-style (rest/
|
||||
// hover) at the far right of the top band; a click opens a REAPER/host TrackPopupMenu listing the
|
||||
// variants, each firing its existing registered command id via NamedCommandLookup/Main_OnCommand
|
||||
// (the SAME contract the visible buttons use — no action changes). A transient OS menu is fine
|
||||
// for panel-external chrome (brief §1); only the button geometry (overflow_menu) is pure.
|
||||
|
||||
// Draws the far-right More button (rest/hover). No-op when suppressed (band too narrow).
|
||||
// Draws the far-right More button (rest/hover) — the entry to the top-toolbar overflow
|
||||
// popup listing the rare capture variants. No-op when suppressed (band too narrow).
|
||||
void drawMoreButton(LICE_IBitmap* bmp, int w) {
|
||||
const MenuButtonRect mb = topMenuButtonRect(w);
|
||||
if (mb.empty()) return;
|
||||
const InteractionState state = hoverState(g_panel.hovered, HoverKind::MoreButton, -1);
|
||||
const KitButtonBox box{KitBox{mb.x, mb.y, mb.width, mb.height}};
|
||||
drawButton(bmp, box, /*label=*/nullptr, state, /*warn=*/false);
|
||||
// The glyph: three ASCII dots (portable — no UTF-8/codepage dependency in the LICE text
|
||||
// path). Drawn as text so it picks up the kit font + AA. Reads as the conventional "More".
|
||||
// Three ASCII dots (portable — no UTF-8/codepage dependency in the LICE text path).
|
||||
kitText(bmp, KitBox{mb.x, mb.y, mb.width, mb.height}, "...",
|
||||
Font::Label, Role::TextPrimary, Align::Center);
|
||||
}
|
||||
|
||||
// Draws the hover-delay tooltip over the given anchor button, if a tooltip is due (the current
|
||||
// hover is a toolbar button AND it has been hovered past kTooltipDelayMs). Drawn LAST in the
|
||||
// paint so it overlays the toolbars. The box is placed by the pure tooltip module (below the
|
||||
// anchor, flipping above near the bottom edge, clamped to the client).
|
||||
// Draws the hover-delay tooltip over the given anchor button, if due. Drawn LAST so it
|
||||
// overlays the toolbars. Box placement (below anchor, flip above near the bottom edge,
|
||||
// clamp to client) is the pure tooltip module's.
|
||||
void drawTooltip(LICE_IBitmap* bmp, int w, int h) {
|
||||
if (!g_panel.tooltipShown) return;
|
||||
std::string txt;
|
||||
@@ -295,8 +234,6 @@ void drawTooltip(LICE_IBitmap* bmp, int w, int h) {
|
||||
kitText(bmp, box, txt.c_str(), Font::Label, Role::TextPrimary, Align::Center);
|
||||
}
|
||||
|
||||
// --- Drawing: a grid region ---------------------------------------------------
|
||||
|
||||
// Draws one region's grid of thumbnails (or an empty-state line) clipped to its
|
||||
// viewport. `selectionOwner` is true when this region holds the live selection, so
|
||||
// its cells show selection/focus chrome; the other region draws plain.
|
||||
@@ -311,14 +248,12 @@ void drawRegionGrid(LICE_IBitmap* bmp, const RECT& region, bool isBanks,
|
||||
return;
|
||||
}
|
||||
|
||||
// L7: iterate the bank's SPARSE slot layout (slot order, gaps included), not the dense
|
||||
// Iterate the bank's SPARSE slot layout (slot order, gaps included), not the dense
|
||||
// BankModel insertion order. Selection/focus are keyed by the occupied-ordinal (selection
|
||||
// space); a slot maps back to its ordinal via selectionForSlot.
|
||||
const RegionDisplay disp = regionDisplay(region, isBanks, reg);
|
||||
// FA3 gap-free: request one bin per drawn pixel column; drawWaveform's
|
||||
// peaks::columnMinMax exact partition makes every column gap-free — overbinning
|
||||
// produces byte-identical pixels at higher memory/CPU cost. computeThumbnail clamps
|
||||
// the request to the frame count.
|
||||
// Request one bin per drawn pixel column; drawWaveform's peaks::columnMinMax exact
|
||||
// partition makes every column gap-free regardless. computeThumbnail clamps to frame count.
|
||||
const int binWidth = kWaveformOversample *
|
||||
waveformColumnCount(KitBox{0, 0, kGrid.cellWidth, kGrid.cellHeight});
|
||||
for (const SlotCellRect& r : disp.slotRects) {
|
||||
@@ -327,9 +262,8 @@ void drawRegionGrid(LICE_IBitmap* bmp, const RECT& region, bool isBanks,
|
||||
const std::string id = disp.idAtSlot(r.slot);
|
||||
if (id.empty()) {
|
||||
// Interior gap slot: a subtle empty-slot treatment through the kit — a hairline
|
||||
// outline on bg/cell, clearly NOT a card (decorative, per the L7 spec). No
|
||||
// selection/focus/waveform, and not a hover or hit target (the grid never tracks
|
||||
// cell hover; a click on an empty slot clears selection like any grid miss).
|
||||
// outline on bg/cell, clearly NOT a card. No selection/focus/waveform, and not a
|
||||
// hover or hit target (a click on an empty slot clears selection like any grid miss).
|
||||
fillSurface(bmp, KitBox{rect.x, rect.y, rect.width, rect.height},
|
||||
Role::BgCell, InteractionState::Rest);
|
||||
LICE_DrawRect(bmp, rect.x, rect.y, rect.width, rect.height,
|
||||
@@ -349,12 +283,11 @@ void drawRegionGrid(LICE_IBitmap* bmp, const RECT& region, bool isBanks,
|
||||
}
|
||||
}
|
||||
|
||||
// L7: draws the per-slot reorder/replace drop-target highlight on the target slot's cell, but
|
||||
// Draws the per-slot reorder/replace drop-target highlight on the target slot's cell, but
|
||||
// ONLY when a same-bank in-grid drag (Reorder or Replace) is live over THIS region (the drag
|
||||
// source region). An accent/HOT outline (distinct from the accent/tertiary purple selection
|
||||
// border, per the spec's "must not be confusable" constraint); Replace draws a doubled outline
|
||||
// so an Alt-over-occupied replace reads as a stronger "swap" cue than a plain reorder. No-op
|
||||
// for a move/copy/OS drag or when the pointer is off any slot (dragTargetSlot < 0).
|
||||
// source region). An accent/HOT outline, distinct from the accent/tertiary purple selection
|
||||
// border so it is never confusable; Replace draws a doubled outline so an Alt-over-occupied
|
||||
// replace reads as a stronger "swap" cue than a plain reorder.
|
||||
void drawCardDropTarget(LICE_IBitmap* bmp, const RECT& region, bool isBanks, Region reg) {
|
||||
if (!g_panel.dragging) return;
|
||||
if (g_panel.cardGesture != CardGesture::Reorder &&
|
||||
@@ -365,8 +298,8 @@ void drawCardDropTarget(LICE_IBitmap* bmp, const RECT& region, bool isBanks, Reg
|
||||
|
||||
const RECT grid = regionGridRect(region, isBanks);
|
||||
const RegionDisplay disp = regionDisplay(region, isBanks, reg);
|
||||
// Use the drop rects (includes the trailing row past maxSlot) so a beyond-extent
|
||||
// target slot gets a visible highlight cue, not silence.
|
||||
// The drop rects include a trailing row past maxSlot so a beyond-extent target
|
||||
// slot gets a visible highlight cue, not silence.
|
||||
const int gridW = grid.right - grid.left;
|
||||
const int maxSlot = disp.bank ? disp.bank->slots.maxSlot() : -1;
|
||||
std::vector<SlotCellRect> dropRects = computeSlotRectsForDrop(maxSlot, gridW, kGrid);
|
||||
@@ -386,26 +319,24 @@ void drawCardDropTarget(LICE_IBitmap* bmp, const RECT& region, bool isBanks, Reg
|
||||
void drawRegionHeader(LICE_IBitmap* bmp, const RECT& region, const char* title,
|
||||
const std::string& activeName, bool poolBtnIsPool) {
|
||||
const RECT hdr = regionHeaderRect(region);
|
||||
// Region header band (kit bg/panel — a raised region title bar). A hairline underline.
|
||||
fillSurface(bmp, KitBox{hdr.left, hdr.top, hdr.right - hdr.left, hdr.bottom - hdr.top},
|
||||
Role::BgPanel, InteractionState::Rest);
|
||||
LICE_Line(bmp, hdr.left, hdr.bottom - 1, hdr.right, hdr.bottom - 1,
|
||||
toLice(roleColor(Role::LineHairline)), 1.0f, 0, false);
|
||||
|
||||
// Title, left (Font::Title — a region heading). The two regions are distinct KINDS of
|
||||
// container, so the title carries a CATEGORICAL accent (DS-2 revised: secondary/tertiary
|
||||
// mark kinds, never intensity) — Pool = secondary teal, Banks = tertiary purple. This is
|
||||
// a category mark, NOT the "what's live" signal (that stays the primary-lime "Active:"
|
||||
// readout beside it), keeping primary reserved for the live/active layer.
|
||||
// Title, left. The two regions are distinct KINDS of container, so the title carries a
|
||||
// CATEGORICAL accent (secondary/tertiary mark kinds, never intensity) — Pool = secondary
|
||||
// teal, Banks = tertiary purple. This is a category mark, NOT the "what's live" signal
|
||||
// (that stays the primary-lime "Active:" readout beside it).
|
||||
RECT titleRc = hdr;
|
||||
titleRc.left += 8;
|
||||
titleRc.right = titleRc.left + 120;
|
||||
const Role titleRole = poolBtnIsPool ? Role::AccentSecondary : Role::AccentTertiary;
|
||||
kitText(bmp, toKitBox(titleRc), title, Font::Title, titleRole, Align::Left);
|
||||
|
||||
// Active-bank readout — the UNMISTAKABLE indicator (settled B4 constraint), in the PRIMARY
|
||||
// accent role in BOTH region headers so the active/capture-target bank is legible even when
|
||||
// it is not the shown tab and even when it is the pool. Primary = "what's live" (DS-2).
|
||||
// Active-bank readout — the UNMISTAKABLE indicator, in the PRIMARY accent role in BOTH
|
||||
// region headers so the active/capture-target bank is legible even when it is not the
|
||||
// shown tab and even when it is the pool. Primary = "what's live".
|
||||
const std::string readout = "Active: " + activeName;
|
||||
RECT actRc = hdr;
|
||||
actRc.left = titleRc.right + 6;
|
||||
@@ -413,8 +344,8 @@ void drawRegionHeader(LICE_IBitmap* bmp, const RECT& region, const char* title,
|
||||
if (actRc.right > actRc.left)
|
||||
kitText(bmp, toKitBox(actRc), readout.c_str(), Font::Label, Role::AccentPrimary, Align::Left);
|
||||
|
||||
// Full-height toggle button: an arrow glyph. In split it means "maximize this region";
|
||||
// when this region is already full it means "restore the split". Kit drawButton + hover.
|
||||
// Arrow glyph: in split it means "maximize this region"; when already full it means
|
||||
// "restore the split".
|
||||
const RECT btn = fullHtBtnRect(region);
|
||||
const bool thisFull =
|
||||
poolBtnIsPool ? (g_panel.fullHeight == BankPanelFullHeight::PoolOnly)
|
||||
@@ -434,7 +365,6 @@ void drawRegionHeader(LICE_IBitmap* bmp, const RECT& region, const char* title,
|
||||
void drawTabStrip(LICE_IBitmap* bmp, const RECT& region) {
|
||||
const TabStripRect strip = banksTabStripRect(region);
|
||||
if (strip.height <= 0) return;
|
||||
// Tab strip band (kit bg/base — recessed relative to the region header above it).
|
||||
fillSurface(bmp, KitBox{strip.x, strip.y, strip.width, strip.height},
|
||||
Role::BgBase, InteractionState::Rest);
|
||||
|
||||
@@ -474,9 +404,8 @@ void drawTabStrip(LICE_IBitmap* bmp, const RECT& region) {
|
||||
const bool hovered = g_panel.hovered.kind == HoverKind::Tab &&
|
||||
g_panel.hovered.index == tr.index;
|
||||
|
||||
// Surface state: the ACTIVE bank (capture target) carries the accent (Active); a drag
|
||||
// drop-target reads Dragging; the SHOWN (browsed) tab reads Pressed (recessed-lit);
|
||||
// else hover-or-rest bg/cell.
|
||||
// The ACTIVE bank (capture target) carries the accent; a drag drop-target reads
|
||||
// Dragging; the SHOWN (browsed) tab reads Pressed; else hover-or-rest bg/cell.
|
||||
const KitBox tb{tr.x, tr.y, tr.width, tr.height};
|
||||
InteractionState state = InteractionState::Rest;
|
||||
if (active) state = InteractionState::Active;
|
||||
@@ -510,8 +439,6 @@ std::string activeBankName() {
|
||||
|
||||
} // namespace
|
||||
|
||||
// --- Full paint ---------------------------------------------------------------
|
||||
|
||||
void paintPanel(HWND hwnd, HDC hdc) {
|
||||
RECT cr{};
|
||||
GetClientRect(hwnd, &cr);
|
||||
@@ -525,16 +452,14 @@ void paintPanel(HWND hwnd, HDC hdc) {
|
||||
const std::string projectDir = currentProjectDir();
|
||||
const std::string activeName = activeBankName();
|
||||
|
||||
// Pool region (top).
|
||||
if (poolShown()) {
|
||||
const RECT region = poolRegionRect(w, h);
|
||||
drawRegionHeader(&bmp, region, "Pool", activeName, /*poolBtnIsPool=*/true);
|
||||
drawRegionGrid(&bmp, region, /*isBanks=*/false, indexForRegion(Region::Pool),
|
||||
"No samples in the pool yet. Capture one to see it here.",
|
||||
g_panel.focusedRegion == Region::Pool, projectDir, Region::Pool);
|
||||
// Drop-target highlight for the pool region during a MOVE/COPY drag (a whole-grid
|
||||
// outline signalling "drop here to move/copy into this bank"). Suppressed for a
|
||||
// same-bank reorder (that shows a per-SLOT highlight below, not the whole grid).
|
||||
// Whole-grid drop-target outline for a MOVE/COPY drag; a same-bank reorder shows a
|
||||
// per-SLOT highlight instead (drawCardDropTarget below).
|
||||
if (g_panel.dragging && g_panel.dropKind == DropKind::PoolRegion &&
|
||||
(g_panel.cardGesture == CardGesture::Move ||
|
||||
g_panel.cardGesture == CardGesture::Copy)) {
|
||||
@@ -543,13 +468,9 @@ void paintPanel(HWND hwnd, HDC hdc) {
|
||||
grid.right - grid.left - 2, grid.bottom - grid.top - 2,
|
||||
toLice(roleColor(Role::AccentHot)), 1.0f, 0);
|
||||
}
|
||||
// L7 per-slot reorder/replace target highlight (source = pool). An accent/hot outline
|
||||
// on the target slot's cell — distinct from the accent/tertiary purple selection
|
||||
// border, so it is never confusable with a selected card.
|
||||
drawCardDropTarget(&bmp, region, /*isBanks=*/false, Region::Pool);
|
||||
}
|
||||
|
||||
// Split divider.
|
||||
if (poolShown() && banksShown()) {
|
||||
const RECT body = splitBody(w, h);
|
||||
const int dy = body.top + (body.bottom - body.top - kSplitDividerHeight) / 2;
|
||||
@@ -557,7 +478,6 @@ void paintPanel(HWND hwnd, HDC hdc) {
|
||||
toLice(roleColor(Role::BgBase)), 1.0f, 0);
|
||||
}
|
||||
|
||||
// Named-banks region (bottom).
|
||||
if (banksShown()) {
|
||||
const RECT region = banksRegionRect(w, h);
|
||||
drawRegionHeader(&bmp, region, "Banks", activeName, /*poolBtnIsPool=*/false);
|
||||
@@ -575,9 +495,8 @@ void paintPanel(HWND hwnd, HDC hdc) {
|
||||
? "Select or create a named bank."
|
||||
: "This bank is empty. Move samples here from the pool.",
|
||||
g_panel.focusedRegion == Region::Banks, projectDir, Region::Banks);
|
||||
// Drop-target highlight for the banks region during a drag. BanksRegion fires
|
||||
// when the pointer is in the grid but not on a specific tab; Tab draws its own
|
||||
// highlight on the individual tab (drawTabStrip above handles that case).
|
||||
// BanksRegion fires when the pointer is in the grid but not on a specific tab;
|
||||
// Tab draws its own highlight on the individual tab (drawTabStrip above).
|
||||
if (g_panel.dragging && g_panel.dropKind == DropKind::BanksRegion &&
|
||||
(g_panel.cardGesture == CardGesture::Move ||
|
||||
g_panel.cardGesture == CardGesture::Copy)) {
|
||||
@@ -586,16 +505,12 @@ void paintPanel(HWND hwnd, HDC hdc) {
|
||||
grid.right - grid.left - 2, grid.bottom - grid.top - 2,
|
||||
toLice(roleColor(Role::AccentHot)), 1.0f, 0);
|
||||
}
|
||||
// L7 per-slot reorder/replace target highlight (source = banks region).
|
||||
drawCardDropTarget(&bmp, region, /*isBanks=*/true, Region::Banks);
|
||||
}
|
||||
|
||||
// L4 three-zone chrome + L5 refinements: TOP toolbar (frequent capture + placement) tiles
|
||||
// into the band MINUS the far-right More-button reserve; the More button is drawn over the
|
||||
// band's reserved right strip; the BOTTOM toolbar (four opposite-mode tag buttons + Show
|
||||
// Both); then the footer (mode toggle + count + Tail button + Prune). Drawn last so they sit
|
||||
// over the split body's edges. drawToolbar fills only its passed (action) rect, so fill the
|
||||
// WHOLE top band first — otherwise the reserved right strip behind the More button is bare.
|
||||
// Toolbars + footer drawn last so they sit over the split body's edges. drawToolbar
|
||||
// fills only its passed (action) rect, so fill the WHOLE top band first — otherwise
|
||||
// the reserved right strip behind the More button is bare.
|
||||
fillSurface(&bmp, KitBox{0, 0, w, kTopToolbarHeight}, Role::BgPanel, InteractionState::Rest);
|
||||
drawToolbar(&bmp, topToolbarActionRect(w), topBarRows(), HoverKind::TopBarButton,
|
||||
/*topDivider=*/false);
|
||||
@@ -604,7 +519,6 @@ void paintPanel(HWND hwnd, HDC hdc) {
|
||||
/*topDivider=*/true);
|
||||
drawFooter(&bmp, w, h);
|
||||
|
||||
// The custom hover-delay tooltip overlays everything (L5 refinement 2).
|
||||
drawTooltip(&bmp, w, h);
|
||||
|
||||
BitBlt(hdc, 0, 0, w, h, bmp.getDC(), 0, 0, SRCCOPY);
|
||||
|
||||
Reference in New Issue
Block a user