xybrid/xybrid/ui/patternsequencermodel.cpp

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