middle click to remove sequence entry
parent
f173a0e87f
commit
9d45d78795
14
notes
14
notes
|
@ -32,8 +32,9 @@ parameters {
|
||||||
|
|
||||||
TODO {
|
TODO {
|
||||||
immediate frontburner {
|
immediate frontburner {
|
||||||
- add standardized step values for knobs and set a default (int enum)
|
spacer rows on top/bottom of pattern editor (keep centered)
|
||||||
global pan (PXX) for InstrumentCore?
|
|
||||||
|
global pan (PXX) for InstrumentCore? *default* pan
|
||||||
|
|
||||||
- node function to release unneeded old data when stopping playback
|
- node function to release unneeded old data when stopping playback
|
||||||
...
|
...
|
||||||
|
@ -47,19 +48,12 @@ TODO {
|
||||||
|
|
||||||
|
|
||||||
bugs to fix {
|
bugs to fix {
|
||||||
-? it sometimes crashes on exit??
|
playback after stopping immediately after a note in the first pattern played sometimes skips that note
|
||||||
|
|
||||||
... does graph really need to call reset() on its children at this point
|
|
||||||
}
|
}
|
||||||
|
|
||||||
misc features needed before proper release {
|
misc features needed before proper release {
|
||||||
- song metadata (title, artist, comment, default bpm)
|
|
||||||
|
|
||||||
at *least* js plugin support, with lua+lv2 highly preferable
|
at *least* js plugin support, with lua+lv2 highly preferable
|
||||||
- SAMPLES and SAMPLING
|
|
||||||
|
|
||||||
- gadget widgets (w/container) - at least a knob with nice range and such
|
|
||||||
|
|
||||||
different context menu for multiple selected nodes
|
different context menu for multiple selected nodes
|
||||||
/ pack/unpack selection to/from subgraph (partial; can copy/paste a selection)
|
/ pack/unpack selection to/from subgraph (partial; can copy/paste a selection)
|
||||||
|
|
||||||
|
|
|
@ -362,7 +362,7 @@ Pattern* AudioEngine::findPattern(int adv) {
|
||||||
|
|
||||||
if (mode == Rendering && !s) return nullptr; // stop
|
if (mode == Rendering && !s) return nullptr; // stop
|
||||||
else if (mode == Rendering && s->type == SequenceEntry::LoopTrigger) { seqPos++; continue; }
|
else if (mode == Rendering && s->type == SequenceEntry::LoopTrigger) { seqPos++; continue; }
|
||||||
else if (!s || s->type == SequenceEntry::LoopTrigger) { // off end or explicit loop, find loop point
|
else if (!s || (s->type == SequenceEntry::LoopTrigger && seqPos > 0)) { // off end or explicit loop, find loop point
|
||||||
for (seqPos = std::min(seqPos, static_cast<int>(project->sequence.size()) - 1); seqPos >= 0; --seqPos)
|
for (seqPos = std::min(seqPos, static_cast<int>(project->sequence.size()) - 1); seqPos >= 0; --seqPos)
|
||||||
if (project->sequence[static_cast<size_t>(seqPos)].type == SequenceEntry::LoopStart) break;
|
if (project->sequence[static_cast<size_t>(seqPos)].type == SequenceEntry::LoopStart) break;
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -20,8 +20,8 @@ bool ProjectCommand::cancel() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ProjectSequencerDeltaCommand::ProjectSequencerDeltaCommand(const std::shared_ptr<Project>& project) {
|
ProjectSequencerDeltaCommand::ProjectSequencerDeltaCommand(const std::shared_ptr<Project>& project_) {
|
||||||
this->project = project;
|
project = project_;
|
||||||
oldSeq = project->sequence;
|
oldSeq = project->sequence;
|
||||||
oldSeqSel = project->socket->window->sequenceSelection();
|
oldSeqSel = project->socket->window->sequenceSelection();
|
||||||
seq = oldSeq;
|
seq = oldSeq;
|
||||||
|
@ -50,8 +50,8 @@ void ProjectSequencerDeltaCommand::undo() {
|
||||||
project->socket->window->sequenceSelection(oldSeqSel);
|
project->socket->window->sequenceSelection(oldSeqSel);
|
||||||
}
|
}
|
||||||
|
|
||||||
ProjectPatternMoveCommand::ProjectPatternMoveCommand(const std::shared_ptr<Project>& project, int f, int t) {
|
ProjectPatternMoveCommand::ProjectPatternMoveCommand(const std::shared_ptr<Project>& project_, int f, int t) {
|
||||||
this->project = project;
|
project = project_;
|
||||||
from = f;
|
from = f;
|
||||||
to = t;
|
to = t;
|
||||||
setText("move pattern");
|
setText("move pattern");
|
||||||
|
@ -85,8 +85,8 @@ void ProjectPatternMoveCommand::undo() {
|
||||||
if (move) project->socket->window->patternSelection(from);
|
if (move) project->socket->window->patternSelection(from);
|
||||||
}
|
}
|
||||||
|
|
||||||
ProjectPatternAddCommand::ProjectPatternAddCommand(const std::shared_ptr<Project>& project, int at, int atSeq, const std::shared_ptr<Pattern>& copyOf) {
|
ProjectPatternAddCommand::ProjectPatternAddCommand(const std::shared_ptr<Project>& project_, int at, int atSeq, const std::shared_ptr<Pattern>& copyOf) {
|
||||||
this->project = project;
|
project = project_;
|
||||||
if (at < 0) at = std::numeric_limits<int>::max();
|
if (at < 0) at = std::numeric_limits<int>::max();
|
||||||
this->at = std::max(0, std::min(at, static_cast<int>(project->patterns.size())));
|
this->at = std::max(0, std::min(at, static_cast<int>(project->patterns.size())));
|
||||||
this->atSeq = atSeq;
|
this->atSeq = atSeq;
|
||||||
|
|
|
@ -207,6 +207,23 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||||
this->selectPatternForEditing(project->sequence[idx].pattern().get());
|
this->selectPatternForEditing(project->sequence[idx].pattern().get());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// middle click
|
||||||
|
auto mouselmb = [this, seq = ui->patternSequencer](QObject*, QEvent* e) {
|
||||||
|
if (e->type() == QEvent::MouseButtonRelease) {
|
||||||
|
auto me = static_cast<QMouseEvent*>(e);
|
||||||
|
if (me->button() == Qt::MouseButton::MiddleButton) {
|
||||||
|
auto idx = static_cast<size_t>(seq->indexAt(me->pos()).column());
|
||||||
|
if (idx >= project->sequence.size()) return false; // nothing to remove
|
||||||
|
auto* c = new ProjectSequencerDeltaCommand(project);
|
||||||
|
c->seq.erase(c->seq.begin() + static_cast<ptrdiff_t>(idx));
|
||||||
|
c->seqSel = static_cast<int>(idx)-1;
|
||||||
|
return c->commit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
ui->patternSequencer->viewport()->installEventFilter(new LambdaEventFilter(this, mouselmb));
|
||||||
|
|
||||||
// rightclick menu
|
// rightclick menu
|
||||||
connect(ui->patternSequencer, &QTableView::customContextMenuRequested, this, [this](const QPoint& pt) {
|
connect(ui->patternSequencer, &QTableView::customContextMenuRequested, this, [this](const QPoint& pt) {
|
||||||
size_t idx = static_cast<size_t>(ui->patternSequencer->indexAt(pt).column());
|
size_t idx = static_cast<size_t>(ui->patternSequencer->indexAt(pt).column());
|
||||||
|
@ -223,7 +240,7 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||||
menu->addAction("Insert Separator", this, [this, idx] {
|
menu->addAction("Insert Separator", this, [this, idx] {
|
||||||
int si = static_cast<int>(std::min(idx, project->sequence.size()));
|
int si = static_cast<int>(std::min(idx, project->sequence.size()));
|
||||||
auto* c = new ProjectSequencerDeltaCommand(project);
|
auto* c = new ProjectSequencerDeltaCommand(project);
|
||||||
c->seq.insert(c->seq.begin() + si, { });
|
c->seq.insert(c->seq.begin() + si, SequenceEntry::Separator);
|
||||||
c->seqSel = si+1;
|
c->seqSel = si+1;
|
||||||
c->commit();
|
c->commit();
|
||||||
});
|
});
|
||||||
|
@ -263,7 +280,7 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||||
|
|
||||||
menu->setAttribute(Qt::WA_DeleteOnClose);
|
menu->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
menu->popup(ui->patternSequencer->mapToGlobal(pt));
|
menu->popup(ui->patternSequencer->mapToGlobal(pt));
|
||||||
});//*/
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
{ /* Set up keyboard shortcuts for pattern view */ } {
|
{ /* Set up keyboard shortcuts for pattern view */ } {
|
||||||
|
|
|
@ -7,6 +7,7 @@ class LambdaEventFilter : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
std::function<bool(QObject*, QEvent*)> filter;
|
std::function<bool(QObject*, QEvent*)> filter;
|
||||||
public:
|
public:
|
||||||
LambdaEventFilter(QObject* parent, std::function<bool(QObject*, QEvent*)> f) : QObject(parent), filter(f) { }
|
LambdaEventFilter(QObject* parent, const std::function<bool(QObject*, QEvent*)>& f) : QObject(parent), filter(f) { }
|
||||||
bool eventFilter(QObject* watched, QEvent* event) override { return filter(watched, event); }
|
bool eventFilter(QObject* watched, QEvent* event) override { return filter(watched, event); }
|
||||||
|
static inline LambdaEventFilter* create(QObject* parent, const std::function<bool(QObject*, QEvent*)>& f) { return new LambdaEventFilter(parent, f); }
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue