mirror of https://github.com/AxioDL/amuse.git
Integrate undo infrastructure with SoundMacroEditor
This commit is contained in:
parent
ca81c07600
commit
cb24322fc1
|
@ -1,6 +1,11 @@
|
||||||
#include "ADSREditor.hpp"
|
#include "ADSREditor.hpp"
|
||||||
|
|
||||||
ADSREditor::ADSREditor(ProjectModel::ADSRNode* node, QWidget* parent)
|
bool ADSREditor::loadData(ProjectModel::ADSRNode* node)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ADSREditor::ADSREditor(QWidget* parent)
|
||||||
: EditorWidget(parent)
|
: EditorWidget(parent)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,8 @@ class ADSREditor : public EditorWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit ADSREditor(ProjectModel::ADSRNode* node, QWidget* parent = Q_NULLPTR);
|
explicit ADSREditor(QWidget* parent = Q_NULLPTR);
|
||||||
|
bool loadData(ProjectModel::ADSRNode* node);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,9 @@
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
class MainWindow;
|
||||||
|
extern MainWindow* g_MainWindow;
|
||||||
|
|
||||||
class UIMessenger : public QObject
|
class UIMessenger : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -38,4 +41,5 @@ static QLatin1String StringViewToQString(std::string_view sv)
|
||||||
return QLatin1String(sv.data(), int(sv.size()));
|
return QLatin1String(sv.data(), int(sv.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif //AMUSE_COMMON_HPP
|
#endif //AMUSE_COMMON_HPP
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
#include "CurveEditor.hpp"
|
#include "CurveEditor.hpp"
|
||||||
|
|
||||||
CurveEditor::CurveEditor(ProjectModel::CurveNode* node, QWidget* parent)
|
bool CurveEditor::loadData(ProjectModel::CurveNode* node)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CurveEditor::CurveEditor(QWidget* parent)
|
||||||
: EditorWidget(parent)
|
: EditorWidget(parent)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,8 @@ class CurveEditor : public EditorWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit CurveEditor(ProjectModel::CurveNode* node, QWidget* parent = Q_NULLPTR);
|
explicit CurveEditor(QWidget* parent = Q_NULLPTR);
|
||||||
|
bool loadData(ProjectModel::CurveNode* node);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,18 @@
|
||||||
#include "EditorWidget.hpp"
|
#include "EditorWidget.hpp"
|
||||||
|
#include "MainWindow.hpp"
|
||||||
|
|
||||||
EditorWidget::EditorWidget(QWidget* parent)
|
EditorWidget::EditorWidget(QWidget* parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EditorUndoCommand::undo()
|
||||||
|
{
|
||||||
|
g_MainWindow->openEditor(m_node.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorUndoCommand::redo()
|
||||||
|
{
|
||||||
|
g_MainWindow->openEditor(m_node.get());
|
||||||
|
}
|
||||||
|
|
|
@ -2,15 +2,33 @@
|
||||||
#define AMUSE_EDITOR_WIDGET_HPP
|
#define AMUSE_EDITOR_WIDGET_HPP
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
#include <QUndoCommand>
|
||||||
|
#include <QApplication>
|
||||||
#include "ProjectModel.hpp"
|
#include "ProjectModel.hpp"
|
||||||
|
|
||||||
class EditorWidget : public QWidget
|
class EditorWidget : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit EditorWidget(QWidget* parent = Q_NULLPTR);
|
explicit EditorWidget(QWidget* parent = Q_NULLPTR);
|
||||||
virtual bool valid() const { return true; }
|
virtual bool valid() const { return true; }
|
||||||
|
virtual void unloadData() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class EditorUndoCommand : public QUndoCommand
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
std::shared_ptr<ProjectModel::INode> m_node;
|
||||||
|
enum class Id
|
||||||
|
{
|
||||||
|
SMChangeVal,
|
||||||
|
};
|
||||||
|
public:
|
||||||
|
EditorUndoCommand(std::shared_ptr<ProjectModel::INode> node,
|
||||||
|
const QString& text, QUndoCommand* parent = nullptr)
|
||||||
|
: QUndoCommand(text, parent), m_node(node) {}
|
||||||
|
void undo();
|
||||||
|
void redo();
|
||||||
|
};
|
||||||
|
|
||||||
#endif //AMUSE_EDITOR_WIDGET_HPP
|
#endif //AMUSE_EDITOR_WIDGET_HPP
|
||||||
|
|
|
@ -150,7 +150,8 @@ void KeyboardWidget::_moveOnKey(int octave, int key)
|
||||||
m_lastOctave = octave;
|
m_lastOctave = octave;
|
||||||
m_lastKey = key;
|
m_lastKey = key;
|
||||||
if (m_statusFocus)
|
if (m_statusFocus)
|
||||||
m_statusFocus->setMessage(QStringLiteral("%1%2").arg(KeyStrings[key]).arg(octave - 1));
|
m_statusFocus->setMessage(QStringLiteral("%1%2 (%3)").
|
||||||
|
arg(KeyStrings[key]).arg(octave - 1).arg(octave * 12 + key));
|
||||||
if (m_holding)
|
if (m_holding)
|
||||||
_startKey(octave, key);
|
_startKey(octave, key);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
#include "KeymapEditor.hpp"
|
#include "KeymapEditor.hpp"
|
||||||
|
|
||||||
KeymapEditor::KeymapEditor(ProjectModel::KeymapNode* node, QWidget* parent)
|
bool KeymapEditor::loadData(ProjectModel::KeymapNode* node)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
KeymapEditor::KeymapEditor(QWidget* parent)
|
||||||
: EditorWidget(parent)
|
: EditorWidget(parent)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,8 @@ class KeymapEditor : public EditorWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit KeymapEditor(ProjectModel::KeymapNode* node, QWidget* parent = Q_NULLPTR);
|
explicit KeymapEditor(QWidget* parent = Q_NULLPTR);
|
||||||
|
bool loadData(ProjectModel::KeymapNode* node);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
#include "LayersEditor.hpp"
|
#include "LayersEditor.hpp"
|
||||||
|
|
||||||
LayersEditor::LayersEditor(ProjectModel::LayersNode* node, QWidget* parent)
|
bool LayersEditor::loadData(ProjectModel::LayersNode* node)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LayersEditor::LayersEditor(QWidget* parent)
|
||||||
: EditorWidget(parent)
|
: EditorWidget(parent)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,8 @@ class LayersEditor : public EditorWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit LayersEditor(ProjectModel::LayersNode* node, QWidget* parent = Q_NULLPTR);
|
explicit LayersEditor(QWidget* parent = Q_NULLPTR);
|
||||||
|
bool loadData(ProjectModel::LayersNode* node);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -46,8 +46,13 @@ MainWindow::MainWindow(QWidget* parent)
|
||||||
connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
|
connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
m_ui.actionUndo->setShortcut(QKeySequence::Undo);
|
QAction* undoAction = m_undoStack->createUndoAction(this);
|
||||||
m_ui.actionRedo->setShortcut(QKeySequence::Redo);
|
undoAction->setShortcut(QKeySequence::Undo);
|
||||||
|
m_ui.menuEdit->insertAction(m_ui.actionCut, undoAction);
|
||||||
|
QAction* redoAction = m_undoStack->createRedoAction(this);
|
||||||
|
redoAction->setShortcut(QKeySequence::Redo);
|
||||||
|
m_ui.menuEdit->insertAction(m_ui.actionCut, redoAction);
|
||||||
|
m_ui.menuEdit->insertSeparator(m_ui.actionCut);
|
||||||
m_ui.actionCut->setShortcut(QKeySequence::Cut);
|
m_ui.actionCut->setShortcut(QKeySequence::Cut);
|
||||||
m_ui.actionCopy->setShortcut(QKeySequence::Copy);
|
m_ui.actionCopy->setShortcut(QKeySequence::Copy);
|
||||||
m_ui.actionPaste->setShortcut(QKeySequence::Paste);
|
m_ui.actionPaste->setShortcut(QKeySequence::Paste);
|
||||||
|
@ -62,6 +67,21 @@ MainWindow::MainWindow(QWidget* parent)
|
||||||
m_faceSvg = new QWidget;
|
m_faceSvg = new QWidget;
|
||||||
m_faceSvg->setLayout(faceLayout);
|
m_faceSvg->setLayout(faceLayout);
|
||||||
m_ui.editorContents->addWidget(m_faceSvg);
|
m_ui.editorContents->addWidget(m_faceSvg);
|
||||||
|
m_songGroupEditor = new SongGroupEditor;
|
||||||
|
m_ui.editorContents->addWidget(m_songGroupEditor);
|
||||||
|
m_soundGroupEditor = new SoundGroupEditor;
|
||||||
|
m_ui.editorContents->addWidget(m_soundGroupEditor);
|
||||||
|
m_soundMacroEditor = new SoundMacroEditor;
|
||||||
|
m_ui.editorContents->addWidget(m_soundMacroEditor);
|
||||||
|
m_adsrEditor = new ADSREditor;
|
||||||
|
m_ui.editorContents->addWidget(m_adsrEditor);
|
||||||
|
m_curveEditor = new CurveEditor;
|
||||||
|
m_ui.editorContents->addWidget(m_curveEditor);
|
||||||
|
m_keymapEditor = new KeymapEditor;
|
||||||
|
m_ui.editorContents->addWidget(m_keymapEditor);
|
||||||
|
m_layersEditor = new LayersEditor;
|
||||||
|
m_ui.editorContents->addWidget(m_layersEditor);
|
||||||
|
m_ui.editorContents->setCurrentWidget(m_faceSvg);
|
||||||
|
|
||||||
connect(m_ui.actionNew_Subproject, SIGNAL(triggered()), this, SLOT(newSubprojectAction()));
|
connect(m_ui.actionNew_Subproject, SIGNAL(triggered()), this, SLOT(newSubprojectAction()));
|
||||||
connect(m_ui.actionNew_SFX_Group, SIGNAL(triggered()), this, SLOT(newSFXGroupAction()));
|
connect(m_ui.actionNew_SFX_Group, SIGNAL(triggered()), this, SLOT(newSFXGroupAction()));
|
||||||
|
@ -239,19 +259,14 @@ void MainWindow::startBackgroundTask(const QString& windowTitle, const QString&
|
||||||
|
|
||||||
bool MainWindow::_setEditor(EditorWidget* editor)
|
bool MainWindow::_setEditor(EditorWidget* editor)
|
||||||
{
|
{
|
||||||
while (m_ui.editorContents->currentWidget() != m_faceSvg)
|
if (editor != m_ui.editorContents->currentWidget() &&
|
||||||
|
m_ui.editorContents->currentWidget() != m_faceSvg)
|
||||||
|
static_cast<EditorWidget*>(m_ui.editorContents->currentWidget())->unloadData();
|
||||||
|
if (!editor || !editor->valid())
|
||||||
{
|
{
|
||||||
m_ui.editorContents->currentWidget()->deleteLater();
|
m_ui.editorContents->setCurrentWidget(m_faceSvg);
|
||||||
m_ui.editorContents->removeWidget(m_ui.editorContents->currentWidget());
|
|
||||||
}
|
|
||||||
if (!editor)
|
|
||||||
return false;
|
|
||||||
if (!editor->valid())
|
|
||||||
{
|
|
||||||
editor->deleteLater();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
m_ui.editorContents->addWidget(editor);
|
|
||||||
m_ui.editorContents->setCurrentWidget(editor);
|
m_ui.editorContents->setCurrentWidget(editor);
|
||||||
m_ui.editorContents->update();
|
m_ui.editorContents->update();
|
||||||
return true;
|
return true;
|
||||||
|
@ -259,37 +274,37 @@ bool MainWindow::_setEditor(EditorWidget* editor)
|
||||||
|
|
||||||
bool MainWindow::openEditor(ProjectModel::SongGroupNode* node)
|
bool MainWindow::openEditor(ProjectModel::SongGroupNode* node)
|
||||||
{
|
{
|
||||||
return _setEditor(new SongGroupEditor(node));
|
return _setEditor(m_songGroupEditor->loadData(node) ? m_songGroupEditor : nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MainWindow::openEditor(ProjectModel::SoundGroupNode* node)
|
bool MainWindow::openEditor(ProjectModel::SoundGroupNode* node)
|
||||||
{
|
{
|
||||||
return _setEditor(new SoundGroupEditor(node));
|
return _setEditor(m_soundGroupEditor->loadData(node) ? m_soundGroupEditor : nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MainWindow::openEditor(ProjectModel::SoundMacroNode* node)
|
bool MainWindow::openEditor(ProjectModel::SoundMacroNode* node)
|
||||||
{
|
{
|
||||||
return _setEditor(new SoundMacroEditor(node));
|
return _setEditor(m_soundMacroEditor->loadData(node) ? m_soundMacroEditor : nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MainWindow::openEditor(ProjectModel::ADSRNode* node)
|
bool MainWindow::openEditor(ProjectModel::ADSRNode* node)
|
||||||
{
|
{
|
||||||
return _setEditor(new ADSREditor(node));
|
return _setEditor(m_adsrEditor->loadData(node) ? m_adsrEditor : nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MainWindow::openEditor(ProjectModel::CurveNode* node)
|
bool MainWindow::openEditor(ProjectModel::CurveNode* node)
|
||||||
{
|
{
|
||||||
return _setEditor(new CurveEditor(node));
|
return _setEditor(m_curveEditor->loadData(node) ? m_curveEditor : nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MainWindow::openEditor(ProjectModel::KeymapNode* node)
|
bool MainWindow::openEditor(ProjectModel::KeymapNode* node)
|
||||||
{
|
{
|
||||||
return _setEditor(new KeymapEditor(node));
|
return _setEditor(m_keymapEditor->loadData(node) ? m_keymapEditor : nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MainWindow::openEditor(ProjectModel::LayersNode* node)
|
bool MainWindow::openEditor(ProjectModel::LayersNode* node)
|
||||||
{
|
{
|
||||||
return _setEditor(new LayersEditor(node));
|
return _setEditor(m_layersEditor->loadData(node) ? m_layersEditor : nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MainWindow::openEditor(ProjectModel::INode* node)
|
bool MainWindow::openEditor(ProjectModel::INode* node)
|
||||||
|
@ -320,6 +335,11 @@ void MainWindow::closeEditor()
|
||||||
_setEditor(nullptr);
|
_setEditor(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::pushUndoCommand(QUndoCommand* cmd)
|
||||||
|
{
|
||||||
|
m_undoStack->push(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::newAction()
|
void MainWindow::newAction()
|
||||||
{
|
{
|
||||||
QString path = QFileDialog::getSaveFileName(this, tr("New Project"));
|
QString path = QFileDialog::getSaveFileName(this, tr("New Project"));
|
||||||
|
@ -592,10 +612,6 @@ void MainWindow::setMIDIIO()
|
||||||
|
|
||||||
void MainWindow::onFocusChanged(QWidget* old, QWidget* now)
|
void MainWindow::onFocusChanged(QWidget* old, QWidget* now)
|
||||||
{
|
{
|
||||||
disconnect(m_undoConn);
|
|
||||||
disconnect(m_canUndoConn);
|
|
||||||
disconnect(m_redoConn);
|
|
||||||
disconnect(m_canRedoConn);
|
|
||||||
disconnect(m_cutConn);
|
disconnect(m_cutConn);
|
||||||
disconnect(m_copyConn);
|
disconnect(m_copyConn);
|
||||||
disconnect(m_pasteConn);
|
disconnect(m_pasteConn);
|
||||||
|
@ -604,11 +620,6 @@ void MainWindow::onFocusChanged(QWidget* old, QWidget* now)
|
||||||
|
|
||||||
if (QLineEdit* le = qobject_cast<QLineEdit*>(now))
|
if (QLineEdit* le = qobject_cast<QLineEdit*>(now))
|
||||||
{
|
{
|
||||||
m_undoConn = connect(m_ui.actionUndo, SIGNAL(triggered()), le, SLOT(undo()));
|
|
||||||
m_canUndoConn = connect(le, SIGNAL(textChanged(const QString&)), this, SLOT(onTextEdited()));
|
|
||||||
m_ui.actionUndo->setEnabled(le->isUndoAvailable());
|
|
||||||
m_redoConn = connect(m_ui.actionRedo, SIGNAL(triggered()), le, SLOT(redo()));
|
|
||||||
m_ui.actionRedo->setEnabled(le->isRedoAvailable());
|
|
||||||
m_cutConn = connect(m_ui.actionCut, SIGNAL(triggered()), le, SLOT(cut()));
|
m_cutConn = connect(m_ui.actionCut, SIGNAL(triggered()), le, SLOT(cut()));
|
||||||
m_ui.actionCut->setEnabled(le->hasSelectedText());
|
m_ui.actionCut->setEnabled(le->hasSelectedText());
|
||||||
m_copyConn = connect(m_ui.actionCopy, SIGNAL(triggered()), le, SLOT(copy()));
|
m_copyConn = connect(m_ui.actionCopy, SIGNAL(triggered()), le, SLOT(copy()));
|
||||||
|
@ -621,13 +632,6 @@ void MainWindow::onFocusChanged(QWidget* old, QWidget* now)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_undoConn = connect(m_ui.actionUndo, SIGNAL(triggered()), m_undoStack, SLOT(undo()));
|
|
||||||
m_canUndoConn = connect(m_undoStack, SIGNAL(canUndoChanged(bool)), m_ui.actionUndo, SLOT(setEnabled(bool)));
|
|
||||||
m_ui.actionUndo->setEnabled(m_undoStack->canUndo());
|
|
||||||
m_redoConn = connect(m_ui.actionRedo, SIGNAL(triggered()), m_undoStack, SLOT(redo()));
|
|
||||||
m_canRedoConn = connect(m_undoStack, SIGNAL(canRedoChanged(bool)), m_ui.actionRedo, SLOT(setEnabled(bool)));
|
|
||||||
m_ui.actionRedo->setEnabled(m_undoStack->canRedo());
|
|
||||||
|
|
||||||
if (now == m_ui.projectOutline || m_ui.projectOutline->isAncestorOf(now))
|
if (now == m_ui.projectOutline || m_ui.projectOutline->isAncestorOf(now))
|
||||||
{
|
{
|
||||||
m_ui.actionCut->setEnabled(false);
|
m_ui.actionCut->setEnabled(false);
|
||||||
|
@ -648,15 +652,6 @@ void MainWindow::onFocusChanged(QWidget* old, QWidget* now)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::onTextEdited()
|
|
||||||
{
|
|
||||||
if (QLineEdit* le = qobject_cast<QLineEdit*>(sender()))
|
|
||||||
{
|
|
||||||
m_ui.actionUndo->setEnabled(le->isUndoAvailable());
|
|
||||||
m_ui.actionRedo->setEnabled(le->isRedoAvailable());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::onTextSelect()
|
void MainWindow::onTextSelect()
|
||||||
{
|
{
|
||||||
if (QLineEdit* le = qobject_cast<QLineEdit*>(sender()))
|
if (QLineEdit* le = qobject_cast<QLineEdit*>(sender()))
|
||||||
|
|
|
@ -19,6 +19,13 @@ class MainWindow;
|
||||||
|
|
||||||
class MainWindow;
|
class MainWindow;
|
||||||
class AudioGroupModel;
|
class AudioGroupModel;
|
||||||
|
class SongGroupEditor;
|
||||||
|
class SoundGroupEditor;
|
||||||
|
class SoundMacroEditor;
|
||||||
|
class ADSREditor;
|
||||||
|
class CurveEditor;
|
||||||
|
class KeymapEditor;
|
||||||
|
class LayersEditor;
|
||||||
|
|
||||||
class BackgroundTask : public QObject
|
class BackgroundTask : public QObject
|
||||||
{
|
{
|
||||||
|
@ -67,6 +74,13 @@ class MainWindow : public QMainWindow
|
||||||
ProjectModel* m_projectModel = nullptr;
|
ProjectModel* m_projectModel = nullptr;
|
||||||
AudioGroupModel* m_focusAudioGroup = nullptr;
|
AudioGroupModel* m_focusAudioGroup = nullptr;
|
||||||
QWidget* m_faceSvg;
|
QWidget* m_faceSvg;
|
||||||
|
SongGroupEditor* m_songGroupEditor = nullptr;
|
||||||
|
SoundGroupEditor* m_soundGroupEditor = nullptr;
|
||||||
|
SoundMacroEditor* m_soundMacroEditor = nullptr;
|
||||||
|
ADSREditor* m_adsrEditor = nullptr;
|
||||||
|
CurveEditor* m_curveEditor = nullptr;
|
||||||
|
KeymapEditor* m_keymapEditor = nullptr;
|
||||||
|
LayersEditor* m_layersEditor = nullptr;
|
||||||
|
|
||||||
std::unique_ptr<boo::IAudioVoiceEngine> m_voxEngine;
|
std::unique_ptr<boo::IAudioVoiceEngine> m_voxEngine;
|
||||||
std::unique_ptr<amuse::BooBackendVoiceAllocator> m_voxAllocator;
|
std::unique_ptr<amuse::BooBackendVoiceAllocator> m_voxAllocator;
|
||||||
|
@ -74,10 +88,6 @@ class MainWindow : public QMainWindow
|
||||||
|
|
||||||
QUndoStack* m_undoStack;
|
QUndoStack* m_undoStack;
|
||||||
|
|
||||||
QMetaObject::Connection m_undoConn;
|
|
||||||
QMetaObject::Connection m_canUndoConn;
|
|
||||||
QMetaObject::Connection m_redoConn;
|
|
||||||
QMetaObject::Connection m_canRedoConn;
|
|
||||||
QMetaObject::Connection m_cutConn;
|
QMetaObject::Connection m_cutConn;
|
||||||
QMetaObject::Connection m_copyConn;
|
QMetaObject::Connection m_copyConn;
|
||||||
QMetaObject::Connection m_pasteConn;
|
QMetaObject::Connection m_pasteConn;
|
||||||
|
@ -114,6 +124,8 @@ public:
|
||||||
bool openEditor(ProjectModel::INode* node);
|
bool openEditor(ProjectModel::INode* node);
|
||||||
void closeEditor();
|
void closeEditor();
|
||||||
|
|
||||||
|
void pushUndoCommand(QUndoCommand* cmd);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void newAction();
|
void newAction();
|
||||||
void openAction();
|
void openAction();
|
||||||
|
@ -136,7 +148,6 @@ public slots:
|
||||||
void setMIDIIO();
|
void setMIDIIO();
|
||||||
|
|
||||||
void onFocusChanged(QWidget* old, QWidget* now);
|
void onFocusChanged(QWidget* old, QWidget* now);
|
||||||
void onTextEdited();
|
|
||||||
void onTextSelect();
|
void onTextSelect();
|
||||||
void onTextDelete();
|
void onTextDelete();
|
||||||
|
|
||||||
|
|
|
@ -221,9 +221,6 @@
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>&Edit</string>
|
<string>&Edit</string>
|
||||||
</property>
|
</property>
|
||||||
<addaction name="actionUndo"/>
|
|
||||||
<addaction name="actionRedo"/>
|
|
||||||
<addaction name="separator"/>
|
|
||||||
<addaction name="actionCut"/>
|
<addaction name="actionCut"/>
|
||||||
<addaction name="actionCopy"/>
|
<addaction name="actionCopy"/>
|
||||||
<addaction name="actionPaste"/>
|
<addaction name="actionPaste"/>
|
||||||
|
@ -246,22 +243,6 @@
|
||||||
<string>&Open Project</string>
|
<string>&Open Project</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionUndo">
|
|
||||||
<property name="enabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>&Undo</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="actionRedo">
|
|
||||||
<property name="enabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>&Redo</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="actionCut">
|
<action name="actionCut">
|
||||||
<property name="enabled">
|
<property name="enabled">
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
|
|
|
@ -11,7 +11,7 @@ QIcon ProjectModel::SoundGroupNode::Icon;
|
||||||
ProjectModel::ProjectModel(const QString& path, QObject* parent)
|
ProjectModel::ProjectModel(const QString& path, QObject* parent)
|
||||||
: QAbstractItemModel(parent), m_dir(path)
|
: QAbstractItemModel(parent), m_dir(path)
|
||||||
{
|
{
|
||||||
m_root = std::make_unique<RootNode>();
|
m_root = std::make_shared<RootNode>();
|
||||||
|
|
||||||
GroupNode::Icon = QIcon(":/icons/IconGroup.svg");
|
GroupNode::Icon = QIcon(":/icons/IconGroup.svg");
|
||||||
SongGroupNode::Icon = QIcon(":/icons/IconSongGroup.svg");
|
SongGroupNode::Icon = QIcon(":/icons/IconSongGroup.svg");
|
||||||
|
@ -102,7 +102,7 @@ void ProjectModel::_resetModelData()
|
||||||
{
|
{
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
m_projectDatabase.setIdDatabases();
|
m_projectDatabase.setIdDatabases();
|
||||||
m_root = std::make_unique<RootNode>();
|
m_root = std::make_shared<RootNode>();
|
||||||
m_root->reserve(m_groups.size());
|
m_root->reserve(m_groups.size());
|
||||||
for (auto it = m_groups.begin() ; it != m_groups.end() ; ++it)
|
for (auto it = m_groups.begin() ; it != m_groups.end() ; ++it)
|
||||||
{
|
{
|
||||||
|
@ -150,7 +150,7 @@ void ProjectModel::_resetModelData()
|
||||||
{
|
{
|
||||||
amuse::ITable::Type tp = t.second.get()->Isa();
|
amuse::ITable::Type tp = t.second.get()->Isa();
|
||||||
if (tp == amuse::ITable::Type::ADSR || tp == amuse::ITable::Type::ADSRDLS)
|
if (tp == amuse::ITable::Type::ADSR || tp == amuse::ITable::Type::ADSRDLS)
|
||||||
col.makeChild<ADSRNode>(t.first, *t.second.get());
|
col.makeChild<ADSRNode>(t.first, t.second.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (curveCount)
|
if (curveCount)
|
||||||
|
@ -162,7 +162,7 @@ void ProjectModel::_resetModelData()
|
||||||
{
|
{
|
||||||
amuse::ITable::Type tp = t.second.get()->Isa();
|
amuse::ITable::Type tp = t.second.get()->Isa();
|
||||||
if (tp == amuse::ITable::Type::Curve)
|
if (tp == amuse::ITable::Type::Curve)
|
||||||
col.makeChild<CurveNode>(t.first, static_cast<amuse::Curve&>(*t.second.get()));
|
col.makeChild<CurveNode>(t.first, std::static_pointer_cast<amuse::Curve>(t.second.get()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ private:
|
||||||
std::map<QString, amuse::AudioGroupDatabase> m_groups;
|
std::map<QString, amuse::AudioGroupDatabase> m_groups;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
class INode
|
class INode : public std::enable_shared_from_this<INode>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum class Type
|
enum class Type
|
||||||
|
@ -48,7 +48,7 @@ public:
|
||||||
};
|
};
|
||||||
private:
|
private:
|
||||||
INode* m_parent;
|
INode* m_parent;
|
||||||
std::vector<std::unique_ptr<INode>> m_children;
|
std::vector<std::shared_ptr<INode>> m_children;
|
||||||
int m_row;
|
int m_row;
|
||||||
public:
|
public:
|
||||||
virtual ~INode() = default;
|
virtual ~INode() = default;
|
||||||
|
@ -63,7 +63,7 @@ public:
|
||||||
template<class T, class... _Args>
|
template<class T, class... _Args>
|
||||||
T& makeChild(_Args&&... args)
|
T& makeChild(_Args&&... args)
|
||||||
{
|
{
|
||||||
m_children.push_back(std::make_unique<T>(this, m_children.size(), std::forward<_Args>(args)...));
|
m_children.push_back(std::make_shared<T>(this, m_children.size(), std::forward<_Args>(args)...));
|
||||||
return static_cast<T&>(*m_children.back());
|
return static_cast<T&>(*m_children.back());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,32 +89,41 @@ public:
|
||||||
Type type() const { return Type::Group; }
|
Type type() const { return Type::Group; }
|
||||||
QString text() const { return m_it->first; }
|
QString text() const { return m_it->first; }
|
||||||
QIcon icon() const { return Icon; }
|
QIcon icon() const { return Icon; }
|
||||||
|
|
||||||
|
std::shared_ptr<GroupNode> shared_from_this()
|
||||||
|
{ return std::static_pointer_cast<GroupNode>(INode::shared_from_this()); }
|
||||||
};
|
};
|
||||||
struct SongGroupNode : INode
|
struct SongGroupNode : INode
|
||||||
{
|
{
|
||||||
amuse::GroupId m_id;
|
amuse::GroupId m_id;
|
||||||
QString m_name;
|
QString m_name;
|
||||||
amuse::SongGroupIndex& m_index;
|
std::shared_ptr<amuse::SongGroupIndex> m_index;
|
||||||
SongGroupNode(INode* parent, int row, amuse::GroupId id, amuse::SongGroupIndex& index)
|
SongGroupNode(INode* parent, int row, amuse::GroupId id, std::shared_ptr<amuse::SongGroupIndex> index)
|
||||||
: INode(parent, row), m_id(id), m_name(amuse::GroupId::CurNameDB->resolveNameFromId(id).data()), m_index(index) {}
|
: INode(parent, row), m_id(id), m_name(amuse::GroupId::CurNameDB->resolveNameFromId(id).data()), m_index(index) {}
|
||||||
|
|
||||||
static QIcon Icon;
|
static QIcon Icon;
|
||||||
Type type() const { return Type::SongGroup; }
|
Type type() const { return Type::SongGroup; }
|
||||||
QString text() const { return m_name; }
|
QString text() const { return m_name; }
|
||||||
QIcon icon() const { return Icon; }
|
QIcon icon() const { return Icon; }
|
||||||
|
|
||||||
|
std::shared_ptr<SongGroupNode> shared_from_this()
|
||||||
|
{ return std::static_pointer_cast<SongGroupNode>(INode::shared_from_this()); }
|
||||||
};
|
};
|
||||||
struct SoundGroupNode : INode
|
struct SoundGroupNode : INode
|
||||||
{
|
{
|
||||||
amuse::GroupId m_id;
|
amuse::GroupId m_id;
|
||||||
QString m_name;
|
QString m_name;
|
||||||
amuse::SFXGroupIndex& m_index;
|
std::shared_ptr<amuse::SFXGroupIndex> m_index;
|
||||||
SoundGroupNode(INode* parent, int row, amuse::GroupId id, amuse::SFXGroupIndex& index)
|
SoundGroupNode(INode* parent, int row, amuse::GroupId id, std::shared_ptr<amuse::SFXGroupIndex> index)
|
||||||
: INode(parent, row), m_id(id), m_name(amuse::GroupId::CurNameDB->resolveNameFromId(id).data()), m_index(index) {}
|
: INode(parent, row), m_id(id), m_name(amuse::GroupId::CurNameDB->resolveNameFromId(id).data()), m_index(index) {}
|
||||||
|
|
||||||
static QIcon Icon;
|
static QIcon Icon;
|
||||||
Type type() const { return Type::SoundGroup; }
|
Type type() const { return Type::SoundGroup; }
|
||||||
QString text() const { return m_name; }
|
QString text() const { return m_name; }
|
||||||
QIcon icon() const { return Icon; }
|
QIcon icon() const { return Icon; }
|
||||||
|
|
||||||
|
std::shared_ptr<SoundGroupNode> shared_from_this()
|
||||||
|
{ return std::static_pointer_cast<SoundGroupNode>(INode::shared_from_this()); }
|
||||||
};
|
};
|
||||||
struct CollectionNode : INode
|
struct CollectionNode : INode
|
||||||
{
|
{
|
||||||
|
@ -126,19 +135,25 @@ public:
|
||||||
Type type() const { return Type::Collection; }
|
Type type() const { return Type::Collection; }
|
||||||
QString text() const { return m_name; }
|
QString text() const { return m_name; }
|
||||||
QIcon icon() const { return m_icon; }
|
QIcon icon() const { return m_icon; }
|
||||||
|
|
||||||
|
std::shared_ptr<CollectionNode> shared_from_this()
|
||||||
|
{ return std::static_pointer_cast<CollectionNode>(INode::shared_from_this()); }
|
||||||
};
|
};
|
||||||
template <class ID, class T, INode::Type TP>
|
template <class ID, class T, INode::Type TP>
|
||||||
struct PoolObjectNode : INode
|
struct PoolObjectNode : INode
|
||||||
{
|
{
|
||||||
ID m_id;
|
ID m_id;
|
||||||
QString m_name;
|
QString m_name;
|
||||||
T& m_obj;
|
std::shared_ptr<T> m_obj;
|
||||||
PoolObjectNode(INode* parent, int row, ID id, T& obj)
|
PoolObjectNode(INode* parent, int row, ID id, std::shared_ptr<T> obj)
|
||||||
: INode(parent, row), m_id(id), m_name(ID::CurNameDB->resolveNameFromId(id).data()), m_obj(obj) {}
|
: INode(parent, row), m_id(id), m_name(ID::CurNameDB->resolveNameFromId(id).data()), m_obj(obj) {}
|
||||||
|
|
||||||
Type type() const { return TP; }
|
Type type() const { return TP; }
|
||||||
QString text() const { return m_name; }
|
QString text() const { return m_name; }
|
||||||
QIcon icon() const { return {}; }
|
QIcon icon() const { return {}; }
|
||||||
|
|
||||||
|
std::shared_ptr<PoolObjectNode<ID, T, TP>> shared_from_this()
|
||||||
|
{ return std::static_pointer_cast<PoolObjectNode<ID, T, TP>>(INode::shared_from_this()); }
|
||||||
};
|
};
|
||||||
using SoundMacroNode = PoolObjectNode<amuse::SoundMacroId, amuse::SoundMacro, INode::Type::SoundMacro>;
|
using SoundMacroNode = PoolObjectNode<amuse::SoundMacroId, amuse::SoundMacro, INode::Type::SoundMacro>;
|
||||||
using ADSRNode = PoolObjectNode<amuse::TableId, amuse::ITable, INode::Type::ADSR>;
|
using ADSRNode = PoolObjectNode<amuse::TableId, amuse::ITable, INode::Type::ADSR>;
|
||||||
|
@ -146,7 +161,7 @@ public:
|
||||||
using KeymapNode = PoolObjectNode<amuse::KeymapId, amuse::Keymap, INode::Type::Keymap>;
|
using KeymapNode = PoolObjectNode<amuse::KeymapId, amuse::Keymap, INode::Type::Keymap>;
|
||||||
using LayersNode = PoolObjectNode<amuse::LayersId, std::vector<amuse::LayerMapping>, INode::Type::Layer>;
|
using LayersNode = PoolObjectNode<amuse::LayersId, std::vector<amuse::LayerMapping>, INode::Type::Layer>;
|
||||||
|
|
||||||
std::unique_ptr<RootNode> m_root;
|
std::shared_ptr<RootNode> m_root;
|
||||||
|
|
||||||
bool m_needsReset = false;
|
bool m_needsReset = false;
|
||||||
void _resetModelData();
|
void _resetModelData();
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
#include "SongGroupEditor.hpp"
|
#include "SongGroupEditor.hpp"
|
||||||
|
|
||||||
SongGroupEditor::SongGroupEditor(ProjectModel::SongGroupNode* node, QWidget* parent)
|
bool SongGroupEditor::loadData(ProjectModel::SongGroupNode* node)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SongGroupEditor::SongGroupEditor(QWidget* parent)
|
||||||
: EditorWidget(parent)
|
: EditorWidget(parent)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,8 @@ class SongGroupEditor : public EditorWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit SongGroupEditor(ProjectModel::SongGroupNode* node, QWidget* parent = Q_NULLPTR);
|
explicit SongGroupEditor(QWidget* parent = Q_NULLPTR);
|
||||||
|
bool loadData(ProjectModel::SongGroupNode* node);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
#include "SoundGroupEditor.hpp"
|
#include "SoundGroupEditor.hpp"
|
||||||
|
|
||||||
SoundGroupEditor::SoundGroupEditor(ProjectModel::SoundGroupNode* node, QWidget* parent)
|
bool SoundGroupEditor::loadData(ProjectModel::SoundGroupNode* node)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SoundGroupEditor::SoundGroupEditor(QWidget* parent)
|
||||||
: EditorWidget(parent)
|
: EditorWidget(parent)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,8 @@ class SoundGroupEditor : public EditorWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit SoundGroupEditor(ProjectModel::SoundGroupNode* node, QWidget* parent = Q_NULLPTR);
|
explicit SoundGroupEditor(QWidget* parent = Q_NULLPTR);
|
||||||
|
bool loadData(ProjectModel::SoundGroupNode* node);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "SoundMacroEditor.hpp"
|
#include "SoundMacroEditor.hpp"
|
||||||
|
#include "MainWindow.hpp"
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QPropertyAnimation>
|
#include <QPropertyAnimation>
|
||||||
#include <QGridLayout>
|
#include <QGridLayout>
|
||||||
|
@ -12,37 +13,65 @@
|
||||||
CommandWidget::CommandWidget(amuse::SoundMacro::ICmd* cmd, amuse::SoundMacro::CmdOp op, QWidget* parent)
|
CommandWidget::CommandWidget(amuse::SoundMacro::ICmd* cmd, amuse::SoundMacro::CmdOp op, QWidget* parent)
|
||||||
: QWidget(parent), m_cmd(cmd), m_introspection(amuse::SoundMacro::GetCmdIntrospection(op))
|
: QWidget(parent), m_cmd(cmd), m_introspection(amuse::SoundMacro::GetCmdIntrospection(op))
|
||||||
{
|
{
|
||||||
m_titleFont.setWeight(QFont::Bold);
|
QFont titleFont = m_titleLabel.font();
|
||||||
|
titleFont.setWeight(QFont::Bold);
|
||||||
|
m_titleLabel.setFont(titleFont);
|
||||||
|
m_titleLabel.setForegroundRole(QPalette::Background);
|
||||||
|
//m_titleLabel.setAutoFillBackground(true);
|
||||||
|
//m_titleLabel.setBackgroundRole(QPalette::Text);
|
||||||
|
m_titleLabel.setContentsMargins(46, 0, 0, 0);
|
||||||
|
m_titleLabel.setFixedHeight(20);
|
||||||
m_numberText.setTextOption(QTextOption(Qt::AlignRight));
|
m_numberText.setTextOption(QTextOption(Qt::AlignRight));
|
||||||
m_numberText.setTextWidth(25);
|
m_numberText.setTextWidth(25);
|
||||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||||
setMinimumHeight(100);
|
|
||||||
m_numberFont.setWeight(QFont::Bold);
|
m_numberFont.setWeight(QFont::Bold);
|
||||||
m_numberFont.setStyleHint(QFont::Monospace);
|
m_numberFont.setStyleHint(QFont::Monospace);
|
||||||
m_numberFont.setPointSize(16);
|
m_numberFont.setPointSize(16);
|
||||||
|
|
||||||
setContentsMargins(54, 4, 0, 4);
|
setContentsMargins(QMargins());
|
||||||
|
setFixedHeight(100);
|
||||||
|
|
||||||
QVBoxLayout* mainLayout = new QVBoxLayout;
|
QVBoxLayout* mainLayout = new QVBoxLayout;
|
||||||
mainLayout->addStretch();
|
mainLayout->setContentsMargins(QMargins());
|
||||||
|
mainLayout->setSpacing(0);
|
||||||
|
|
||||||
|
QHBoxLayout* headLayout = new QHBoxLayout;
|
||||||
|
headLayout->setContentsMargins(QMargins());
|
||||||
|
headLayout->setSpacing(0);
|
||||||
|
headLayout->addWidget(&m_titleLabel);
|
||||||
|
if (op != amuse::SoundMacro::CmdOp::End)
|
||||||
|
{
|
||||||
|
m_deleteButton.setFixedSize(21, 21);
|
||||||
|
m_deleteButton.setIcon(QIcon(QStringLiteral(":/icons/IconSoundMacroDelete.svg")));
|
||||||
|
m_deleteButton.setFlat(true);
|
||||||
|
connect(&m_deleteButton, SIGNAL(clicked(bool)), this, SLOT(deleteClicked()));
|
||||||
|
headLayout->addWidget(&m_deleteButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
mainLayout->addLayout(headLayout);
|
||||||
|
mainLayout->addSpacing(8);
|
||||||
|
|
||||||
QGridLayout* layout = new QGridLayout;
|
QGridLayout* layout = new QGridLayout;
|
||||||
|
layout->setSpacing(6);
|
||||||
|
layout->setContentsMargins(64, 0, 12, 12);
|
||||||
if (m_introspection)
|
if (m_introspection)
|
||||||
{
|
{
|
||||||
m_titleText.setText(tr(m_introspection->m_name.data()));
|
m_titleLabel.setText(tr(m_introspection->m_name.data()));
|
||||||
|
m_titleLabel.setToolTip(tr(m_introspection->m_description.data()));
|
||||||
for (int f = 0; f < 7; ++f)
|
for (int f = 0; f < 7; ++f)
|
||||||
{
|
{
|
||||||
const amuse::SoundMacro::CmdIntrospection::Field& field = m_introspection->m_fields[f];
|
const amuse::SoundMacro::CmdIntrospection::Field& field = m_introspection->m_fields[f];
|
||||||
if (!field.m_name.empty())
|
if (!field.m_name.empty())
|
||||||
{
|
{
|
||||||
layout->addWidget(new QLabel(tr(field.m_name.data())), 0, f);
|
QString fieldName = tr(field.m_name.data());
|
||||||
int value;
|
layout->addWidget(new QLabel(fieldName), 0, f);
|
||||||
switch (field.m_tp)
|
switch (field.m_tp)
|
||||||
{
|
{
|
||||||
case amuse::SoundMacro::CmdIntrospection::Field::Type::Bool:
|
case amuse::SoundMacro::CmdIntrospection::Field::Type::Bool:
|
||||||
{
|
{
|
||||||
QCheckBox* cb = new QCheckBox;
|
QCheckBox* cb = new QCheckBox;
|
||||||
cb->setProperty("fieldIndex", f);
|
cb->setProperty("fieldIndex", f);
|
||||||
|
cb->setProperty("fieldName", fieldName);
|
||||||
cb->setCheckState(amuse::AccessField<bool>(m_cmd, field) ? Qt::Checked : Qt::Unchecked);
|
cb->setCheckState(amuse::AccessField<bool>(m_cmd, field) ? Qt::Checked : Qt::Unchecked);
|
||||||
connect(cb, SIGNAL(stateChanged(int)), this, SLOT(boolChanged(int)));
|
connect(cb, SIGNAL(stateChanged(int)), this, SLOT(boolChanged(int)));
|
||||||
layout->addWidget(cb, 1, f);
|
layout->addWidget(cb, 1, f);
|
||||||
|
@ -57,6 +86,7 @@ CommandWidget::CommandWidget(amuse::SoundMacro::ICmd* cmd, amuse::SoundMacro::Cm
|
||||||
{
|
{
|
||||||
FieldSpinBox* sb = new FieldSpinBox;
|
FieldSpinBox* sb = new FieldSpinBox;
|
||||||
sb->setProperty("fieldIndex", f);
|
sb->setProperty("fieldIndex", f);
|
||||||
|
sb->setProperty("fieldName", fieldName);
|
||||||
sb->setMinimum(int(field.m_min));
|
sb->setMinimum(int(field.m_min));
|
||||||
sb->setMaximum(int(field.m_max));
|
sb->setMaximum(int(field.m_max));
|
||||||
switch (field.m_tp)
|
switch (field.m_tp)
|
||||||
|
@ -90,9 +120,10 @@ CommandWidget::CommandWidget(amuse::SoundMacro::ICmd* cmd, amuse::SoundMacro::Cm
|
||||||
{
|
{
|
||||||
FieldComboBox* cb = new FieldComboBox;
|
FieldComboBox* cb = new FieldComboBox;
|
||||||
cb->setProperty("fieldIndex", f);
|
cb->setProperty("fieldIndex", f);
|
||||||
|
cb->setProperty("fieldName", fieldName);
|
||||||
for (int j = 0; j < 4; ++j)
|
for (int j = 0; j < 4; ++j)
|
||||||
{
|
{
|
||||||
if (field.m_choices->empty())
|
if (field.m_choices[j].empty())
|
||||||
break;
|
break;
|
||||||
cb->addItem(tr(field.m_choices[j].data()));
|
cb->addItem(tr(field.m_choices[j].data()));
|
||||||
}
|
}
|
||||||
|
@ -108,6 +139,8 @@ CommandWidget::CommandWidget(amuse::SoundMacro::ICmd* cmd, amuse::SoundMacro::Cm
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mainLayout->addLayout(layout);
|
mainLayout->addLayout(layout);
|
||||||
|
layout->setRowMinimumHeight(0, 22);
|
||||||
|
layout->setRowMinimumHeight(1, 37);
|
||||||
setLayout(mainLayout);
|
setLayout(mainLayout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,6 +150,102 @@ CommandWidget::CommandWidget(amuse::SoundMacro::ICmd* cmd, QWidget* parent)
|
||||||
CommandWidget::CommandWidget(amuse::SoundMacro::CmdOp op, QWidget* parent)
|
CommandWidget::CommandWidget(amuse::SoundMacro::CmdOp op, QWidget* parent)
|
||||||
: CommandWidget(nullptr, op, parent) {}
|
: CommandWidget(nullptr, op, parent) {}
|
||||||
|
|
||||||
|
class ValChangedUndoCommand : public EditorUndoCommand
|
||||||
|
{
|
||||||
|
amuse::SoundMacro::ICmd* m_cmd;
|
||||||
|
const amuse::SoundMacro::CmdIntrospection::Field& m_field;
|
||||||
|
int m_redoVal, m_undoVal;
|
||||||
|
bool m_undid = false;
|
||||||
|
public:
|
||||||
|
ValChangedUndoCommand(amuse::SoundMacro::ICmd* cmd, const QString& fieldName,
|
||||||
|
const amuse::SoundMacro::CmdIntrospection::Field& field,
|
||||||
|
int redoVal, std::shared_ptr<ProjectModel::SoundMacroNode> node)
|
||||||
|
: EditorUndoCommand(node, QUndoStack::tr("Change %1").arg(fieldName)),
|
||||||
|
m_cmd(cmd), m_field(field), m_redoVal(redoVal) {}
|
||||||
|
void undo()
|
||||||
|
{
|
||||||
|
m_undid = true;
|
||||||
|
switch (m_field.m_tp)
|
||||||
|
{
|
||||||
|
case amuse::SoundMacro::CmdIntrospection::Field::Type::Bool:
|
||||||
|
amuse::AccessField<bool>(m_cmd, m_field) = bool(m_undoVal);
|
||||||
|
break;
|
||||||
|
case amuse::SoundMacro::CmdIntrospection::Field::Type::Int8:
|
||||||
|
case amuse::SoundMacro::CmdIntrospection::Field::Type::Choice:
|
||||||
|
amuse::AccessField<int8_t>(m_cmd, m_field) = int8_t(m_undoVal);
|
||||||
|
break;
|
||||||
|
case amuse::SoundMacro::CmdIntrospection::Field::Type::UInt8:
|
||||||
|
amuse::AccessField<uint8_t>(m_cmd, m_field) = uint8_t(m_undoVal);
|
||||||
|
break;
|
||||||
|
case amuse::SoundMacro::CmdIntrospection::Field::Type::Int16:
|
||||||
|
amuse::AccessField<int16_t>(m_cmd, m_field) = int16_t(m_undoVal);
|
||||||
|
break;
|
||||||
|
case amuse::SoundMacro::CmdIntrospection::Field::Type::UInt16:
|
||||||
|
amuse::AccessField<uint16_t>(m_cmd, m_field) = uint16_t(m_undoVal);
|
||||||
|
break;
|
||||||
|
case amuse::SoundMacro::CmdIntrospection::Field::Type::Int32:
|
||||||
|
amuse::AccessField<int32_t>(m_cmd, m_field) = int32_t(m_undoVal);
|
||||||
|
break;
|
||||||
|
case amuse::SoundMacro::CmdIntrospection::Field::Type::UInt32:
|
||||||
|
amuse::AccessField<uint32_t>(m_cmd, m_field) = uint32_t(m_undoVal);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
EditorUndoCommand::undo();
|
||||||
|
}
|
||||||
|
void redo()
|
||||||
|
{
|
||||||
|
switch (m_field.m_tp)
|
||||||
|
{
|
||||||
|
case amuse::SoundMacro::CmdIntrospection::Field::Type::Bool:
|
||||||
|
m_undoVal = amuse::AccessField<bool>(m_cmd, m_field);
|
||||||
|
amuse::AccessField<bool>(m_cmd, m_field) = bool(m_redoVal);
|
||||||
|
break;
|
||||||
|
case amuse::SoundMacro::CmdIntrospection::Field::Type::Int8:
|
||||||
|
case amuse::SoundMacro::CmdIntrospection::Field::Type::Choice:
|
||||||
|
m_undoVal = amuse::AccessField<int8_t>(m_cmd, m_field);
|
||||||
|
amuse::AccessField<int8_t>(m_cmd, m_field) = int8_t(m_redoVal);
|
||||||
|
break;
|
||||||
|
case amuse::SoundMacro::CmdIntrospection::Field::Type::UInt8:
|
||||||
|
m_undoVal = amuse::AccessField<uint8_t>(m_cmd, m_field);
|
||||||
|
amuse::AccessField<uint8_t>(m_cmd, m_field) = uint8_t(m_redoVal);
|
||||||
|
break;
|
||||||
|
case amuse::SoundMacro::CmdIntrospection::Field::Type::Int16:
|
||||||
|
m_undoVal = amuse::AccessField<int16_t>(m_cmd, m_field);
|
||||||
|
amuse::AccessField<int16_t>(m_cmd, m_field) = int16_t(m_redoVal);
|
||||||
|
break;
|
||||||
|
case amuse::SoundMacro::CmdIntrospection::Field::Type::UInt16:
|
||||||
|
m_undoVal = amuse::AccessField<uint16_t>(m_cmd, m_field);
|
||||||
|
amuse::AccessField<uint16_t>(m_cmd, m_field) = uint16_t(m_redoVal);
|
||||||
|
break;
|
||||||
|
case amuse::SoundMacro::CmdIntrospection::Field::Type::Int32:
|
||||||
|
m_undoVal = amuse::AccessField<int32_t>(m_cmd, m_field);
|
||||||
|
amuse::AccessField<int32_t>(m_cmd, m_field) = int32_t(m_redoVal);
|
||||||
|
break;
|
||||||
|
case amuse::SoundMacro::CmdIntrospection::Field::Type::UInt32:
|
||||||
|
m_undoVal = amuse::AccessField<uint32_t>(m_cmd, m_field);
|
||||||
|
amuse::AccessField<uint32_t>(m_cmd, m_field) = uint32_t(m_redoVal);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (m_undid)
|
||||||
|
EditorUndoCommand::redo();
|
||||||
|
}
|
||||||
|
bool mergeWith(const QUndoCommand* other)
|
||||||
|
{
|
||||||
|
if (other->id() == id() && m_cmd == static_cast<const ValChangedUndoCommand*>(other)->m_cmd &&
|
||||||
|
&m_field == &static_cast<const ValChangedUndoCommand*>(other)->m_field)
|
||||||
|
{
|
||||||
|
m_redoVal = static_cast<const ValChangedUndoCommand*>(other)->m_redoVal;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int id() const { return int(Id::SMChangeVal); }
|
||||||
|
};
|
||||||
|
|
||||||
void CommandWidget::boolChanged(int state)
|
void CommandWidget::boolChanged(int state)
|
||||||
{
|
{
|
||||||
if (m_introspection)
|
if (m_introspection)
|
||||||
|
@ -124,7 +253,8 @@ void CommandWidget::boolChanged(int state)
|
||||||
QCheckBox* cb = static_cast<QCheckBox*>(sender());
|
QCheckBox* cb = static_cast<QCheckBox*>(sender());
|
||||||
const amuse::SoundMacro::CmdIntrospection::Field& field =
|
const amuse::SoundMacro::CmdIntrospection::Field& field =
|
||||||
m_introspection->m_fields[cb->property("fieldIndex").toInt()];
|
m_introspection->m_fields[cb->property("fieldIndex").toInt()];
|
||||||
amuse::AccessField<bool>(m_cmd, field) = state == Qt::Checked;
|
g_MainWindow->pushUndoCommand(new ValChangedUndoCommand(m_cmd, cb->property("fieldName").toString(), field,
|
||||||
|
state == Qt::Checked, getParent()->m_node));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,80 +265,40 @@ void CommandWidget::numChanged(int value)
|
||||||
FieldSpinBox* sb = static_cast<FieldSpinBox*>(sender());
|
FieldSpinBox* sb = static_cast<FieldSpinBox*>(sender());
|
||||||
const amuse::SoundMacro::CmdIntrospection::Field& field =
|
const amuse::SoundMacro::CmdIntrospection::Field& field =
|
||||||
m_introspection->m_fields[sb->property("fieldIndex").toInt()];
|
m_introspection->m_fields[sb->property("fieldIndex").toInt()];
|
||||||
switch (field.m_tp)
|
g_MainWindow->pushUndoCommand(new ValChangedUndoCommand(m_cmd, sb->property("fieldName").toString(), field,
|
||||||
|
value, getParent()->m_node));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommandWidget::choiceChanged(int choice)
|
||||||
|
{
|
||||||
|
if (m_introspection)
|
||||||
{
|
{
|
||||||
case amuse::SoundMacro::CmdIntrospection::Field::Type::Int8:
|
FieldComboBox* cb = static_cast<FieldComboBox*>(sender());
|
||||||
amuse::AccessField<int8_t>(m_cmd, field) = int8_t(value);
|
const amuse::SoundMacro::CmdIntrospection::Field& field =
|
||||||
break;
|
m_introspection->m_fields[cb->property("fieldIndex").toInt()];
|
||||||
case amuse::SoundMacro::CmdIntrospection::Field::Type::UInt8:
|
g_MainWindow->pushUndoCommand(new ValChangedUndoCommand(m_cmd, cb->property("fieldName").toString(), field,
|
||||||
amuse::AccessField<uint8_t>(m_cmd, field) = uint8_t(value);
|
choice, getParent()->m_node));
|
||||||
break;
|
|
||||||
case amuse::SoundMacro::CmdIntrospection::Field::Type::Int16:
|
|
||||||
amuse::AccessField<int16_t>(m_cmd, field) = int16_t(value);
|
|
||||||
break;
|
|
||||||
case amuse::SoundMacro::CmdIntrospection::Field::Type::UInt16:
|
|
||||||
amuse::AccessField<uint16_t>(m_cmd, field) = uint16_t(value);
|
|
||||||
break;
|
|
||||||
case amuse::SoundMacro::CmdIntrospection::Field::Type::Int32:
|
|
||||||
amuse::AccessField<int32_t>(m_cmd, field) = int32_t(value);
|
|
||||||
break;
|
|
||||||
case amuse::SoundMacro::CmdIntrospection::Field::Type::UInt32:
|
|
||||||
amuse::AccessField<uint32_t>(m_cmd, field) = uint32_t(value);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandWidget::animateOpen()
|
void CommandWidget::deleteClicked()
|
||||||
{
|
{
|
||||||
int newHeight = 200 + parentWidget()->layout()->spacing();
|
if (m_index != -1)
|
||||||
m_animation = new QPropertyAnimation(this, "minimumHeight");
|
if (SoundMacroListing* listing = qobject_cast<SoundMacroListing*>(parentWidget()->parentWidget()))
|
||||||
m_animation->setDuration(abs(minimumHeight() - newHeight) * 4);
|
listing->deleteCommand(m_index);
|
||||||
m_animation->setStartValue(minimumHeight());
|
|
||||||
m_animation->setEndValue(newHeight);
|
|
||||||
m_animation->setEasingCurve(QEasingCurve::InOutExpo);
|
|
||||||
connect(m_animation, SIGNAL(valueChanged(const QVariant&)), parentWidget(), SLOT(update()));
|
|
||||||
connect(m_animation, SIGNAL(destroyed(QObject*)), this, SLOT(animationDestroyed()));
|
|
||||||
m_animation->start(QAbstractAnimation::DeleteWhenStopped);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CommandWidget::animateClosed()
|
|
||||||
{
|
|
||||||
m_animation = new QPropertyAnimation(this, "minimumHeight");
|
|
||||||
m_animation->setDuration(abs(minimumHeight() - 100) * 4);
|
|
||||||
m_animation->setStartValue(minimumHeight());
|
|
||||||
m_animation->setEndValue(100);
|
|
||||||
m_animation->setEasingCurve(QEasingCurve::InOutExpo);
|
|
||||||
connect(m_animation, SIGNAL(valueChanged(const QVariant&)), parentWidget(), SLOT(update()));
|
|
||||||
connect(m_animation, SIGNAL(destroyed(QObject*)), this, SLOT(animationDestroyed()));
|
|
||||||
m_animation->start(QAbstractAnimation::DeleteWhenStopped);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CommandWidget::snapOpen()
|
|
||||||
{
|
|
||||||
if (m_animation)
|
|
||||||
m_animation->stop();
|
|
||||||
setMinimumHeight(200 + parentWidget()->layout()->spacing());
|
|
||||||
}
|
|
||||||
|
|
||||||
void CommandWidget::snapClosed()
|
|
||||||
{
|
|
||||||
if (m_animation)
|
|
||||||
m_animation->stop();
|
|
||||||
setMinimumHeight(100);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandWidget::setIndex(int index)
|
void CommandWidget::setIndex(int index)
|
||||||
{
|
{
|
||||||
|
m_index = index;
|
||||||
m_numberText.setText(QString::number(index));
|
m_numberText.setText(QString::number(index));
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandWidget::animationDestroyed()
|
SoundMacroListing* CommandWidget::getParent() const
|
||||||
{
|
{
|
||||||
m_animation = nullptr;
|
return qobject_cast<SoundMacroListing*>(parentWidget()->parentWidget());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandWidget::paintEvent(QPaintEvent* event)
|
void CommandWidget::paintEvent(QPaintEvent* event)
|
||||||
|
@ -217,8 +307,6 @@ void CommandWidget::paintEvent(QPaintEvent* event)
|
||||||
QPainter painter(this);
|
QPainter painter(this);
|
||||||
painter.setRenderHint(QPainter::Antialiasing);
|
painter.setRenderHint(QPainter::Antialiasing);
|
||||||
|
|
||||||
QTransform mainXf = QTransform::fromTranslate(0, rect().bottom() - 99);
|
|
||||||
painter.setTransform(mainXf);
|
|
||||||
QPoint points[] =
|
QPoint points[] =
|
||||||
{
|
{
|
||||||
{1, 20},
|
{1, 20},
|
||||||
|
@ -248,17 +336,71 @@ void CommandWidget::paintEvent(QPaintEvent* event)
|
||||||
|
|
||||||
painter.drawRect(17, 51, 32, 32);
|
painter.drawRect(17, 51, 32, 32);
|
||||||
|
|
||||||
painter.setPen(palette().color(QPalette::Background));
|
|
||||||
painter.setFont(m_titleFont);
|
|
||||||
painter.drawStaticText(40, -1, m_titleText);
|
|
||||||
|
|
||||||
QTransform rotate;
|
QTransform rotate;
|
||||||
rotate.rotate(-45.0);
|
rotate.rotate(-45.0);
|
||||||
painter.setTransform(rotate * mainXf);
|
painter.setTransform(rotate);
|
||||||
painter.setFont(m_numberFont);
|
painter.setFont(m_numberFont);
|
||||||
|
painter.setPen(palette().color(QPalette::Background));
|
||||||
painter.drawStaticText(-15, 10, m_numberText);
|
painter.drawStaticText(-15, 10, m_numberText);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CommandWidgetContainer::animateOpen()
|
||||||
|
{
|
||||||
|
int newHeight = 200 + parentWidget()->layout()->spacing();
|
||||||
|
m_animation = new QPropertyAnimation(this, "minimumHeight");
|
||||||
|
m_animation->setDuration(abs(minimumHeight() - newHeight) * 4);
|
||||||
|
m_animation->setStartValue(minimumHeight());
|
||||||
|
m_animation->setEndValue(newHeight);
|
||||||
|
m_animation->setEasingCurve(QEasingCurve::InOutExpo);
|
||||||
|
connect(m_animation, SIGNAL(valueChanged(const QVariant&)), parentWidget(), SLOT(update()));
|
||||||
|
connect(m_animation, SIGNAL(destroyed(QObject*)), this, SLOT(animationDestroyed()));
|
||||||
|
m_animation->start(QAbstractAnimation::DeleteWhenStopped);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommandWidgetContainer::animateClosed()
|
||||||
|
{
|
||||||
|
m_animation = new QPropertyAnimation(this, "minimumHeight");
|
||||||
|
m_animation->setDuration(abs(minimumHeight() - 100) * 4);
|
||||||
|
m_animation->setStartValue(minimumHeight());
|
||||||
|
m_animation->setEndValue(100);
|
||||||
|
m_animation->setEasingCurve(QEasingCurve::InOutExpo);
|
||||||
|
connect(m_animation, SIGNAL(valueChanged(const QVariant&)), parentWidget(), SLOT(update()));
|
||||||
|
connect(m_animation, SIGNAL(destroyed(QObject*)), this, SLOT(animationDestroyed()));
|
||||||
|
m_animation->start(QAbstractAnimation::DeleteWhenStopped);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommandWidgetContainer::snapOpen()
|
||||||
|
{
|
||||||
|
if (m_animation)
|
||||||
|
m_animation->stop();
|
||||||
|
setMinimumHeight(200 + parentWidget()->layout()->spacing());
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommandWidgetContainer::snapClosed()
|
||||||
|
{
|
||||||
|
if (m_animation)
|
||||||
|
m_animation->stop();
|
||||||
|
setMinimumHeight(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommandWidgetContainer::animationDestroyed()
|
||||||
|
{
|
||||||
|
m_animation = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
CommandWidgetContainer::CommandWidgetContainer(CommandWidget* child, QWidget* parent)
|
||||||
|
: QWidget(parent), m_commandWidget(child)
|
||||||
|
{
|
||||||
|
setMinimumHeight(100);
|
||||||
|
setContentsMargins(QMargins());
|
||||||
|
QBoxLayout* outerLayout = new QVBoxLayout;
|
||||||
|
outerLayout->setContentsMargins(QMargins());
|
||||||
|
outerLayout->setSpacing(0);
|
||||||
|
outerLayout->addStretch();
|
||||||
|
outerLayout->addWidget(child);
|
||||||
|
setLayout(outerLayout);
|
||||||
|
}
|
||||||
|
|
||||||
void SoundMacroListing::startAutoscroll(QWidget* source, QMouseEvent* event, int delta)
|
void SoundMacroListing::startAutoscroll(QWidget* source, QMouseEvent* event, int delta)
|
||||||
{
|
{
|
||||||
if (m_autoscrollTimer == -1)
|
if (m_autoscrollTimer == -1)
|
||||||
|
@ -298,7 +440,7 @@ void SoundMacroListing::timerEvent(QTimerEvent* event)
|
||||||
|
|
||||||
bool SoundMacroListing::beginDrag(CommandWidget* widget)
|
bool SoundMacroListing::beginDrag(CommandWidget* widget)
|
||||||
{
|
{
|
||||||
int origIdx = m_layout->indexOf(widget);
|
int origIdx = m_layout->indexOf(widget->parentWidget());
|
||||||
/* Don't allow dragging last command (END command) */
|
/* Don't allow dragging last command (END command) */
|
||||||
if (origIdx < 0 || origIdx >= m_layout->count() - 2)
|
if (origIdx < 0 || origIdx >= m_layout->count() - 2)
|
||||||
return false;
|
return false;
|
||||||
|
@ -306,7 +448,8 @@ bool SoundMacroListing::beginDrag(CommandWidget* widget)
|
||||||
{
|
{
|
||||||
// Animate next item open
|
// Animate next item open
|
||||||
m_dragOpenIdx = origIdx;
|
m_dragOpenIdx = origIdx;
|
||||||
if (CommandWidget* nextItem = qobject_cast<CommandWidget*>(m_layout->itemAt(origIdx + 1)->widget()))
|
if (CommandWidgetContainer* nextItem =
|
||||||
|
qobject_cast<CommandWidgetContainer*>(m_layout->itemAt(origIdx + 1)->widget()))
|
||||||
nextItem->snapOpen();
|
nextItem->snapOpen();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -319,24 +462,57 @@ bool SoundMacroListing::beginDrag(CommandWidget* widget)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundMacroListing::endDrag(CommandWidget* widget)
|
class ReorderCommandsUndoCommand : public EditorUndoCommand
|
||||||
{
|
{
|
||||||
|
int m_a, m_b;
|
||||||
|
bool m_undid = false;
|
||||||
|
public:
|
||||||
|
ReorderCommandsUndoCommand(int a, int b, const QString& text, std::shared_ptr<ProjectModel::SoundMacroNode> node)
|
||||||
|
: EditorUndoCommand(node, QUndoStack::tr("Reorder %1").arg(text)), m_a(a), m_b(b) {}
|
||||||
|
void undo()
|
||||||
|
{
|
||||||
|
m_undid = true;
|
||||||
|
std::static_pointer_cast<ProjectModel::SoundMacroNode>(m_node)->
|
||||||
|
m_obj->swapPositions(m_a, m_b);
|
||||||
|
EditorUndoCommand::undo();
|
||||||
|
}
|
||||||
|
void redo()
|
||||||
|
{
|
||||||
|
std::static_pointer_cast<ProjectModel::SoundMacroNode>(m_node)->
|
||||||
|
m_obj->swapPositions(m_a, m_b);
|
||||||
|
if (m_undid)
|
||||||
|
EditorUndoCommand::redo();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void SoundMacroListing::endDrag()
|
||||||
|
{
|
||||||
|
int insertIdx;
|
||||||
if (m_dragOpenIdx != -1)
|
if (m_dragOpenIdx != -1)
|
||||||
{
|
{
|
||||||
if (CommandWidget* prevItem = qobject_cast<CommandWidget*>(m_layout->itemAt(m_dragOpenIdx)->widget()))
|
if (CommandWidgetContainer* prevItem =
|
||||||
|
qobject_cast<CommandWidgetContainer*>(m_layout->itemAt(m_dragOpenIdx)->widget()))
|
||||||
prevItem->snapClosed();
|
prevItem->snapClosed();
|
||||||
m_layout->insertItem(m_dragOpenIdx, m_dragItem);
|
insertIdx = m_dragOpenIdx;
|
||||||
m_dragOpenIdx = -1;
|
m_dragOpenIdx = -1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_layout->insertItem(m_layout->count() - 2, m_dragItem);
|
insertIdx = m_layout->count() - 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_prevDragOpen)
|
if (m_prevDragOpen)
|
||||||
{
|
{
|
||||||
m_prevDragOpen->snapClosed();
|
m_prevDragOpen->snapClosed();
|
||||||
m_prevDragOpen = nullptr;
|
m_prevDragOpen = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_origIdx != insertIdx)
|
||||||
|
{
|
||||||
|
CommandWidget* cmd = static_cast<CommandWidgetContainer*>(m_dragItem->widget())->m_commandWidget;
|
||||||
|
g_MainWindow->pushUndoCommand(new ReorderCommandsUndoCommand(m_origIdx, insertIdx, cmd->getText(), m_node));
|
||||||
|
}
|
||||||
|
m_layout->insertItem(insertIdx, m_dragItem);
|
||||||
m_dragItem = nullptr;
|
m_dragItem = nullptr;
|
||||||
stopAutoscroll();
|
stopAutoscroll();
|
||||||
reindex();
|
reindex();
|
||||||
|
@ -346,7 +522,8 @@ void SoundMacroListing::cancelDrag()
|
||||||
{
|
{
|
||||||
if (m_dragOpenIdx != -1)
|
if (m_dragOpenIdx != -1)
|
||||||
{
|
{
|
||||||
if (CommandWidget* prevItem = qobject_cast<CommandWidget*>(m_layout->itemAt(m_dragOpenIdx)->widget()))
|
if (CommandWidgetContainer* prevItem =
|
||||||
|
qobject_cast<CommandWidgetContainer*>(m_layout->itemAt(m_dragOpenIdx)->widget()))
|
||||||
prevItem->snapClosed();
|
prevItem->snapClosed();
|
||||||
m_dragOpenIdx = -1;
|
m_dragOpenIdx = -1;
|
||||||
}
|
}
|
||||||
|
@ -376,12 +553,14 @@ void SoundMacroListing::_moveDrag(int hoverIdx, const QPoint& pt, QWidget* sourc
|
||||||
if (hoverIdx != m_dragOpenIdx)
|
if (hoverIdx != m_dragOpenIdx)
|
||||||
{
|
{
|
||||||
if (m_dragOpenIdx != -1)
|
if (m_dragOpenIdx != -1)
|
||||||
if (CommandWidget* prevItem = qobject_cast<CommandWidget*>(m_layout->itemAt(m_dragOpenIdx)->widget()))
|
if (CommandWidgetContainer* prevItem =
|
||||||
|
qobject_cast<CommandWidgetContainer*>(m_layout->itemAt(m_dragOpenIdx)->widget()))
|
||||||
{
|
{
|
||||||
m_prevDragOpen = prevItem;
|
m_prevDragOpen = prevItem;
|
||||||
prevItem->animateClosed();
|
prevItem->animateClosed();
|
||||||
}
|
}
|
||||||
if (CommandWidget* nextItem = qobject_cast<CommandWidget*>(m_layout->itemAt(hoverIdx)->widget()))
|
if (CommandWidgetContainer* nextItem =
|
||||||
|
qobject_cast<CommandWidgetContainer*>(m_layout->itemAt(hoverIdx)->widget()))
|
||||||
nextItem->animateOpen();
|
nextItem->animateOpen();
|
||||||
m_dragOpenIdx = hoverIdx;
|
m_dragOpenIdx = hoverIdx;
|
||||||
}
|
}
|
||||||
|
@ -390,8 +569,9 @@ void SoundMacroListing::_moveDrag(int hoverIdx, const QPoint& pt, QWidget* sourc
|
||||||
|
|
||||||
void SoundMacroListing::moveDrag(CommandWidget* widget, const QPoint& pt, QWidget* source, QMouseEvent* event)
|
void SoundMacroListing::moveDrag(CommandWidget* widget, const QPoint& pt, QWidget* source, QMouseEvent* event)
|
||||||
{
|
{
|
||||||
|
CommandWidgetContainer* container = static_cast<CommandWidgetContainer*>(widget->parentWidget());
|
||||||
int pitch = 100 + m_layout->spacing();
|
int pitch = 100 + m_layout->spacing();
|
||||||
_moveDrag((widget->pos().y() - m_layout->contentsMargins().top() + pitch / 2) / pitch, pt, source, event);
|
_moveDrag((container->pos().y() - m_layout->contentsMargins().top() + pitch / 2) / pitch, pt, source, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
int SoundMacroListing::moveInsertDrag(const QPoint& pt, QWidget* source, QMouseEvent* event)
|
int SoundMacroListing::moveInsertDrag(const QPoint& pt, QWidget* source, QMouseEvent* event)
|
||||||
|
@ -405,7 +585,8 @@ void SoundMacroListing::insertDragout()
|
||||||
{
|
{
|
||||||
if (m_dragOpenIdx != -1)
|
if (m_dragOpenIdx != -1)
|
||||||
{
|
{
|
||||||
if (CommandWidget* prevItem = qobject_cast<CommandWidget*>(m_layout->itemAt(m_dragOpenIdx)->widget()))
|
if (CommandWidgetContainer* prevItem =
|
||||||
|
qobject_cast<CommandWidgetContainer*>(m_layout->itemAt(m_dragOpenIdx)->widget()))
|
||||||
{
|
{
|
||||||
m_prevDragOpen = prevItem;
|
m_prevDragOpen = prevItem;
|
||||||
prevItem->animateClosed();
|
prevItem->animateClosed();
|
||||||
|
@ -415,40 +596,139 @@ void SoundMacroListing::insertDragout()
|
||||||
stopAutoscroll();
|
stopAutoscroll();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundMacroListing::insert(amuse::SoundMacro::CmdOp op)
|
class InsertCommandUndoCommand : public EditorUndoCommand
|
||||||
{
|
{
|
||||||
CommandWidget* newCmd = new CommandWidget(amuse::SoundMacro::MakeCmd(op).release(), this);
|
int m_insertIdx;
|
||||||
|
std::unique_ptr<amuse::SoundMacro::ICmd> m_cmd;
|
||||||
|
public:
|
||||||
|
InsertCommandUndoCommand(int insertIdx, const QString& text, std::shared_ptr<ProjectModel::SoundMacroNode> node)
|
||||||
|
: EditorUndoCommand(node, QUndoStack::tr("Insert %1").arg(text)), m_insertIdx(insertIdx) {}
|
||||||
|
void undo()
|
||||||
|
{
|
||||||
|
m_cmd = std::static_pointer_cast<ProjectModel::SoundMacroNode>(m_node)->
|
||||||
|
m_obj->deleteCmd(m_insertIdx);
|
||||||
|
EditorUndoCommand::undo();
|
||||||
|
}
|
||||||
|
void redo()
|
||||||
|
{
|
||||||
|
if (!m_cmd)
|
||||||
|
return;
|
||||||
|
std::static_pointer_cast<ProjectModel::SoundMacroNode>(m_node)->
|
||||||
|
m_obj->insertCmd(m_insertIdx, std::move(m_cmd));
|
||||||
|
m_cmd.reset();
|
||||||
|
EditorUndoCommand::redo();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void SoundMacroListing::insert(amuse::SoundMacro::CmdOp op, const QString& text)
|
||||||
|
{
|
||||||
|
int insertIdx;
|
||||||
if (m_dragOpenIdx != -1)
|
if (m_dragOpenIdx != -1)
|
||||||
{
|
{
|
||||||
if (CommandWidget* prevItem = qobject_cast<CommandWidget*>(m_layout->itemAt(m_dragOpenIdx)->widget()))
|
if (CommandWidgetContainer* prevItem =
|
||||||
|
qobject_cast<CommandWidgetContainer*>(m_layout->itemAt(m_dragOpenIdx)->widget()))
|
||||||
prevItem->snapClosed();
|
prevItem->snapClosed();
|
||||||
m_layout->insertWidget(m_dragOpenIdx, newCmd);
|
insertIdx = m_dragOpenIdx;
|
||||||
m_dragOpenIdx = -1;
|
m_dragOpenIdx = -1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_layout->insertWidget(m_layout->count() - 2, newCmd);
|
insertIdx = m_layout->count() - 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_prevDragOpen)
|
if (m_prevDragOpen)
|
||||||
{
|
{
|
||||||
m_prevDragOpen->snapClosed();
|
m_prevDragOpen->snapClosed();
|
||||||
m_prevDragOpen = nullptr;
|
m_prevDragOpen = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_MainWindow->pushUndoCommand(new InsertCommandUndoCommand(insertIdx, text, m_node));
|
||||||
|
m_layout->insertWidget(insertIdx,
|
||||||
|
new CommandWidgetContainer(new CommandWidget(m_node->m_obj->insertNewCmd(insertIdx, op))));
|
||||||
|
|
||||||
stopAutoscroll();
|
stopAutoscroll();
|
||||||
reindex();
|
reindex();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DeleteCommandUndoCommand : public EditorUndoCommand
|
||||||
|
{
|
||||||
|
int m_deleteIdx;
|
||||||
|
std::unique_ptr<amuse::SoundMacro::ICmd> m_cmd;
|
||||||
|
bool m_undid = false;
|
||||||
|
public:
|
||||||
|
DeleteCommandUndoCommand(int deleteIdx, const QString& text, std::shared_ptr<ProjectModel::SoundMacroNode> node)
|
||||||
|
: EditorUndoCommand(node, QUndoStack::tr("Delete %1").arg(text)), m_deleteIdx(deleteIdx) {}
|
||||||
|
void undo()
|
||||||
|
{
|
||||||
|
m_undid = true;
|
||||||
|
std::static_pointer_cast<ProjectModel::SoundMacroNode>(m_node)->
|
||||||
|
m_obj->insertCmd(m_deleteIdx, std::move(m_cmd));
|
||||||
|
m_cmd.reset();
|
||||||
|
EditorUndoCommand::undo();
|
||||||
|
}
|
||||||
|
void redo()
|
||||||
|
{
|
||||||
|
m_cmd = std::static_pointer_cast<ProjectModel::SoundMacroNode>(m_node)->
|
||||||
|
m_obj->deleteCmd(m_deleteIdx);
|
||||||
|
if (m_undid)
|
||||||
|
EditorUndoCommand::redo();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void SoundMacroListing::deleteCommand(int index)
|
||||||
|
{
|
||||||
|
QLayoutItem* item = m_layout->takeAt(index);
|
||||||
|
CommandWidget* cmd = static_cast<CommandWidgetContainer*>(item->widget())->m_commandWidget;
|
||||||
|
g_MainWindow->pushUndoCommand(new DeleteCommandUndoCommand(index, cmd->getText(), m_node));
|
||||||
|
item->widget()->deleteLater();
|
||||||
|
delete item;
|
||||||
|
reindex();
|
||||||
|
}
|
||||||
|
|
||||||
void SoundMacroListing::reindex()
|
void SoundMacroListing::reindex()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < m_layout->count() - 1; ++i)
|
for (int i = 0; i < m_layout->count() - 1; ++i)
|
||||||
if (CommandWidget* item = qobject_cast<CommandWidget*>(m_layout->itemAt(i)->widget()))
|
if (CommandWidgetContainer* item =
|
||||||
item->setIndex(i);
|
qobject_cast<CommandWidgetContainer*>(m_layout->itemAt(i)->widget()))
|
||||||
|
item->m_commandWidget->setIndex(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
SoundMacroListing::SoundMacroListing(ProjectModel::SoundMacroNode* node, QWidget* parent)
|
void SoundMacroListing::clear()
|
||||||
|
{
|
||||||
|
while (m_layout->count() > 2)
|
||||||
|
{
|
||||||
|
QLayoutItem* item = m_layout->takeAt(0);
|
||||||
|
item->widget()->deleteLater();
|
||||||
|
delete item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SoundMacroListing::loadData(ProjectModel::SoundMacroNode* node)
|
||||||
|
{
|
||||||
|
m_node = node->shared_from_this();
|
||||||
|
clear();
|
||||||
|
int i = 0;
|
||||||
|
for (auto& cmd : node->m_obj->m_cmds)
|
||||||
|
{
|
||||||
|
if (cmd->Isa() == amuse::SoundMacro::CmdOp::End)
|
||||||
|
break;
|
||||||
|
m_layout->insertWidget(i++, new CommandWidgetContainer(new CommandWidget(cmd.get())));
|
||||||
|
}
|
||||||
|
reindex();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundMacroListing::unloadData()
|
||||||
|
{
|
||||||
|
m_node.reset();
|
||||||
|
clear();
|
||||||
|
reindex();
|
||||||
|
}
|
||||||
|
|
||||||
|
SoundMacroListing::SoundMacroListing(QWidget* parent)
|
||||||
: QWidget(parent), m_layout(new QVBoxLayout)
|
: QWidget(parent), m_layout(new QVBoxLayout)
|
||||||
{
|
{
|
||||||
m_layout->addWidget(new CommandWidget(amuse::SoundMacro::CmdOp::End, this));
|
m_layout->addWidget(new CommandWidgetContainer(new CommandWidget(amuse::SoundMacro::CmdOp::End)));
|
||||||
m_layout->addStretch();
|
m_layout->addStretch();
|
||||||
setLayout(m_layout);
|
setLayout(m_layout);
|
||||||
reindex();
|
reindex();
|
||||||
|
@ -456,17 +736,16 @@ SoundMacroListing::SoundMacroListing(ProjectModel::SoundMacroNode* node, QWidget
|
||||||
|
|
||||||
CatalogueItem::CatalogueItem(amuse::SoundMacro::CmdOp op, const QString& name,
|
CatalogueItem::CatalogueItem(amuse::SoundMacro::CmdOp op, const QString& name,
|
||||||
const QString& doc, QWidget* parent)
|
const QString& doc, QWidget* parent)
|
||||||
: QWidget(parent), m_op(op)
|
: QWidget(parent), m_op(op), m_label(name)
|
||||||
{
|
{
|
||||||
QHBoxLayout* layout = new QHBoxLayout;
|
QHBoxLayout* layout = new QHBoxLayout;
|
||||||
QLabel* iconLab = new QLabel;
|
|
||||||
QString iconPath = QStringLiteral(":/commands/%1.svg").arg(name);
|
QString iconPath = QStringLiteral(":/commands/%1.svg").arg(name);
|
||||||
if (QFile(iconPath).exists())
|
if (QFile(iconPath).exists())
|
||||||
iconLab->setPixmap(QIcon(iconPath).pixmap(32, 32));
|
m_iconLab.setPixmap(QIcon(iconPath).pixmap(32, 32));
|
||||||
else
|
else
|
||||||
iconLab->setPixmap(QIcon(QStringLiteral(":/icons/IconOpen.svg")).pixmap(32, 32));
|
m_iconLab.setPixmap(QIcon(QStringLiteral(":/icons/IconOpen.svg")).pixmap(32, 32));
|
||||||
layout->addWidget(iconLab);
|
layout->addWidget(&m_iconLab);
|
||||||
layout->addWidget(new QLabel(name));
|
layout->addWidget(&m_label);
|
||||||
layout->addStretch();
|
layout->addStretch();
|
||||||
layout->setContentsMargins(QMargins());
|
layout->setContentsMargins(QMargins());
|
||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
|
@ -478,10 +757,10 @@ CatalogueItem::CatalogueItem(const CatalogueItem& other, QWidget* parent)
|
||||||
{
|
{
|
||||||
QHBoxLayout* layout = new QHBoxLayout;
|
QHBoxLayout* layout = new QHBoxLayout;
|
||||||
QHBoxLayout* oldLayout = static_cast<QHBoxLayout*>(other.layout());
|
QHBoxLayout* oldLayout = static_cast<QHBoxLayout*>(other.layout());
|
||||||
QLabel* iconLab = new QLabel;
|
m_iconLab.setPixmap(*static_cast<QLabel*>(oldLayout->itemAt(0)->widget())->pixmap());
|
||||||
iconLab->setPixmap(*static_cast<QLabel*>(oldLayout->itemAt(0)->widget())->pixmap());
|
layout->addWidget(&m_iconLab);
|
||||||
layout->addWidget(iconLab);
|
m_label.setText(static_cast<QLabel*>(oldLayout->itemAt(1)->widget())->text());
|
||||||
layout->addWidget(new QLabel(static_cast<QLabel*>(oldLayout->itemAt(1)->widget())->text()));
|
layout->addWidget(&m_label);
|
||||||
layout->addStretch();
|
layout->addStretch();
|
||||||
layout->setContentsMargins(QMargins());
|
layout->setContentsMargins(QMargins());
|
||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
|
@ -617,13 +896,14 @@ void SoundMacroEditor::mouseReleaseEvent(QMouseEvent* event)
|
||||||
if (m_draggedItem)
|
if (m_draggedItem)
|
||||||
{
|
{
|
||||||
amuse::SoundMacro::CmdOp op = m_draggedItem->getCmdOp();
|
amuse::SoundMacro::CmdOp op = m_draggedItem->getCmdOp();
|
||||||
|
QString text = m_draggedItem->getText();
|
||||||
m_draggedItem->deleteLater();
|
m_draggedItem->deleteLater();
|
||||||
m_draggedItem = nullptr;
|
m_draggedItem = nullptr;
|
||||||
|
|
||||||
if (m_listing->parentWidget()->parentWidget()->geometry().contains(event->pos()))
|
if (m_listing->parentWidget()->parentWidget()->geometry().contains(event->pos()))
|
||||||
{
|
{
|
||||||
if (m_dragInsertIdx != -1)
|
if (m_dragInsertIdx != -1)
|
||||||
m_listing->insert(op);
|
m_listing->insert(op, text);
|
||||||
else
|
else
|
||||||
m_listing->insertDragout();
|
m_listing->insertDragout();
|
||||||
}
|
}
|
||||||
|
@ -635,7 +915,7 @@ void SoundMacroEditor::mouseReleaseEvent(QMouseEvent* event)
|
||||||
}
|
}
|
||||||
else if (m_draggedCmd)
|
else if (m_draggedCmd)
|
||||||
{
|
{
|
||||||
m_listing->endDrag(m_draggedCmd);
|
m_listing->endDrag();
|
||||||
m_draggedCmd = nullptr;
|
m_draggedCmd = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -660,7 +940,8 @@ void SoundMacroEditor::mouseMoveEvent(QMouseEvent* event)
|
||||||
else if (m_draggedCmd)
|
else if (m_draggedCmd)
|
||||||
{
|
{
|
||||||
QPoint listingPt = m_listing->mapFrom(this, event->pos());
|
QPoint listingPt = m_listing->mapFrom(this, event->pos());
|
||||||
m_draggedCmd->move(m_draggedCmd->x(), listingPt.y() - m_draggedPt.y());
|
CommandWidgetContainer* container = static_cast<CommandWidgetContainer*>(m_draggedCmd->parentWidget());
|
||||||
|
container->move(container->x(), listingPt.y() - m_draggedPt.y());
|
||||||
if (m_listing->parentWidget()->parentWidget()->geometry().contains(event->pos()))
|
if (m_listing->parentWidget()->parentWidget()->geometry().contains(event->pos()))
|
||||||
m_listing->moveDrag(m_draggedCmd, listingPt, this, event);
|
m_listing->moveDrag(m_draggedCmd, listingPt, this, event);
|
||||||
m_listing->update();
|
m_listing->update();
|
||||||
|
@ -692,13 +973,23 @@ void SoundMacroEditor::catalogueDoubleClicked(QTreeWidgetItem* item, int column)
|
||||||
{
|
{
|
||||||
amuse::SoundMacro::CmdOp op = cItem->getCmdOp();
|
amuse::SoundMacro::CmdOp op = cItem->getCmdOp();
|
||||||
if (op != amuse::SoundMacro::CmdOp::Invalid)
|
if (op != amuse::SoundMacro::CmdOp::Invalid)
|
||||||
m_listing->insert(op);
|
m_listing->insert(op, cItem->getText());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SoundMacroEditor::SoundMacroEditor(ProjectModel::SoundMacroNode* node, QWidget* parent)
|
bool SoundMacroEditor::loadData(ProjectModel::SoundMacroNode* node)
|
||||||
|
{
|
||||||
|
return m_listing->loadData(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundMacroEditor::unloadData()
|
||||||
|
{
|
||||||
|
m_listing->unloadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
SoundMacroEditor::SoundMacroEditor(QWidget* parent)
|
||||||
: EditorWidget(parent), m_splitter(new QSplitter),
|
: EditorWidget(parent), m_splitter(new QSplitter),
|
||||||
m_listing(new SoundMacroListing(node)), m_catalogue(new SoundMacroCatalogue)
|
m_listing(new SoundMacroListing), m_catalogue(new SoundMacroCatalogue)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
QScrollArea* listingScroll = new QScrollArea;
|
QScrollArea* listingScroll = new QScrollArea;
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <QSpinBox>
|
#include <QSpinBox>
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
#include <QTreeWidget>
|
#include <QTreeWidget>
|
||||||
|
#include <QPushButton>
|
||||||
|
|
||||||
class SoundMacroListing;
|
class SoundMacroListing;
|
||||||
class CatalogueItem;
|
class CatalogueItem;
|
||||||
|
@ -41,28 +42,43 @@ class CommandWidget : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
friend class SoundMacroListing;
|
friend class SoundMacroListing;
|
||||||
QPropertyAnimation* m_animation = nullptr;
|
|
||||||
QFont m_numberFont;
|
QFont m_numberFont;
|
||||||
QFont m_titleFont;
|
QLabel m_titleLabel;
|
||||||
|
QPushButton m_deleteButton;
|
||||||
QStaticText m_numberText;
|
QStaticText m_numberText;
|
||||||
QStaticText m_titleText;
|
int m_index = -1;
|
||||||
amuse::SoundMacro::ICmd* m_cmd;
|
amuse::SoundMacro::ICmd* m_cmd;
|
||||||
const amuse::SoundMacro::CmdIntrospection* m_introspection;
|
const amuse::SoundMacro::CmdIntrospection* m_introspection;
|
||||||
void animateOpen();
|
|
||||||
void animateClosed();
|
|
||||||
void snapOpen();
|
|
||||||
void snapClosed();
|
|
||||||
void setIndex(int index);
|
void setIndex(int index);
|
||||||
|
SoundMacroListing* getParent() const;
|
||||||
private slots:
|
private slots:
|
||||||
void animationDestroyed();
|
|
||||||
void boolChanged(int);
|
void boolChanged(int);
|
||||||
void numChanged(int);
|
void numChanged(int);
|
||||||
|
void choiceChanged(int);
|
||||||
|
void deleteClicked();
|
||||||
private:
|
private:
|
||||||
CommandWidget(amuse::SoundMacro::ICmd* cmd, amuse::SoundMacro::CmdOp op, QWidget* parent = Q_NULLPTR);
|
CommandWidget(amuse::SoundMacro::ICmd* cmd, amuse::SoundMacro::CmdOp op, QWidget* parent = Q_NULLPTR);
|
||||||
public:
|
public:
|
||||||
CommandWidget(amuse::SoundMacro::ICmd* cmd, QWidget* parent = Q_NULLPTR);
|
CommandWidget(amuse::SoundMacro::ICmd* cmd, QWidget* parent = Q_NULLPTR);
|
||||||
CommandWidget(amuse::SoundMacro::CmdOp op, QWidget* parent = Q_NULLPTR);
|
CommandWidget(amuse::SoundMacro::CmdOp op, QWidget* parent = Q_NULLPTR);
|
||||||
void paintEvent(QPaintEvent* event);
|
void paintEvent(QPaintEvent* event);
|
||||||
|
QString getText() const { return m_titleLabel.text(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
class CommandWidgetContainer : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class SoundMacroListing;
|
||||||
|
CommandWidget* m_commandWidget;
|
||||||
|
QPropertyAnimation* m_animation = nullptr;
|
||||||
|
void animateOpen();
|
||||||
|
void animateClosed();
|
||||||
|
void snapOpen();
|
||||||
|
void snapClosed();
|
||||||
|
private slots:
|
||||||
|
void animationDestroyed();
|
||||||
|
public:
|
||||||
|
CommandWidgetContainer(CommandWidget* child, QWidget* parent = Q_NULLPTR);
|
||||||
};
|
};
|
||||||
|
|
||||||
class SoundMacroListing : public QWidget
|
class SoundMacroListing : public QWidget
|
||||||
|
@ -70,11 +86,12 @@ class SoundMacroListing : public QWidget
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
friend class CommandWidget;
|
friend class CommandWidget;
|
||||||
friend class SoundMacroEditor;
|
friend class SoundMacroEditor;
|
||||||
|
std::shared_ptr<ProjectModel::SoundMacroNode> m_node;
|
||||||
QVBoxLayout* m_layout;
|
QVBoxLayout* m_layout;
|
||||||
QLayoutItem* m_dragItem = nullptr;
|
QLayoutItem* m_dragItem = nullptr;
|
||||||
int m_origIdx = -1;
|
int m_origIdx = -1;
|
||||||
int m_dragOpenIdx = -1;
|
int m_dragOpenIdx = -1;
|
||||||
CommandWidget* m_prevDragOpen = nullptr;
|
CommandWidgetContainer* m_prevDragOpen = nullptr;
|
||||||
int m_autoscrollTimer = -1;
|
int m_autoscrollTimer = -1;
|
||||||
int m_autoscrollDelta = 0;
|
int m_autoscrollDelta = 0;
|
||||||
QWidget* m_autoscrollSource = nullptr;
|
QWidget* m_autoscrollSource = nullptr;
|
||||||
|
@ -82,16 +99,20 @@ class SoundMacroListing : public QWidget
|
||||||
void startAutoscroll(QWidget* source, QMouseEvent* event, int delta);
|
void startAutoscroll(QWidget* source, QMouseEvent* event, int delta);
|
||||||
void stopAutoscroll();
|
void stopAutoscroll();
|
||||||
bool beginDrag(CommandWidget* widget);
|
bool beginDrag(CommandWidget* widget);
|
||||||
void endDrag(CommandWidget* widget);
|
void endDrag();
|
||||||
void cancelDrag();
|
void cancelDrag();
|
||||||
void _moveDrag(int hoverIdx, const QPoint& pt, QWidget* source, QMouseEvent* event);
|
void _moveDrag(int hoverIdx, const QPoint& pt, QWidget* source, QMouseEvent* event);
|
||||||
void moveDrag(CommandWidget* widget, const QPoint& pt, QWidget* source, QMouseEvent* event);
|
void moveDrag(CommandWidget* widget, const QPoint& pt, QWidget* source, QMouseEvent* event);
|
||||||
int moveInsertDrag(const QPoint& pt, QWidget* source, QMouseEvent* event);
|
int moveInsertDrag(const QPoint& pt, QWidget* source, QMouseEvent* event);
|
||||||
void insertDragout();
|
void insertDragout();
|
||||||
void insert(amuse::SoundMacro::CmdOp op);
|
void insert(amuse::SoundMacro::CmdOp op, const QString& text);
|
||||||
|
void deleteCommand(int index);
|
||||||
void reindex();
|
void reindex();
|
||||||
|
void clear();
|
||||||
public:
|
public:
|
||||||
explicit SoundMacroListing(ProjectModel::SoundMacroNode* node, QWidget* parent = Q_NULLPTR);
|
explicit SoundMacroListing(QWidget* parent = Q_NULLPTR);
|
||||||
|
bool loadData(ProjectModel::SoundMacroNode* node);
|
||||||
|
void unloadData();
|
||||||
void timerEvent(QTimerEvent* event);
|
void timerEvent(QTimerEvent* event);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -99,11 +120,14 @@ class CatalogueItem : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
amuse::SoundMacro::CmdOp m_op;
|
amuse::SoundMacro::CmdOp m_op;
|
||||||
|
QLabel m_iconLab;
|
||||||
|
QLabel m_label;
|
||||||
public:
|
public:
|
||||||
explicit CatalogueItem(amuse::SoundMacro::CmdOp op, const QString& name,
|
explicit CatalogueItem(amuse::SoundMacro::CmdOp op, const QString& name,
|
||||||
const QString& doc, QWidget* parent = Q_NULLPTR);
|
const QString& doc, QWidget* parent = Q_NULLPTR);
|
||||||
explicit CatalogueItem(const CatalogueItem& other, QWidget* parent = Q_NULLPTR);
|
explicit CatalogueItem(const CatalogueItem& other, QWidget* parent = Q_NULLPTR);
|
||||||
amuse::SoundMacro::CmdOp getCmdOp() const { return m_op; }
|
amuse::SoundMacro::CmdOp getCmdOp() const { return m_op; }
|
||||||
|
QString getText() const { return m_label.text(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class SoundMacroCatalogue : public QTreeWidget
|
class SoundMacroCatalogue : public QTreeWidget
|
||||||
|
@ -130,7 +154,9 @@ class SoundMacroEditor : public EditorWidget
|
||||||
void beginCommandDrag(CommandWidget* widget, const QPoint& eventPt, const QPoint& pt);
|
void beginCommandDrag(CommandWidget* widget, const QPoint& eventPt, const QPoint& pt);
|
||||||
void beginCatalogueDrag(CatalogueItem* item, const QPoint& eventPt, const QPoint& pt);
|
void beginCatalogueDrag(CatalogueItem* item, const QPoint& eventPt, const QPoint& pt);
|
||||||
public:
|
public:
|
||||||
explicit SoundMacroEditor(ProjectModel::SoundMacroNode* node, QWidget* parent = Q_NULLPTR);
|
explicit SoundMacroEditor(QWidget* parent = Q_NULLPTR);
|
||||||
|
bool loadData(ProjectModel::SoundMacroNode* node);
|
||||||
|
void unloadData();
|
||||||
|
|
||||||
void mousePressEvent(QMouseEvent* event);
|
void mousePressEvent(QMouseEvent* event);
|
||||||
void mouseReleaseEvent(QMouseEvent* event);
|
void mouseReleaseEvent(QMouseEvent* event);
|
||||||
|
|
|
@ -51,6 +51,8 @@ public:
|
||||||
std::shared_ptr<boo::IWindow> newWindow(boo::SystemStringView title) { return {}; }
|
std::shared_ptr<boo::IWindow> newWindow(boo::SystemStringView title) { return {}; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
MainWindow* g_MainWindow = nullptr;
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
|
||||||
|
@ -97,6 +99,7 @@ int main(int argc, char* argv[])
|
||||||
a.installTranslator(&translator);
|
a.installTranslator(&translator);
|
||||||
|
|
||||||
MainWindow w;
|
MainWindow w;
|
||||||
|
g_MainWindow = &w;
|
||||||
w.show();
|
w.show();
|
||||||
return a.exec();
|
return a.exec();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="20"
|
||||||
|
height="20"
|
||||||
|
viewBox="0 0 5.2916665 5.2916668"
|
||||||
|
version="1.1"
|
||||||
|
id="svg8"
|
||||||
|
inkscape:version="0.92.2 2405546, 2018-03-11"
|
||||||
|
sodipodi:docname="IconSoundMacroDelete.svg">
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#7f7f7f"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="16.12"
|
||||||
|
inkscape:cx="4.9858624"
|
||||||
|
inkscape:cy="10.149308"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="1280"
|
||||||
|
inkscape:window-height="877"
|
||||||
|
inkscape:window-x="80"
|
||||||
|
inkscape:window-y="214"
|
||||||
|
inkscape:window-maximized="0">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid817"
|
||||||
|
empspacing="0"
|
||||||
|
spacingx="0.52916666"
|
||||||
|
spacingy="0.52916666"
|
||||||
|
visible="true" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-291.70832)">
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#353535;stroke-width:0.52916664;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 1.0583333,292.76665 3.175,3.175"
|
||||||
|
id="path10"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cc" />
|
||||||
|
<path
|
||||||
|
sodipodi:nodetypes="cc"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path819"
|
||||||
|
d="m 4.2333333,292.76665 -3.175,3.175"
|
||||||
|
style="fill:none;stroke:#353535;stroke-width:0.52916664;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.4 KiB |
|
@ -34,7 +34,7 @@
|
||||||
<translation>&Bearbeiten</translation>
|
<translation>&Bearbeiten</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location line="+19"/>
|
<location line="+16"/>
|
||||||
<source>&New Project</source>
|
<source>&New Project</source>
|
||||||
<translation>&Neues Projekt</translation>
|
<translation>&Neues Projekt</translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -44,14 +44,12 @@
|
||||||
<translation>&Offenes Projekt</translation>
|
<translation>&Offenes Projekt</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location line="+8"/>
|
|
||||||
<source>&Undo</source>
|
<source>&Undo</source>
|
||||||
<translation>&Rückgängig machen</translation>
|
<translation type="vanished">&Rückgängig machen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location line="+8"/>
|
|
||||||
<source>&Redo</source>
|
<source>&Redo</source>
|
||||||
<translation>& Wiederholen</translation>
|
<translation type="vanished">& Wiederholen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location line="+8"/>
|
<location line="+8"/>
|
||||||
|
@ -154,7 +152,7 @@
|
||||||
<translation>Verlassen</translation>
|
<translation>Verlassen</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location line="+86"/>
|
<location line="+106"/>
|
||||||
<source>The directory at '%1' must exist for the Amuse editor.</source>
|
<source>The directory at '%1' must exist for the Amuse editor.</source>
|
||||||
<translation>Das Verzeichnis unter '% 1' muss für den Amuse-Editor vorhanden sein.</translation>
|
<translation>Das Verzeichnis unter '% 1' muss für den Amuse-Editor vorhanden sein.</translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -339,10 +337,33 @@
|
||||||
<translation>Kann kein Verzeichnis erstellen</translation>
|
<translation>Kann kein Verzeichnis erstellen</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>QUndoStack</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../SoundMacroEditor.cpp" line="+163"/>
|
||||||
|
<source>Change %1</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location line="+308"/>
|
||||||
|
<source>Reorder %1</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location line="+134"/>
|
||||||
|
<source>Insert %1</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location line="+55"/>
|
||||||
|
<source>Delete %1</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>SoundMacroCatalogue</name>
|
<name>SoundMacroCatalogue</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../SoundMacroEditor.cpp" line="+492"/>
|
<location line="+111"/>
|
||||||
<source>Control</source>
|
<source>Control</source>
|
||||||
<translation>Steuerung</translation>
|
<translation>Steuerung</translation>
|
||||||
</message>
|
</message>
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
<file>IconNewADSR.svg</file>
|
<file>IconNewADSR.svg</file>
|
||||||
<file>IconCurve.svg</file>
|
<file>IconCurve.svg</file>
|
||||||
<file>IconNewCurve.svg</file>
|
<file>IconNewCurve.svg</file>
|
||||||
|
<file>IconSoundMacroDelete.svg</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
<qresource prefix="/bg">
|
<qresource prefix="/bg">
|
||||||
<file>FaceGrey.svg</file>
|
<file>FaceGrey.svg</file>
|
||||||
|
|
|
@ -1131,6 +1131,27 @@ struct SoundMacro
|
||||||
|
|
||||||
template <athena::Endian DNAE>
|
template <athena::Endian DNAE>
|
||||||
void readCmds(athena::io::IStreamReader& r, uint32_t size);
|
void readCmds(athena::io::IStreamReader& r, uint32_t size);
|
||||||
|
|
||||||
|
ICmd* insertNewCmd(int idx, CmdOp op)
|
||||||
|
{
|
||||||
|
return m_cmds.insert(m_cmds.begin() + idx, MakeCmd(op))->get();
|
||||||
|
}
|
||||||
|
ICmd* insertCmd(int idx, std::unique_ptr<ICmd>&& cmd)
|
||||||
|
{
|
||||||
|
return m_cmds.insert(m_cmds.begin() + idx, std::move(cmd))->get();
|
||||||
|
}
|
||||||
|
std::unique_ptr<ICmd> deleteCmd(int idx)
|
||||||
|
{
|
||||||
|
std::unique_ptr<ICmd> ret = std::move(m_cmds[idx]);
|
||||||
|
m_cmds.erase(m_cmds.begin() + idx);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
void swapPositions(int a, int b)
|
||||||
|
{
|
||||||
|
if (a == b)
|
||||||
|
return;
|
||||||
|
std::swap(m_cmds[a], m_cmds[b]);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -1316,10 +1337,10 @@ struct LayerMapping : BigDNA
|
||||||
/** Database of functional objects within Audio Group */
|
/** Database of functional objects within Audio Group */
|
||||||
class AudioGroupPool
|
class AudioGroupPool
|
||||||
{
|
{
|
||||||
std::unordered_map<SoundMacroId, SoundMacro> m_soundMacros;
|
std::unordered_map<SoundMacroId, std::shared_ptr<SoundMacro>> m_soundMacros;
|
||||||
std::unordered_map<TableId, std::unique_ptr<ITable>> m_tables;
|
std::unordered_map<TableId, std::shared_ptr<ITable>> m_tables;
|
||||||
std::unordered_map<KeymapId, Keymap> m_keymaps;
|
std::unordered_map<KeymapId, std::shared_ptr<Keymap>> m_keymaps;
|
||||||
std::unordered_map<LayersId, std::vector<LayerMapping>> m_layers;
|
std::unordered_map<LayersId, std::shared_ptr<std::vector<LayerMapping>>> m_layers;
|
||||||
|
|
||||||
template <athena::Endian DNAE>
|
template <athena::Endian DNAE>
|
||||||
static AudioGroupPool _AudioGroupPool(athena::io::IStreamReader& r);
|
static AudioGroupPool _AudioGroupPool(athena::io::IStreamReader& r);
|
||||||
|
@ -1328,14 +1349,14 @@ public:
|
||||||
static AudioGroupPool CreateAudioGroupPool(const AudioGroupData& data);
|
static AudioGroupPool CreateAudioGroupPool(const AudioGroupData& data);
|
||||||
static AudioGroupPool CreateAudioGroupPool(SystemStringView groupPath);
|
static AudioGroupPool CreateAudioGroupPool(SystemStringView groupPath);
|
||||||
|
|
||||||
const std::unordered_map<SoundMacroId, SoundMacro>& soundMacros() const { return m_soundMacros; }
|
const std::unordered_map<SoundMacroId, std::shared_ptr<SoundMacro>>& soundMacros() const { return m_soundMacros; }
|
||||||
const std::unordered_map<TableId, std::unique_ptr<ITable>>& tables() const { return m_tables; }
|
const std::unordered_map<TableId, std::shared_ptr<ITable>>& tables() const { return m_tables; }
|
||||||
const std::unordered_map<KeymapId, Keymap>& keymaps() const { return m_keymaps; }
|
const std::unordered_map<KeymapId, std::shared_ptr<Keymap>>& keymaps() const { return m_keymaps; }
|
||||||
const std::unordered_map<LayersId, std::vector<LayerMapping>>& layers() const { return m_layers; }
|
const std::unordered_map<LayersId, std::shared_ptr<std::vector<LayerMapping>>>& layers() const { return m_layers; }
|
||||||
std::unordered_map<SoundMacroId, SoundMacro>& soundMacros() { return m_soundMacros; }
|
std::unordered_map<SoundMacroId, std::shared_ptr<SoundMacro>>& soundMacros() { return m_soundMacros; }
|
||||||
std::unordered_map<TableId, std::unique_ptr<ITable>>& tables() { return m_tables; }
|
std::unordered_map<TableId, std::shared_ptr<ITable>>& tables() { return m_tables; }
|
||||||
std::unordered_map<KeymapId, Keymap>& keymaps() { return m_keymaps; }
|
std::unordered_map<KeymapId, std::shared_ptr<Keymap>>& keymaps() { return m_keymaps; }
|
||||||
std::unordered_map<LayersId, std::vector<LayerMapping>>& layers() { return m_layers; }
|
std::unordered_map<LayersId, std::shared_ptr<std::vector<LayerMapping>>>& layers() { return m_layers; }
|
||||||
|
|
||||||
const SoundMacro* soundMacro(ObjectId id) const;
|
const SoundMacro* soundMacro(ObjectId id) const;
|
||||||
const Keymap* keymap(ObjectId id) const;
|
const Keymap* keymap(ObjectId id) const;
|
||||||
|
|
|
@ -180,8 +180,8 @@ struct SFXGroupIndex : AudioGroupIndex
|
||||||
/** Collection of SongGroup and SFXGroup indexes */
|
/** Collection of SongGroup and SFXGroup indexes */
|
||||||
class AudioGroupProject
|
class AudioGroupProject
|
||||||
{
|
{
|
||||||
std::unordered_map<GroupId, SongGroupIndex> m_songGroups;
|
std::unordered_map<GroupId, std::shared_ptr<SongGroupIndex>> m_songGroups;
|
||||||
std::unordered_map<GroupId, SFXGroupIndex> m_sfxGroups;
|
std::unordered_map<GroupId, std::shared_ptr<SFXGroupIndex>> m_sfxGroups;
|
||||||
|
|
||||||
AudioGroupProject(athena::io::IStreamReader& r, GCNDataTag);
|
AudioGroupProject(athena::io::IStreamReader& r, GCNDataTag);
|
||||||
template <athena::Endian DNAE>
|
template <athena::Endian DNAE>
|
||||||
|
@ -199,10 +199,10 @@ public:
|
||||||
const SongGroupIndex* getSongGroupIndex(int groupId) const;
|
const SongGroupIndex* getSongGroupIndex(int groupId) const;
|
||||||
const SFXGroupIndex* getSFXGroupIndex(int groupId) const;
|
const SFXGroupIndex* getSFXGroupIndex(int groupId) const;
|
||||||
|
|
||||||
const std::unordered_map<GroupId, SongGroupIndex>& songGroups() const { return m_songGroups; }
|
const std::unordered_map<GroupId, std::shared_ptr<SongGroupIndex>>& songGroups() const { return m_songGroups; }
|
||||||
const std::unordered_map<GroupId, SFXGroupIndex>& sfxGroups() const { return m_sfxGroups; }
|
const std::unordered_map<GroupId, std::shared_ptr<SFXGroupIndex>>& sfxGroups() const { return m_sfxGroups; }
|
||||||
std::unordered_map<GroupId, SongGroupIndex>& songGroups() { return m_songGroups; }
|
std::unordered_map<GroupId, std::shared_ptr<SongGroupIndex>>& songGroups() { return m_songGroups; }
|
||||||
std::unordered_map<GroupId, SFXGroupIndex>& sfxGroups() { return m_sfxGroups; }
|
std::unordered_map<GroupId, std::shared_ptr<SFXGroupIndex>>& sfxGroups() { return m_sfxGroups; }
|
||||||
|
|
||||||
bool toYAML(SystemStringView groupPath) const;
|
bool toYAML(SystemStringView groupPath) const;
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ class Engine
|
||||||
std::list<std::weak_ptr<Studio>> m_activeStudios; /* lifetime dependent on contributing audio entities */
|
std::list<std::weak_ptr<Studio>> m_activeStudios; /* lifetime dependent on contributing audio entities */
|
||||||
bool m_defaultStudioReady = false;
|
bool m_defaultStudioReady = false;
|
||||||
std::shared_ptr<Studio> m_defaultStudio;
|
std::shared_ptr<Studio> m_defaultStudio;
|
||||||
std::unordered_map<uint16_t, std::tuple<AudioGroup*, int, const SFXGroupIndex::SFXEntry*>> m_sfxLookup;
|
std::unordered_map<SFXId, std::tuple<AudioGroup*, int, const SFXGroupIndex::SFXEntry*>> m_sfxLookup;
|
||||||
std::linear_congruential_engine<uint32_t, 0x41c64e6d, 0x3039, UINT32_MAX> m_random;
|
std::linear_congruential_engine<uint32_t, 0x41c64e6d, 0x3039, UINT32_MAX> m_random;
|
||||||
int m_nextVid = 0;
|
int m_nextVid = 0;
|
||||||
float m_masterVolume = 1.f;
|
float m_masterVolume = 1.f;
|
||||||
|
|
|
@ -107,8 +107,9 @@ AudioGroupPool AudioGroupPool::_AudioGroupPool(athena::io::IStreamReader& r)
|
||||||
ObjectHeader<DNAE> objHead;
|
ObjectHeader<DNAE> objHead;
|
||||||
atInt64 startPos = r.position();
|
atInt64 startPos = r.position();
|
||||||
objHead.read(r);
|
objHead.read(r);
|
||||||
SoundMacro& macro = ret.m_soundMacros[objHead.objectId.id];
|
auto& macro = ret.m_soundMacros[objHead.objectId.id];
|
||||||
macro.readCmds<DNAE>(r, objHead.size - 8);
|
macro = std::make_shared<SoundMacro>();
|
||||||
|
macro->template readCmds<DNAE>(r, objHead.size - 8);
|
||||||
r.seek(startPos + objHead.size, athena::Begin);
|
r.seek(startPos + objHead.size, athena::Begin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,15 +126,15 @@ AudioGroupPool AudioGroupPool::_AudioGroupPool(athena::io::IStreamReader& r)
|
||||||
switch (objHead.size)
|
switch (objHead.size)
|
||||||
{
|
{
|
||||||
case 0x10:
|
case 0x10:
|
||||||
ptr = std::make_unique<ADSR>();
|
ptr = std::make_shared<ADSR>();
|
||||||
static_cast<ADSR&>(*ptr).read(r);
|
static_cast<ADSR&>(*ptr).read(r);
|
||||||
break;
|
break;
|
||||||
case 0x1c:
|
case 0x1c:
|
||||||
ptr = std::make_unique<ADSRDLS>();
|
ptr = std::make_shared<ADSRDLS>();
|
||||||
static_cast<ADSRDLS&>(*ptr).read(r);
|
static_cast<ADSRDLS&>(*ptr).read(r);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ptr = std::make_unique<Curve>();
|
ptr = std::make_shared<Curve>();
|
||||||
static_cast<Curve&>(*ptr).data.resize(objHead.size - 8);
|
static_cast<Curve&>(*ptr).data.resize(objHead.size - 8);
|
||||||
r.readUBytesToBuf(&static_cast<Curve&>(*ptr).data[0], objHead.size - 8);
|
r.readUBytesToBuf(&static_cast<Curve&>(*ptr).data[0], objHead.size - 8);
|
||||||
break;
|
break;
|
||||||
|
@ -152,7 +153,7 @@ AudioGroupPool AudioGroupPool::_AudioGroupPool(athena::io::IStreamReader& r)
|
||||||
objHead.read(r);
|
objHead.read(r);
|
||||||
KeymapDNA<DNAE> kmData;
|
KeymapDNA<DNAE> kmData;
|
||||||
kmData.read(r);
|
kmData.read(r);
|
||||||
ret.m_keymaps[objHead.objectId.id] = kmData;
|
*ret.m_keymaps[objHead.objectId.id] = kmData;
|
||||||
r.seek(startPos + objHead.size, athena::Begin);
|
r.seek(startPos + objHead.size, athena::Begin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -165,7 +166,7 @@ AudioGroupPool AudioGroupPool::_AudioGroupPool(athena::io::IStreamReader& r)
|
||||||
ObjectHeader<DNAE> objHead;
|
ObjectHeader<DNAE> objHead;
|
||||||
atInt64 startPos = r.position();
|
atInt64 startPos = r.position();
|
||||||
objHead.read(r);
|
objHead.read(r);
|
||||||
std::vector<LayerMapping>& lm = ret.m_layers[objHead.objectId.id];
|
std::vector<LayerMapping>& lm = *ret.m_layers[objHead.objectId.id];
|
||||||
uint32_t count;
|
uint32_t count;
|
||||||
athena::io::Read<athena::io::PropType::None>::Do<decltype(count), DNAE>({}, count, r);
|
athena::io::Read<athena::io::PropType::None>::Do<decltype(count), DNAE>({}, count, r);
|
||||||
lm.reserve(count);
|
lm.reserve(count);
|
||||||
|
@ -210,7 +211,6 @@ AudioGroupPool AudioGroupPool::CreateAudioGroupPool(SystemStringView groupPath)
|
||||||
{
|
{
|
||||||
if (auto __r = r.enterSubRecord("soundMacros"))
|
if (auto __r = r.enterSubRecord("soundMacros"))
|
||||||
{
|
{
|
||||||
ret.m_soundMacros.reserve(r.getCurNode()->m_mapChildren.size());
|
|
||||||
for (const auto& sm : r.getCurNode()->m_mapChildren)
|
for (const auto& sm : r.getCurNode()->m_mapChildren)
|
||||||
{
|
{
|
||||||
ObjectId macroId = SoundMacroId::CurNameDB->generateId(NameDB::Type::SoundMacro);
|
ObjectId macroId = SoundMacroId::CurNameDB->generateId(NameDB::Type::SoundMacro);
|
||||||
|
@ -220,7 +220,6 @@ AudioGroupPool AudioGroupPool::CreateAudioGroupPool(SystemStringView groupPath)
|
||||||
|
|
||||||
if (auto __r = r.enterSubRecord("tables"))
|
if (auto __r = r.enterSubRecord("tables"))
|
||||||
{
|
{
|
||||||
ret.m_tables.reserve(r.getCurNode()->m_mapChildren.size());
|
|
||||||
for (const auto& t : r.getCurNode()->m_mapChildren)
|
for (const auto& t : r.getCurNode()->m_mapChildren)
|
||||||
{
|
{
|
||||||
if (auto __v = r.enterSubRecord(t.first.c_str()))
|
if (auto __v = r.enterSubRecord(t.first.c_str()))
|
||||||
|
@ -233,7 +232,6 @@ AudioGroupPool AudioGroupPool::CreateAudioGroupPool(SystemStringView groupPath)
|
||||||
|
|
||||||
if (auto __r = r.enterSubRecord("keymaps"))
|
if (auto __r = r.enterSubRecord("keymaps"))
|
||||||
{
|
{
|
||||||
ret.m_keymaps.reserve(r.getCurNode()->m_mapChildren.size());
|
|
||||||
for (const auto& k : r.getCurNode()->m_mapChildren)
|
for (const auto& k : r.getCurNode()->m_mapChildren)
|
||||||
if (auto __v = r.enterSubRecord(k.first.c_str()))
|
if (auto __v = r.enterSubRecord(k.first.c_str()))
|
||||||
{
|
{
|
||||||
|
@ -260,14 +258,15 @@ AudioGroupPool AudioGroupPool::CreateAudioGroupPool(SystemStringView groupPath)
|
||||||
ret.m_soundMacros.reserve(r.getCurNode()->m_mapChildren.size());
|
ret.m_soundMacros.reserve(r.getCurNode()->m_mapChildren.size());
|
||||||
for (const auto& sm : r.getCurNode()->m_mapChildren)
|
for (const auto& sm : r.getCurNode()->m_mapChildren)
|
||||||
{
|
{
|
||||||
SoundMacro& smOut = ret.m_soundMacros[SoundMacroId::CurNameDB->resolveIdFromName(sm.first)];
|
auto& smOut = ret.m_soundMacros[SoundMacroId::CurNameDB->resolveIdFromName(sm.first)];
|
||||||
|
smOut = std::make_shared<SoundMacro>();
|
||||||
size_t cmdCount;
|
size_t cmdCount;
|
||||||
if (auto __v = r.enterSubVector(sm.first.c_str(), cmdCount))
|
if (auto __v = r.enterSubVector(sm.first.c_str(), cmdCount))
|
||||||
{
|
{
|
||||||
smOut.m_cmds.reserve(cmdCount);
|
smOut->m_cmds.reserve(cmdCount);
|
||||||
for (int c = 0; c < cmdCount; ++c)
|
for (int c = 0; c < cmdCount; ++c)
|
||||||
if (auto __r2 = r.enterSubRecord(nullptr))
|
if (auto __r2 = r.enterSubRecord(nullptr))
|
||||||
smOut.m_cmds.push_back(SoundMacro::CmdDo<MakeCmdOp, std::unique_ptr<SoundMacro::ICmd>>(r));
|
smOut->m_cmds.push_back(SoundMacro::CmdDo<MakeCmdOp, std::unique_ptr<SoundMacro::ICmd>>(r));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -279,26 +278,26 @@ AudioGroupPool AudioGroupPool::CreateAudioGroupPool(SystemStringView groupPath)
|
||||||
{
|
{
|
||||||
if (auto __v = r.enterSubRecord(t.first.c_str()))
|
if (auto __v = r.enterSubRecord(t.first.c_str()))
|
||||||
{
|
{
|
||||||
std::unique_ptr<ITable>& tableOut = ret.m_tables[TableId::CurNameDB->resolveIdFromName(t.first)];
|
auto& tableOut = ret.m_tables[TableId::CurNameDB->resolveIdFromName(t.first)];
|
||||||
if (auto __att = r.enterSubRecord("attack"))
|
if (auto __att = r.enterSubRecord("attack"))
|
||||||
{
|
{
|
||||||
__att.leave();
|
__att.leave();
|
||||||
if (auto __vta = r.enterSubRecord("velToAttack"))
|
if (auto __vta = r.enterSubRecord("velToAttack"))
|
||||||
{
|
{
|
||||||
__vta.leave();
|
__vta.leave();
|
||||||
tableOut = std::make_unique<ADSRDLS>();
|
tableOut = std::make_shared<ADSRDLS>();
|
||||||
static_cast<ADSRDLS&>(*tableOut).read(r);
|
static_cast<ADSRDLS&>(*tableOut).read(r);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tableOut = std::make_unique<ADSR>();
|
tableOut = std::make_shared<ADSR>();
|
||||||
static_cast<ADSR&>(*tableOut).read(r);
|
static_cast<ADSR&>(*tableOut).read(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (auto __dat = r.enterSubRecord("data"))
|
else if (auto __dat = r.enterSubRecord("data"))
|
||||||
{
|
{
|
||||||
__dat.leave();
|
__dat.leave();
|
||||||
tableOut = std::make_unique<Curve>();
|
tableOut = std::make_shared<Curve>();
|
||||||
static_cast<Curve&>(*tableOut).read(r);
|
static_cast<Curve&>(*tableOut).read(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -310,7 +309,11 @@ AudioGroupPool AudioGroupPool::CreateAudioGroupPool(SystemStringView groupPath)
|
||||||
ret.m_keymaps.reserve(r.getCurNode()->m_mapChildren.size());
|
ret.m_keymaps.reserve(r.getCurNode()->m_mapChildren.size());
|
||||||
for (const auto& k : r.getCurNode()->m_mapChildren)
|
for (const auto& k : r.getCurNode()->m_mapChildren)
|
||||||
if (auto __v = r.enterSubRecord(k.first.c_str()))
|
if (auto __v = r.enterSubRecord(k.first.c_str()))
|
||||||
ret.m_keymaps[KeymapId::CurNameDB->resolveIdFromName(k.first)].read(r);
|
{
|
||||||
|
auto& kmOut = ret.m_keymaps[KeymapId::CurNameDB->resolveIdFromName(k.first)];
|
||||||
|
kmOut = std::make_shared<Keymap>();
|
||||||
|
kmOut->read(r);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto __r = r.enterSubRecord("layers"))
|
if (auto __r = r.enterSubRecord("layers"))
|
||||||
|
@ -321,14 +324,15 @@ AudioGroupPool AudioGroupPool::CreateAudioGroupPool(SystemStringView groupPath)
|
||||||
size_t mappingCount;
|
size_t mappingCount;
|
||||||
if (auto __v = r.enterSubVector(l.first.c_str(), mappingCount))
|
if (auto __v = r.enterSubVector(l.first.c_str(), mappingCount))
|
||||||
{
|
{
|
||||||
std::vector<LayerMapping>& layOut = ret.m_layers[LayersId::CurNameDB->resolveIdFromName(l.first)];
|
auto& layOut = ret.m_layers[LayersId::CurNameDB->resolveIdFromName(l.first)];
|
||||||
layOut.reserve(mappingCount);
|
layOut = std::make_shared<std::vector<LayerMapping>>();
|
||||||
|
layOut->reserve(mappingCount);
|
||||||
for (int lm = 0; lm < mappingCount; ++lm)
|
for (int lm = 0; lm < mappingCount; ++lm)
|
||||||
{
|
{
|
||||||
if (auto __r2 = r.enterSubRecord(nullptr))
|
if (auto __r2 = r.enterSubRecord(nullptr))
|
||||||
{
|
{
|
||||||
layOut.emplace_back();
|
layOut->emplace_back();
|
||||||
layOut.back().read(r);
|
layOut->back().read(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -373,7 +377,7 @@ const SoundMacro* AudioGroupPool::soundMacro(ObjectId id) const
|
||||||
auto search = m_soundMacros.find(id);
|
auto search = m_soundMacros.find(id);
|
||||||
if (search == m_soundMacros.cend())
|
if (search == m_soundMacros.cend())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return &search->second;
|
return search->second.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
const Keymap* AudioGroupPool::keymap(ObjectId id) const
|
const Keymap* AudioGroupPool::keymap(ObjectId id) const
|
||||||
|
@ -381,7 +385,7 @@ const Keymap* AudioGroupPool::keymap(ObjectId id) const
|
||||||
auto search = m_keymaps.find(id);
|
auto search = m_keymaps.find(id);
|
||||||
if (search == m_keymaps.cend())
|
if (search == m_keymaps.cend())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return &search->second;
|
return search->second.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<LayerMapping>* AudioGroupPool::layer(ObjectId id) const
|
const std::vector<LayerMapping>* AudioGroupPool::layer(ObjectId id) const
|
||||||
|
@ -389,7 +393,7 @@ const std::vector<LayerMapping>* AudioGroupPool::layer(ObjectId id) const
|
||||||
auto search = m_layers.find(id);
|
auto search = m_layers.find(id);
|
||||||
if (search == m_layers.cend())
|
if (search == m_layers.cend())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return &search->second;
|
return search->second.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
const ADSR* AudioGroupPool::tableAsAdsr(ObjectId id) const
|
const ADSR* AudioGroupPool::tableAsAdsr(ObjectId id) const
|
||||||
|
@ -949,7 +953,7 @@ bool AudioGroupPool::toYAML(SystemStringView groupPath) const
|
||||||
{
|
{
|
||||||
if (auto __v = w.enterSubVector(SoundMacroId::CurNameDB->resolveNameFromId(p.first).data()))
|
if (auto __v = w.enterSubVector(SoundMacroId::CurNameDB->resolveNameFromId(p.first).data()))
|
||||||
{
|
{
|
||||||
for (const auto& c : p.second.get().m_cmds)
|
for (const auto& c : p.second.get()->m_cmds)
|
||||||
{
|
{
|
||||||
if (auto __r2 = w.enterSubRecord(nullptr))
|
if (auto __r2 = w.enterSubRecord(nullptr))
|
||||||
{
|
{
|
||||||
|
@ -987,7 +991,7 @@ bool AudioGroupPool::toYAML(SystemStringView groupPath) const
|
||||||
if (auto __v = w.enterSubRecord(KeymapId::CurNameDB->resolveNameFromId(p.first).data()))
|
if (auto __v = w.enterSubRecord(KeymapId::CurNameDB->resolveNameFromId(p.first).data()))
|
||||||
{
|
{
|
||||||
w.setStyle(athena::io::YAMLNodeStyle::Flow);
|
w.setStyle(athena::io::YAMLNodeStyle::Flow);
|
||||||
p.second.get().write(w);
|
p.second.get()->write(w);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1001,7 +1005,7 @@ bool AudioGroupPool::toYAML(SystemStringView groupPath) const
|
||||||
{
|
{
|
||||||
if (auto __v = w.enterSubVector(LayersId::CurNameDB->resolveNameFromId(p.first).data()))
|
if (auto __v = w.enterSubVector(LayersId::CurNameDB->resolveNameFromId(p.first).data()))
|
||||||
{
|
{
|
||||||
for (const auto& lm : p.second.get())
|
for (const auto& lm : *p.second.get())
|
||||||
{
|
{
|
||||||
if (auto __r2 = w.enterSubRecord(nullptr))
|
if (auto __r2 = w.enterSubRecord(nullptr))
|
||||||
{
|
{
|
||||||
|
|
|
@ -30,7 +30,8 @@ AudioGroupProject::AudioGroupProject(athena::io::IStreamReader& r, GCNDataTag)
|
||||||
|
|
||||||
if (header.type == GroupType::Song)
|
if (header.type == GroupType::Song)
|
||||||
{
|
{
|
||||||
SongGroupIndex& idx = m_songGroups[header.groupId];
|
auto& idx = m_songGroups[header.groupId];
|
||||||
|
idx = std::make_shared<SongGroupIndex>();
|
||||||
|
|
||||||
/* Normal pages */
|
/* Normal pages */
|
||||||
r.seek(header.pageTableOff, athena::Begin);
|
r.seek(header.pageTableOff, athena::Begin);
|
||||||
|
@ -38,7 +39,7 @@ AudioGroupProject::AudioGroupProject(athena::io::IStreamReader& r, GCNDataTag)
|
||||||
{
|
{
|
||||||
SongGroupIndex::PageEntryDNA<athena::Big> entry;
|
SongGroupIndex::PageEntryDNA<athena::Big> entry;
|
||||||
entry.read(r);
|
entry.read(r);
|
||||||
idx.m_normPages[entry.programNo] = entry;
|
idx->m_normPages[entry.programNo] = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Drum pages */
|
/* Drum pages */
|
||||||
|
@ -47,7 +48,7 @@ AudioGroupProject::AudioGroupProject(athena::io::IStreamReader& r, GCNDataTag)
|
||||||
{
|
{
|
||||||
SongGroupIndex::PageEntryDNA<athena::Big> entry;
|
SongGroupIndex::PageEntryDNA<athena::Big> entry;
|
||||||
entry.read(r);
|
entry.read(r);
|
||||||
idx.m_drumPages[entry.programNo] = entry;
|
idx->m_drumPages[entry.programNo] = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* MIDI setups */
|
/* MIDI setups */
|
||||||
|
@ -56,25 +57,26 @@ AudioGroupProject::AudioGroupProject(athena::io::IStreamReader& r, GCNDataTag)
|
||||||
{
|
{
|
||||||
uint16_t songId = r.readUint16Big();
|
uint16_t songId = r.readUint16Big();
|
||||||
r.seek(2, athena::Current);
|
r.seek(2, athena::Current);
|
||||||
std::array<SongGroupIndex::MIDISetup, 16>& setup = idx.m_midiSetups[songId];
|
std::array<SongGroupIndex::MIDISetup, 16>& setup = idx->m_midiSetups[songId];
|
||||||
for (int i = 0; i < 16 ; ++i)
|
for (int i = 0; i < 16 ; ++i)
|
||||||
setup[i].read(r);
|
setup[i].read(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (header.type == GroupType::SFX)
|
else if (header.type == GroupType::SFX)
|
||||||
{
|
{
|
||||||
SFXGroupIndex& idx = m_sfxGroups[header.groupId];
|
auto& idx = m_sfxGroups[header.groupId];
|
||||||
|
idx = std::make_shared<SFXGroupIndex>();
|
||||||
|
|
||||||
/* SFX entries */
|
/* SFX entries */
|
||||||
r.seek(header.pageTableOff, athena::Begin);
|
r.seek(header.pageTableOff, athena::Begin);
|
||||||
uint16_t count = r.readUint16Big();
|
uint16_t count = r.readUint16Big();
|
||||||
r.seek(2, athena::Current);
|
r.seek(2, athena::Current);
|
||||||
idx.m_sfxEntries.reserve(count);
|
idx->m_sfxEntries.reserve(count);
|
||||||
for (int i = 0; i < count; ++i)
|
for (int i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
SFXGroupIndex::SFXEntryDNA<athena::Big> entry;
|
SFXGroupIndex::SFXEntryDNA<athena::Big> entry;
|
||||||
entry.read(r);
|
entry.read(r);
|
||||||
idx.m_sfxEntries[entry.sfxId.id] = entry;
|
idx->m_sfxEntries[entry.sfxId.id] = entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,7 +98,8 @@ AudioGroupProject AudioGroupProject::_AudioGroupProject(athena::io::IStreamReade
|
||||||
|
|
||||||
if (header.type == GroupType::Song)
|
if (header.type == GroupType::Song)
|
||||||
{
|
{
|
||||||
SongGroupIndex& idx = ret.m_songGroups[header.groupId];
|
auto& idx = ret.m_songGroups[header.groupId];
|
||||||
|
idx = std::make_shared<SongGroupIndex>();
|
||||||
|
|
||||||
if (absOffs)
|
if (absOffs)
|
||||||
{
|
{
|
||||||
|
@ -106,7 +109,7 @@ AudioGroupProject AudioGroupProject::_AudioGroupProject(athena::io::IStreamReade
|
||||||
{
|
{
|
||||||
SongGroupIndex::PageEntryDNA<DNAE> entry;
|
SongGroupIndex::PageEntryDNA<DNAE> entry;
|
||||||
entry.read(r);
|
entry.read(r);
|
||||||
idx.m_normPages[entry.programNo] = entry;
|
idx->m_normPages[entry.programNo] = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Drum pages */
|
/* Drum pages */
|
||||||
|
@ -115,7 +118,7 @@ AudioGroupProject AudioGroupProject::_AudioGroupProject(athena::io::IStreamReade
|
||||||
{
|
{
|
||||||
SongGroupIndex::PageEntryDNA<DNAE> entry;
|
SongGroupIndex::PageEntryDNA<DNAE> entry;
|
||||||
entry.read(r);
|
entry.read(r);
|
||||||
idx.m_drumPages[entry.programNo] = entry;
|
idx->m_drumPages[entry.programNo] = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* MIDI setups */
|
/* MIDI setups */
|
||||||
|
@ -125,7 +128,7 @@ AudioGroupProject AudioGroupProject::_AudioGroupProject(athena::io::IStreamReade
|
||||||
uint16_t songId;
|
uint16_t songId;
|
||||||
athena::io::Read<athena::io::PropType::None>::Do<decltype(songId), DNAE>({}, songId, r);
|
athena::io::Read<athena::io::PropType::None>::Do<decltype(songId), DNAE>({}, songId, r);
|
||||||
r.seek(2, athena::Current);
|
r.seek(2, athena::Current);
|
||||||
std::array<SongGroupIndex::MIDISetup, 16>& setup = idx.m_midiSetups[songId];
|
std::array<SongGroupIndex::MIDISetup, 16>& setup = idx->m_midiSetups[songId];
|
||||||
for (int i = 0; i < 16 ; ++i)
|
for (int i = 0; i < 16 ; ++i)
|
||||||
setup[i].read(r);
|
setup[i].read(r);
|
||||||
}
|
}
|
||||||
|
@ -138,7 +141,7 @@ AudioGroupProject AudioGroupProject::_AudioGroupProject(athena::io::IStreamReade
|
||||||
{
|
{
|
||||||
SongGroupIndex::MusyX1PageEntryDNA<DNAE> entry;
|
SongGroupIndex::MusyX1PageEntryDNA<DNAE> entry;
|
||||||
entry.read(r);
|
entry.read(r);
|
||||||
idx.m_normPages[entry.programNo] = entry;
|
idx->m_normPages[entry.programNo] = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Drum pages */
|
/* Drum pages */
|
||||||
|
@ -147,7 +150,7 @@ AudioGroupProject AudioGroupProject::_AudioGroupProject(athena::io::IStreamReade
|
||||||
{
|
{
|
||||||
SongGroupIndex::MusyX1PageEntryDNA<DNAE> entry;
|
SongGroupIndex::MusyX1PageEntryDNA<DNAE> entry;
|
||||||
entry.read(r);
|
entry.read(r);
|
||||||
idx.m_drumPages[entry.programNo] = entry;
|
idx->m_drumPages[entry.programNo] = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* MIDI setups */
|
/* MIDI setups */
|
||||||
|
@ -157,7 +160,7 @@ AudioGroupProject AudioGroupProject::_AudioGroupProject(athena::io::IStreamReade
|
||||||
uint16_t songId;
|
uint16_t songId;
|
||||||
athena::io::Read<athena::io::PropType::None>::Do<decltype(songId), DNAE>({}, songId, r);
|
athena::io::Read<athena::io::PropType::None>::Do<decltype(songId), DNAE>({}, songId, r);
|
||||||
r.seek(2, athena::Current);
|
r.seek(2, athena::Current);
|
||||||
std::array<SongGroupIndex::MIDISetup, 16>& setup = idx.m_midiSetups[songId];
|
std::array<SongGroupIndex::MIDISetup, 16>& setup = idx->m_midiSetups[songId];
|
||||||
for (int i = 0; i < 16 ; ++i)
|
for (int i = 0; i < 16 ; ++i)
|
||||||
{
|
{
|
||||||
SongGroupIndex::MusyX1MIDISetup ent;
|
SongGroupIndex::MusyX1MIDISetup ent;
|
||||||
|
@ -169,20 +172,21 @@ AudioGroupProject AudioGroupProject::_AudioGroupProject(athena::io::IStreamReade
|
||||||
}
|
}
|
||||||
else if (header.type == GroupType::SFX)
|
else if (header.type == GroupType::SFX)
|
||||||
{
|
{
|
||||||
SFXGroupIndex& idx = ret.m_sfxGroups[header.groupId];
|
auto& idx = ret.m_sfxGroups[header.groupId];
|
||||||
|
idx = std::make_shared<SFXGroupIndex>();
|
||||||
|
|
||||||
/* SFX entries */
|
/* SFX entries */
|
||||||
r.seek(subDataOff + header.pageTableOff, athena::Begin);
|
r.seek(subDataOff + header.pageTableOff, athena::Begin);
|
||||||
uint16_t count;
|
uint16_t count;
|
||||||
athena::io::Read<athena::io::PropType::None>::Do<decltype(count), DNAE>({}, count, r);
|
athena::io::Read<athena::io::PropType::None>::Do<decltype(count), DNAE>({}, count, r);
|
||||||
r.seek(2, athena::Current);
|
r.seek(2, athena::Current);
|
||||||
idx.m_sfxEntries.reserve(count);
|
idx->m_sfxEntries.reserve(count);
|
||||||
for (int i = 0; i < count; ++i)
|
for (int i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
SFXGroupIndex::SFXEntryDNA<DNAE> entry;
|
SFXGroupIndex::SFXEntryDNA<DNAE> entry;
|
||||||
entry.read(r);
|
entry.read(r);
|
||||||
r.seek(2, athena::Current);
|
r.seek(2, athena::Current);
|
||||||
idx.m_sfxEntries[entry.sfxId.id] = entry;
|
idx->m_sfxEntries[entry.sfxId.id] = entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,24 +248,25 @@ AudioGroupProject AudioGroupProject::CreateAudioGroupProject(SystemStringView gr
|
||||||
continue;
|
continue;
|
||||||
GroupId::CurNameDB->registerPair(groupName, groupId);
|
GroupId::CurNameDB->registerPair(groupName, groupId);
|
||||||
|
|
||||||
SongGroupIndex& idx = ret.m_songGroups[groupId];
|
auto& idx = ret.m_songGroups[groupId];
|
||||||
|
idx = std::make_shared<SongGroupIndex>();
|
||||||
if (auto __v2 = r.enterSubRecord("normPages"))
|
if (auto __v2 = r.enterSubRecord("normPages"))
|
||||||
{
|
{
|
||||||
idx.m_normPages.reserve(r.getCurNode()->m_mapChildren.size());
|
idx->m_normPages.reserve(r.getCurNode()->m_mapChildren.size());
|
||||||
for (const auto& pg : r.getCurNode()->m_mapChildren)
|
for (const auto& pg : r.getCurNode()->m_mapChildren)
|
||||||
if (auto __r2 = r.enterSubRecord(pg.first.c_str()))
|
if (auto __r2 = r.enterSubRecord(pg.first.c_str()))
|
||||||
idx.m_normPages[strtoul(pg.first.c_str(), nullptr, 0)].read(r);
|
idx->m_normPages[strtoul(pg.first.c_str(), nullptr, 0)].read(r);
|
||||||
}
|
}
|
||||||
if (auto __v2 = r.enterSubRecord("drumPages"))
|
if (auto __v2 = r.enterSubRecord("drumPages"))
|
||||||
{
|
{
|
||||||
idx.m_drumPages.reserve(r.getCurNode()->m_mapChildren.size());
|
idx->m_drumPages.reserve(r.getCurNode()->m_mapChildren.size());
|
||||||
for (const auto& pg : r.getCurNode()->m_mapChildren)
|
for (const auto& pg : r.getCurNode()->m_mapChildren)
|
||||||
if (auto __r2 = r.enterSubRecord(pg.first.c_str()))
|
if (auto __r2 = r.enterSubRecord(pg.first.c_str()))
|
||||||
idx.m_drumPages[strtoul(pg.first.c_str(), nullptr, 0)].read(r);
|
idx->m_drumPages[strtoul(pg.first.c_str(), nullptr, 0)].read(r);
|
||||||
}
|
}
|
||||||
if (auto __v2 = r.enterSubRecord("songs"))
|
if (auto __v2 = r.enterSubRecord("songs"))
|
||||||
{
|
{
|
||||||
idx.m_midiSetups.reserve(r.getCurNode()->m_mapChildren.size());
|
idx->m_midiSetups.reserve(r.getCurNode()->m_mapChildren.size());
|
||||||
for (const auto& song : r.getCurNode()->m_mapChildren)
|
for (const auto& song : r.getCurNode()->m_mapChildren)
|
||||||
{
|
{
|
||||||
size_t chanCount;
|
size_t chanCount;
|
||||||
|
@ -273,7 +278,7 @@ AudioGroupProject AudioGroupProject::CreateAudioGroupProject(SystemStringView gr
|
||||||
continue;
|
continue;
|
||||||
SongId::CurNameDB->registerPair(songName, songId);
|
SongId::CurNameDB->registerPair(songName, songId);
|
||||||
|
|
||||||
std::array<SongGroupIndex::MIDISetup, 16>& setup = idx.m_midiSetups[songId];
|
std::array<SongGroupIndex::MIDISetup, 16>& setup = idx->m_midiSetups[songId];
|
||||||
for (int i = 0; i < 16 && i < chanCount; ++i)
|
for (int i = 0; i < 16 && i < chanCount; ++i)
|
||||||
if (auto __r2 = r.enterSubRecord(nullptr))
|
if (auto __r2 = r.enterSubRecord(nullptr))
|
||||||
setup[i].read(r);
|
setup[i].read(r);
|
||||||
|
@ -297,7 +302,8 @@ AudioGroupProject AudioGroupProject::CreateAudioGroupProject(SystemStringView gr
|
||||||
continue;
|
continue;
|
||||||
GroupId::CurNameDB->registerPair(groupName, groupId);
|
GroupId::CurNameDB->registerPair(groupName, groupId);
|
||||||
|
|
||||||
SFXGroupIndex& idx = ret.m_sfxGroups[groupId];
|
auto& idx = ret.m_sfxGroups[groupId];
|
||||||
|
idx = std::make_shared<SFXGroupIndex>();
|
||||||
for (const auto& sfx : r.getCurNode()->m_mapChildren)
|
for (const auto& sfx : r.getCurNode()->m_mapChildren)
|
||||||
if (auto __r2 = r.enterSubRecord(sfx.first.c_str()))
|
if (auto __r2 = r.enterSubRecord(sfx.first.c_str()))
|
||||||
{
|
{
|
||||||
|
@ -306,7 +312,7 @@ AudioGroupProject AudioGroupProject::CreateAudioGroupProject(SystemStringView gr
|
||||||
if (sfxName.empty() || sfxId == 0xffff)
|
if (sfxName.empty() || sfxId == 0xffff)
|
||||||
continue;
|
continue;
|
||||||
SFXId::CurNameDB->registerPair(sfxName, sfxId);
|
SFXId::CurNameDB->registerPair(sfxName, sfxId);
|
||||||
idx.m_sfxEntries[sfxId].read(r);
|
idx->m_sfxEntries[sfxId].read(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -513,7 +519,7 @@ const SongGroupIndex* AudioGroupProject::getSongGroupIndex(int groupId) const
|
||||||
{
|
{
|
||||||
auto search = m_songGroups.find(groupId);
|
auto search = m_songGroups.find(groupId);
|
||||||
if (search != m_songGroups.cend())
|
if (search != m_songGroups.cend())
|
||||||
return &search->second;
|
return search->second.get();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -521,7 +527,7 @@ const SFXGroupIndex* AudioGroupProject::getSFXGroupIndex(int groupId) const
|
||||||
{
|
{
|
||||||
auto search = m_sfxGroups.find(groupId);
|
auto search = m_sfxGroups.find(groupId);
|
||||||
if (search != m_sfxGroups.cend())
|
if (search != m_sfxGroups.cend())
|
||||||
return &search->second;
|
return search->second.get();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -539,11 +545,11 @@ bool AudioGroupProject::toYAML(SystemStringView groupPath) const
|
||||||
snprintf(groupString, 64, "%s/0x%04X", GroupId::CurNameDB->resolveNameFromId(p.first).data(), int(p.first.id));
|
snprintf(groupString, 64, "%s/0x%04X", GroupId::CurNameDB->resolveNameFromId(p.first).data(), int(p.first.id));
|
||||||
if (auto __r = w.enterSubRecord(groupString))
|
if (auto __r = w.enterSubRecord(groupString))
|
||||||
{
|
{
|
||||||
if (!p.second.get().m_normPages.empty())
|
if (!p.second.get()->m_normPages.empty())
|
||||||
{
|
{
|
||||||
if (auto __v2 = w.enterSubRecord("normPages"))
|
if (auto __v2 = w.enterSubRecord("normPages"))
|
||||||
{
|
{
|
||||||
for (const auto& pg : SortUnorderedMap(p.second.get().m_normPages))
|
for (const auto& pg : SortUnorderedMap(p.second.get()->m_normPages))
|
||||||
{
|
{
|
||||||
char name[16];
|
char name[16];
|
||||||
snprintf(name, 16, "%d", pg.first);
|
snprintf(name, 16, "%d", pg.first);
|
||||||
|
@ -555,11 +561,11 @@ bool AudioGroupProject::toYAML(SystemStringView groupPath) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!p.second.get().m_drumPages.empty())
|
if (!p.second.get()->m_drumPages.empty())
|
||||||
{
|
{
|
||||||
if (auto __v2 = w.enterSubRecord("drumPages"))
|
if (auto __v2 = w.enterSubRecord("drumPages"))
|
||||||
{
|
{
|
||||||
for (const auto& pg : SortUnorderedMap(p.second.get().m_drumPages))
|
for (const auto& pg : SortUnorderedMap(p.second.get()->m_drumPages))
|
||||||
{
|
{
|
||||||
char name[16];
|
char name[16];
|
||||||
snprintf(name, 16, "%d", pg.first);
|
snprintf(name, 16, "%d", pg.first);
|
||||||
|
@ -571,11 +577,11 @@ bool AudioGroupProject::toYAML(SystemStringView groupPath) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!p.second.get().m_midiSetups.empty())
|
if (!p.second.get()->m_midiSetups.empty())
|
||||||
{
|
{
|
||||||
if (auto __v2 = w.enterSubRecord("songs"))
|
if (auto __v2 = w.enterSubRecord("songs"))
|
||||||
{
|
{
|
||||||
for (const auto& song : SortUnorderedMap(p.second.get().m_midiSetups))
|
for (const auto& song : SortUnorderedMap(p.second.get()->m_midiSetups))
|
||||||
{
|
{
|
||||||
char songString[64];
|
char songString[64];
|
||||||
snprintf(songString, 64, "%s/0x%04X", SongId::CurNameDB->resolveNameFromId(song.first).data(), int(song.first.id));
|
snprintf(songString, 64, "%s/0x%04X", SongId::CurNameDB->resolveNameFromId(song.first).data(), int(song.first.id));
|
||||||
|
@ -604,7 +610,7 @@ bool AudioGroupProject::toYAML(SystemStringView groupPath) const
|
||||||
snprintf(groupString, 64, "%s/0x%04X", GroupId::CurNameDB->resolveNameFromId(p.first).data(), int(p.first.id));
|
snprintf(groupString, 64, "%s/0x%04X", GroupId::CurNameDB->resolveNameFromId(p.first).data(), int(p.first.id));
|
||||||
if (auto __r = w.enterSubRecord(groupString))
|
if (auto __r = w.enterSubRecord(groupString))
|
||||||
{
|
{
|
||||||
for (const auto& sfx : SortUnorderedMap(p.second.get().m_sfxEntries))
|
for (const auto& sfx : SortUnorderedMap(p.second.get()->m_sfxEntries))
|
||||||
{
|
{
|
||||||
char sfxString[64];
|
char sfxString[64];
|
||||||
snprintf(sfxString, 64, "%s/0x%04X", SFXId::CurNameDB->resolveNameFromId(sfx.first).data(), int(sfx.first.id));
|
snprintf(sfxString, 64, "%s/0x%04X", SFXId::CurNameDB->resolveNameFromId(sfx.first).data(), int(sfx.first.id));
|
||||||
|
|
|
@ -200,7 +200,7 @@ AudioGroup* Engine::_addAudioGroup(const AudioGroupData& data, std::unique_ptr<A
|
||||||
/* setup SFX index for contained objects */
|
/* setup SFX index for contained objects */
|
||||||
for (const auto& grp : ret->getProj().sfxGroups())
|
for (const auto& grp : ret->getProj().sfxGroups())
|
||||||
{
|
{
|
||||||
const SFXGroupIndex& sfxGroup = grp.second;
|
const SFXGroupIndex& sfxGroup = *grp.second;
|
||||||
m_sfxLookup.reserve(m_sfxLookup.size() + sfxGroup.m_sfxEntries.size());
|
m_sfxLookup.reserve(m_sfxLookup.size() + sfxGroup.m_sfxEntries.size());
|
||||||
for (const auto& ent : sfxGroup.m_sfxEntries)
|
for (const auto& ent : sfxGroup.m_sfxEntries)
|
||||||
m_sfxLookup[ent.first] = std::make_tuple(ret, grp.first, &ent.second);
|
m_sfxLookup[ent.first] = std::make_tuple(ret, grp.first, &ent.second);
|
||||||
|
@ -264,7 +264,7 @@ void Engine::removeAudioGroup(const AudioGroupData& data)
|
||||||
/* teardown SFX index for contained objects */
|
/* teardown SFX index for contained objects */
|
||||||
for (const auto& pair : grp->getProj().sfxGroups())
|
for (const auto& pair : grp->getProj().sfxGroups())
|
||||||
{
|
{
|
||||||
const SFXGroupIndex& sfxGroup = pair.second;
|
const SFXGroupIndex& sfxGroup = *pair.second;
|
||||||
for (const auto& pair : sfxGroup.m_sfxEntries)
|
for (const auto& pair : sfxGroup.m_sfxEntries)
|
||||||
m_sfxLookup.erase(pair.first);
|
m_sfxLookup.erase(pair.first);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue