Ω-W1-T3: run the master meter on its own 60 FPS timer, and make a meter frame cost one rect
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
// editor_paint.cpp — the ReaSamplerEditor's paint dispatch: the WM_PAINT entry, the Sample
|
||||
// face's band composition (chrome / waveform / decks, each drawn by its own TU), the empty
|
||||
// state, and the drop-affordance banner. Windows-only; draws through the shared kit by
|
||||
// palette role. All layout math is pure (sample_bands) — this TU only sequences.
|
||||
// editor_paint.cpp — the ReaSamplerEditor's paint dispatch: the WM_PAINT entry over a retained
|
||||
// back buffer (with the meter's dirty-rect fast path), the Sample face's band composition
|
||||
// (chrome / waveform / decks, each drawn by its own TU), the empty state, and the
|
||||
// drop-affordance banner. Windows-only; draws through the shared kit by palette role. All
|
||||
// layout math is pure (sample_bands) — this TU only sequences.
|
||||
|
||||
#include "shell/instrument/reasampler_editor.h"
|
||||
|
||||
@@ -18,37 +19,75 @@ namespace reasampler::vst {
|
||||
using namespace reasampler::ui; // kit vocabulary (Role / InteractionState / KitBox / …)
|
||||
using namespace reasampler::instrument::ui; // pure geometry (bands / chrome)
|
||||
|
||||
void ReaSamplerEditor::paint(HDC hdc) {
|
||||
LICE_IBitmap* ReaSamplerEditor::ensureBackBuffer(int w, int h) {
|
||||
if (w <= 0 || h <= 0) return nullptr;
|
||||
// resize() is a no-op at the current size, so the steady-state paint allocates nothing.
|
||||
if (!backBuffer_) backBuffer_ = new LICE_SysBitmap(w, h);
|
||||
else backBuffer_->resize(w, h);
|
||||
return backBuffer_;
|
||||
}
|
||||
|
||||
void ReaSamplerEditor::releaseBackBuffer() {
|
||||
delete backBuffer_;
|
||||
backBuffer_ = nullptr;
|
||||
}
|
||||
|
||||
void ReaSamplerEditor::paint(HDC hdc, const RECT& dirty) {
|
||||
RECT cr{};
|
||||
GetClientRect(childHwnd_, &cr);
|
||||
const int w = cr.right - cr.left;
|
||||
const int h = cr.bottom - cr.top;
|
||||
if (w <= 0 || h <= 0) return;
|
||||
|
||||
LICE_SysBitmap bmp(w, h);
|
||||
LICE_Clear(&bmp, toLice(roleColor(Role::BgBase)));
|
||||
LICE_IBitmap* bmp = ensureBackBuffer(w, h);
|
||||
if (!bmp) return;
|
||||
|
||||
// Sample is home; Browse is a full-window modal overlay drawn over it, so the Sample
|
||||
// face draws first and the modal reads as a sheet layered on top.
|
||||
paintSample(&bmp, w, h);
|
||||
if (view_ == View::kBrowse) paintBrowse(&bmp, w, h);
|
||||
// The host's update rect, clipped to the client area.
|
||||
const int dx = (std::max)(0, static_cast<int>(dirty.left));
|
||||
const int dy = (std::max)(0, static_cast<int>(dirty.top));
|
||||
const int dr = (std::min)(w, static_cast<int>(dirty.right));
|
||||
const int db = (std::min)(h, static_cast<int>(dirty.bottom));
|
||||
if (dr <= dx || db <= dy) return;
|
||||
|
||||
// A transient banner flashed after a file was dropped on this window. It reiterates the
|
||||
// shipped ingest gesture rather than swallowing the drop silently. Drawn last so it
|
||||
// overlays whatever view is up; decays via onSyncTimer (dropHintTicks_).
|
||||
if (dropHintTicks_ > 0) {
|
||||
const int bannerTop = (std::min)(kTitleHeight, h);
|
||||
const int bannerH = (std::min)(kTitleHeight + 8, (std::max)(0, h - bannerTop));
|
||||
Rect banner = Rect::ltrb(0, bannerTop, w, bannerTop + bannerH);
|
||||
// A transient notice, not the live layer — draw it on the accent-tertiary categorical
|
||||
// hue with a dark label so it reads as "attention, not action".
|
||||
fillSurface(&bmp, toKitBox(banner), Role::AccentTertiary, InteractionState::Rest);
|
||||
kitTextCentered(&bmp, banner,
|
||||
"Dropped here isn't loaded yet - drop files onto the ReaSampler bank panel to add them.",
|
||||
Font::Label, Role::BgBase);
|
||||
// A meter frame's dirty rect lies wholly inside the bar field, and nothing else is drawn
|
||||
// there — so the field is all that needs redrawing, and the rest of the face is still in the
|
||||
// back buffer from the last full compose. Decided GEOMETRICALLY rather than by a flag,
|
||||
// because Windows coalesces a meter invalidate with any other pending one into a single
|
||||
// union rect: a flag would then paint a meter frame over a face that had really changed.
|
||||
const Rect& mf = meterRects_.field;
|
||||
if (!mf.empty() && dx >= mf.x && dy >= mf.y && dr <= mf.right() && db <= mf.bottom()) {
|
||||
paintMeterField(bmp);
|
||||
} else {
|
||||
// Repopulated by paintDeck when the meter is on screen; left empty by the empty state.
|
||||
meterRects_ = {};
|
||||
LICE_Clear(bmp, toLice(roleColor(Role::BgBase)));
|
||||
|
||||
// Sample is home; Browse is a full-window modal overlay drawn over it, so the Sample
|
||||
// face draws first and the modal reads as a sheet layered on top.
|
||||
paintSample(bmp, w, h);
|
||||
if (view_ == View::kBrowse) paintBrowse(bmp, w, h);
|
||||
|
||||
// A transient banner flashed after a file was dropped on this window. It reiterates the
|
||||
// shipped ingest gesture rather than swallowing the drop silently. Drawn last so it
|
||||
// overlays whatever view is up; decays via onSyncTimer (dropHintTicks_).
|
||||
if (dropHintTicks_ > 0) {
|
||||
const int bannerTop = (std::min)(kTitleHeight, h);
|
||||
const int bannerH = (std::min)(kTitleHeight + 8, (std::max)(0, h - bannerTop));
|
||||
Rect banner = Rect::ltrb(0, bannerTop, w, bannerTop + bannerH);
|
||||
// A transient notice, not the live layer — draw it on the accent-tertiary
|
||||
// categorical hue with a dark label so it reads as "attention, not action".
|
||||
fillSurface(bmp, toKitBox(banner), Role::AccentTertiary, InteractionState::Rest);
|
||||
kitTextCentered(bmp, banner,
|
||||
"Dropped here isn't loaded yet - drop files onto the ReaSampler bank panel to add them.",
|
||||
Font::Label, Role::BgBase);
|
||||
}
|
||||
|
||||
// A sheet layered over the face covers the meter, so the fast path must not paint
|
||||
// through it — dropping the rect routes the next meter tick down this path instead.
|
||||
if (view_ == View::kBrowse || curvePopup_ != CurveTarget::kNone) meterRects_ = {};
|
||||
}
|
||||
|
||||
BitBlt(hdc, 0, 0, w, h, bmp.getDC(), 0, 0, SRCCOPY);
|
||||
BitBlt(hdc, dx, dy, dr - dx, db - dy, bmp->getDC(), dx, dy, SRCCOPY);
|
||||
}
|
||||
|
||||
void ReaSamplerEditor::paintSample(LICE_IBitmap* bmp, int w, int h) {
|
||||
|
||||
Reference in New Issue
Block a user