deck: filter mod moves to FILTER ENV, cell runs centre in their reserves, two-segment toggles become single buttons, deck focuses its overlay

This commit is contained in:
2026-08-03 13:12:28 -04:00
parent 0eb2c67875
commit 450559f155
22 changed files with 885 additions and 504 deletions
+22 -37
View File
@@ -1,6 +1,6 @@
// editor_paint_chrome.cpp — the CHROME band's painter: the toolbar row (product title +
// live readout, then the control run — preview, preview-velocity knob, Loop Off|On,
// Mono|Stereo, Browse) over the strip row, which the piano strip has to itself. Windows-only;
// live readout, then the control run — preview, preview-velocity knob, Loop, the channel mode,
// Browse) over the strip row, which the piano strip has to itself. Windows-only;
// all rects come from the pure sample_chrome interior and the pure keyboard_strip geometry.
#include "shell/instrument/reasampler_editor.h"
@@ -212,44 +212,29 @@ void ReaSamplerEditor::paintChrome(LICE_IBitmap* bmp, const FaceLayout& fl, bool
}
}
// Loop Off | On. A two-segment toggle in the same primitive as Mono|Stereo because it is
// the same class of control: a playback mode of the loaded capture. Outside Gate both
// segments draw Disabled and neither accepts a click — the state is preserved, not cleared,
// so the return to Gate restores it.
// The two single-button chrome controls, in the deck's own grammar: Loop is an ENABLE
// (Primary on, dim gray off), the channel button is a MODE SELECTOR whose label reads the
// current mode and so has no off state. Outside Gate the loop button draws Disabled and
// accepts no click — a third state, not an off: the enable's own state is preserved, not
// cleared, so the return to Gate restores it.
{
const bool live = loopControlsLive();
const bool on = marks.hasLoop;
const auto segState = [&](bool active, HoverKind hk) {
if (!live) return InteractionState::Disabled;
if (active) return InteractionState::Active;
return isHovered(hk, -1) ? InteractionState::Hover : InteractionState::Rest;
const auto drawChromeToggle = [&](const Rect& r, const char* label, HoverKind hk,
bool active, bool disabled) {
const bool hov = !disabled && isHovered(hk, -1);
const InteractionState st =
disabled ? InteractionState::Disabled
: (active ? InteractionState::Active
: (hov ? InteractionState::Hover : InteractionState::Rest));
fillSurface(bmp, toKitBox(r), Role::BgCell, st);
kitTextCentered(bmp, r, label, kToolbarFont,
active && !disabled ? Role::BgBase
: (hov ? Role::TextPrimary : Role::TextDim));
};
const InteractionState offState = segState(!on, HoverKind::kLoopOff);
const InteractionState onState = segState(on, HoverKind::kLoopOn);
fillSurface(bmp, toKitBox(cr.loopOff), Role::BgCell, offState);
fillSurface(bmp, toKitBox(cr.loopOn), Role::BgCell, onState);
const Role dim = live ? Role::TextPrimary : Role::TextDim;
kitTextCentered(bmp, cr.loopOff, "Loop Off", kToolbarFont,
(live && !on) ? Role::BgBase : dim);
kitTextCentered(bmp, cr.loopOn, "Loop On", kToolbarFont,
(live && on) ? Role::BgBase : dim);
}
// Mono | Stereo output-mode toggle.
{
drawChromeToggle(cr.loop, "Loop", HoverKind::kLoop, marks.hasLoop,
!loopControlsLive());
const bool isStereo = (channelMode_ == ChannelMode::Stereo);
const InteractionState monoState = !isStereo ? InteractionState::Active
: (isHovered(HoverKind::kChanMono, -1) ? InteractionState::Hover
: InteractionState::Rest);
const InteractionState stereoState = isStereo ? InteractionState::Active
: (isHovered(HoverKind::kChanStereo, -1) ? InteractionState::Hover
: InteractionState::Rest);
fillSurface(bmp, toKitBox(cr.chanMono), Role::BgCell, monoState);
fillSurface(bmp, toKitBox(cr.chanStereo), Role::BgCell, stereoState);
kitTextCentered(bmp, cr.chanMono, "Mono", kToolbarFont,
!isStereo ? Role::BgBase : Role::TextPrimary);
kitTextCentered(bmp, cr.chanStereo, "Stereo", kToolbarFont,
isStereo ? Role::BgBase : Role::TextPrimary);
drawChromeToggle(cr.channel, isStereo ? "Stereo" : "Mono", HoverKind::kChannel,
/*active=*/true, /*disabled=*/false);
}
// The strip row: the full 128-key piano with the root lit. The loaded capture responds