mirror of https://github.com/AxioDL/amuse.git
Bug fixes, xref search, more context menus
This commit is contained in:
parent
27cdee0c14
commit
19c5443e9e
|
@ -278,3 +278,47 @@ ListingDeleteButton::ListingDeleteButton(QWidget* parent)
|
||||||
setToolTip(tr("Delete this SoundMacro"));
|
setToolTip(tr("Delete this SoundMacro"));
|
||||||
setIcon(ListingDeleteIcon);
|
setIcon(ListingDeleteIcon);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool BaseObjectDelegate::editorEvent(QEvent *event, QAbstractItemModel* model,
|
||||||
|
const QStyleOptionViewItem &option, const QModelIndex &index)
|
||||||
|
{
|
||||||
|
if (event->type() == QEvent::MouseButtonPress)
|
||||||
|
{
|
||||||
|
QMouseEvent* ev = static_cast<QMouseEvent*>(event);
|
||||||
|
if (ev->button() == Qt::RightButton)
|
||||||
|
{
|
||||||
|
ProjectModel::INode* node = getNode(model, index);
|
||||||
|
|
||||||
|
ContextMenu* menu = new ContextMenu;
|
||||||
|
|
||||||
|
QAction* openEditorAction = new QAction(tr("Open in Editor"), menu);
|
||||||
|
openEditorAction->setData(QVariant::fromValue((void*)node));
|
||||||
|
openEditorAction->setIcon(QIcon::fromTheme(QStringLiteral("document-edit")));
|
||||||
|
connect(openEditorAction, SIGNAL(triggered()), this, SLOT(doOpenEditor()));
|
||||||
|
menu->addAction(openEditorAction);
|
||||||
|
|
||||||
|
QAction* findUsagesAction = new QAction(tr("Find Usages"), menu);
|
||||||
|
findUsagesAction->setData(QVariant::fromValue((void*)node));
|
||||||
|
findUsagesAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-find")));
|
||||||
|
connect(findUsagesAction, SIGNAL(triggered()), this, SLOT(doFindUsages()));
|
||||||
|
menu->addAction(findUsagesAction);
|
||||||
|
|
||||||
|
menu->popup(ev->globalPos());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BaseObjectDelegate::doOpenEditor()
|
||||||
|
{
|
||||||
|
QAction* act = static_cast<QAction*>(sender());
|
||||||
|
if (ProjectModel::INode* node = reinterpret_cast<ProjectModel::INode*>(act->data().value<void*>()))
|
||||||
|
g_MainWindow->openEditor(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BaseObjectDelegate::doFindUsages()
|
||||||
|
{
|
||||||
|
QAction* act = static_cast<QAction*>(sender());
|
||||||
|
if (ProjectModel::INode* node = reinterpret_cast<ProjectModel::INode*>(act->data().value<void*>()))
|
||||||
|
g_MainWindow->findUsages(node);
|
||||||
|
}
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
|
#include <QMenu>
|
||||||
|
#include <QStyledItemDelegate>
|
||||||
#include "ProjectModel.hpp"
|
#include "ProjectModel.hpp"
|
||||||
|
|
||||||
class EditorWidget : public QWidget
|
class EditorWidget : public QWidget
|
||||||
|
@ -225,4 +227,28 @@ public:
|
||||||
void leaveEvent(QEvent* event);
|
void leaveEvent(QEvent* event);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ContextMenu : public QMenu
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void hideEvent(QHideEvent* ev)
|
||||||
|
{
|
||||||
|
QMenu::hideEvent(ev);
|
||||||
|
deleteLater();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class BaseObjectDelegate : public QStyledItemDelegate
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
protected:
|
||||||
|
virtual ProjectModel::INode* getNode(const QAbstractItemModel* model, const QModelIndex& index) const = 0;
|
||||||
|
public:
|
||||||
|
explicit BaseObjectDelegate(QObject* parent = Q_NULLPTR) : QStyledItemDelegate(parent) {}
|
||||||
|
bool editorEvent(QEvent *event, QAbstractItemModel *model,
|
||||||
|
const QStyleOptionViewItem &option, const QModelIndex &index);
|
||||||
|
private slots:
|
||||||
|
void doOpenEditor();
|
||||||
|
void doFindUsages();
|
||||||
|
};
|
||||||
|
|
||||||
#endif //AMUSE_EDITOR_WIDGET_HPP
|
#endif //AMUSE_EDITOR_WIDGET_HPP
|
||||||
|
|
|
@ -98,7 +98,16 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
SoundMacroDelegate::SoundMacroDelegate(QObject* parent)
|
SoundMacroDelegate::SoundMacroDelegate(QObject* parent)
|
||||||
: QStyledItemDelegate(parent) {}
|
: BaseObjectDelegate(parent) {}
|
||||||
|
|
||||||
|
ProjectModel::INode* SoundMacroDelegate::getNode(const QAbstractItemModel* __model, const QModelIndex& index) const
|
||||||
|
{
|
||||||
|
const LayersModel* model = static_cast<const LayersModel*>(__model);
|
||||||
|
const amuse::LayerMapping& layer = (*model->m_node->m_obj)[index.row()];
|
||||||
|
ProjectModel::GroupNode* group = g_MainWindow->projectModel()->getGroupNode(model->m_node.get());
|
||||||
|
ProjectModel::CollectionNode* smColl = group->getCollectionOfType(ProjectModel::INode::Type::SoundMacro);
|
||||||
|
return smColl->nodeOfId(layer.macro.id);
|
||||||
|
}
|
||||||
|
|
||||||
QWidget* SoundMacroDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
QWidget* SoundMacroDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,9 +8,11 @@
|
||||||
#include <QToolButton>
|
#include <QToolButton>
|
||||||
#include <QStyledItemDelegate>
|
#include <QStyledItemDelegate>
|
||||||
|
|
||||||
class SoundMacroDelegate : public QStyledItemDelegate
|
class SoundMacroDelegate : public BaseObjectDelegate
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
protected:
|
||||||
|
ProjectModel::INode* getNode(const QAbstractItemModel* model, const QModelIndex& index) const;
|
||||||
public:
|
public:
|
||||||
explicit SoundMacroDelegate(QObject* parent = Q_NULLPTR);
|
explicit SoundMacroDelegate(QObject* parent = Q_NULLPTR);
|
||||||
QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const;
|
QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const;
|
||||||
|
|
|
@ -7,7 +7,10 @@ MIDIReader::MIDIReader(amuse::Engine& engine, bool useLock)
|
||||||
void MIDIReader::noteOff(uint8_t chan, uint8_t key, uint8_t velocity)
|
void MIDIReader::noteOff(uint8_t chan, uint8_t key, uint8_t velocity)
|
||||||
{
|
{
|
||||||
if (g_MainWindow->m_interactiveSeq)
|
if (g_MainWindow->m_interactiveSeq)
|
||||||
|
{
|
||||||
g_MainWindow->m_interactiveSeq->keyOff(chan, key, velocity);
|
g_MainWindow->m_interactiveSeq->keyOff(chan, key, velocity);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto keySearch = m_chanVoxs.find(key);
|
auto keySearch = m_chanVoxs.find(key);
|
||||||
if (keySearch == m_chanVoxs.cend())
|
if (keySearch == m_chanVoxs.cend())
|
||||||
|
@ -23,7 +26,10 @@ void MIDIReader::noteOff(uint8_t chan, uint8_t key, uint8_t velocity)
|
||||||
void MIDIReader::noteOn(uint8_t chan, uint8_t key, uint8_t velocity)
|
void MIDIReader::noteOn(uint8_t chan, uint8_t key, uint8_t velocity)
|
||||||
{
|
{
|
||||||
if (g_MainWindow->m_interactiveSeq)
|
if (g_MainWindow->m_interactiveSeq)
|
||||||
|
{
|
||||||
g_MainWindow->m_interactiveSeq->keyOn(chan, key, velocity);
|
g_MainWindow->m_interactiveSeq->keyOn(chan, key, velocity);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_lastVoice && m_lastVoice->isDestroyed())
|
if (m_lastVoice && m_lastVoice->isDestroyed())
|
||||||
m_lastVoice.reset();
|
m_lastVoice.reset();
|
||||||
|
@ -65,7 +71,10 @@ void MIDIReader::notePressure(uint8_t /*chan*/, uint8_t /*key*/, uint8_t /*press
|
||||||
void MIDIReader::controlChange(uint8_t chan, uint8_t control, uint8_t value)
|
void MIDIReader::controlChange(uint8_t chan, uint8_t control, uint8_t value)
|
||||||
{
|
{
|
||||||
if (g_MainWindow->m_interactiveSeq)
|
if (g_MainWindow->m_interactiveSeq)
|
||||||
|
{
|
||||||
g_MainWindow->m_interactiveSeq->setCtrlValue(chan, control, value);
|
g_MainWindow->m_interactiveSeq->setCtrlValue(chan, control, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (control == 1)
|
if (control == 1)
|
||||||
{
|
{
|
||||||
|
@ -103,7 +112,10 @@ void MIDIReader::pitchBend(uint8_t chan, int16_t pitch)
|
||||||
void MIDIReader::allSoundOff(uint8_t chan)
|
void MIDIReader::allSoundOff(uint8_t chan)
|
||||||
{
|
{
|
||||||
if (g_MainWindow->m_interactiveSeq)
|
if (g_MainWindow->m_interactiveSeq)
|
||||||
|
{
|
||||||
g_MainWindow->m_interactiveSeq->kill();
|
g_MainWindow->m_interactiveSeq->kill();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (auto& v : m_engine.getActiveVoices())
|
for (auto& v : m_engine.getActiveVoices())
|
||||||
v->kill();
|
v->kill();
|
||||||
|
@ -116,7 +128,10 @@ void MIDIReader::localControl(uint8_t /*chan*/, bool /*on*/) {}
|
||||||
void MIDIReader::allNotesOff(uint8_t chan)
|
void MIDIReader::allNotesOff(uint8_t chan)
|
||||||
{
|
{
|
||||||
if (g_MainWindow->m_interactiveSeq)
|
if (g_MainWindow->m_interactiveSeq)
|
||||||
|
{
|
||||||
g_MainWindow->m_interactiveSeq->kill();
|
g_MainWindow->m_interactiveSeq->kill();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (auto& v : m_engine.getActiveVoices())
|
for (auto& v : m_engine.getActiveVoices())
|
||||||
v->kill();
|
v->kill();
|
||||||
|
|
|
@ -25,7 +25,6 @@ MainWindow::MainWindow(QWidget* parent)
|
||||||
m_navIt(m_navList.begin()),
|
m_navIt(m_navList.begin()),
|
||||||
m_treeDelegate(*this, this),
|
m_treeDelegate(*this, this),
|
||||||
m_mainMessenger(this),
|
m_mainMessenger(this),
|
||||||
m_filterProjectModel(this),
|
|
||||||
m_undoStack(new QUndoStack(this)),
|
m_undoStack(new QUndoStack(this)),
|
||||||
m_backgroundThread(this)
|
m_backgroundThread(this)
|
||||||
{
|
{
|
||||||
|
@ -36,10 +35,6 @@ MainWindow::MainWindow(QWidget* parent)
|
||||||
QPalette palette = m_ui.projectOutlineFilter->palette();
|
QPalette palette = m_ui.projectOutlineFilter->palette();
|
||||||
palette.setColor(QPalette::Base, palette.color(QPalette::Background));
|
palette.setColor(QPalette::Base, palette.color(QPalette::Background));
|
||||||
m_ui.projectOutlineFilter->setPalette(palette);
|
m_ui.projectOutlineFilter->setPalette(palette);
|
||||||
connect(m_ui.projectOutlineFilter, SIGNAL(textChanged(const QString&)),
|
|
||||||
&m_filterProjectModel, SLOT(setFilterRegExp(const QString&)));
|
|
||||||
m_filterProjectModel.setRecursiveFilteringEnabled(true);
|
|
||||||
m_filterProjectModel.setFilterCaseSensitivity(Qt::CaseInsensitive);
|
|
||||||
m_ui.projectOutline->setItemDelegate(&m_treeDelegate);
|
m_ui.projectOutline->setItemDelegate(&m_treeDelegate);
|
||||||
connect(m_ui.projectOutline, SIGNAL(activated(const QModelIndex&)),
|
connect(m_ui.projectOutline, SIGNAL(activated(const QModelIndex&)),
|
||||||
this, SLOT(outlineItemActivated(const QModelIndex&)));
|
this, SLOT(outlineItemActivated(const QModelIndex&)));
|
||||||
|
@ -286,8 +281,10 @@ bool MainWindow::setProjectPath(const QString& path)
|
||||||
if (m_projectModel)
|
if (m_projectModel)
|
||||||
m_projectModel->deleteLater();
|
m_projectModel->deleteLater();
|
||||||
m_projectModel = new ProjectModel(path, this);
|
m_projectModel = new ProjectModel(path, this);
|
||||||
m_filterProjectModel.setSourceModel(m_projectModel);
|
m_ui.projectOutlineFilter->clear();
|
||||||
m_ui.projectOutline->setModel(&m_filterProjectModel);
|
connect(m_ui.projectOutlineFilter, SIGNAL(textChanged(const QString&)),
|
||||||
|
m_projectModel->getOutlineProxy(), SLOT(setFilterRegExp(const QString&)));
|
||||||
|
m_ui.projectOutline->setModel(m_projectModel->getOutlineProxy());
|
||||||
connect(m_ui.projectOutline->selectionModel(),
|
connect(m_ui.projectOutline->selectionModel(),
|
||||||
SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
|
SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
|
||||||
this, SLOT(onOutlineSelectionChanged(const QItemSelection&, const QItemSelection&)));
|
this, SLOT(onOutlineSelectionChanged(const QItemSelection&, const QItemSelection&)));
|
||||||
|
@ -1165,8 +1162,25 @@ bool TreeDelegate::editorEvent(QEvent* event,
|
||||||
QMouseEvent* ev = static_cast<QMouseEvent*>(event);
|
QMouseEvent* ev = static_cast<QMouseEvent*>(event);
|
||||||
if (ev->button() == Qt::RightButton)
|
if (ev->button() == Qt::RightButton)
|
||||||
{
|
{
|
||||||
m_window.m_ui.projectOutline->setCurrentIndex(index);
|
ContextMenu* menu = new ContextMenu;
|
||||||
QMenu* menu = new QMenu(g_MainWindow->m_ui.projectOutline);
|
|
||||||
|
if (node->type() == ProjectModel::INode::Type::Group)
|
||||||
|
{
|
||||||
|
QAction* exportGroupAction = new QAction(tr("Export GameCube Group"), menu);
|
||||||
|
exportGroupAction->setData(QVariant::fromValue((void*)node));
|
||||||
|
connect(exportGroupAction, SIGNAL(triggered()), this, SLOT(doExportGroup()));
|
||||||
|
menu->addAction(exportGroupAction);
|
||||||
|
|
||||||
|
menu->addSeparator();
|
||||||
|
}
|
||||||
|
|
||||||
|
QAction* findUsagesAction = new QAction(tr("Find Usages"), menu);
|
||||||
|
findUsagesAction->setData(QVariant::fromValue((void*)node));
|
||||||
|
findUsagesAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-find")));
|
||||||
|
connect(findUsagesAction, SIGNAL(triggered()), this, SLOT(doFindUsages()));
|
||||||
|
menu->addAction(findUsagesAction);
|
||||||
|
|
||||||
|
menu->addSeparator();
|
||||||
|
|
||||||
QAction* cutAction = new QAction(tr("Cut"), menu);
|
QAction* cutAction = new QAction(tr("Cut"), menu);
|
||||||
cutAction->setData(index);
|
cutAction->setData(index);
|
||||||
|
@ -1207,24 +1221,56 @@ bool TreeDelegate::editorEvent(QEvent* event,
|
||||||
|
|
||||||
QAction* renameAction = new QAction(tr("Rename"), menu);
|
QAction* renameAction = new QAction(tr("Rename"), menu);
|
||||||
renameAction->setData(index);
|
renameAction->setData(index);
|
||||||
renameAction->setShortcut(tr("F2"));
|
renameAction->setShortcut(Qt::Key_F2);
|
||||||
connect(renameAction, SIGNAL(triggered()), this, SLOT(doRename()));
|
connect(renameAction, SIGNAL(triggered()), this, SLOT(doRename()));
|
||||||
menu->addAction(renameAction);
|
menu->addAction(renameAction);
|
||||||
|
|
||||||
menu->popup(ev->globalPos());
|
menu->popup(ev->globalPos());
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TreeDelegate::doExportGroup()
|
||||||
|
{
|
||||||
|
if (!m_window.m_projectModel)
|
||||||
|
return;
|
||||||
|
QAction* act = qobject_cast<QAction*>(sender());
|
||||||
|
if (ProjectModel::INode* node = reinterpret_cast<ProjectModel::INode*>(act->data().value<void*>()))
|
||||||
|
{
|
||||||
|
if (node->type() != ProjectModel::INode::Type::Group)
|
||||||
|
return;
|
||||||
|
QString groupName = static_cast<ProjectModel::GroupNode*>(node)->name();
|
||||||
|
ProjectModel* model = m_window.m_projectModel;
|
||||||
|
|
||||||
|
QFileInfo dirInfo(model->dir(), QStringLiteral("out"));
|
||||||
|
if (!MkPath(dirInfo.filePath(), m_window.m_mainMessenger))
|
||||||
|
return;
|
||||||
|
|
||||||
|
QDir dir(dirInfo.filePath());
|
||||||
|
|
||||||
|
m_window.startBackgroundTask(BackgroundTaskId::TaskExport, tr("Exporting"), tr("Exporting %1").arg(groupName),
|
||||||
|
[model, dir, groupName](BackgroundTask& task)
|
||||||
|
{
|
||||||
|
model->exportGroup(dir.path(), groupName, task.uiMessenger());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TreeDelegate::doFindUsages()
|
||||||
|
{
|
||||||
|
QAction* act = qobject_cast<QAction*>(sender());
|
||||||
|
if (ProjectModel::INode* node = reinterpret_cast<ProjectModel::INode*>(act->data().value<void*>()))
|
||||||
|
m_window.findUsages(node);
|
||||||
|
}
|
||||||
|
|
||||||
void TreeDelegate::doCut()
|
void TreeDelegate::doCut()
|
||||||
{
|
{
|
||||||
QAction* act = qobject_cast<QAction*>(sender());
|
QAction* act = qobject_cast<QAction*>(sender());
|
||||||
if (!m_window.m_projectModel)
|
if (!m_window.m_projectModel)
|
||||||
return;
|
return;
|
||||||
m_window.m_projectModel->cut(m_window.m_filterProjectModel.mapToSource(act->data().toModelIndex()));
|
m_window.m_projectModel->cut(m_window.m_projectModel->getOutlineProxy()->mapToSource(act->data().toModelIndex()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TreeDelegate::doCopy()
|
void TreeDelegate::doCopy()
|
||||||
|
@ -1232,7 +1278,7 @@ void TreeDelegate::doCopy()
|
||||||
QAction* act = qobject_cast<QAction*>(sender());
|
QAction* act = qobject_cast<QAction*>(sender());
|
||||||
if (!m_window.m_projectModel)
|
if (!m_window.m_projectModel)
|
||||||
return;
|
return;
|
||||||
m_window.m_projectModel->copy(m_window.m_filterProjectModel.mapToSource(act->data().toModelIndex()));
|
m_window.m_projectModel->copy(m_window.m_projectModel->getOutlineProxy()->mapToSource(act->data().toModelIndex()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TreeDelegate::doPaste()
|
void TreeDelegate::doPaste()
|
||||||
|
@ -1240,7 +1286,7 @@ void TreeDelegate::doPaste()
|
||||||
QAction* act = qobject_cast<QAction*>(sender());
|
QAction* act = qobject_cast<QAction*>(sender());
|
||||||
if (!m_window.m_projectModel)
|
if (!m_window.m_projectModel)
|
||||||
return;
|
return;
|
||||||
m_window.m_projectModel->paste(m_window.m_filterProjectModel.mapToSource(act->data().toModelIndex()));
|
m_window.m_projectModel->paste(m_window.m_projectModel->getOutlineProxy()->mapToSource(act->data().toModelIndex()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TreeDelegate::doDuplicate()
|
void TreeDelegate::doDuplicate()
|
||||||
|
@ -1249,10 +1295,10 @@ void TreeDelegate::doDuplicate()
|
||||||
if (!m_window.m_projectModel)
|
if (!m_window.m_projectModel)
|
||||||
return;
|
return;
|
||||||
QModelIndex newIdx =
|
QModelIndex newIdx =
|
||||||
m_window.m_projectModel->duplicate(m_window.m_filterProjectModel.mapToSource(act->data().toModelIndex()));
|
m_window.m_projectModel->duplicate(m_window.m_projectModel->getOutlineProxy()->mapToSource(act->data().toModelIndex()));
|
||||||
if (newIdx.isValid())
|
if (newIdx.isValid())
|
||||||
{
|
{
|
||||||
newIdx = m_window.m_filterProjectModel.mapFromSource(newIdx);
|
newIdx = m_window.m_projectModel->getOutlineProxy()->mapFromSource(newIdx);
|
||||||
m_window.m_ui.projectOutline->edit(newIdx);
|
m_window.m_ui.projectOutline->edit(newIdx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1262,7 +1308,7 @@ void TreeDelegate::doDelete()
|
||||||
QAction* act = qobject_cast<QAction*>(sender());
|
QAction* act = qobject_cast<QAction*>(sender());
|
||||||
if (!m_window.m_projectModel)
|
if (!m_window.m_projectModel)
|
||||||
return;
|
return;
|
||||||
m_window.m_projectModel->del(m_window.m_filterProjectModel.mapToSource(act->data().toModelIndex()));
|
m_window.m_projectModel->del(m_window.m_projectModel->getOutlineProxy()->mapToSource(act->data().toModelIndex()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TreeDelegate::doRename()
|
void TreeDelegate::doRename()
|
||||||
|
@ -1285,7 +1331,7 @@ ProjectModel::GroupNode* MainWindow::getSelectedGroupNode() const
|
||||||
if (!m_ui.projectOutline->currentIndex().isValid())
|
if (!m_ui.projectOutline->currentIndex().isValid())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return m_projectModel->getGroupNode(m_projectModel->node(
|
return m_projectModel->getGroupNode(m_projectModel->node(
|
||||||
m_filterProjectModel.mapToSource(m_ui.projectOutline->currentIndex())));
|
m_projectModel->getOutlineProxy()->mapToSource(m_ui.projectOutline->currentIndex())));
|
||||||
}
|
}
|
||||||
|
|
||||||
QString MainWindow::getSelectedGroupName() const
|
QString MainWindow::getSelectedGroupName() const
|
||||||
|
@ -1304,7 +1350,7 @@ void MainWindow::_recursiveExpandOutline(const QModelIndex& filterIndex) const
|
||||||
|
|
||||||
void MainWindow::recursiveExpandAndSelectOutline(const QModelIndex& index) const
|
void MainWindow::recursiveExpandAndSelectOutline(const QModelIndex& index) const
|
||||||
{
|
{
|
||||||
QModelIndex filterIndex = m_filterProjectModel.mapFromSource(index);
|
QModelIndex filterIndex = m_projectModel->getOutlineProxy()->mapFromSource(index);
|
||||||
_recursiveExpandOutline(filterIndex);
|
_recursiveExpandOutline(filterIndex);
|
||||||
if (filterIndex.isValid())
|
if (filterIndex.isValid())
|
||||||
m_ui.projectOutline->setCurrentIndex(filterIndex);
|
m_ui.projectOutline->setCurrentIndex(filterIndex);
|
||||||
|
@ -1484,6 +1530,11 @@ void MainWindow::goBack()
|
||||||
updateNavigationButtons();
|
updateNavigationButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::findUsages(ProjectModel::INode* node)
|
||||||
|
{
|
||||||
|
m_ui.projectOutlineFilter->setText(QStringLiteral("usages:") + node->name());
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::aboutToShowAudioIOMenu()
|
void MainWindow::aboutToShowAudioIOMenu()
|
||||||
{
|
{
|
||||||
refreshAudioIO();
|
refreshAudioIO();
|
||||||
|
@ -1661,28 +1712,28 @@ void MainWindow::outlineCutAction()
|
||||||
{
|
{
|
||||||
if (!m_projectModel)
|
if (!m_projectModel)
|
||||||
return;
|
return;
|
||||||
m_projectModel->cut(m_filterProjectModel.mapToSource(m_ui.projectOutline->currentIndex()));
|
m_projectModel->cut(m_projectModel->getOutlineProxy()->mapToSource(m_ui.projectOutline->currentIndex()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::outlineCopyAction()
|
void MainWindow::outlineCopyAction()
|
||||||
{
|
{
|
||||||
if (!m_projectModel)
|
if (!m_projectModel)
|
||||||
return;
|
return;
|
||||||
m_projectModel->copy(m_filterProjectModel.mapToSource(m_ui.projectOutline->currentIndex()));
|
m_projectModel->copy(m_projectModel->getOutlineProxy()->mapToSource(m_ui.projectOutline->currentIndex()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::outlinePasteAction()
|
void MainWindow::outlinePasteAction()
|
||||||
{
|
{
|
||||||
if (!m_projectModel)
|
if (!m_projectModel)
|
||||||
return;
|
return;
|
||||||
m_projectModel->paste(m_filterProjectModel.mapToSource(m_ui.projectOutline->currentIndex()));
|
m_projectModel->paste(m_projectModel->getOutlineProxy()->mapToSource(m_ui.projectOutline->currentIndex()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::outlineDeleteAction()
|
void MainWindow::outlineDeleteAction()
|
||||||
{
|
{
|
||||||
if (!m_projectModel)
|
if (!m_projectModel)
|
||||||
return;
|
return;
|
||||||
m_projectModel->del(m_filterProjectModel.mapToSource(m_ui.projectOutline->currentIndex()));
|
m_projectModel->del(m_projectModel->getOutlineProxy()->mapToSource(m_ui.projectOutline->currentIndex()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::onFocusChanged(QWidget* old, QWidget* now)
|
void MainWindow::onFocusChanged(QWidget* old, QWidget* now)
|
||||||
|
@ -1761,7 +1812,7 @@ void MainWindow::onClipboardChanged()
|
||||||
|
|
||||||
void MainWindow::outlineItemActivated(const QModelIndex& index)
|
void MainWindow::outlineItemActivated(const QModelIndex& index)
|
||||||
{
|
{
|
||||||
ProjectModel::INode* node = m_projectModel->node(m_filterProjectModel.mapToSource(index));
|
ProjectModel::INode* node = m_projectModel->node(m_projectModel->getOutlineProxy()->mapToSource(index));
|
||||||
if (!node)
|
if (!node)
|
||||||
return;
|
return;
|
||||||
openEditor(node);
|
openEditor(node);
|
||||||
|
@ -1793,7 +1844,7 @@ AmuseItemEditFlags MainWindow::outlineEditFlags()
|
||||||
QModelIndex curIndex = m_ui.projectOutline->currentIndex();
|
QModelIndex curIndex = m_ui.projectOutline->currentIndex();
|
||||||
if (!curIndex.isValid())
|
if (!curIndex.isValid())
|
||||||
return AmuseItemNone;
|
return AmuseItemNone;
|
||||||
return m_projectModel->editFlags(m_filterProjectModel.mapToSource(curIndex));
|
return m_projectModel->editFlags(m_projectModel->getOutlineProxy()->mapToSource(curIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::onOutlineSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected)
|
void MainWindow::onOutlineSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected)
|
||||||
|
@ -1804,7 +1855,7 @@ void MainWindow::onOutlineSelectionChanged(const QItemSelection& selected, const
|
||||||
if (selected.indexes().empty())
|
if (selected.indexes().empty())
|
||||||
setItemEditFlags(AmuseItemNone);
|
setItemEditFlags(AmuseItemNone);
|
||||||
else
|
else
|
||||||
setItemEditFlags(m_projectModel->editFlags(m_filterProjectModel.mapToSource(selected.indexes().front())));
|
setItemEditFlags(m_projectModel->editFlags(m_projectModel->getOutlineProxy()->mapToSource(selected.indexes().front())));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::onTextSelect()
|
void MainWindow::onTextSelect()
|
||||||
|
|
|
@ -79,6 +79,8 @@ public:
|
||||||
const QStyleOptionViewItem &option,
|
const QStyleOptionViewItem &option,
|
||||||
const QModelIndex &index);
|
const QModelIndex &index);
|
||||||
public slots:
|
public slots:
|
||||||
|
void doExportGroup();
|
||||||
|
void doFindUsages();
|
||||||
void doCut();
|
void doCut();
|
||||||
void doCopy();
|
void doCopy();
|
||||||
void doPaste();
|
void doPaste();
|
||||||
|
@ -104,7 +106,6 @@ class MainWindow : public QMainWindow
|
||||||
TreeDelegate m_treeDelegate;
|
TreeDelegate m_treeDelegate;
|
||||||
UIMessenger m_mainMessenger;
|
UIMessenger m_mainMessenger;
|
||||||
ProjectModel* m_projectModel = nullptr;
|
ProjectModel* m_projectModel = nullptr;
|
||||||
QSortFilterProxyModel m_filterProjectModel;
|
|
||||||
QWidget* m_faceSvg;
|
QWidget* m_faceSvg;
|
||||||
SongGroupEditor* m_songGroupEditor = nullptr;
|
SongGroupEditor* m_songGroupEditor = nullptr;
|
||||||
SoundGroupEditor* m_soundGroupEditor = nullptr;
|
SoundGroupEditor* m_soundGroupEditor = nullptr;
|
||||||
|
@ -201,6 +202,7 @@ public:
|
||||||
void setItemNewEnabled(bool enabled);
|
void setItemNewEnabled(bool enabled);
|
||||||
AmuseItemEditFlags outlineEditFlags();
|
AmuseItemEditFlags outlineEditFlags();
|
||||||
bool isUiDisabled() const { return m_uiDisabled; }
|
bool isUiDisabled() const { return m_uiDisabled; }
|
||||||
|
void findUsages(ProjectModel::INode* node);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void newAction();
|
void newAction();
|
||||||
|
|
|
@ -16,6 +16,165 @@ QIcon ProjectModel::GroupNode::Icon;
|
||||||
QIcon ProjectModel::SongGroupNode::Icon;
|
QIcon ProjectModel::SongGroupNode::Icon;
|
||||||
QIcon ProjectModel::SoundGroupNode::Icon;
|
QIcon ProjectModel::SoundGroupNode::Icon;
|
||||||
|
|
||||||
|
OutlineFilterProxyModel::OutlineFilterProxyModel(ProjectModel* source)
|
||||||
|
: QSortFilterProxyModel(source), m_usageKey({}, Qt::CaseInsensitive)
|
||||||
|
{
|
||||||
|
setSourceModel(source);
|
||||||
|
setRecursiveFilteringEnabled(true);
|
||||||
|
setFilterCaseSensitivity(Qt::CaseInsensitive);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OutlineFilterProxyModel::setFilterRegExp(const QString& pattern)
|
||||||
|
{
|
||||||
|
if (pattern.startsWith(QStringLiteral("usages:")))
|
||||||
|
{
|
||||||
|
m_usageKey.setPattern(pattern.mid(7));
|
||||||
|
QSortFilterProxyModel::setFilterRegExp(QString());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_usageKey.setPattern(QString());
|
||||||
|
QSortFilterProxyModel::setFilterRegExp(pattern);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void VisitObjectFields(ProjectModel::SongGroupNode* n,
|
||||||
|
const std::function<bool(amuse::ObjectId, amuse::NameDB*)>& func)
|
||||||
|
{
|
||||||
|
for (const auto& p : n->m_index->m_normPages)
|
||||||
|
if (!func(p.second.objId.id, nullptr))
|
||||||
|
return;
|
||||||
|
for (const auto& p : n->m_index->m_drumPages)
|
||||||
|
if (!func(p.second.objId.id, nullptr))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void VisitObjectFields(ProjectModel::SoundGroupNode* n,
|
||||||
|
const std::function<bool(amuse::ObjectId, amuse::NameDB*)>& func)
|
||||||
|
{
|
||||||
|
for (const auto& p : n->m_index->m_sfxEntries)
|
||||||
|
if (!func(p.second.objId.id, nullptr))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void VisitObjectFields(ProjectModel::SoundMacroNode* n,
|
||||||
|
const std::function<bool(amuse::ObjectId, amuse::NameDB*)>& func)
|
||||||
|
{
|
||||||
|
for (const auto& p : n->m_obj->m_cmds)
|
||||||
|
{
|
||||||
|
const amuse::SoundMacro::CmdIntrospection* in = amuse::SoundMacro::GetCmdIntrospection(p->Isa());
|
||||||
|
if (!in)
|
||||||
|
continue;
|
||||||
|
for (int i = 0; i < 7; ++i)
|
||||||
|
{
|
||||||
|
const auto& field = in->m_fields[i];
|
||||||
|
if (field.m_name.empty())
|
||||||
|
break;
|
||||||
|
switch (field.m_tp)
|
||||||
|
{
|
||||||
|
case amuse::SoundMacro::CmdIntrospection::Field::Type::SoundMacroId:
|
||||||
|
if (!func(amuse::AccessField<amuse::SoundMacroIdDNA<athena::Little>>(p.get(), field).id, amuse::SoundMacroId::CurNameDB))
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
case amuse::SoundMacro::CmdIntrospection::Field::Type::TableId:
|
||||||
|
if (!func(amuse::AccessField<amuse::TableIdDNA<athena::Little>>(p.get(), field).id, amuse::TableId::CurNameDB))
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
case amuse::SoundMacro::CmdIntrospection::Field::Type::SampleId:
|
||||||
|
if (!func(amuse::AccessField<amuse::SampleIdDNA<athena::Little>>(p.get(), field).id, amuse::SampleId::CurNameDB))
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void VisitObjectFields(ProjectModel::KeymapNode* n,
|
||||||
|
const std::function<bool(amuse::ObjectId, amuse::NameDB*)>& func)
|
||||||
|
{
|
||||||
|
for (const auto& p : *n->m_obj)
|
||||||
|
if (!func(p.macro.id, amuse::SoundMacroId::CurNameDB))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void VisitObjectFields(ProjectModel::LayersNode* n,
|
||||||
|
const std::function<bool(amuse::ObjectId, amuse::NameDB*)>& func)
|
||||||
|
{
|
||||||
|
for (const auto& p : *n->m_obj)
|
||||||
|
if (!func(p.macro.id, amuse::SoundMacroId::CurNameDB))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OutlineFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const
|
||||||
|
{
|
||||||
|
if (m_usageKey.pattern().isEmpty())
|
||||||
|
return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
|
||||||
|
|
||||||
|
ProjectModel* model = static_cast<ProjectModel*>(sourceModel());
|
||||||
|
ProjectModel::INode* node = model->node(model->index(sourceRow, 0, sourceParent));
|
||||||
|
ProjectModel::GroupNode* gn = model->getGroupNode(node);
|
||||||
|
if (!gn)
|
||||||
|
return true;
|
||||||
|
model->setIdDatabases(gn);
|
||||||
|
|
||||||
|
bool foundMatch = false;
|
||||||
|
auto visitor = [this, &foundMatch](amuse::ObjectId id, amuse::NameDB* db)
|
||||||
|
{
|
||||||
|
if (id.id == 0xffff)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
std::string_view name;
|
||||||
|
if (!db)
|
||||||
|
{
|
||||||
|
if (id.id & 0x8000)
|
||||||
|
name = amuse::LayersId::CurNameDB->resolveNameFromId(id);
|
||||||
|
else if (id.id & 0x4000)
|
||||||
|
name = amuse::KeymapId::CurNameDB->resolveNameFromId(id);
|
||||||
|
else
|
||||||
|
name = amuse::SoundMacroId::CurNameDB->resolveNameFromId(id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto search = db->m_idToString.find(id);
|
||||||
|
if (search != db->m_idToString.cend())
|
||||||
|
name = search->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!name.empty() && QString::fromUtf8(name.data(), int(name.length())).contains(m_usageKey))
|
||||||
|
{
|
||||||
|
foundMatch = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (node->type())
|
||||||
|
{
|
||||||
|
case ProjectModel::INode::Type::SongGroup:
|
||||||
|
VisitObjectFields(static_cast<ProjectModel::SongGroupNode*>(node), visitor);
|
||||||
|
break;
|
||||||
|
case ProjectModel::INode::Type::SoundGroup:
|
||||||
|
VisitObjectFields(static_cast<ProjectModel::SoundGroupNode*>(node), visitor);
|
||||||
|
break;
|
||||||
|
case ProjectModel::INode::Type::SoundMacro:
|
||||||
|
VisitObjectFields(static_cast<ProjectModel::SoundMacroNode*>(node), visitor);
|
||||||
|
break;
|
||||||
|
case ProjectModel::INode::Type::Keymap:
|
||||||
|
VisitObjectFields(static_cast<ProjectModel::KeymapNode*>(node), visitor);
|
||||||
|
break;
|
||||||
|
case ProjectModel::INode::Type::Layer:
|
||||||
|
VisitObjectFields(static_cast<ProjectModel::LayersNode*>(node), visitor);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return foundMatch;
|
||||||
|
}
|
||||||
|
|
||||||
NullItemProxyModel::NullItemProxyModel(ProjectModel* source)
|
NullItemProxyModel::NullItemProxyModel(ProjectModel* source)
|
||||||
: QIdentityProxyModel(source)
|
: QIdentityProxyModel(source)
|
||||||
{
|
{
|
||||||
|
@ -407,7 +566,7 @@ ProjectModel::BasePoolObjectNode* ProjectModel::CollectionNode::nodeOfId(amuse::
|
||||||
}
|
}
|
||||||
|
|
||||||
ProjectModel::ProjectModel(const QString& path, QObject* parent)
|
ProjectModel::ProjectModel(const QString& path, QObject* parent)
|
||||||
: QAbstractItemModel(parent), m_dir(path), m_nullProxy(this), m_pageObjectProxy(this)
|
: QAbstractItemModel(parent), m_dir(path), m_outlineProxy(this), m_nullProxy(this), m_pageObjectProxy(this)
|
||||||
{
|
{
|
||||||
m_root = amuse::MakeObj<RootNode>();
|
m_root = amuse::MakeObj<RootNode>();
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include <QAbstractItemModel>
|
#include <QAbstractItemModel>
|
||||||
#include <QIdentityProxyModel>
|
#include <QIdentityProxyModel>
|
||||||
|
#include <QSortFilterProxyModel>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
@ -28,6 +29,17 @@ enum AmuseItemEditFlags
|
||||||
AmuseItemAll = (AmuseItemCut | AmuseItemCopy | AmuseItemPaste | AmuseItemDelete)
|
AmuseItemAll = (AmuseItemCut | AmuseItemCopy | AmuseItemPaste | AmuseItemDelete)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class OutlineFilterProxyModel : public QSortFilterProxyModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
QRegExp m_usageKey;
|
||||||
|
public:
|
||||||
|
explicit OutlineFilterProxyModel(ProjectModel* source);
|
||||||
|
public slots:
|
||||||
|
void setFilterRegExp(const QString &pattern);
|
||||||
|
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
|
||||||
|
};
|
||||||
|
|
||||||
class NullItemProxyModel : public QIdentityProxyModel
|
class NullItemProxyModel : public QIdentityProxyModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -82,6 +94,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QDir m_dir;
|
QDir m_dir;
|
||||||
|
OutlineFilterProxyModel m_outlineProxy;
|
||||||
NullItemProxyModel m_nullProxy;
|
NullItemProxyModel m_nullProxy;
|
||||||
PageObjectProxyModel m_pageObjectProxy;
|
PageObjectProxyModel m_pageObjectProxy;
|
||||||
|
|
||||||
|
@ -484,6 +497,7 @@ public:
|
||||||
|
|
||||||
const QDir& dir() const { return m_dir; }
|
const QDir& dir() const { return m_dir; }
|
||||||
QString path() const { return m_dir.path(); }
|
QString path() const { return m_dir.path(); }
|
||||||
|
OutlineFilterProxyModel* getOutlineProxy() { return &m_outlineProxy; }
|
||||||
NullItemProxyModel* getNullProxy() { return &m_nullProxy; }
|
NullItemProxyModel* getNullProxy() { return &m_nullProxy; }
|
||||||
PageObjectProxyModel* getPageObjectProxy() { return &m_pageObjectProxy; }
|
PageObjectProxyModel* getPageObjectProxy() { return &m_pageObjectProxy; }
|
||||||
|
|
||||||
|
|
|
@ -229,7 +229,17 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
PageObjectDelegate::PageObjectDelegate(QObject* parent)
|
PageObjectDelegate::PageObjectDelegate(QObject* parent)
|
||||||
: QStyledItemDelegate(parent) {}
|
: BaseObjectDelegate(parent) {}
|
||||||
|
|
||||||
|
ProjectModel::INode* PageObjectDelegate::getNode(const QAbstractItemModel* __model, const QModelIndex& index) const
|
||||||
|
{
|
||||||
|
const PageModel* model = static_cast<const PageModel*>(__model);
|
||||||
|
auto entry = model->m_sorted[index.row()];
|
||||||
|
if (entry->second.objId.id.id == 0xffff)
|
||||||
|
return nullptr;
|
||||||
|
ProjectModel::GroupNode* group = g_MainWindow->projectModel()->getGroupNode(model->m_node.get());
|
||||||
|
return group->pageObjectNodeOfId(entry->second.objId.id);
|
||||||
|
}
|
||||||
|
|
||||||
QWidget* PageObjectDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
QWidget* PageObjectDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||||
{
|
{
|
||||||
|
@ -242,12 +252,8 @@ QWidget* PageObjectDelegate::createEditor(QWidget* parent, const QStyleOptionVie
|
||||||
|
|
||||||
void PageObjectDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const
|
void PageObjectDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const
|
||||||
{
|
{
|
||||||
const PageModel* model = static_cast<const PageModel*>(index.model());
|
|
||||||
auto entry = model->m_sorted[index.row()];
|
|
||||||
ProjectModel::GroupNode* group = g_MainWindow->projectModel()->getGroupNode(model->m_node.get());
|
|
||||||
ProjectModel::BasePoolObjectNode* node = group->pageObjectNodeOfId(entry->second.objId.id);
|
|
||||||
int idx = 0;
|
int idx = 0;
|
||||||
if (node)
|
if (ProjectModel::BasePoolObjectNode* node = static_cast<ProjectModel::BasePoolObjectNode*>(getNode(index.model(), index)))
|
||||||
idx = g_MainWindow->projectModel()->getPageObjectProxy()->mapFromSource(g_MainWindow->projectModel()->index(node)).row();
|
idx = g_MainWindow->projectModel()->getPageObjectProxy()->mapFromSource(g_MainWindow->projectModel()->index(node)).row();
|
||||||
static_cast<EditorFieldPageObjectNode*>(editor)->setCurrentIndex(idx);
|
static_cast<EditorFieldPageObjectNode*>(editor)->setCurrentIndex(idx);
|
||||||
if (static_cast<EditorFieldPageObjectNode*>(editor)->shouldPopupOpen())
|
if (static_cast<EditorFieldPageObjectNode*>(editor)->shouldPopupOpen())
|
||||||
|
@ -316,6 +322,14 @@ QWidget* MIDIFileDelegate::createEditor(QWidget* parent, const QStyleOptionViewI
|
||||||
return field;
|
return field;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MIDIFileDelegate::destroyEditor(QWidget *editor, const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
QTableView* table = static_cast<QTableView*>(editor->parentWidget()->parentWidget());
|
||||||
|
editor->deleteLater();
|
||||||
|
emit const_cast<QAbstractItemModel*>(index.model())->dataChanged(index, index);
|
||||||
|
table->setCurrentIndex(index);
|
||||||
|
}
|
||||||
|
|
||||||
void MIDIFileDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const
|
void MIDIFileDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const
|
||||||
{
|
{
|
||||||
MIDIFileFieldWidget* widget = static_cast<MIDIFileFieldWidget*>(editor);
|
MIDIFileFieldWidget* widget = static_cast<MIDIFileFieldWidget*>(editor);
|
||||||
|
@ -339,6 +353,152 @@ void MIDIFileDelegate::setModelData(QWidget* editor, QAbstractItemModel* m, cons
|
||||||
emit m->dataChanged(index, index);
|
emit m->dataChanged(index, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MIDIFileDelegate::editorEvent(QEvent* event, QAbstractItemModel* model,
|
||||||
|
const QStyleOptionViewItem& option, const QModelIndex& index)
|
||||||
|
{
|
||||||
|
if (event->type() == QEvent::MouseButtonPress)
|
||||||
|
{
|
||||||
|
QMouseEvent* ev = static_cast<QMouseEvent*>(event);
|
||||||
|
if (ev->button() == Qt::RightButton)
|
||||||
|
{
|
||||||
|
QString path = index.data().toString();
|
||||||
|
if (path.isEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ContextMenu* menu = new ContextMenu;
|
||||||
|
|
||||||
|
QAction* midiAction = new QAction(tr("Save As MIDI"), menu);
|
||||||
|
midiAction->setData(path);
|
||||||
|
midiAction->setIcon(QIcon::fromTheme(QStringLiteral("file-save")));
|
||||||
|
connect(midiAction, SIGNAL(triggered()), this, SLOT(doExportMIDI()));
|
||||||
|
menu->addAction(midiAction);
|
||||||
|
|
||||||
|
QAction* sngAction = new QAction(tr("Save As SNG"), menu);
|
||||||
|
sngAction->setData(path);
|
||||||
|
sngAction->setIcon(QIcon::fromTheme(QStringLiteral("file-save")));
|
||||||
|
connect(sngAction, SIGNAL(triggered()), this, SLOT(doExportSNG()));
|
||||||
|
menu->addAction(sngAction);
|
||||||
|
|
||||||
|
menu->popup(ev->globalPos());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MIDIFileDelegate::doExportMIDI()
|
||||||
|
{
|
||||||
|
QAction* act = static_cast<QAction*>(sender());
|
||||||
|
QString path = act->data().toString();
|
||||||
|
if (path.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
QString inPath = g_MainWindow->projectModel()->dir().absoluteFilePath(path);
|
||||||
|
std::vector<uint8_t> data;
|
||||||
|
{
|
||||||
|
QFile fi(inPath);
|
||||||
|
if (!fi.open(QFile::ReadOnly))
|
||||||
|
{
|
||||||
|
g_MainWindow->uiMessenger().critical(tr("File Error"),
|
||||||
|
tr("Unable to open %1 for reading: %1").arg(inPath).arg(fi.errorString()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto d = fi.readAll();
|
||||||
|
data.resize(d.size());
|
||||||
|
memcpy(&data[0], d.data(), d.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!memcmp(data.data(), "MThd", 4))
|
||||||
|
{
|
||||||
|
//data = amuse::SongConverter::MIDIToSong(data, 1, true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool isBig;
|
||||||
|
if (amuse::SongState::DetectVersion(data.data(), isBig) < 0)
|
||||||
|
{
|
||||||
|
g_MainWindow->uiMessenger().critical(tr("File Error"),
|
||||||
|
tr("Invalid song data at %1").arg(inPath));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int version;
|
||||||
|
data = amuse::SongConverter::SongToMIDI(data.data(), version, isBig);
|
||||||
|
}
|
||||||
|
|
||||||
|
QFileInfo inInfo(inPath);
|
||||||
|
QString outPath =
|
||||||
|
QFileDialog::getSaveFileName(g_MainWindow, tr("Export MIDI"),
|
||||||
|
QFileInfo(inInfo.path(), inInfo.completeBaseName() + QStringLiteral(".mid")).filePath(), tr("MIDI(*.mid)"));
|
||||||
|
if (outPath.isEmpty())
|
||||||
|
return;
|
||||||
|
QFile fo(outPath);
|
||||||
|
if (!fo.open(QFile::WriteOnly))
|
||||||
|
{
|
||||||
|
g_MainWindow->uiMessenger().critical(tr("File Error"),
|
||||||
|
tr("Unable to open %1 for writing: %1").arg(outPath).arg(fo.errorString()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fo.write((char*)data.data(), data.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MIDIFileDelegate::doExportSNG()
|
||||||
|
{
|
||||||
|
QAction* act = static_cast<QAction*>(sender());
|
||||||
|
QString path = act->data().toString();
|
||||||
|
if (path.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
QString inPath = g_MainWindow->projectModel()->dir().absoluteFilePath(path);
|
||||||
|
std::vector<uint8_t> data;
|
||||||
|
{
|
||||||
|
QFile fi(inPath);
|
||||||
|
if (!fi.open(QFile::ReadOnly))
|
||||||
|
{
|
||||||
|
g_MainWindow->uiMessenger().critical(tr("File Error"),
|
||||||
|
tr("Unable to open %1 for reading: %1").arg(inPath).arg(fi.errorString()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto d = fi.readAll();
|
||||||
|
data.resize(d.size());
|
||||||
|
memcpy(&data[0], d.data(), d.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!memcmp(data.data(), "MThd", 4))
|
||||||
|
{
|
||||||
|
data = amuse::SongConverter::MIDIToSong(data, 1, true);
|
||||||
|
if (data.empty())
|
||||||
|
{
|
||||||
|
g_MainWindow->uiMessenger().critical(tr("File Error"),
|
||||||
|
tr("Invalid MIDI data at %1").arg(inPath));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool isBig;
|
||||||
|
if (amuse::SongState::DetectVersion(data.data(), isBig) < 0)
|
||||||
|
{
|
||||||
|
g_MainWindow->uiMessenger().critical(tr("File Error"),
|
||||||
|
tr("Invalid song data at %1").arg(inPath));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QFileInfo inInfo(inPath);
|
||||||
|
QString outPath =
|
||||||
|
QFileDialog::getSaveFileName(g_MainWindow, tr("Export SNG"),
|
||||||
|
QFileInfo(inInfo.path(), inInfo.completeBaseName() + QStringLiteral(".sng")).filePath(), tr("Song(*.sng)"));
|
||||||
|
if (outPath.isEmpty())
|
||||||
|
return;
|
||||||
|
QFile fo(outPath);
|
||||||
|
if (!fo.open(QFile::WriteOnly))
|
||||||
|
{
|
||||||
|
g_MainWindow->uiMessenger().critical(tr("File Error"),
|
||||||
|
tr("Unable to open %1 for writing: %1").arg(outPath).arg(fo.errorString()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fo.write((char*)data.data(), data.size());
|
||||||
|
}
|
||||||
|
|
||||||
void MIDIFileDelegate::pathChanged()
|
void MIDIFileDelegate::pathChanged()
|
||||||
{
|
{
|
||||||
emit commitData(static_cast<MIDIFileFieldWidget*>(sender()));
|
emit commitData(static_cast<MIDIFileFieldWidget*>(sender()));
|
||||||
|
@ -1210,7 +1370,8 @@ void MIDIPlayerWidget::stopped()
|
||||||
|
|
||||||
void MIDIPlayerWidget::resizeEvent(QResizeEvent* event)
|
void MIDIPlayerWidget::resizeEvent(QResizeEvent* event)
|
||||||
{
|
{
|
||||||
m_button.setGeometry(event->size().width() - event->size().height(), 0, event->size().height(), event->size().height());
|
m_button.setGeometry(event->size().width() - event->size().height(), 0,
|
||||||
|
event->size().height(), event->size().height());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MIDIPlayerWidget::mouseDoubleClickEvent(QMouseEvent* event)
|
void MIDIPlayerWidget::mouseDoubleClickEvent(QMouseEvent* event)
|
||||||
|
@ -1219,6 +1380,17 @@ void MIDIPlayerWidget::mouseDoubleClickEvent(QMouseEvent* event)
|
||||||
event->ignore();
|
event->ignore();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MIDIPlayerWidget::mousePressEvent(QMouseEvent* event)
|
||||||
|
{
|
||||||
|
if (event->button() == Qt::RightButton)
|
||||||
|
{
|
||||||
|
QTableView* view = qobject_cast<QTableView*>(parentWidget()->parentWidget());
|
||||||
|
QAbstractItemDelegate* delegate = view->itemDelegateForColumn(1);
|
||||||
|
delegate->editorEvent(event, view->model(), {}, m_index);
|
||||||
|
}
|
||||||
|
event->ignore();
|
||||||
|
}
|
||||||
|
|
||||||
MIDIPlayerWidget::~MIDIPlayerWidget()
|
MIDIPlayerWidget::~MIDIPlayerWidget()
|
||||||
{
|
{
|
||||||
if (m_seq)
|
if (m_seq)
|
||||||
|
@ -1406,6 +1578,11 @@ void SongGroupEditor::setupDataChanged()
|
||||||
{
|
{
|
||||||
QString path = g_MainWindow->projectModel()->getMIDIPathOfSong(p.m_it->first);
|
QString path = g_MainWindow->projectModel()->getMIDIPathOfSong(p.m_it->first);
|
||||||
QModelIndex index = m_setupList.index(idx, 1);
|
QModelIndex index = m_setupList.index(idx, 1);
|
||||||
|
if (m_setupTable->m_listView->isPersistentEditorOpen(index))
|
||||||
|
{
|
||||||
|
++idx;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (path.isEmpty())
|
if (path.isEmpty())
|
||||||
{
|
{
|
||||||
m_setupTable->m_listView->setIndexWidget(index, nullptr);
|
m_setupTable->m_listView->setIndexWidget(index, nullptr);
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
#include "EditorWidget.hpp"
|
#include "EditorWidget.hpp"
|
||||||
#include <QTabWidget>
|
#include <QTabWidget>
|
||||||
#include <QAbstractTableModel>
|
#include <QAbstractTableModel>
|
||||||
#include <QStyledItemDelegate>
|
|
||||||
#include <QTableView>
|
#include <QTableView>
|
||||||
#include <QToolButton>
|
#include <QToolButton>
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
|
@ -16,9 +15,11 @@
|
||||||
#include <QProxyStyle>
|
#include <QProxyStyle>
|
||||||
#include "amuse/Sequencer.hpp"
|
#include "amuse/Sequencer.hpp"
|
||||||
|
|
||||||
class PageObjectDelegate : public QStyledItemDelegate
|
class PageObjectDelegate : public BaseObjectDelegate
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
protected:
|
||||||
|
ProjectModel::INode* getNode(const QAbstractItemModel* model, const QModelIndex& index) const;
|
||||||
public:
|
public:
|
||||||
explicit PageObjectDelegate(QObject* parent = Q_NULLPTR);
|
explicit PageObjectDelegate(QObject* parent = Q_NULLPTR);
|
||||||
QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const;
|
QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const;
|
||||||
|
@ -51,8 +52,14 @@ class MIDIFileDelegate : public QStyledItemDelegate
|
||||||
public:
|
public:
|
||||||
explicit MIDIFileDelegate(QObject* parent = Q_NULLPTR);
|
explicit MIDIFileDelegate(QObject* parent = Q_NULLPTR);
|
||||||
QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const;
|
QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const;
|
||||||
|
void destroyEditor(QWidget *editor, const QModelIndex &index) const;
|
||||||
void setEditorData(QWidget* editor, const QModelIndex& index) const;
|
void setEditorData(QWidget* editor, const QModelIndex& index) const;
|
||||||
void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const;
|
void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const;
|
||||||
|
bool editorEvent(QEvent *event, QAbstractItemModel *model,
|
||||||
|
const QStyleOptionViewItem &option, const QModelIndex &index);
|
||||||
|
private slots:
|
||||||
|
void doExportMIDI();
|
||||||
|
void doExportSNG();
|
||||||
public slots:
|
public slots:
|
||||||
void pathChanged();
|
void pathChanged();
|
||||||
};
|
};
|
||||||
|
@ -239,6 +246,8 @@ public:
|
||||||
void stopped();
|
void stopped();
|
||||||
void resizeEvent(QResizeEvent* event);
|
void resizeEvent(QResizeEvent* event);
|
||||||
void mouseDoubleClickEvent(QMouseEvent* event);
|
void mouseDoubleClickEvent(QMouseEvent* event);
|
||||||
|
void mousePressEvent(QMouseEvent* event);
|
||||||
|
void mouseReleaseEvent(QMouseEvent* event) { event->ignore(); }
|
||||||
public slots:
|
public slots:
|
||||||
void clicked();
|
void clicked();
|
||||||
};
|
};
|
||||||
|
|
|
@ -120,7 +120,17 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
SFXObjectDelegate::SFXObjectDelegate(QObject* parent)
|
SFXObjectDelegate::SFXObjectDelegate(QObject* parent)
|
||||||
: QStyledItemDelegate(parent) {}
|
: BaseObjectDelegate(parent) {}
|
||||||
|
|
||||||
|
ProjectModel::INode* SFXObjectDelegate::getNode(const QAbstractItemModel* __model, const QModelIndex& index) const
|
||||||
|
{
|
||||||
|
const SFXModel* model = static_cast<const SFXModel*>(__model);
|
||||||
|
auto entry = model->m_sorted[index.row()];
|
||||||
|
if (entry->second.objId.id.id == 0xffff)
|
||||||
|
return nullptr;
|
||||||
|
ProjectModel::GroupNode* group = g_MainWindow->projectModel()->getGroupNode(model->m_node.get());
|
||||||
|
return group->pageObjectNodeOfId(entry->second.objId.id);
|
||||||
|
}
|
||||||
|
|
||||||
QWidget* SFXObjectDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
QWidget* SFXObjectDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||||
{
|
{
|
||||||
|
@ -133,12 +143,8 @@ QWidget* SFXObjectDelegate::createEditor(QWidget* parent, const QStyleOptionView
|
||||||
|
|
||||||
void SFXObjectDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const
|
void SFXObjectDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const
|
||||||
{
|
{
|
||||||
const SFXModel* model = static_cast<const SFXModel*>(index.model());
|
|
||||||
auto entry = model->m_sorted[index.row()];
|
|
||||||
ProjectModel::GroupNode* group = g_MainWindow->projectModel()->getGroupNode(model->m_node.get());
|
|
||||||
ProjectModel::BasePoolObjectNode* node = group->pageObjectNodeOfId(entry->second.objId.id);
|
|
||||||
int idx = 0;
|
int idx = 0;
|
||||||
if (node)
|
if (ProjectModel::BasePoolObjectNode* node = static_cast<ProjectModel::BasePoolObjectNode*>(getNode(index.model(), index)))
|
||||||
idx = g_MainWindow->projectModel()->getPageObjectProxy()->mapFromSource(g_MainWindow->projectModel()->index(node)).row();
|
idx = g_MainWindow->projectModel()->getPageObjectProxy()->mapFromSource(g_MainWindow->projectModel()->index(node)).row();
|
||||||
static_cast<EditorFieldPageObjectNode*>(editor)->setCurrentIndex(idx);
|
static_cast<EditorFieldPageObjectNode*>(editor)->setCurrentIndex(idx);
|
||||||
if (static_cast<EditorFieldPageObjectNode*>(editor)->shouldPopupOpen())
|
if (static_cast<EditorFieldPageObjectNode*>(editor)->shouldPopupOpen())
|
||||||
|
@ -561,7 +567,8 @@ void SFXPlayerWidget::stopped()
|
||||||
|
|
||||||
void SFXPlayerWidget::resizeEvent(QResizeEvent* event)
|
void SFXPlayerWidget::resizeEvent(QResizeEvent* event)
|
||||||
{
|
{
|
||||||
m_button.setGeometry(event->size().width() - event->size().height(), 0, event->size().height(), event->size().height());
|
m_button.setGeometry(event->size().width() - event->size().height(), 0,
|
||||||
|
event->size().height(), event->size().height());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SFXPlayerWidget::mouseDoubleClickEvent(QMouseEvent* event)
|
void SFXPlayerWidget::mouseDoubleClickEvent(QMouseEvent* event)
|
||||||
|
@ -570,6 +577,17 @@ void SFXPlayerWidget::mouseDoubleClickEvent(QMouseEvent* event)
|
||||||
event->ignore();
|
event->ignore();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SFXPlayerWidget::mousePressEvent(QMouseEvent* event)
|
||||||
|
{
|
||||||
|
if (event->button() == Qt::RightButton)
|
||||||
|
{
|
||||||
|
QTableView* view = qobject_cast<QTableView*>(parentWidget()->parentWidget());
|
||||||
|
QAbstractItemDelegate* delegate = view->itemDelegateForColumn(1);
|
||||||
|
delegate->editorEvent(event, view->model(), {}, m_index);
|
||||||
|
}
|
||||||
|
event->ignore();
|
||||||
|
}
|
||||||
|
|
||||||
SFXPlayerWidget::~SFXPlayerWidget()
|
SFXPlayerWidget::~SFXPlayerWidget()
|
||||||
{
|
{
|
||||||
if (m_vox)
|
if (m_vox)
|
||||||
|
|
|
@ -6,9 +6,11 @@
|
||||||
#include <QTableView>
|
#include <QTableView>
|
||||||
#include "amuse/Voice.hpp"
|
#include "amuse/Voice.hpp"
|
||||||
|
|
||||||
class SFXObjectDelegate : public QStyledItemDelegate
|
class SFXObjectDelegate : public BaseObjectDelegate
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
protected:
|
||||||
|
ProjectModel::INode* getNode(const QAbstractItemModel* model, const QModelIndex& index) const;
|
||||||
public:
|
public:
|
||||||
explicit SFXObjectDelegate(QObject* parent = Q_NULLPTR);
|
explicit SFXObjectDelegate(QObject* parent = Q_NULLPTR);
|
||||||
QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const;
|
QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const;
|
||||||
|
@ -98,6 +100,8 @@ public:
|
||||||
void stopped();
|
void stopped();
|
||||||
void resizeEvent(QResizeEvent* event);
|
void resizeEvent(QResizeEvent* event);
|
||||||
void mouseDoubleClickEvent(QMouseEvent* event);
|
void mouseDoubleClickEvent(QMouseEvent* event);
|
||||||
|
void mousePressEvent(QMouseEvent* event);
|
||||||
|
void mouseReleaseEvent(QMouseEvent* event) { event->ignore(); }
|
||||||
public slots:
|
public slots:
|
||||||
void clicked();
|
void clicked();
|
||||||
};
|
};
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -315,7 +315,7 @@ inline T ClampFull(float in)
|
||||||
{
|
{
|
||||||
if (std::is_floating_point<T>())
|
if (std::is_floating_point<T>())
|
||||||
{
|
{
|
||||||
return std::min<T>(std::max<T>(in, -1.f), 1.f);
|
return in;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -515,6 +515,7 @@ void Sequencer::ChannelState::killKeygroup(uint8_t kg, bool now)
|
||||||
m_lastVoice.reset();
|
m_lastVoice.reset();
|
||||||
if (now)
|
if (now)
|
||||||
{
|
{
|
||||||
|
vox->kill();
|
||||||
it = m_chanVoxs.erase(it);
|
it = m_chanVoxs.erase(it);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -533,6 +534,7 @@ void Sequencer::ChannelState::killKeygroup(uint8_t kg, bool now)
|
||||||
Voice* vox = it->get();
|
Voice* vox = it->get();
|
||||||
if (vox->m_keygroup == kg)
|
if (vox->m_keygroup == kg)
|
||||||
{
|
{
|
||||||
|
vox->kill();
|
||||||
it = m_keyoffVoxs.erase(it);
|
it = m_keyoffVoxs.erase(it);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -520,6 +520,8 @@ bool SongState::Track::advance(Sequencer& seq, int32_t ticks)
|
||||||
uint16_t length = (m_parent->m_bigEndian ? SBig(*reinterpret_cast<const uint16_t*>(m_data + 2))
|
uint16_t length = (m_parent->m_bigEndian ? SBig(*reinterpret_cast<const uint16_t*>(m_data + 2))
|
||||||
: *reinterpret_cast<const uint16_t*>(m_data + 2));
|
: *reinterpret_cast<const uint16_t*>(m_data + 2));
|
||||||
seq.keyOn(m_midiChan, note, vel);
|
seq.keyOn(m_midiChan, note, vel);
|
||||||
|
if (length == 0)
|
||||||
|
seq.keyOff(m_midiChan, note, 0);
|
||||||
m_remNoteLengths[note] = length;
|
m_remNoteLengths[note] = length;
|
||||||
m_data += 4;
|
m_data += 4;
|
||||||
}
|
}
|
||||||
|
@ -559,6 +561,8 @@ bool SongState::Track::advance(Sequencer& seq, int32_t ticks)
|
||||||
uint8_t note = m_data[2] & 0x7f;
|
uint8_t note = m_data[2] & 0x7f;
|
||||||
uint8_t vel = m_data[3] & 0x7f;
|
uint8_t vel = m_data[3] & 0x7f;
|
||||||
seq.keyOn(m_midiChan, note, vel);
|
seq.keyOn(m_midiChan, note, vel);
|
||||||
|
if (length == 0)
|
||||||
|
seq.keyOff(m_midiChan, note, 0);
|
||||||
m_remNoteLengths[note] = length;
|
m_remNoteLengths[note] = length;
|
||||||
}
|
}
|
||||||
else if (m_data[2] & 0x80 && m_data[3] & 0x80)
|
else if (m_data[2] & 0x80 && m_data[3] & 0x80)
|
||||||
|
|
Loading…
Reference in New Issue