139 lines
5.7 KiB
C++
139 lines
5.7 KiB
C++
#include "patternsequencermodel.h"
|
|
using Xybrid::UI::PatternSequencerModel;
|
|
|
|
#include <QMimeData>
|
|
#include <QIODevice>
|
|
|
|
using Xybrid::Data::Pattern;
|
|
using Xybrid::Data::Project;
|
|
using Xybrid::Data::SequenceEntry;
|
|
|
|
#include "mainwindow.h"
|
|
|
|
#include "editing/projectcommands.h"
|
|
using namespace Xybrid::Editing;
|
|
|
|
PatternSequencerModel::PatternSequencerModel(QObject *parent, MainWindow* window) : QAbstractTableModel (parent) {
|
|
this->window = window;
|
|
}
|
|
|
|
int PatternSequencerModel::rowCount(const QModelIndex &parent [[maybe_unused]]) const {
|
|
return 1;
|
|
}
|
|
|
|
int PatternSequencerModel::columnCount(const QModelIndex &parent [[maybe_unused]]) const {
|
|
auto* project = window->getProject().get();
|
|
if (!project) return 0;
|
|
return static_cast<int>(window->getProject()->sequence.size() + 1);
|
|
}
|
|
|
|
QVariant PatternSequencerModel::data(const QModelIndex &index, int role) const {
|
|
auto* project = window->getProject().get();
|
|
if (!project) return QVariant();
|
|
if (role == Qt::DisplayRole || role == Qt::ToolTipRole) {
|
|
bool toolTip = (role == Qt::ToolTipRole);
|
|
if (static_cast<size_t>(index.column()) >= project->sequence.size()) return !toolTip ? QString("+") : QString("Add new");
|
|
auto& e = project->sequence[static_cast<size_t>(index.column())];
|
|
return toolTip ? e.toolTip() : e.symbol();
|
|
/*auto& pattern = project->sequence[static_cast<size_t>(index.column())];
|
|
if (!pattern) return !toolTip ? QString("-") : QString("(separator)");
|
|
if (!toolTip) return QString("%1").arg(pattern->index, 1, 10, QChar('0'));
|
|
if (pattern->name.isEmpty()) return QVariant(); // no tool tip without name
|
|
return QString("(%1) %2").arg(pattern->index, 1, 10, QChar('0')).arg(pattern->name);*/
|
|
}
|
|
if (role == Qt::TextAlignmentRole ) return {Qt::AlignHCenter | Qt::AlignVCenter};
|
|
return QVariant();
|
|
}
|
|
|
|
Qt::ItemFlags PatternSequencerModel::flags(const QModelIndex &index) const {
|
|
return Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | QAbstractTableModel::flags(index);
|
|
}
|
|
|
|
Qt::DropActions PatternSequencerModel::supportedDropActions() const {
|
|
return Qt::CopyAction | Qt::MoveAction;
|
|
}
|
|
|
|
QStringList PatternSequencerModel::mimeTypes() const {
|
|
QStringList types;
|
|
types << "xybrid-internal/x-pattern-index";
|
|
types << "xybrid-internal/x-sequence-index";
|
|
return types;
|
|
}
|
|
|
|
QMimeData* PatternSequencerModel::mimeData(const QModelIndexList &indexes) const {
|
|
auto d = new QMimeData();
|
|
QByteArray dd;
|
|
QDataStream stream(&dd, QIODevice::WriteOnly);
|
|
size_t idx = static_cast<size_t>(indexes[0].column());
|
|
Project* prj = window->getProject().get();
|
|
if (!prj) return d; // if somehow nullptr, just return a blank
|
|
stream.writeRawData(reinterpret_cast<char*>(&idx), sizeof(size_t));
|
|
stream.writeRawData(reinterpret_cast<char*>(&prj), sizeof(void*));
|
|
d->setData("xybrid-internal/x-sequence-index", dd);
|
|
return d;
|
|
}
|
|
|
|
bool PatternSequencerModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row [[maybe_unused]], int column, const QModelIndex &parent [[maybe_unused]]) {
|
|
if (data->hasFormat("xybrid-internal/x-pattern-index")) {
|
|
if (action == Qt::IgnoreAction) return true; // can accept type
|
|
|
|
Pattern* p;
|
|
{
|
|
QByteArray dd = data->data("xybrid-internal/x-pattern-index");
|
|
QDataStream stream(&dd, QIODevice::ReadOnly);
|
|
size_t idx;
|
|
Project* prj;
|
|
stream.readRawData(reinterpret_cast<char*>(&idx), sizeof(size_t));
|
|
stream.readRawData(reinterpret_cast<char*>(&prj), sizeof(void*));
|
|
if (prj != window->getProject().get()) return false; // wrong or invalid project
|
|
if (idx >= prj->patterns.size()) return false; // index out of range
|
|
p = prj->patterns[idx].get();
|
|
}
|
|
|
|
if (parent.isValid()) column = parent.column(); // always insert before
|
|
if (column < 0 || column > static_cast<int>(p->project->sequence.size())) column = static_cast<int>(p->project->sequence.size()); // if dropped on empty space, snap to end
|
|
|
|
auto* c = new ProjectSequencerDeltaCommand(window->getProject());
|
|
c->seq.insert(c->seq.begin() + column, p->shared_from_this());
|
|
c->seqSel = column;
|
|
|
|
return c->commit();
|
|
}
|
|
if (data->hasFormat("xybrid-internal/x-sequence-index")) {
|
|
if (action == Qt::IgnoreAction) return true; // can accept type
|
|
bool copy = (action == Qt::CopyAction);
|
|
|
|
size_t idx;
|
|
Project* prj;
|
|
{
|
|
QByteArray dd = data->data("xybrid-internal/x-sequence-index");
|
|
QDataStream stream(&dd, QIODevice::ReadOnly);
|
|
stream.readRawData(reinterpret_cast<char*>(&idx), sizeof(size_t));
|
|
stream.readRawData(reinterpret_cast<char*>(&prj), sizeof(void*));
|
|
if (prj != window->getProject().get()) return false; // wrong or invalid project
|
|
if (idx >= prj->sequence.size()) return false; // index out of range
|
|
}
|
|
|
|
if (parent.isValid()) { // if dropped onto an item and not between, place on opposite side
|
|
column = parent.column();
|
|
if (column > static_cast<int>(idx)) column += 1;
|
|
}
|
|
if (column < 0 || column > static_cast<int>(prj->sequence.size())) column = static_cast<int>(prj->sequence.size()); // if dropped on empty space, snap to end
|
|
|
|
if (!copy && column > static_cast<int>(idx)) column -= 1; // compensate ahead of time for snap-out
|
|
|
|
auto* c = new ProjectSequencerDeltaCommand(window->getProject());
|
|
SequenceEntry s = c->seq[idx];
|
|
if (!copy) c->seq.erase(c->seq.begin() + static_cast<int>(idx));
|
|
c->seq.insert(c->seq.begin() + column, s);
|
|
c->seqSel = column;
|
|
|
|
return c->commit();
|
|
}
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|