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"));
|
||||
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 <QPushButton>
|
||||
#include <QLabel>
|
||||
#include <QMenu>
|
||||
#include <QStyledItemDelegate>
|
||||
#include "ProjectModel.hpp"
|
||||
|
||||
class EditorWidget : public QWidget
|
||||
|
@ -225,4 +227,28 @@ public:
|
|||
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
|
||||
|
|
|
@ -98,7 +98,16 @@ public:
|
|||
};
|
||||
|
||||
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
|
||||
{
|
||||
|
|
|
@ -8,9 +8,11 @@
|
|||
#include <QToolButton>
|
||||
#include <QStyledItemDelegate>
|
||||
|
||||
class SoundMacroDelegate : public QStyledItemDelegate
|
||||
class SoundMacroDelegate : public BaseObjectDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
protected:
|
||||
ProjectModel::INode* getNode(const QAbstractItemModel* model, const QModelIndex& index) const;
|
||||
public:
|
||||
explicit SoundMacroDelegate(QObject* parent = Q_NULLPTR);
|
||||
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)
|
||||
{
|
||||
if (g_MainWindow->m_interactiveSeq)
|
||||
{
|
||||
g_MainWindow->m_interactiveSeq->keyOff(chan, key, velocity);
|
||||
return;
|
||||
}
|
||||
|
||||
auto keySearch = m_chanVoxs.find(key);
|
||||
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)
|
||||
{
|
||||
if (g_MainWindow->m_interactiveSeq)
|
||||
{
|
||||
g_MainWindow->m_interactiveSeq->keyOn(chan, key, velocity);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_lastVoice && m_lastVoice->isDestroyed())
|
||||
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)
|
||||
{
|
||||
if (g_MainWindow->m_interactiveSeq)
|
||||
{
|
||||
g_MainWindow->m_interactiveSeq->setCtrlValue(chan, control, value);
|
||||
return;
|
||||
}
|
||||
|
||||
if (control == 1)
|
||||
{
|
||||
|
@ -103,7 +112,10 @@ void MIDIReader::pitchBend(uint8_t chan, int16_t pitch)
|
|||
void MIDIReader::allSoundOff(uint8_t chan)
|
||||
{
|
||||
if (g_MainWindow->m_interactiveSeq)
|
||||
{
|
||||
g_MainWindow->m_interactiveSeq->kill();
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& v : m_engine.getActiveVoices())
|
||||
v->kill();
|
||||
|
@ -116,7 +128,10 @@ void MIDIReader::localControl(uint8_t /*chan*/, bool /*on*/) {}
|
|||
void MIDIReader::allNotesOff(uint8_t chan)
|
||||
{
|
||||
if (g_MainWindow->m_interactiveSeq)
|
||||
{
|
||||
g_MainWindow->m_interactiveSeq->kill();
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& v : m_engine.getActiveVoices())
|
||||
v->kill();
|
||||
|
|
|
@ -25,7 +25,6 @@ MainWindow::MainWindow(QWidget* parent)
|
|||
m_navIt(m_navList.begin()),
|
||||
m_treeDelegate(*this, this),
|
||||
m_mainMessenger(this),
|
||||
m_filterProjectModel(this),
|
||||
m_undoStack(new QUndoStack(this)),
|
||||
m_backgroundThread(this)
|
||||
{
|
||||
|
@ -36,10 +35,6 @@ MainWindow::MainWindow(QWidget* parent)
|
|||
QPalette palette = m_ui.projectOutlineFilter->palette();
|
||||
palette.setColor(QPalette::Base, palette.color(QPalette::Background));
|
||||
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);
|
||||
connect(m_ui.projectOutline, SIGNAL(activated(const QModelIndex&)),
|
||||
this, SLOT(outlineItemActivated(const QModelIndex&)));
|
||||
|
@ -286,8 +281,10 @@ bool MainWindow::setProjectPath(const QString& path)
|
|||
if (m_projectModel)
|
||||
m_projectModel->deleteLater();
|
||||
m_projectModel = new ProjectModel(path, this);
|
||||
m_filterProjectModel.setSourceModel(m_projectModel);
|
||||
m_ui.projectOutline->setModel(&m_filterProjectModel);
|
||||
m_ui.projectOutlineFilter->clear();
|
||||
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(),
|
||||
SIGNAL(selectionChanged(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);
|
||||
if (ev->button() == Qt::RightButton)
|
||||
{
|
||||
m_window.m_ui.projectOutline->setCurrentIndex(index);
|
||||
QMenu* menu = new QMenu(g_MainWindow->m_ui.projectOutline);
|
||||
ContextMenu* menu = new ContextMenu;
|
||||
|
||||
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);
|
||||
cutAction->setData(index);
|
||||
|
@ -1207,24 +1221,56 @@ bool TreeDelegate::editorEvent(QEvent* event,
|
|||
|
||||
QAction* renameAction = new QAction(tr("Rename"), menu);
|
||||
renameAction->setData(index);
|
||||
renameAction->setShortcut(tr("F2"));
|
||||
renameAction->setShortcut(Qt::Key_F2);
|
||||
connect(renameAction, SIGNAL(triggered()), this, SLOT(doRename()));
|
||||
menu->addAction(renameAction);
|
||||
|
||||
menu->popup(ev->globalPos());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
QAction* act = qobject_cast<QAction*>(sender());
|
||||
if (!m_window.m_projectModel)
|
||||
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()
|
||||
|
@ -1232,7 +1278,7 @@ void TreeDelegate::doCopy()
|
|||
QAction* act = qobject_cast<QAction*>(sender());
|
||||
if (!m_window.m_projectModel)
|
||||
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()
|
||||
|
@ -1240,7 +1286,7 @@ void TreeDelegate::doPaste()
|
|||
QAction* act = qobject_cast<QAction*>(sender());
|
||||
if (!m_window.m_projectModel)
|
||||
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()
|
||||
|
@ -1249,10 +1295,10 @@ void TreeDelegate::doDuplicate()
|
|||
if (!m_window.m_projectModel)
|
||||
return;
|
||||
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())
|
||||
{
|
||||
newIdx = m_window.m_filterProjectModel.mapFromSource(newIdx);
|
||||
newIdx = m_window.m_projectModel->getOutlineProxy()->mapFromSource(newIdx);
|
||||
m_window.m_ui.projectOutline->edit(newIdx);
|
||||
}
|
||||
}
|
||||
|
@ -1262,7 +1308,7 @@ void TreeDelegate::doDelete()
|
|||
QAction* act = qobject_cast<QAction*>(sender());
|
||||
if (!m_window.m_projectModel)
|
||||
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()
|
||||
|
@ -1285,7 +1331,7 @@ ProjectModel::GroupNode* MainWindow::getSelectedGroupNode() const
|
|||
if (!m_ui.projectOutline->currentIndex().isValid())
|
||||
return nullptr;
|
||||
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
|
||||
|
@ -1304,7 +1350,7 @@ void MainWindow::_recursiveExpandOutline(const QModelIndex& filterIndex) const
|
|||
|
||||
void MainWindow::recursiveExpandAndSelectOutline(const QModelIndex& index) const
|
||||
{
|
||||
QModelIndex filterIndex = m_filterProjectModel.mapFromSource(index);
|
||||
QModelIndex filterIndex = m_projectModel->getOutlineProxy()->mapFromSource(index);
|
||||
_recursiveExpandOutline(filterIndex);
|
||||
if (filterIndex.isValid())
|
||||
m_ui.projectOutline->setCurrentIndex(filterIndex);
|
||||
|
@ -1484,6 +1530,11 @@ void MainWindow::goBack()
|
|||
updateNavigationButtons();
|
||||
}
|
||||
|
||||
void MainWindow::findUsages(ProjectModel::INode* node)
|
||||
{
|
||||
m_ui.projectOutlineFilter->setText(QStringLiteral("usages:") + node->name());
|
||||
}
|
||||
|
||||
void MainWindow::aboutToShowAudioIOMenu()
|
||||
{
|
||||
refreshAudioIO();
|
||||
|
@ -1661,28 +1712,28 @@ void MainWindow::outlineCutAction()
|
|||
{
|
||||
if (!m_projectModel)
|
||||
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()
|
||||
{
|
||||
if (!m_projectModel)
|
||||
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()
|
||||
{
|
||||
if (!m_projectModel)
|
||||
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()
|
||||
{
|
||||
if (!m_projectModel)
|
||||
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)
|
||||
|
@ -1761,7 +1812,7 @@ void MainWindow::onClipboardChanged()
|
|||
|
||||
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)
|
||||
return;
|
||||
openEditor(node);
|
||||
|
@ -1793,7 +1844,7 @@ AmuseItemEditFlags MainWindow::outlineEditFlags()
|
|||
QModelIndex curIndex = m_ui.projectOutline->currentIndex();
|
||||
if (!curIndex.isValid())
|
||||
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)
|
||||
|
@ -1804,7 +1855,7 @@ void MainWindow::onOutlineSelectionChanged(const QItemSelection& selected, const
|
|||
if (selected.indexes().empty())
|
||||
setItemEditFlags(AmuseItemNone);
|
||||
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()
|
||||
|
|
|
@ -79,6 +79,8 @@ public:
|
|||
const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index);
|
||||
public slots:
|
||||
void doExportGroup();
|
||||
void doFindUsages();
|
||||
void doCut();
|
||||
void doCopy();
|
||||
void doPaste();
|
||||
|
@ -104,7 +106,6 @@ class MainWindow : public QMainWindow
|
|||
TreeDelegate m_treeDelegate;
|
||||
UIMessenger m_mainMessenger;
|
||||
ProjectModel* m_projectModel = nullptr;
|
||||
QSortFilterProxyModel m_filterProjectModel;
|
||||
QWidget* m_faceSvg;
|
||||
SongGroupEditor* m_songGroupEditor = nullptr;
|
||||
SoundGroupEditor* m_soundGroupEditor = nullptr;
|
||||
|
@ -201,6 +202,7 @@ public:
|
|||
void setItemNewEnabled(bool enabled);
|
||||
AmuseItemEditFlags outlineEditFlags();
|
||||
bool isUiDisabled() const { return m_uiDisabled; }
|
||||
void findUsages(ProjectModel::INode* node);
|
||||
|
||||
public slots:
|
||||
void newAction();
|
||||
|
|
|
@ -16,6 +16,165 @@ QIcon ProjectModel::GroupNode::Icon;
|
|||
QIcon ProjectModel::SongGroupNode::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)
|
||||
: QIdentityProxyModel(source)
|
||||
{
|
||||
|
@ -407,7 +566,7 @@ ProjectModel::BasePoolObjectNode* ProjectModel::CollectionNode::nodeOfId(amuse::
|
|||
}
|
||||
|
||||
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>();
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <QAbstractItemModel>
|
||||
#include <QIdentityProxyModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QDir>
|
||||
#include <QIcon>
|
||||
#include <map>
|
||||
|
@ -28,6 +29,17 @@ enum AmuseItemEditFlags
|
|||
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
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -82,6 +94,7 @@ public:
|
|||
|
||||
private:
|
||||
QDir m_dir;
|
||||
OutlineFilterProxyModel m_outlineProxy;
|
||||
NullItemProxyModel m_nullProxy;
|
||||
PageObjectProxyModel m_pageObjectProxy;
|
||||
|
||||
|
@ -484,6 +497,7 @@ public:
|
|||
|
||||
const QDir& dir() const { return m_dir; }
|
||||
QString path() const { return m_dir.path(); }
|
||||
OutlineFilterProxyModel* getOutlineProxy() { return &m_outlineProxy; }
|
||||
NullItemProxyModel* getNullProxy() { return &m_nullProxy; }
|
||||
PageObjectProxyModel* getPageObjectProxy() { return &m_pageObjectProxy; }
|
||||
|
||||
|
|
|
@ -229,7 +229,17 @@ public:
|
|||
};
|
||||
|
||||
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
|
||||
{
|
||||
|
@ -242,12 +252,8 @@ QWidget* PageObjectDelegate::createEditor(QWidget* parent, const QStyleOptionVie
|
|||
|
||||
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;
|
||||
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();
|
||||
static_cast<EditorFieldPageObjectNode*>(editor)->setCurrentIndex(idx);
|
||||
if (static_cast<EditorFieldPageObjectNode*>(editor)->shouldPopupOpen())
|
||||
|
@ -316,6 +322,14 @@ QWidget* MIDIFileDelegate::createEditor(QWidget* parent, const QStyleOptionViewI
|
|||
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
|
||||
{
|
||||
MIDIFileFieldWidget* widget = static_cast<MIDIFileFieldWidget*>(editor);
|
||||
|
@ -339,6 +353,152 @@ void MIDIFileDelegate::setModelData(QWidget* editor, QAbstractItemModel* m, cons
|
|||
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()
|
||||
{
|
||||
emit commitData(static_cast<MIDIFileFieldWidget*>(sender()));
|
||||
|
@ -1210,7 +1370,8 @@ void MIDIPlayerWidget::stopped()
|
|||
|
||||
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)
|
||||
|
@ -1219,6 +1380,17 @@ void MIDIPlayerWidget::mouseDoubleClickEvent(QMouseEvent* event)
|
|||
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()
|
||||
{
|
||||
if (m_seq)
|
||||
|
@ -1406,6 +1578,11 @@ void SongGroupEditor::setupDataChanged()
|
|||
{
|
||||
QString path = g_MainWindow->projectModel()->getMIDIPathOfSong(p.m_it->first);
|
||||
QModelIndex index = m_setupList.index(idx, 1);
|
||||
if (m_setupTable->m_listView->isPersistentEditorOpen(index))
|
||||
{
|
||||
++idx;
|
||||
continue;
|
||||
}
|
||||
if (path.isEmpty())
|
||||
{
|
||||
m_setupTable->m_listView->setIndexWidget(index, nullptr);
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
#include "EditorWidget.hpp"
|
||||
#include <QTabWidget>
|
||||
#include <QAbstractTableModel>
|
||||
#include <QStyledItemDelegate>
|
||||
#include <QTableView>
|
||||
#include <QToolButton>
|
||||
#include <QAction>
|
||||
|
@ -16,9 +15,11 @@
|
|||
#include <QProxyStyle>
|
||||
#include "amuse/Sequencer.hpp"
|
||||
|
||||
class PageObjectDelegate : public QStyledItemDelegate
|
||||
class PageObjectDelegate : public BaseObjectDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
protected:
|
||||
ProjectModel::INode* getNode(const QAbstractItemModel* model, const QModelIndex& index) const;
|
||||
public:
|
||||
explicit PageObjectDelegate(QObject* parent = Q_NULLPTR);
|
||||
QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const;
|
||||
|
@ -51,8 +52,14 @@ class MIDIFileDelegate : public QStyledItemDelegate
|
|||
public:
|
||||
explicit MIDIFileDelegate(QObject* parent = Q_NULLPTR);
|
||||
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 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:
|
||||
void pathChanged();
|
||||
};
|
||||
|
@ -239,6 +246,8 @@ public:
|
|||
void stopped();
|
||||
void resizeEvent(QResizeEvent* event);
|
||||
void mouseDoubleClickEvent(QMouseEvent* event);
|
||||
void mousePressEvent(QMouseEvent* event);
|
||||
void mouseReleaseEvent(QMouseEvent* event) { event->ignore(); }
|
||||
public slots:
|
||||
void clicked();
|
||||
};
|
||||
|
|
|
@ -120,7 +120,17 @@ public:
|
|||
};
|
||||
|
||||
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
|
||||
{
|
||||
|
@ -133,12 +143,8 @@ QWidget* SFXObjectDelegate::createEditor(QWidget* parent, const QStyleOptionView
|
|||
|
||||
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;
|
||||
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();
|
||||
static_cast<EditorFieldPageObjectNode*>(editor)->setCurrentIndex(idx);
|
||||
if (static_cast<EditorFieldPageObjectNode*>(editor)->shouldPopupOpen())
|
||||
|
@ -561,7 +567,8 @@ void SFXPlayerWidget::stopped()
|
|||
|
||||
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)
|
||||
|
@ -570,6 +577,17 @@ void SFXPlayerWidget::mouseDoubleClickEvent(QMouseEvent* event)
|
|||
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()
|
||||
{
|
||||
if (m_vox)
|
||||
|
|
|
@ -6,9 +6,11 @@
|
|||
#include <QTableView>
|
||||
#include "amuse/Voice.hpp"
|
||||
|
||||
class SFXObjectDelegate : public QStyledItemDelegate
|
||||
class SFXObjectDelegate : public BaseObjectDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
protected:
|
||||
ProjectModel::INode* getNode(const QAbstractItemModel* model, const QModelIndex& index) const;
|
||||
public:
|
||||
explicit SFXObjectDelegate(QObject* parent = Q_NULLPTR);
|
||||
QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const;
|
||||
|
@ -98,6 +100,8 @@ public:
|
|||
void stopped();
|
||||
void resizeEvent(QResizeEvent* event);
|
||||
void mouseDoubleClickEvent(QMouseEvent* event);
|
||||
void mousePressEvent(QMouseEvent* event);
|
||||
void mouseReleaseEvent(QMouseEvent* event) { event->ignore(); }
|
||||
public slots:
|
||||
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>())
|
||||
{
|
||||
return std::min<T>(std::max<T>(in, -1.f), 1.f);
|
||||
return in;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -515,6 +515,7 @@ void Sequencer::ChannelState::killKeygroup(uint8_t kg, bool now)
|
|||
m_lastVoice.reset();
|
||||
if (now)
|
||||
{
|
||||
vox->kill();
|
||||
it = m_chanVoxs.erase(it);
|
||||
continue;
|
||||
}
|
||||
|
@ -533,6 +534,7 @@ void Sequencer::ChannelState::killKeygroup(uint8_t kg, bool now)
|
|||
Voice* vox = it->get();
|
||||
if (vox->m_keygroup == kg)
|
||||
{
|
||||
vox->kill();
|
||||
it = m_keyoffVoxs.erase(it);
|
||||
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))
|
||||
: *reinterpret_cast<const uint16_t*>(m_data + 2));
|
||||
seq.keyOn(m_midiChan, note, vel);
|
||||
if (length == 0)
|
||||
seq.keyOff(m_midiChan, note, 0);
|
||||
m_remNoteLengths[note] = length;
|
||||
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 vel = m_data[3] & 0x7f;
|
||||
seq.keyOn(m_midiChan, note, vel);
|
||||
if (length == 0)
|
||||
seq.keyOff(m_midiChan, note, 0);
|
||||
m_remNoteLengths[note] = length;
|
||||
}
|
||||
else if (m_data[2] & 0x80 && m_data[3] & 0x80)
|
||||
|
|
Loading…
Reference in New Issue