fully working beatpad configuration; esc on patchboard to go up a level

portability/boost
zetaPRIME 2019-06-23 02:26:52 -04:00
parent 807c923543
commit f7f5e15070
6 changed files with 105 additions and 67 deletions

View File

@ -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) {

View File

@ -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);
}

View File

@ -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();

View File

@ -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();
};
}

View File

@ -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());
}

View File

@ -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*) {