127 lines
4.3 KiB
C++
127 lines
4.3 KiB
C++
#include "waveformpreviewwidget.h"
|
|
using Xybrid::UI::WaveformPreviewWidget;
|
|
|
|
#include "data/sample.h"
|
|
using Xybrid::Data::Sample;
|
|
|
|
#include "config/colorscheme.h"
|
|
|
|
#include "util/strings.h"
|
|
|
|
#include <cmath>
|
|
|
|
#include <QDebug>
|
|
|
|
#include <QPaintEvent>
|
|
#include <QPainter>
|
|
#include <QPainterPath>
|
|
#include <QStylePainter>
|
|
#include <QStyle>
|
|
#include <QStyleOptionFrame>
|
|
#include <QFocusFrame>
|
|
|
|
WaveformPreviewWidget::WaveformPreviewWidget(QWidget* parent) : QFrame(parent) {
|
|
setFrameStyle(Shape::StyledPanel | Shadow::Sunken);
|
|
setLineWidth(2);
|
|
}
|
|
|
|
void WaveformPreviewWidget::setSample(std::shared_ptr<Sample> smp) {
|
|
currentSample = smp;
|
|
//int ch = 1;
|
|
//if (smp) ch = std::max(1, smp->numChannels());
|
|
//setMinimumHeight(128 * ch);
|
|
repaint(); // invalidate paint state
|
|
}
|
|
|
|
void WaveformPreviewWidget::paintChannel(QPainter& p, std::shared_ptr<Sample> smp, size_t ch, QRect rect) {
|
|
auto x = rect.x();
|
|
auto y = rect.y();
|
|
auto h = rect.height();
|
|
auto c = h / 2;
|
|
double scale = static_cast<double>(smp->length()) / static_cast<double>(rect.width());
|
|
for (int i = 0; i < rect.width(); i++) {
|
|
size_t sp1 = static_cast<size_t>(std::floor(static_cast<double>(i) * scale));
|
|
size_t sp2 = static_cast<size_t>(std::floor(static_cast<double>(i+1) * scale)); // would be - 1, but this makes sure adjacent pixels always share at least one value
|
|
auto v = smp->plotBetween(ch, sp1, sp2);
|
|
v[0] = std::clamp(v[0], -1.0f, 1.0f);
|
|
v[1] = std::clamp(v[1], -1.0f, 1.0f);
|
|
//qDebug() << "x" << i << "v" << v[1] << v[2];
|
|
p.drawLine(QPoint(x+i, static_cast<int>(y+c - (c * v[0]))), QPoint(x+i, static_cast<int>(y+c - (c * v[1]))));
|
|
}
|
|
}
|
|
|
|
void WaveformPreviewWidget::paintEvent(QPaintEvent* event [[maybe_unused]]) {
|
|
auto disabled = !isEnabled();
|
|
|
|
QStylePainter p(this);
|
|
p.setRenderHint(QPainter::RenderHint::Antialiasing, false); // ensure sharpness even when rendered in a QGraphicsScene
|
|
QRect rect(QPoint(), size());
|
|
auto lw = lineWidth();
|
|
rect.adjust(lw, lw, -lw, -lw);
|
|
|
|
if (highlighted && !disabled) p.fillRect(rect, Config::colorScheme.waveformBgHighlight);
|
|
else p.fillRect(rect, Config::colorScheme.waveformBg);
|
|
|
|
p.setPen(QPen(Config::colorScheme.waveformFgPrimary));
|
|
if (disabled) p.setPen(Config::colorScheme.waveformFgPrimary.darker());
|
|
|
|
QString name = qs("(no data)");
|
|
if (auto smp = currentSample.lock(); smp) {
|
|
name = smp->name;
|
|
auto chs = smp->numChannels();
|
|
if (chs == 1) paintChannel(p, smp, 0, rect);
|
|
else if (chs == 2) {
|
|
auto cs = rect.height() / 2;
|
|
auto r = rect.adjusted(0, 0, 0, -cs);
|
|
paintChannel(p, smp, 0, r);
|
|
paintChannel(p, smp, 1, r.translated(0, cs));
|
|
}
|
|
if (showLoopPoints && smp->loopStart >= 0) { // draw loop points if able
|
|
double scale = static_cast<double>(smp->length()) / static_cast<double>(rect.width());
|
|
p.setPen(Config::colorScheme.waveformLoopPoints);
|
|
auto x = rect.x();
|
|
auto y = rect.y();
|
|
auto h = rect.height();
|
|
auto xs = x + static_cast<int>(static_cast<double>(smp->loopStart)/scale);
|
|
auto xe = x + static_cast<int>(static_cast<double>(smp->loopEnd)/scale);
|
|
p.drawLine(QPoint(xs, y), QPoint(xs, y+h));
|
|
p.drawLine(QPoint(xe, y), QPoint(xe, y+h));
|
|
}
|
|
}
|
|
|
|
if (showName) {
|
|
// draw label
|
|
QFont font("Arcon Rounded", 8);
|
|
QFontMetrics fm(font);
|
|
name = fm.elidedText(name.section('/', -1, -1), Qt::ElideRight, rect.width() - 4);
|
|
QPainterPath path;
|
|
path.addText(rect.bottomLeft() + QPointF(2, -fm.descent()), font, name);
|
|
|
|
p.setRenderHint(QPainter::Antialiasing, true);
|
|
p.fillPath(path, QColor(0, 0, 0));
|
|
p.strokePath(path, QPen(QColor(0, 0, 0), 3));
|
|
p.fillPath(path, QColor(255, 255, 255));
|
|
}
|
|
|
|
setAttribute(Qt::WA_Hover, highlighted);
|
|
QStyleOptionFrame optF;
|
|
optF.initFrom(this);
|
|
optF.lineWidth = 2;
|
|
optF.state |= QStyle::State_Sunken;
|
|
style()->drawPrimitive(QStyle::PE_Frame, &optF, &p, this);
|
|
}
|
|
|
|
void WaveformPreviewWidget::enterEvent(QEvent*) {
|
|
if (highlightable) {
|
|
highlighted = true;
|
|
repaint();
|
|
}
|
|
}
|
|
|
|
void WaveformPreviewWidget::leaveEvent(QEvent*) {
|
|
if (highlightable) {
|
|
highlighted = false;
|
|
repaint();
|
|
}
|
|
}
|