support channel reordering via dragging header
parent
e7a8093b8c
commit
14f1f2d783
33
notes
33
notes
|
@ -45,6 +45,11 @@ project data {
|
|||
|
||||
TODO {
|
||||
immediate frontburner {
|
||||
- allow swapping channels around
|
||||
|
||||
double click to rename channel
|
||||
^ QHeaderView is a QAbstractItemView as of qt5, so can set an item delegate
|
||||
|
||||
create new Project and hook that up to the main window instead of just making an empty pattern
|
||||
( Project::new(), Pattern::new(Project*) )
|
||||
make and hook up UI for displaying all existing patterns by index, and for displaying the sequence
|
||||
|
@ -54,18 +59,12 @@ TODO {
|
|||
- make pattern editor detect ctrl and alt modifiers
|
||||
make everything relevant check if editing is locked
|
||||
|
||||
- figure out what library to use for messagepack
|
||||
- figure out what library to use for messagepack (official msgpack-c)
|
||||
implement saving (probably a FileIO helper class)
|
||||
hook up new/open/save menu items
|
||||
}
|
||||
|
||||
? de-hardcode the "» " (probably just make it a static const variable somewhere?)
|
||||
- implement (top) header span and return channel names
|
||||
double click to rename channel
|
||||
QHeaderView::setSectionsMovable(bool movable)
|
||||
QHeaderView::sectionMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex)
|
||||
^ need to re-reposition the thing?
|
||||
QHeaderView is a QAbstractItemView as of qt5, so can set an item delegate
|
||||
|
||||
pattern background colors (and time signature, duh)
|
||||
|
||||
|
@ -84,6 +83,12 @@ TODO {
|
|||
|
||||
use signals/slots to signal project/pattern updates etc.
|
||||
|
||||
saving and loading {
|
||||
msgpack object
|
||||
|
||||
probably have a field of raw data for (some) node saves, and keep it resident in case of plugin crashes
|
||||
}
|
||||
|
||||
resampler object {
|
||||
one used internally for each note
|
||||
reference to sample
|
||||
|
@ -104,6 +109,12 @@ JS example of sine panning, -1.0 to +1.0 {
|
|||
}
|
||||
}
|
||||
|
||||
plugin registry {
|
||||
queuing function for static construction
|
||||
PluginInfo base class, virtual function for creating a node of said plugin
|
||||
(separate function for loading from save file?)
|
||||
}
|
||||
|
||||
lv2 support: lilv (duh) for actual plugin loading, suil for UI embedding
|
||||
|
||||
eventually hook luajit up with TLSF allocator to aid in real time (maybe look at nedmalloc too)
|
||||
|
@ -121,6 +132,14 @@ graph+node+port system {
|
|||
something something ready flags (all input nodes and containing graph; main graph and command ports always have the bit set)
|
||||
|
||||
graphs are also nodes
|
||||
|
||||
can use locks on processing node-ports since they'll basically never be contended; this allows for editing during playback
|
||||
^ or just double-buffer the connections
|
||||
UI thread takes full responsibility for both replacement and eventual collection; atomic bool marking is enough threadsafety to deflect the collection timer
|
||||
have to signal playback thread that queues have been invalidated
|
||||
...or just use locks and a flag since it's probably not worth the added complexity of implementing lockfree to avoid hangups when *fiddling with connections*
|
||||
though we do want a queue system for plugin parameter changes! don't want xruns from fiddling with instruments or mixing
|
||||
(most built-in gadgets can avoid this by nature of aligned power-of-two types (<=8bytes) inherently atomic on modern CPUs)
|
||||
}
|
||||
|
||||
keybinds {
|
||||
|
|
|
@ -36,6 +36,7 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||
pattern->channels[0].rows[0].addParam('v', 255);
|
||||
pattern->channels[1].rows[0].port = 1;
|
||||
pattern->channels[1].rows[0].note = 0;
|
||||
pattern->channels[5].name = "I have a name";
|
||||
|
||||
auto pe = t->findChild<Xybrid::UI::PatternEditorView*>("patternEditor");
|
||||
|
||||
|
|
|
@ -26,9 +26,13 @@ PatternEditorView::PatternEditorView(QWidget *parent) : QTableView(parent) {
|
|||
hdr->setSectionResizeMode(QHeaderView::Fixed);//ResizeToContents);
|
||||
hdr->setTextElideMode(Qt::ElideMiddle);
|
||||
hdr->setStretchLastSection(true);
|
||||
hdr->setSectionsMovable(true);
|
||||
hdr->setFirstSectionMovable(true);
|
||||
|
||||
// hook up scrolling to update header position
|
||||
connect(horizontalScrollBar(), &QScrollBar::valueChanged, this, &PatternEditorView::updateHeaderOffset);
|
||||
// and header swap
|
||||
connect(hdr.get(), &QHeaderView::sectionMoved, this, &PatternEditorView::headerMoved);
|
||||
|
||||
horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
||||
verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
||||
|
@ -99,3 +103,25 @@ void PatternEditorView::updateHeader(bool full) {
|
|||
void PatternEditorView::updateHeaderOffset(int) {
|
||||
updateHeader(false);
|
||||
}
|
||||
|
||||
void PatternEditorView::headerMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex) {
|
||||
if (logicalIndex == newVisualIndex) return; // assume moving back
|
||||
hdr->moveSection(newVisualIndex, logicalIndex); // maintain straight-through order
|
||||
if (logicalIndex >= hdr->count() - 1) return; // no dragging the endcap :|
|
||||
|
||||
int min = std::min(oldVisualIndex, newVisualIndex);
|
||||
int max = std::max(oldVisualIndex, newVisualIndex);
|
||||
int nf = 0;
|
||||
if (newVisualIndex > oldVisualIndex) nf = min + 1;
|
||||
else nf = max;
|
||||
auto& chn = mdl->getPattern().channels;
|
||||
std::rotate(chn.begin() + min, chn.begin() + nf, chn.begin() + max + 1);
|
||||
this->dataChanged( // update everything
|
||||
mdl->index(0, 0, QModelIndex()),
|
||||
mdl->index(mdl->rowCount() - 1, mdl->columnCount() - 1, QModelIndex())
|
||||
);
|
||||
|
||||
mdl->updateColumnDisplay(); // update geometries and hide flags
|
||||
// and make sure header follows
|
||||
emit hdr->model()->headerDataChanged(Qt::Horizontal, 0, static_cast<int>(chn.size()) - 1);
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ namespace Xybrid::UI {
|
|||
void updateGeometries() override;
|
||||
void updateHeader(bool full = false);
|
||||
void updateHeaderOffset(int);
|
||||
void headerMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex);
|
||||
|
||||
void keyboardSearch(const QString&) override {} // disable accidental search
|
||||
|
||||
|
|
Loading…
Reference in New Issue