middle click to remove sequence entry
parent
f173a0e87f
commit
9d45d78795
14
notes
14
notes
|
@ -32,8 +32,9 @@ parameters {
|
|||
|
||||
TODO {
|
||||
immediate frontburner {
|
||||
- add standardized step values for knobs and set a default (int enum)
|
||||
global pan (PXX) for InstrumentCore?
|
||||
spacer rows on top/bottom of pattern editor (keep centered)
|
||||
|
||||
global pan (PXX) for InstrumentCore? *default* pan
|
||||
|
||||
- node function to release unneeded old data when stopping playback
|
||||
...
|
||||
|
@ -47,19 +48,12 @@ TODO {
|
|||
|
||||
|
||||
bugs to fix {
|
||||
-? it sometimes crashes on exit??
|
||||
|
||||
... does graph really need to call reset() on its children at this point
|
||||
playback after stopping immediately after a note in the first pattern played sometimes skips that note
|
||||
}
|
||||
|
||||
misc features needed before proper release {
|
||||
- song metadata (title, artist, comment, default bpm)
|
||||
|
||||
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
|
||||
/ 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
|
||||
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)
|
||||
if (project->sequence[static_cast<size_t>(seqPos)].type == SequenceEntry::LoopStart) break;
|
||||
continue;
|
||||
|
|
|
@ -20,8 +20,8 @@ bool ProjectCommand::cancel() {
|
|||
return false;
|
||||
}
|
||||
|
||||
ProjectSequencerDeltaCommand::ProjectSequencerDeltaCommand(const std::shared_ptr<Project>& project) {
|
||||
this->project = project;
|
||||
ProjectSequencerDeltaCommand::ProjectSequencerDeltaCommand(const std::shared_ptr<Project>& project_) {
|
||||
project = project_;
|
||||
oldSeq = project->sequence;
|
||||
oldSeqSel = project->socket->window->sequenceSelection();
|
||||
seq = oldSeq;
|
||||
|
@ -50,8 +50,8 @@ void ProjectSequencerDeltaCommand::undo() {
|
|||
project->socket->window->sequenceSelection(oldSeqSel);
|
||||
}
|
||||
|
||||
ProjectPatternMoveCommand::ProjectPatternMoveCommand(const std::shared_ptr<Project>& project, int f, int t) {
|
||||
this->project = project;
|
||||
ProjectPatternMoveCommand::ProjectPatternMoveCommand(const std::shared_ptr<Project>& project_, int f, int t) {
|
||||
project = project_;
|
||||
from = f;
|
||||
to = t;
|
||||
setText("move pattern");
|
||||
|
@ -85,8 +85,8 @@ void ProjectPatternMoveCommand::undo() {
|
|||
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) {
|
||||
this->project = project;
|
||||
ProjectPatternAddCommand::ProjectPatternAddCommand(const std::shared_ptr<Project>& project_, int at, int atSeq, const std::shared_ptr<Pattern>& copyOf) {
|
||||
project = project_;
|
||||
if (at < 0) at = std::numeric_limits<int>::max();
|
||||
this->at = std::max(0, std::min(at, static_cast<int>(project->patterns.size())));
|
||||
this->atSeq = atSeq;
|
||||
|
|
|
@ -207,6 +207,23 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||
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
|
||||
connect(ui->patternSequencer, &QTableView::customContextMenuRequested, this, [this](const QPoint& pt) {
|
||||
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] {
|
||||
int si = static_cast<int>(std::min(idx, project->sequence.size()));
|
||||
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->commit();
|
||||
});
|
||||
|
@ -263,7 +280,7 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||
|
||||
menu->setAttribute(Qt::WA_DeleteOnClose);
|
||||
menu->popup(ui->patternSequencer->mapToGlobal(pt));
|
||||
});//*/
|
||||
});
|
||||
}
|
||||
|
||||
{ /* Set up keyboard shortcuts for pattern view */ } {
|
||||
|
|
|
@ -7,6 +7,7 @@ class LambdaEventFilter : public QObject {
|
|||
Q_OBJECT
|
||||
std::function<bool(QObject*, QEvent*)> filter;
|
||||
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); }
|
||||
static inline LambdaEventFilter* create(QObject* parent, const std::function<bool(QObject*, QEvent*)>& f) { return new LambdaEventFilter(parent, f); }
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue