monoslicer/Source/PianoRollDisplay.cpp

134 lines
4.5 KiB
C++
Raw Normal View History

2026-07-21 02:06:45 +02:00
#include "PianoRollDisplay.h"
PianoRollDisplay::PianoRollDisplay(SliceManager& sm) : sliceManager(sm)
{
startTimerHz(20);
}
PianoRollDisplay::~PianoRollDisplay() { stopTimer(); }
void PianoRollDisplay::timerCallback() { repaint(); }
void PianoRollDisplay::setActiveSlice(int index) { activeSlice = index; }
void PianoRollDisplay::setSelectedSlice(int index) { selectedSlice = index; }
void PianoRollDisplay::setTotalSamples(int total) { totalSamples = total; }
void PianoRollDisplay::setOnKeyClick(std::function<void(int)> callback) { onKeyClick = std::move(callback); }
juce::Colour PianoRollDisplay::sliceColour(int sliceIndex) const
{
juce::Colour colours[] = {
juce::Colour(0xffff6b6b), juce::Colour(0xff4ecdc4), juce::Colour(0xffffe66d),
juce::Colour(0xffa8e6cf), juce::Colour(0xff8b94ff), juce::Colour(0xffff8b94),
juce::Colour(0xffdda0dd), juce::Colour(0xff87ceeb), juce::Colour(0xff98fb98),
juce::Colour(0xffffb347), juce::Colour(0xffc39bd3), juce::Colour(0xff76d7c4)
};
return colours[sliceIndex % 12];
}
int PianoRollDisplay::rowToSliceIndex(int row) const
{
int noteRow = numRows - 1 - row;
const auto& slices = sliceManager.getSlices();
for (int i = 0; i < sliceManager.getNumSlices(); ++i)
{
if (slices[static_cast<size_t>(i)].midiNote % numRows == noteRow)
return i;
}
return -1;
}
void PianoRollDisplay::paint(juce::Graphics& g)
{
auto bounds = getLocalBounds();
float w = static_cast<float>(bounds.getWidth());
float h = static_cast<float>(bounds.getHeight());
float rowHeight = h / static_cast<float>(numRows);
g.fillAll(juce::Colour(0xff1a1a2e));
const auto& slices = sliceManager.getSlices();
int numSlices = sliceManager.getNumSlices();
int total = totalSamples;
if (total <= 0 && numSlices > 0)
total = slices[static_cast<size_t>(numSlices - 1)].endSample;
// Draw grid lines
for (int row = 0; row < numRows; ++row)
{
float y = static_cast<float>(row) * rowHeight;
g.setColour(juce::Colour(0x20ffffff));
g.drawHorizontalLine(static_cast<int>(y), 0.0f, w);
}
g.drawHorizontalLine(static_cast<int>(h), 0.0f, w);
// Draw slice blocks
if (numSlices > 0 && total > 0)
{
for (int i = 0; i < numSlices; ++i)
{
const auto& slice = slices[static_cast<size_t>(i)];
int noteRow = slice.midiNote % numRows;
int row = numRows - 1 - noteRow;
float xFrac = static_cast<float>(slice.startSample) / static_cast<float>(total);
float endFrac = static_cast<float>(slice.endSample) / static_cast<float>(total);
float x = xFrac * w;
float bw = (endFrac - xFrac) * w;
float y = static_cast<float>(row) * rowHeight + 2.0f;
float bh = rowHeight - 4.0f;
bw = juce::jmax(bw, 2.0f);
juce::Colour col = sliceColour(i);
bool isActive = (i == activeSlice);
bool isSelected = (i == selectedSlice);
g.setColour(isActive ? col.brighter(0.3f) : col.withAlpha(0.8f));
g.fillRoundedRectangle(x + 1.0f, y, bw - 2.0f, bh, 3.0f);
if (isSelected && !isActive)
{
g.setColour(col.brighter(0.5f));
g.drawRoundedRectangle(x + 1.0f, y, bw - 2.0f, bh, 3.0f, 2.0f);
}
else
{
g.setColour(col.brighter(0.5f).withAlpha(0.6f));
g.drawRoundedRectangle(x + 1.0f, y, bw - 2.0f, bh, 3.0f, 1.0f);
}
if (bw > 16.0f)
{
g.setColour(juce::Colours::white);
g.setFont(10.0f);
g.drawText(juce::String(i + 1), static_cast<int>(x + 3.0f), static_cast<int>(y),
static_cast<int>(bw - 6.0f), static_cast<int>(bh),
juce::Justification::centred);
}
}
}
}
void PianoRollDisplay::resized() {}
void PianoRollDisplay::mouseDown(const juce::MouseEvent& e)
{
float rowHeight = static_cast<float>(getHeight()) / static_cast<float>(numRows);
int row = static_cast<int>(static_cast<float>(e.getPosition().getY()) / rowHeight);
row = juce::jlimit(0, numRows - 1, row);
pressedKey = row;
repaint();
int sliceIdx = rowToSliceIndex(row);
if (sliceIdx >= 0 && onKeyClick)
onKeyClick(sliceIdx);
}
void PianoRollDisplay::mouseUp(const juce::MouseEvent&)
{
pressedKey = -1;
repaint();
}