fully working beatpad configuration; esc on patchboard to go up a level
parent
807c923543
commit
f7f5e15070
|
@ -322,6 +322,8 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||
return w->QObject::eventFilter(w, e);
|
||||
}));
|
||||
|
||||
connect(new QShortcut(QKeySequence("Esc"), view), &QShortcut::activated, this, [this] { ui->patchboardBreadcrumbs->up(); });
|
||||
|
||||
}
|
||||
|
||||
{ /* Set up sample list */ } {
|
||||
|
@ -585,8 +587,8 @@ void MainWindow::openGraph(const std::shared_ptr<Data::Graph>& g) {
|
|||
delete ui->patchboardView->scene();
|
||||
//ui->patchboardView->setScene(nullptr);
|
||||
ui->patchboardView->setScene(new PatchboardScene(ui->patchboardView, g));
|
||||
QScroller::scroller(ui->patchboardView)->scrollTo(scrollPt, 0);
|
||||
QScroller::scroller(ui->patchboardView)->scrollTo(scrollPt, 1);
|
||||
auto sz = ui->patchboardView->viewport()->visibleRegion().boundingRect().size();
|
||||
ui->patchboardView->centerOn(scrollPt + QPointF(sz.width()/2, sz.height()/2));
|
||||
}
|
||||
|
||||
void MainWindow::openNodeUI(const std::shared_ptr<Data::Node>& n) {
|
||||
|
|
|
@ -166,64 +166,80 @@ void BeatPad::onGadgetCreated() {
|
|||
|
||||
void BeatPad::onDoubleClick() { emit project->socket->openNodeUI(this); }
|
||||
void BeatPad::initUI(NodeUIScene* scene) {
|
||||
//scene->addItem()
|
||||
// define and create state management struct
|
||||
// (lambda captures will end up managing the lifetime of this thing)
|
||||
struct UIState {
|
||||
std::shared_ptr<NoteConfig> cfg;
|
||||
int16_t note = -1;
|
||||
|
||||
{
|
||||
auto s = new SelectorGadget();
|
||||
//s->setPos(0, 0);
|
||||
s->setWidth(320);
|
||||
s->fGetList = [this] {
|
||||
std::vector<SelectorGadget::Entry> v;
|
||||
v.reserve(cfg.size());
|
||||
for (int16_t i = 0; i < 12*8; i++) {
|
||||
if (auto f = cfg.find(i); f != cfg.end()) {
|
||||
auto c = f->second;
|
||||
QString n;
|
||||
if (auto smp = c->smp.lock(); smp) n = smp->name;
|
||||
v.push_back({ f->first, qs("%1 %2").arg(Util::noteName(i)).arg(n) });
|
||||
}
|
||||
std::function<void(int16_t)> selectNote;
|
||||
std::function<void(std::shared_ptr<Sample>)> setSample;
|
||||
};
|
||||
auto state = std::make_shared<UIState>();
|
||||
|
||||
// set up gadgets
|
||||
auto noteSelector = new SelectorGadget();
|
||||
scene->addItem(noteSelector);
|
||||
noteSelector->setPos(0, 0);
|
||||
noteSelector->setWidth(320);
|
||||
|
||||
noteSelector->fGetList = [=] {
|
||||
std::vector<SelectorGadget::Entry> v;
|
||||
v.reserve(cfg.size());
|
||||
for (int16_t i = 0; i < 12*8; i++) {
|
||||
if (auto f = cfg.find(i); f != cfg.end()) {
|
||||
auto c = f->second;
|
||||
QString n;
|
||||
if (auto smp = c->smp.lock(); smp) n = smp->name;
|
||||
v.push_back({ f->first, qs("%1 %2").arg(Util::noteName(i)).arg(n) });
|
||||
}
|
||||
return v;
|
||||
};
|
||||
s->fEditMenu = [this](QMenu* m) {
|
||||
auto first = m->actions().at(0);
|
||||
auto mAdd = new QMenu("Add...", m);
|
||||
m->insertMenu(first, mAdd);
|
||||
m->insertSeparator(first);
|
||||
for (int16_t oct = 0; oct < 8; oct++) {
|
||||
auto mo = mAdd->addMenu(qs("Octave %1").arg(oct));
|
||||
for (int16_t i = 0; i < 12; i++) {
|
||||
int16_t n = oct*12+i;
|
||||
if (auto f = cfg.find(n); f != cfg.end()) mo->addAction(Util::noteName(n))->setDisabled(true);
|
||||
else mo->addAction(Util::noteName(n));
|
||||
}
|
||||
}
|
||||
return v;
|
||||
};
|
||||
noteSelector->fEditMenu = [=](QMenu* m) {
|
||||
auto first = m->actions().at(0);
|
||||
auto mAdd = new QMenu("Add...", m);
|
||||
m->insertMenu(first, mAdd);
|
||||
m->insertSeparator(first);
|
||||
for (int16_t oct = 0; oct < 8; oct++) {
|
||||
auto mo = mAdd->addMenu(qs("Octave %1").arg(oct));
|
||||
for (int16_t i = 0; i < 12; i++) {
|
||||
int16_t n = oct*12+i;
|
||||
if (auto f = cfg.find(n); f != cfg.end()) mo->addAction(Util::noteName(n))->setDisabled(true);
|
||||
else mo->addAction(Util::noteName(n), [=] { state->selectNote(n); });
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
scene->addItem(s);
|
||||
auto sampleSelector = new SampleSelectorGadget(project);
|
||||
scene->addItem(sampleSelector);
|
||||
sampleSelector->setPos(0, 28);
|
||||
sampleSelector->setSize(320, 96);
|
||||
|
||||
QObject::connect(scene, &NodeUIScene::notePreview, s, [s](int16_t note) {
|
||||
//k->setLabel(Util::noteName(note));
|
||||
s->setEntry({note, Util::noteName(note)});
|
||||
});
|
||||
// create functions now that all UI elements exist to be referenced
|
||||
state->selectNote = [=](int16_t n) {
|
||||
if (auto f = cfg.find(n); f != cfg.end()) state->cfg = f->second;
|
||||
else state->cfg = std::make_shared<NoteConfig>();
|
||||
state->note = n;
|
||||
auto smp = state->cfg->smp.lock();
|
||||
sampleSelector->setSample(smp);
|
||||
|
||||
/*auto wfp = new WaveformPreviewWidget();
|
||||
scene->addWidget(wfp);
|
||||
wfp->move(0, 28);
|
||||
wfp->resize(320, 96);
|
||||
//pw->setCacheMode(QGraphicsProxyWidget::CacheMode::NoCache);
|
||||
//wfp->resize(320, 96);
|
||||
wfp->setSample(project->samples.begin().value());*/
|
||||
noteSelector->setEntry({n, qs("%1 %2").arg(Util::noteName(n)).arg(smp ? smp->name : "")}, false);
|
||||
};
|
||||
state->setSample = [=](std::shared_ptr<Sample> smp) {
|
||||
state->cfg->smp = smp;
|
||||
auto n = state->note;
|
||||
if (smp) cfg[n] = state->cfg;
|
||||
else if (auto f = cfg.find(n); f != cfg.end()) cfg.erase(f);
|
||||
|
||||
auto sampleSelector = new SampleSelectorGadget(project);
|
||||
scene->addItem(sampleSelector);
|
||||
sampleSelector->setPos(0, 28);
|
||||
sampleSelector->setSize(320, 96);
|
||||
noteSelector->setEntry({n, qs("%1 %2").arg(Util::noteName(n)).arg(smp ? smp->name : "")}, false);
|
||||
};
|
||||
|
||||
// TODO hook things up to actually *make* entries
|
||||
auto c = cfg.at(60);
|
||||
sampleSelector->setSample(c->smp.lock());
|
||||
QObject::connect(sampleSelector, &SampleSelectorGadget::sampleSelected, [c](auto s) {c->smp = s;});
|
||||
}
|
||||
// hook up relevantsignals
|
||||
QObject::connect(scene, &NodeUIScene::notePreview, [=](int16_t note) { state->selectNote(note); });
|
||||
QObject::connect(noteSelector, &SelectorGadget::onSelect, [=](auto e) { state->selectNote(e.first); });
|
||||
QObject::connect(sampleSelector, &SampleSelectorGadget::sampleSelected, [=](auto smp) { state->setSample(smp); });
|
||||
|
||||
// and lastly, select C-5 by default
|
||||
state->selectNote(60);
|
||||
}
|
||||
|
|
|
@ -22,6 +22,11 @@ BreadcrumbView::BreadcrumbView(QWidget* parent) : QTableView (parent) {
|
|||
});
|
||||
}
|
||||
|
||||
void BreadcrumbView::up() {
|
||||
auto ind = currentIndex();
|
||||
if (ind.column() > 0) setCurrentIndex(ind.siblingAtColumn(ind.column() - 1));
|
||||
}
|
||||
|
||||
void BreadcrumbView::clear() {
|
||||
mdl->actions.clear();
|
||||
emit mdl->layoutChanged();
|
||||
|
|
|
@ -34,5 +34,7 @@ namespace Xybrid::UI {
|
|||
BreadcrumbView(QWidget* parent = nullptr);
|
||||
void clear();
|
||||
void push(const QString& text, QObject* bind, std::function<void()> action);
|
||||
|
||||
void up();
|
||||
};
|
||||
}
|
||||
|
|
|
@ -114,19 +114,23 @@ void SampleSelectorGadget::mousePressEvent(QGraphicsSceneMouseEvent* e) {
|
|||
if (e->button() == Qt::LeftButton) {
|
||||
auto smp = currentSample.lock();
|
||||
auto* m = new QMenu();
|
||||
for (auto s : displayOrder) {
|
||||
auto wa = new QWidgetAction(m);
|
||||
auto wfp = new WaveformPreviewWidget(m);
|
||||
wa->setDefaultWidget(wfp);
|
||||
wfp->showName = true;
|
||||
wfp->highlightable = true;
|
||||
wfp->setSample(s);
|
||||
wfp->setMinimumSize(192, 48);
|
||||
m->addAction(wa);
|
||||
if (s == smp) wa->setDisabled(true);
|
||||
else connect(wa, &QWidgetAction::triggered, [this, s] { setSample(s); });
|
||||
}
|
||||
if (displayOrder.empty()) m->addAction("(no samples in project)")->setDisabled(true);
|
||||
else {
|
||||
m->addAction("(no sample)", [this] { setSample(nullptr); });
|
||||
m->addSeparator();
|
||||
for (auto s : displayOrder) {
|
||||
auto wa = new QWidgetAction(m);
|
||||
auto wfp = new WaveformPreviewWidget(m);
|
||||
wa->setDefaultWidget(wfp);
|
||||
wfp->showName = true;
|
||||
wfp->highlightable = true;
|
||||
wfp->setSample(s);
|
||||
wfp->setMinimumSize(192, 48);
|
||||
m->addAction(wa);
|
||||
if (s == smp) wa->setDisabled(true);
|
||||
else connect(wa, &QWidgetAction::triggered, [this, s] { setSample(s); });
|
||||
}
|
||||
}
|
||||
m->setAttribute(Qt::WA_DeleteOnClose);
|
||||
m->popup(e->screenPos());
|
||||
}
|
||||
|
|
|
@ -14,6 +14,10 @@ using Xybrid::Data::Sample;
|
|||
|
||||
#include <QPaintEvent>
|
||||
#include <QPainter>
|
||||
#include <QStylePainter>
|
||||
#include <QStyle>
|
||||
#include <QStyleOptionFrame>
|
||||
#include <QFocusFrame>
|
||||
|
||||
WaveformPreviewWidget::WaveformPreviewWidget(QWidget* parent) : QFrame(parent) {
|
||||
setFrameStyle(Shape::StyledPanel | Shadow::Sunken);
|
||||
|
@ -48,7 +52,7 @@ void WaveformPreviewWidget::paintChannel(QPainter& p, std::shared_ptr<Sample> sm
|
|||
void WaveformPreviewWidget::paintEvent(QPaintEvent* event [[maybe_unused]]) {
|
||||
auto disabled = !isEnabled();
|
||||
|
||||
QPainter p(this);
|
||||
QStylePainter p(this);
|
||||
p.setRenderHint(QPainter::RenderHint::Antialiasing, false); // ensure sharpness even when rendered in a QGraphicsScene
|
||||
QRect rect(QPoint(), size());
|
||||
auto lw = lineWidth();
|
||||
|
@ -88,7 +92,12 @@ void WaveformPreviewWidget::paintEvent(QPaintEvent* event [[maybe_unused]]) {
|
|||
p.fillPath(path, QColor(255, 255, 255));
|
||||
}
|
||||
|
||||
QFrame::paintEvent(event);
|
||||
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*) {
|
||||
|
|
Loading…
Reference in New Issue