mirror of https://github.com/AxioDL/amuse.git
Implement SongGroupEditor
This commit is contained in:
parent
32deea8341
commit
eff832bb8c
|
@ -38,3 +38,24 @@ void FieldProjectNode::setCollection(ProjectModel::CollectionNode* collection)
|
||||||
setModel(model->getNullProxy());
|
setModel(model->getNullProxy());
|
||||||
setRootModelIndex(model->getNullProxy()->mapFromSource(model->index(collection)));
|
setRootModelIndex(model->getNullProxy()->mapFromSource(model->index(collection)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FieldPageObjectNode::FieldPageObjectNode(ProjectModel::GroupNode* group, QWidget* parent)
|
||||||
|
: FieldComboBox(parent)
|
||||||
|
{
|
||||||
|
setGroup(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FieldPageObjectNode::setGroup(ProjectModel::GroupNode* group)
|
||||||
|
{
|
||||||
|
m_group = group;
|
||||||
|
|
||||||
|
if (!group)
|
||||||
|
{
|
||||||
|
setModel(new QStandardItemModel(0, 1, this));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProjectModel* model = g_MainWindow->projectModel();
|
||||||
|
setModel(model->getPageObjectProxy());
|
||||||
|
setRootModelIndex(model->getPageObjectProxy()->mapFromSource(model->index(group)));
|
||||||
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <QSpinBox>
|
#include <QSpinBox>
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
#include <QWheelEvent>
|
#include <QWheelEvent>
|
||||||
|
#include <QItemEditorFactory>
|
||||||
#include "ProjectModel.hpp"
|
#include "ProjectModel.hpp"
|
||||||
|
|
||||||
class EditorWidget : public QWidget
|
class EditorWidget : public QWidget
|
||||||
|
@ -85,4 +86,45 @@ public:
|
||||||
ProjectModel::CollectionNode* collection() const { return m_collection; }
|
ProjectModel::CollectionNode* collection() const { return m_collection; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class FieldPageObjectNode : public FieldComboBox
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
ProjectModel::GroupNode* m_group;
|
||||||
|
public:
|
||||||
|
explicit FieldPageObjectNode(ProjectModel::GroupNode* group = Q_NULLPTR, QWidget* parent = Q_NULLPTR);
|
||||||
|
void setGroup(ProjectModel::GroupNode* group);
|
||||||
|
ProjectModel::GroupNode* group() const { return m_group; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class EditorFieldNode : public T
|
||||||
|
{
|
||||||
|
bool m_deferPopupOpen = true;
|
||||||
|
public:
|
||||||
|
using T::T;
|
||||||
|
bool shouldPopupOpen()
|
||||||
|
{
|
||||||
|
bool ret = m_deferPopupOpen;
|
||||||
|
m_deferPopupOpen = false;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using EditorFieldProjectNode = EditorFieldNode<FieldProjectNode>;
|
||||||
|
using EditorFieldPageObjectNode = EditorFieldNode<FieldPageObjectNode>;
|
||||||
|
|
||||||
|
template <int MIN, int MAX>
|
||||||
|
class RangedValueFactory : public QItemEditorFactory
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QWidget* createEditor(int userType, QWidget *parent) const
|
||||||
|
{
|
||||||
|
QSpinBox* sb = new QSpinBox(parent);
|
||||||
|
sb->setFrame(false);
|
||||||
|
sb->setMinimum(MIN);
|
||||||
|
sb->setMaximum(MAX);
|
||||||
|
return sb;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#endif //AMUSE_EDITOR_WIDGET_HPP
|
#endif //AMUSE_EDITOR_WIDGET_HPP
|
||||||
|
|
|
@ -4,28 +4,6 @@
|
||||||
#include <QScrollBar>
|
#include <QScrollBar>
|
||||||
#include <QMimeData>
|
#include <QMimeData>
|
||||||
|
|
||||||
QWidget* SignedValueFactory::createEditor(int userType, QWidget *parent) const
|
|
||||||
{
|
|
||||||
QSpinBox* sb = new QSpinBox(parent);
|
|
||||||
sb->setFrame(false);
|
|
||||||
sb->setMinimum(-128);
|
|
||||||
sb->setMaximum(127);
|
|
||||||
return sb;
|
|
||||||
}
|
|
||||||
|
|
||||||
QWidget* UnsignedValueFactory::createEditor(int userType, QWidget *parent) const
|
|
||||||
{
|
|
||||||
QSpinBox* sb = new QSpinBox(parent);
|
|
||||||
sb->setFrame(false);
|
|
||||||
sb->setMinimum(0);
|
|
||||||
sb->setMaximum(127);
|
|
||||||
return sb;
|
|
||||||
}
|
|
||||||
|
|
||||||
EditorFieldProjectNode::EditorFieldProjectNode(ProjectModel::CollectionNode* collection, QWidget* parent)
|
|
||||||
: FieldProjectNode(collection, parent)
|
|
||||||
{}
|
|
||||||
|
|
||||||
SoundMacroDelegate::SoundMacroDelegate(QObject* parent)
|
SoundMacroDelegate::SoundMacroDelegate(QObject* parent)
|
||||||
: QStyledItemDelegate(parent) {}
|
: QStyledItemDelegate(parent) {}
|
||||||
|
|
||||||
|
@ -61,6 +39,7 @@ void SoundMacroDelegate::setModelData(QWidget* editor, QAbstractItemModel* m, co
|
||||||
layer.macro.id = amuse::SoundMacroId();
|
layer.macro.id = amuse::SoundMacroId();
|
||||||
else
|
else
|
||||||
layer.macro.id = smColl->idOfIndex(idx - 1);
|
layer.macro.id = smColl->idOfIndex(idx - 1);
|
||||||
|
emit m->dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole});
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundMacroDelegate::smIndexChanged()
|
void SoundMacroDelegate::smIndexChanged()
|
||||||
|
@ -150,24 +129,31 @@ bool LayersModel::setData(const QModelIndex& index, const QVariant& value, int r
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
layer.keyLo = value.toInt();
|
layer.keyLo = value.toInt();
|
||||||
|
emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole});
|
||||||
return true;
|
return true;
|
||||||
case 2:
|
case 2:
|
||||||
layer.keyHi = value.toInt();
|
layer.keyHi = value.toInt();
|
||||||
|
emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole});
|
||||||
return true;
|
return true;
|
||||||
case 3:
|
case 3:
|
||||||
layer.transpose = value.toInt();
|
layer.transpose = value.toInt();
|
||||||
|
emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole});
|
||||||
return true;
|
return true;
|
||||||
case 4:
|
case 4:
|
||||||
layer.volume = value.toInt();
|
layer.volume = value.toInt();
|
||||||
|
emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole});
|
||||||
return true;
|
return true;
|
||||||
case 5:
|
case 5:
|
||||||
layer.prioOffset = value.toInt();
|
layer.prioOffset = value.toInt();
|
||||||
|
emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole});
|
||||||
return true;
|
return true;
|
||||||
case 6:
|
case 6:
|
||||||
layer.span = value.toInt();
|
layer.span = value.toInt();
|
||||||
|
emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole});
|
||||||
return true;
|
return true;
|
||||||
case 7:
|
case 7:
|
||||||
layer.pan = value.toInt();
|
layer.pan = value.toInt();
|
||||||
|
emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole});
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -341,8 +327,9 @@ void LayersTableView::deleteSelection()
|
||||||
model()->removeRow(list.back().row());
|
model()->removeRow(list.back().row());
|
||||||
}
|
}
|
||||||
|
|
||||||
void LayersTableView::doItemsLayout()
|
void LayersTableView::setModel(QAbstractItemModel* model)
|
||||||
{
|
{
|
||||||
|
QTableView::setModel(model);
|
||||||
horizontalHeader()->setMinimumSectionSize(75);
|
horizontalHeader()->setMinimumSectionSize(75);
|
||||||
horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
|
horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
|
||||||
horizontalHeader()->setSectionResizeMode(1, QHeaderView::Fixed);
|
horizontalHeader()->setSectionResizeMode(1, QHeaderView::Fixed);
|
||||||
|
@ -359,7 +346,6 @@ void LayersTableView::doItemsLayout()
|
||||||
horizontalHeader()->resizeSection(6, 75);
|
horizontalHeader()->resizeSection(6, 75);
|
||||||
horizontalHeader()->setSectionResizeMode(7, QHeaderView::Fixed);
|
horizontalHeader()->setSectionResizeMode(7, QHeaderView::Fixed);
|
||||||
horizontalHeader()->resizeSection(7, 75);
|
horizontalHeader()->resizeSection(7, 75);
|
||||||
QTableView::doItemsLayout();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LayersTableView::LayersTableView(QWidget* parent)
|
LayersTableView::LayersTableView(QWidget* parent)
|
||||||
|
@ -371,8 +357,19 @@ LayersTableView::LayersTableView(QWidget* parent)
|
||||||
setDefaultDropAction(Qt::MoveAction);
|
setDefaultDropAction(Qt::MoveAction);
|
||||||
setDragEnabled(true);
|
setDragEnabled(true);
|
||||||
setGridStyle(Qt::NoPen);
|
setGridStyle(Qt::NoPen);
|
||||||
}
|
|
||||||
|
|
||||||
|
m_signedDelegate.setItemEditorFactory(&m_signedFactory);
|
||||||
|
m_unsignedDelegate.setItemEditorFactory(&m_unsignedFactory);
|
||||||
|
|
||||||
|
setItemDelegateForColumn(0, &m_smDelegate);
|
||||||
|
setItemDelegateForColumn(1, &m_unsignedDelegate);
|
||||||
|
setItemDelegateForColumn(2, &m_unsignedDelegate);
|
||||||
|
setItemDelegateForColumn(3, &m_signedDelegate);
|
||||||
|
setItemDelegateForColumn(4, &m_unsignedDelegate);
|
||||||
|
setItemDelegateForColumn(5, &m_signedDelegate);
|
||||||
|
setItemDelegateForColumn(6, &m_unsignedDelegate);
|
||||||
|
setItemDelegateForColumn(7, &m_unsignedDelegate);
|
||||||
|
}
|
||||||
|
|
||||||
bool LayersEditor::loadData(ProjectModel::LayersNode* node)
|
bool LayersEditor::loadData(ProjectModel::LayersNode* node)
|
||||||
{
|
{
|
||||||
|
@ -438,31 +435,21 @@ void LayersEditor::itemDeleteAction()
|
||||||
}
|
}
|
||||||
|
|
||||||
LayersEditor::LayersEditor(QWidget* parent)
|
LayersEditor::LayersEditor(QWidget* parent)
|
||||||
: EditorWidget(parent), m_tableView(this),
|
: EditorWidget(parent), m_model(this), m_tableView(this),
|
||||||
m_addAction(tr("Add Row")), m_addButton(this), m_removeAction(tr("Remove Row")), m_removeButton(this)
|
m_addAction(tr("Add Row")), m_addButton(this), m_removeAction(tr("Remove Row")), m_removeButton(this)
|
||||||
{
|
{
|
||||||
m_signedDelegate.setItemEditorFactory(&m_signedFactory);
|
|
||||||
m_unsignedDelegate.setItemEditorFactory(&m_unsignedFactory);
|
|
||||||
|
|
||||||
m_tableView.setItemDelegateForColumn(1, &m_unsignedDelegate);
|
|
||||||
m_tableView.setItemDelegateForColumn(2, &m_unsignedDelegate);
|
|
||||||
m_tableView.setItemDelegateForColumn(3, &m_signedDelegate);
|
|
||||||
m_tableView.setItemDelegateForColumn(4, &m_unsignedDelegate);
|
|
||||||
m_tableView.setItemDelegateForColumn(5, &m_signedDelegate);
|
|
||||||
m_tableView.setItemDelegateForColumn(6, &m_unsignedDelegate);
|
|
||||||
m_tableView.setItemDelegateForColumn(7, &m_unsignedDelegate);
|
|
||||||
|
|
||||||
m_tableView.setModel(&m_model);
|
m_tableView.setModel(&m_model);
|
||||||
m_tableView.setItemDelegateForColumn(0, &m_smDelegate);
|
|
||||||
connect(m_tableView.selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
|
connect(m_tableView.selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
|
||||||
this, SLOT(doSelectionChanged(const QItemSelection&)));
|
this, SLOT(doSelectionChanged(const QItemSelection&)));
|
||||||
|
|
||||||
m_addAction.setIcon(QIcon(QStringLiteral(":/icons/IconAdd.svg")));
|
m_addAction.setIcon(QIcon(QStringLiteral(":/icons/IconAdd.svg")));
|
||||||
|
m_addAction.setToolTip(tr("Add new layer mapping"));
|
||||||
m_addButton.setDefaultAction(&m_addAction);
|
m_addButton.setDefaultAction(&m_addAction);
|
||||||
m_addButton.setFixedSize(32, 32);
|
m_addButton.setFixedSize(32, 32);
|
||||||
connect(&m_addAction, SIGNAL(triggered(bool)), this, SLOT(doAdd()));
|
connect(&m_addAction, SIGNAL(triggered(bool)), this, SLOT(doAdd()));
|
||||||
|
|
||||||
m_removeAction.setIcon(QIcon(QStringLiteral(":/icons/IconRemove.svg")));
|
m_removeAction.setIcon(QIcon(QStringLiteral(":/icons/IconRemove.svg")));
|
||||||
|
m_removeAction.setToolTip(tr("Remove selected layer mappings"));
|
||||||
m_removeButton.setDefaultAction(&m_removeAction);
|
m_removeButton.setDefaultAction(&m_removeAction);
|
||||||
m_removeButton.setFixedSize(32, 32);
|
m_removeButton.setFixedSize(32, 32);
|
||||||
connect(&m_removeAction, SIGNAL(triggered(bool)), this, SLOT(itemDeleteAction()));
|
connect(&m_removeAction, SIGNAL(triggered(bool)), this, SLOT(itemDeleteAction()));
|
||||||
|
|
|
@ -7,33 +7,6 @@
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
#include <QToolButton>
|
#include <QToolButton>
|
||||||
#include <QStyledItemDelegate>
|
#include <QStyledItemDelegate>
|
||||||
#include <QItemEditorFactory>
|
|
||||||
|
|
||||||
class SignedValueFactory : public QItemEditorFactory
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
QWidget* createEditor(int userType, QWidget *parent) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
class UnsignedValueFactory : public QItemEditorFactory
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
QWidget* createEditor(int userType, QWidget *parent) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
class EditorFieldProjectNode : public FieldProjectNode
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
bool m_deferPopupOpen = true;
|
|
||||||
public:
|
|
||||||
explicit EditorFieldProjectNode(ProjectModel::CollectionNode* collection = Q_NULLPTR, QWidget* parent = Q_NULLPTR);
|
|
||||||
bool shouldPopupOpen()
|
|
||||||
{
|
|
||||||
bool ret = m_deferPopupOpen;
|
|
||||||
m_deferPopupOpen = false;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class SoundMacroDelegate : public QStyledItemDelegate
|
class SoundMacroDelegate : public QStyledItemDelegate
|
||||||
{
|
{
|
||||||
|
@ -78,9 +51,13 @@ public:
|
||||||
class LayersTableView : public QTableView
|
class LayersTableView : public QTableView
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
SoundMacroDelegate m_smDelegate;
|
||||||
|
RangedValueFactory<-128, 127> m_signedFactory;
|
||||||
|
RangedValueFactory<0, 127> m_unsignedFactory;
|
||||||
|
QStyledItemDelegate m_signedDelegate, m_unsignedDelegate;
|
||||||
public:
|
public:
|
||||||
explicit LayersTableView(QWidget* parent = Q_NULLPTR);
|
explicit LayersTableView(QWidget* parent = Q_NULLPTR);
|
||||||
void doItemsLayout();
|
void setModel(QAbstractItemModel* model);
|
||||||
void deleteSelection();
|
void deleteSelection();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -88,10 +65,6 @@ class LayersEditor : public EditorWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
LayersModel m_model;
|
LayersModel m_model;
|
||||||
SoundMacroDelegate m_smDelegate;
|
|
||||||
SignedValueFactory m_signedFactory;
|
|
||||||
UnsignedValueFactory m_unsignedFactory;
|
|
||||||
QStyledItemDelegate m_signedDelegate, m_unsignedDelegate;
|
|
||||||
LayersTableView m_tableView;
|
LayersTableView m_tableView;
|
||||||
QAction m_addAction;
|
QAction m_addAction;
|
||||||
QToolButton m_addButton;
|
QToolButton m_addButton;
|
||||||
|
|
|
@ -30,6 +30,8 @@ MainWindow::MainWindow(QWidget* parent)
|
||||||
m_ui.setupUi(this);
|
m_ui.setupUi(this);
|
||||||
m_ui.splitter->setCollapsible(1, false);
|
m_ui.splitter->setCollapsible(1, false);
|
||||||
m_ui.projectOutline->setItemDelegate(&m_treeDelegate);
|
m_ui.projectOutline->setItemDelegate(&m_treeDelegate);
|
||||||
|
connect(m_ui.projectOutline, SIGNAL(activated(const QModelIndex&)),
|
||||||
|
this, SLOT(outlineItemActivated(const QModelIndex&)));
|
||||||
connectMessenger(&m_mainMessenger, Qt::DirectConnection);
|
connectMessenger(&m_mainMessenger, Qt::DirectConnection);
|
||||||
|
|
||||||
m_ui.statusbar->connectKillClicked(this, SLOT(killSounds()));
|
m_ui.statusbar->connectKillClicked(this, SLOT(killSounds()));
|
||||||
|
@ -232,11 +234,13 @@ bool MainWindow::setProjectPath(const QString& path)
|
||||||
QMessageBox::critical(this, tr("Directory does not exist"), msg);
|
QMessageBox::critical(this, tr("Directory does not exist"), msg);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
QString testWritePath = dir.filePath(tr("test"));
|
QString testWritePath = dir.filePath(tr("__amuse_test__"));
|
||||||
QFile testWriteFile(testWritePath);
|
QFile testWriteFile(testWritePath);
|
||||||
if (!testWriteFile.open(QFile::ReadWrite))
|
if (!testWriteFile.open(QFile::ReadWrite))
|
||||||
{
|
{
|
||||||
QString msg = QString(tr("The directory at '%1' must be writable for the Amuse editor.")).arg(path);
|
|
||||||
|
QString msg = QString(tr("The directory at '%1' must be writable for the Amuse editor: %2")).arg(path).
|
||||||
|
arg(testWriteFile.errorString());
|
||||||
QMessageBox::critical(this, tr("Unable to write to directory"), msg);
|
QMessageBox::critical(this, tr("Unable to write to directory"), msg);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -617,6 +621,7 @@ bool MainWindow::openProject(const QString& path)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
model->openSongsData();
|
||||||
});
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -841,12 +846,14 @@ bool TreeDelegate::editorEvent(QEvent* event,
|
||||||
if (!node)
|
if (!node)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
#if 0
|
||||||
if ((event->type() == QEvent::MouseButtonDblClick &&
|
if ((event->type() == QEvent::MouseButtonDblClick &&
|
||||||
static_cast<QMouseEvent*>(event)->button() == Qt::LeftButton))
|
static_cast<QMouseEvent*>(event)->button() == Qt::LeftButton))
|
||||||
{
|
{
|
||||||
// Open in editor
|
// Open in editor
|
||||||
return m_window.openEditor(node);
|
return m_window.openEditor(node);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1032,6 +1039,14 @@ void MainWindow::onFocusChanged(QWidget* old, QWidget* now)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::outlineItemActivated(const QModelIndex& index)
|
||||||
|
{
|
||||||
|
ProjectModel::INode* node = m_projectModel->node(index);
|
||||||
|
if (!node)
|
||||||
|
return;
|
||||||
|
openEditor(node);
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::setItemEditEnabled(bool enabled)
|
void MainWindow::setItemEditEnabled(bool enabled)
|
||||||
{
|
{
|
||||||
m_ui.actionCut->setEnabled(enabled);
|
m_ui.actionCut->setEnabled(enabled);
|
||||||
|
|
|
@ -191,6 +191,7 @@ public slots:
|
||||||
void outlineDeleteAction();
|
void outlineDeleteAction();
|
||||||
|
|
||||||
void onFocusChanged(QWidget* old, QWidget* now);
|
void onFocusChanged(QWidget* old, QWidget* now);
|
||||||
|
void outlineItemActivated(const QModelIndex& index);
|
||||||
void setItemEditEnabled(bool enabled);
|
void setItemEditEnabled(bool enabled);
|
||||||
bool canEditOutline();
|
bool canEditOutline();
|
||||||
void onOutlineSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected);
|
void onOutlineSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected);
|
||||||
|
|
|
@ -77,34 +77,6 @@
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Vertical</enum>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QScrollArea" name="editorScrollArea">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>500</width>
|
|
||||||
<height>400</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="frameShape">
|
|
||||||
<enum>QFrame::NoFrame</enum>
|
|
||||||
</property>
|
|
||||||
<property name="frameShadow">
|
|
||||||
<enum>QFrame::Plain</enum>
|
|
||||||
</property>
|
|
||||||
<property name="lineWidth">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="midLineWidth">
|
|
||||||
<number>-2</number>
|
|
||||||
</property>
|
|
||||||
<property name="widgetResizable">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<widget class="QStackedWidget" name="editorContents">
|
<widget class="QStackedWidget" name="editorContents">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
|
@ -115,7 +87,6 @@
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</widget>
|
|
||||||
<widget class="QWidget" name="keyboard" native="true">
|
<widget class="QWidget" name="keyboard" native="true">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
|
|
|
@ -52,6 +52,219 @@ QVariant NullItemProxyModel::data(const QModelIndex& proxyIndex, int role) const
|
||||||
return QIdentityProxyModel::data(proxyIndex, role);
|
return QIdentityProxyModel::data(proxyIndex, role);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PageObjectProxyModel::PageObjectProxyModel(ProjectModel* source)
|
||||||
|
: QIdentityProxyModel(source)
|
||||||
|
{
|
||||||
|
setSourceModel(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex PageObjectProxyModel::mapFromSource(const QModelIndex& sourceIndex) const
|
||||||
|
{
|
||||||
|
if (!sourceIndex.isValid())
|
||||||
|
return QModelIndex();
|
||||||
|
ProjectModel::INode* node = static_cast<ProjectModel::INode*>(sourceIndex.internalPointer());
|
||||||
|
auto tp = node->type();
|
||||||
|
if ((tp != ProjectModel::INode::Type::SoundMacro &&
|
||||||
|
tp != ProjectModel::INode::Type::Keymap &&
|
||||||
|
tp != ProjectModel::INode::Type::Layer &&
|
||||||
|
tp != ProjectModel::INode::Type::Null) ||
|
||||||
|
(tp == ProjectModel::INode::Type::Null &&
|
||||||
|
node->parent() == static_cast<ProjectModel*>(sourceModel())->rootNode()))
|
||||||
|
return createIndex(sourceIndex.row(), sourceIndex.column(), node);
|
||||||
|
ProjectModel::GroupNode* group = static_cast<ProjectModel*>(sourceModel())->getGroupNode(node);
|
||||||
|
ProjectModel::CollectionNode* smCol = group->getCollectionOfType(ProjectModel::INode::Type::SoundMacro);
|
||||||
|
ProjectModel::CollectionNode* kmCol = group->getCollectionOfType(ProjectModel::INode::Type::Keymap);
|
||||||
|
ProjectModel::CollectionNode* layCol = group->getCollectionOfType(ProjectModel::INode::Type::Layer);
|
||||||
|
switch (tp)
|
||||||
|
{
|
||||||
|
case ProjectModel::INode::Type::Null:
|
||||||
|
if (node->parent() == group)
|
||||||
|
return createIndex(0, sourceIndex.column(), sourceIndex.internalPointer());
|
||||||
|
else if (node->parent() == smCol)
|
||||||
|
return createIndex(1, sourceIndex.column(), sourceIndex.internalPointer());
|
||||||
|
else if (node->parent() == kmCol)
|
||||||
|
return createIndex(2 + smCol->childCount(), sourceIndex.column(), sourceIndex.internalPointer());
|
||||||
|
else if (node->parent() == layCol)
|
||||||
|
return createIndex(3 + smCol->childCount() + kmCol->childCount(), sourceIndex.column(), sourceIndex.internalPointer());
|
||||||
|
break;
|
||||||
|
case ProjectModel::INode::Type::SoundMacro:
|
||||||
|
return createIndex(2 + node->row(), sourceIndex.column(), sourceIndex.internalPointer());
|
||||||
|
case ProjectModel::INode::Type::Keymap:
|
||||||
|
return createIndex(3 + smCol->childCount() + node->row(), sourceIndex.column(), sourceIndex.internalPointer());
|
||||||
|
case ProjectModel::INode::Type::Layer:
|
||||||
|
return createIndex(4 + smCol->childCount() + kmCol->childCount() + node->row(), sourceIndex.column(), sourceIndex.internalPointer());
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return QModelIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex PageObjectProxyModel::mapToSource(const QModelIndex& proxyIndex) const
|
||||||
|
{
|
||||||
|
if (!proxyIndex.isValid())
|
||||||
|
return QModelIndex();
|
||||||
|
ProjectModel::INode* node = static_cast<ProjectModel::INode*>(proxyIndex.internalPointer());
|
||||||
|
auto tp = node->type();
|
||||||
|
if ((tp != ProjectModel::INode::Type::SoundMacro &&
|
||||||
|
tp != ProjectModel::INode::Type::Keymap &&
|
||||||
|
tp != ProjectModel::INode::Type::Layer &&
|
||||||
|
tp != ProjectModel::INode::Type::Null) ||
|
||||||
|
(tp == ProjectModel::INode::Type::Null &&
|
||||||
|
node->parent() == static_cast<ProjectModel*>(sourceModel())->rootNode()))
|
||||||
|
return static_cast<ProjectModel*>(sourceModel())->
|
||||||
|
proxyCreateIndex(proxyIndex.row(), proxyIndex.column(), proxyIndex.internalPointer());
|
||||||
|
ProjectModel::GroupNode* group = static_cast<ProjectModel*>(sourceModel())->getGroupNode(node);
|
||||||
|
ProjectModel::CollectionNode* smCol = group->getCollectionOfType(ProjectModel::INode::Type::SoundMacro);
|
||||||
|
ProjectModel::CollectionNode* kmCol = group->getCollectionOfType(ProjectModel::INode::Type::Keymap);
|
||||||
|
ProjectModel::CollectionNode* layCol = group->getCollectionOfType(ProjectModel::INode::Type::Layer);
|
||||||
|
switch (tp)
|
||||||
|
{
|
||||||
|
case ProjectModel::INode::Type::Null:
|
||||||
|
if (node->parent() == group)
|
||||||
|
return static_cast<ProjectModel*>(sourceModel())->
|
||||||
|
proxyCreateIndex(group->childCount(), proxyIndex.column(), proxyIndex.internalPointer());
|
||||||
|
else if (node->parent() == smCol)
|
||||||
|
return static_cast<ProjectModel*>(sourceModel())->
|
||||||
|
proxyCreateIndex(smCol->childCount(), proxyIndex.column(), proxyIndex.internalPointer());
|
||||||
|
else if (node->parent() == kmCol)
|
||||||
|
return static_cast<ProjectModel*>(sourceModel())->
|
||||||
|
proxyCreateIndex(kmCol->childCount(), proxyIndex.column(), proxyIndex.internalPointer());
|
||||||
|
else if (node->parent() == layCol)
|
||||||
|
return static_cast<ProjectModel*>(sourceModel())->
|
||||||
|
proxyCreateIndex(layCol->childCount(), proxyIndex.column(), proxyIndex.internalPointer());
|
||||||
|
break;
|
||||||
|
case ProjectModel::INode::Type::SoundMacro:
|
||||||
|
return static_cast<ProjectModel*>(sourceModel())->
|
||||||
|
proxyCreateIndex(node->row() - 2, proxyIndex.column(), proxyIndex.internalPointer());
|
||||||
|
case ProjectModel::INode::Type::Keymap:
|
||||||
|
return static_cast<ProjectModel*>(sourceModel())->
|
||||||
|
proxyCreateIndex(node->row() - smCol->childCount() - 3, proxyIndex.column(), proxyIndex.internalPointer());
|
||||||
|
case ProjectModel::INode::Type::Layer:
|
||||||
|
return static_cast<ProjectModel*>(sourceModel())->
|
||||||
|
proxyCreateIndex(node->row() - kmCol->childCount() - smCol->childCount() - 4, proxyIndex.column(), proxyIndex.internalPointer());
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return QModelIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex PageObjectProxyModel::parent(const QModelIndex& child) const
|
||||||
|
{
|
||||||
|
if (!child.isValid())
|
||||||
|
return QModelIndex();
|
||||||
|
ProjectModel::INode* node = static_cast<ProjectModel::INode*>(child.internalPointer());
|
||||||
|
auto tp = node->type();
|
||||||
|
if ((tp != ProjectModel::INode::Type::SoundMacro &&
|
||||||
|
tp != ProjectModel::INode::Type::Keymap &&
|
||||||
|
tp != ProjectModel::INode::Type::Layer &&
|
||||||
|
tp != ProjectModel::INode::Type::Null) ||
|
||||||
|
(tp == ProjectModel::INode::Type::Null &&
|
||||||
|
node->parent() == static_cast<ProjectModel*>(sourceModel())->rootNode()))
|
||||||
|
return QIdentityProxyModel::parent(child);
|
||||||
|
ProjectModel::INode* group = node->parent();
|
||||||
|
if (group->type() == ProjectModel::INode::Type::Collection)
|
||||||
|
group = group->parent();
|
||||||
|
return createIndex(group->row(), 0, group);
|
||||||
|
}
|
||||||
|
|
||||||
|
int PageObjectProxyModel::rowCount(const QModelIndex& parent) const
|
||||||
|
{
|
||||||
|
ProjectModel::INode* node = static_cast<ProjectModel*>(sourceModel())->node(parent);
|
||||||
|
auto tp = node->type();
|
||||||
|
if (tp != ProjectModel::INode::Type::Group)
|
||||||
|
return static_cast<ProjectModel*>(sourceModel())->rowCount(parent);
|
||||||
|
ProjectModel::GroupNode* group = static_cast<ProjectModel::GroupNode*>(node);
|
||||||
|
ProjectModel::CollectionNode* smCol = group->getCollectionOfType(ProjectModel::INode::Type::SoundMacro);
|
||||||
|
ProjectModel::CollectionNode* kmCol = group->getCollectionOfType(ProjectModel::INode::Type::Keymap);
|
||||||
|
ProjectModel::CollectionNode* layCol = group->getCollectionOfType(ProjectModel::INode::Type::Layer);
|
||||||
|
return 4 + smCol->childCount() + kmCol->childCount() + layCol->childCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex PageObjectProxyModel::index(int row, int column, const QModelIndex& parent) const
|
||||||
|
{
|
||||||
|
if (!parent.isValid())
|
||||||
|
return QIdentityProxyModel::index(row, column, parent);
|
||||||
|
ProjectModel::INode* parentNode = static_cast<ProjectModel::INode*>(parent.internalPointer());
|
||||||
|
auto ptp = parentNode->type();
|
||||||
|
if (ptp != ProjectModel::INode::Type::Group)
|
||||||
|
return QIdentityProxyModel::index(row, column, parent);
|
||||||
|
ProjectModel::GroupNode* group = static_cast<ProjectModel::GroupNode*>(parentNode);
|
||||||
|
ProjectModel::CollectionNode* smCol = group->getCollectionOfType(ProjectModel::INode::Type::SoundMacro);
|
||||||
|
ProjectModel::CollectionNode* kmCol = group->getCollectionOfType(ProjectModel::INode::Type::Keymap);
|
||||||
|
ProjectModel::CollectionNode* layCol = group->getCollectionOfType(ProjectModel::INode::Type::Layer);
|
||||||
|
if (row == 0)
|
||||||
|
return createIndex(row, column, group->nullChild());
|
||||||
|
else if (row == 1)
|
||||||
|
return createIndex(row, column, smCol->nullChild());
|
||||||
|
else if (row < 2 + smCol->childCount())
|
||||||
|
return createIndex(row, column, smCol->child(row - 2));
|
||||||
|
else if (row == 2 + smCol->childCount())
|
||||||
|
return createIndex(row, column, kmCol->nullChild());
|
||||||
|
else if (row < 3 + smCol->childCount() + kmCol->childCount())
|
||||||
|
return createIndex(row, column, kmCol->child(row - smCol->childCount() - 3));
|
||||||
|
else if (row == 3 + smCol->childCount() + kmCol->childCount())
|
||||||
|
return createIndex(row, column, layCol->nullChild());
|
||||||
|
else if (row < 4 + smCol->childCount() + kmCol->childCount() + layCol->childCount())
|
||||||
|
return createIndex(row, column, layCol->child(row - kmCol->childCount() - smCol->childCount() - 4));
|
||||||
|
return QModelIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant PageObjectProxyModel::data(const QModelIndex& proxyIndex, int role) const
|
||||||
|
{
|
||||||
|
if (role != Qt::DisplayRole || !proxyIndex.isValid() || proxyIndex.row() == 0)
|
||||||
|
return QVariant();
|
||||||
|
ProjectModel::INode* node = static_cast<ProjectModel::INode*>(proxyIndex.internalPointer());
|
||||||
|
auto tp = node->type();
|
||||||
|
if ((tp != ProjectModel::INode::Type::SoundMacro &&
|
||||||
|
tp != ProjectModel::INode::Type::Keymap &&
|
||||||
|
tp != ProjectModel::INode::Type::Layer &&
|
||||||
|
tp != ProjectModel::INode::Type::Null) ||
|
||||||
|
(tp == ProjectModel::INode::Type::Null &&
|
||||||
|
node->parent() == static_cast<ProjectModel*>(sourceModel())->rootNode()))
|
||||||
|
return QVariant();
|
||||||
|
ProjectModel::GroupNode* group = static_cast<ProjectModel*>(sourceModel())->getGroupNode(node);
|
||||||
|
ProjectModel::CollectionNode* smCol = group->getCollectionOfType(ProjectModel::INode::Type::SoundMacro);
|
||||||
|
ProjectModel::CollectionNode* kmCol = group->getCollectionOfType(ProjectModel::INode::Type::Keymap);
|
||||||
|
ProjectModel::CollectionNode* layCol = group->getCollectionOfType(ProjectModel::INode::Type::Layer);
|
||||||
|
switch (tp)
|
||||||
|
{
|
||||||
|
case ProjectModel::INode::Type::Null:
|
||||||
|
if (node->parent() == group)
|
||||||
|
return QVariant();
|
||||||
|
else if (node->parent() == smCol)
|
||||||
|
return tr("SoundMacros:");
|
||||||
|
else if (node->parent() == kmCol)
|
||||||
|
return tr("Keymaps:");
|
||||||
|
else if (node->parent() == layCol)
|
||||||
|
return tr("Layers:");
|
||||||
|
break;
|
||||||
|
case ProjectModel::INode::Type::SoundMacro:
|
||||||
|
case ProjectModel::INode::Type::Keymap:
|
||||||
|
case ProjectModel::INode::Type::Layer:
|
||||||
|
return node->text();
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::ItemFlags PageObjectProxyModel::flags(const QModelIndex& proxyIndex) const
|
||||||
|
{
|
||||||
|
if (!proxyIndex.isValid())
|
||||||
|
return Qt::NoItemFlags;
|
||||||
|
if (proxyIndex.row() == 0)
|
||||||
|
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
||||||
|
ProjectModel::INode* node = static_cast<ProjectModel::INode*>(proxyIndex.internalPointer());
|
||||||
|
auto tp = node->type();
|
||||||
|
if (tp == ProjectModel::INode::Type::Null)
|
||||||
|
return Qt::NoItemFlags;
|
||||||
|
if (tp != ProjectModel::INode::Type::SoundMacro &&
|
||||||
|
tp != ProjectModel::INode::Type::Keymap &&
|
||||||
|
tp != ProjectModel::INode::Type::Layer)
|
||||||
|
return Qt::NoItemFlags;
|
||||||
|
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
||||||
|
}
|
||||||
|
|
||||||
ProjectModel::INode::INode(INode* parent, int row) : m_parent(parent), m_row(row)
|
ProjectModel::INode::INode(INode* parent, int row) : m_parent(parent), m_row(row)
|
||||||
{
|
{
|
||||||
auto nullNode = amuse::MakeObj<NullNode>(this);
|
auto nullNode = amuse::MakeObj<NullNode>(this);
|
||||||
|
@ -72,6 +285,17 @@ ProjectModel::CollectionNode* ProjectModel::GroupNode::getCollectionOfType(Type
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ProjectModel::BasePoolObjectNode* ProjectModel::GroupNode::pageObjectNodeOfId(amuse::ObjectId id) const
|
||||||
|
{
|
||||||
|
if (ProjectModel::BasePoolObjectNode* ret = getCollectionOfType(Type::SoundMacro)->nodeOfId(id))
|
||||||
|
return ret;
|
||||||
|
if (ProjectModel::BasePoolObjectNode* ret = getCollectionOfType(Type::Keymap)->nodeOfId(id))
|
||||||
|
return ret;
|
||||||
|
if (ProjectModel::BasePoolObjectNode* ret = getCollectionOfType(Type::Layer)->nodeOfId(id))
|
||||||
|
return ret;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
int ProjectModel::CollectionNode::indexOfId(amuse::ObjectId id) const
|
int ProjectModel::CollectionNode::indexOfId(amuse::ObjectId id) const
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
@ -103,7 +327,7 @@ ProjectModel::BasePoolObjectNode* ProjectModel::CollectionNode::nodeOfId(amuse::
|
||||||
}
|
}
|
||||||
|
|
||||||
ProjectModel::ProjectModel(const QString& path, QObject* parent)
|
ProjectModel::ProjectModel(const QString& path, QObject* parent)
|
||||||
: QAbstractItemModel(parent), m_dir(path), m_nullProxy(this)
|
: QAbstractItemModel(parent), m_dir(path), m_nullProxy(this), m_pageObjectProxy(this)
|
||||||
{
|
{
|
||||||
m_root = amuse::MakeObj<RootNode>();
|
m_root = amuse::MakeObj<RootNode>();
|
||||||
|
|
||||||
|
@ -116,6 +340,7 @@ bool ProjectModel::clearProjectData()
|
||||||
{
|
{
|
||||||
m_projectDatabase = amuse::ProjectDatabase();
|
m_projectDatabase = amuse::ProjectDatabase();
|
||||||
m_groups.clear();
|
m_groups.clear();
|
||||||
|
m_midiFiles.clear();
|
||||||
|
|
||||||
m_needsReset = true;
|
m_needsReset = true;
|
||||||
return true;
|
return true;
|
||||||
|
@ -131,6 +356,33 @@ bool ProjectModel::openGroupData(const QString& groupName, UIMessenger& messenge
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ProjectModel::openSongsData()
|
||||||
|
{
|
||||||
|
m_midiFiles.clear();
|
||||||
|
QFileInfo songsFile(m_dir, QStringLiteral("!songs.yaml"));
|
||||||
|
if (songsFile.exists())
|
||||||
|
{
|
||||||
|
athena::io::FileReader r(QStringToSysString(songsFile.path()));
|
||||||
|
if (!r.hasError())
|
||||||
|
{
|
||||||
|
athena::io::YAMLDocReader dr;
|
||||||
|
if (dr.parse(&r))
|
||||||
|
{
|
||||||
|
m_midiFiles.reserve(dr.getRootNode()->m_mapChildren.size());
|
||||||
|
for (auto& p : dr.getRootNode()->m_mapChildren)
|
||||||
|
{
|
||||||
|
char* endPtr;
|
||||||
|
amuse::SongId id = uint16_t(strtoul(p.first.c_str(), &endPtr, 0));
|
||||||
|
if (endPtr == p.first.c_str() || id.id == 0xffff)
|
||||||
|
continue;
|
||||||
|
m_midiFiles[id] = QString::fromStdString(p.second->m_scalarString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool ProjectModel::reloadSampleData(const QString& groupName, UIMessenger& messenger)
|
bool ProjectModel::reloadSampleData(const QString& groupName, UIMessenger& messenger)
|
||||||
{
|
{
|
||||||
m_projectDatabase.setIdDatabases();
|
m_projectDatabase.setIdDatabases();
|
||||||
|
@ -203,6 +455,21 @@ bool ProjectModel::saveToFile(UIMessenger& messenger)
|
||||||
g.second.getPool().toYAML(groupPath);
|
g.second.getPool().toYAML(groupPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!m_midiFiles.empty())
|
||||||
|
{
|
||||||
|
QFileInfo songsFile(m_dir, QStringLiteral("!songs.yaml"));
|
||||||
|
athena::io::YAMLDocWriter dw("amuse::Songs");
|
||||||
|
for (auto& p : m_midiFiles)
|
||||||
|
{
|
||||||
|
char id[16];
|
||||||
|
snprintf(id, 16, "%04X", p.first.id);
|
||||||
|
dw.writeString(id, p.second.toUtf8().data());
|
||||||
|
}
|
||||||
|
athena::io::FileWriter w(QStringToSysString(songsFile.path()));
|
||||||
|
if (!w.hasError())
|
||||||
|
dw.finish(&w);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -405,7 +672,7 @@ QVariant ProjectModel::data(const QModelIndex& index, int role) const
|
||||||
Qt::ItemFlags ProjectModel::flags(const QModelIndex& index) const
|
Qt::ItemFlags ProjectModel::flags(const QModelIndex& index) const
|
||||||
{
|
{
|
||||||
if (!index.isValid())
|
if (!index.isValid())
|
||||||
return 0;
|
return Qt::NoItemFlags;
|
||||||
|
|
||||||
return static_cast<INode*>(index.internalPointer())->flags();
|
return static_cast<INode*>(index.internalPointer())->flags();
|
||||||
}
|
}
|
||||||
|
@ -477,3 +744,56 @@ void ProjectModel::del(const QModelIndex& index)
|
||||||
return;
|
return;
|
||||||
g_MainWindow->pushUndoCommand(new DeleteNodeUndoCommand(index));
|
g_MainWindow->pushUndoCommand(new DeleteNodeUndoCommand(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ProjectModel::GroupNode* ProjectModel::getGroupOfSfx(amuse::SFXId id) const
|
||||||
|
{
|
||||||
|
ProjectModel::GroupNode* ret = nullptr;
|
||||||
|
m_root->oneLevelTraverse([id, &ret](INode* n)
|
||||||
|
{
|
||||||
|
GroupNode* gn = static_cast<GroupNode*>(n);
|
||||||
|
amuse::AudioGroupDatabase* db = gn->getAudioGroup();
|
||||||
|
for (const auto& p : db->getProj().sfxGroups())
|
||||||
|
{
|
||||||
|
if (p.second->m_sfxEntries.find(id) != p.second->m_sfxEntries.cend())
|
||||||
|
{
|
||||||
|
ret = gn;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProjectModel::GroupNode* ProjectModel::getGroupOfSong(amuse::SongId id) const
|
||||||
|
{
|
||||||
|
ProjectModel::GroupNode* ret = nullptr;
|
||||||
|
m_root->oneLevelTraverse([id, &ret](INode* n)
|
||||||
|
{
|
||||||
|
GroupNode* gn = static_cast<GroupNode*>(n);
|
||||||
|
amuse::AudioGroupDatabase* db = gn->getAudioGroup();
|
||||||
|
for (const auto& p : db->getProj().songGroups())
|
||||||
|
{
|
||||||
|
if (p.second->m_midiSetups.find(id) != p.second->m_midiSetups.cend())
|
||||||
|
{
|
||||||
|
ret = gn;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ProjectModel::getMIDIPathOfSong(amuse::SongId id) const
|
||||||
|
{
|
||||||
|
auto search = m_midiFiles.find(id);
|
||||||
|
if (search == m_midiFiles.cend())
|
||||||
|
return {};
|
||||||
|
return search->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectModel::setMIDIPathOfSong(amuse::SongId id, const QString& path)
|
||||||
|
{
|
||||||
|
m_midiFiles[id] = path;
|
||||||
|
}
|
||||||
|
|
|
@ -27,6 +27,20 @@ public:
|
||||||
QVariant data(const QModelIndex& proxyIndex, int role) const;
|
QVariant data(const QModelIndex& proxyIndex, int role) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class PageObjectProxyModel : public QIdentityProxyModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit PageObjectProxyModel(ProjectModel* source);
|
||||||
|
QModelIndex mapFromSource(const QModelIndex& sourceIndex) const;
|
||||||
|
QModelIndex mapToSource(const QModelIndex& proxyIndex) const;
|
||||||
|
QModelIndex parent(const QModelIndex& child) const;
|
||||||
|
int rowCount(const QModelIndex& parent) const;
|
||||||
|
QModelIndex index(int row, int column, const QModelIndex& parent) const;
|
||||||
|
QVariant data(const QModelIndex& proxyIndex, int role) const;
|
||||||
|
Qt::ItemFlags flags(const QModelIndex& proxyIndex) const;
|
||||||
|
};
|
||||||
|
|
||||||
class ProjectModel : public QAbstractItemModel
|
class ProjectModel : public QAbstractItemModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -41,9 +55,11 @@ public:
|
||||||
private:
|
private:
|
||||||
QDir m_dir;
|
QDir m_dir;
|
||||||
NullItemProxyModel m_nullProxy;
|
NullItemProxyModel m_nullProxy;
|
||||||
|
PageObjectProxyModel m_pageObjectProxy;
|
||||||
|
|
||||||
amuse::ProjectDatabase m_projectDatabase;
|
amuse::ProjectDatabase m_projectDatabase;
|
||||||
std::map<QString, amuse::AudioGroupDatabase> m_groups;
|
std::map<QString, amuse::AudioGroupDatabase> m_groups;
|
||||||
|
std::unordered_map<amuse::SongId, QString> m_midiFiles;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
class INode : public amuse::IObj
|
class INode : public amuse::IObj
|
||||||
|
@ -126,6 +142,14 @@ public:
|
||||||
return func(this);
|
return func(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool oneLevelTraverse(const std::function<bool(INode* node)>& func)
|
||||||
|
{
|
||||||
|
for (auto& n : m_children)
|
||||||
|
if (!func(n.get()))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
virtual Type type() const = 0;
|
virtual Type type() const = 0;
|
||||||
virtual QString text() const = 0;
|
virtual QString text() const = 0;
|
||||||
virtual QIcon icon() const = 0;
|
virtual QIcon icon() const = 0;
|
||||||
|
@ -149,6 +173,7 @@ public:
|
||||||
Qt::ItemFlags flags() const { return Qt::ItemIsEnabled; }
|
Qt::ItemFlags flags() const { return Qt::ItemIsEnabled; }
|
||||||
};
|
};
|
||||||
struct CollectionNode;
|
struct CollectionNode;
|
||||||
|
struct BasePoolObjectNode;
|
||||||
struct GroupNode : INode
|
struct GroupNode : INode
|
||||||
{
|
{
|
||||||
std::map<QString, amuse::AudioGroupDatabase>::iterator m_it;
|
std::map<QString, amuse::AudioGroupDatabase>::iterator m_it;
|
||||||
|
@ -162,6 +187,7 @@ public:
|
||||||
|
|
||||||
CollectionNode* getCollectionOfType(Type tp) const;
|
CollectionNode* getCollectionOfType(Type tp) const;
|
||||||
amuse::AudioGroupDatabase* getAudioGroup() const { return &m_it->second; }
|
amuse::AudioGroupDatabase* getAudioGroup() const { return &m_it->second; }
|
||||||
|
BasePoolObjectNode* pageObjectNodeOfId(amuse::ObjectId id) const;
|
||||||
};
|
};
|
||||||
struct SongGroupNode : INode
|
struct SongGroupNode : INode
|
||||||
{
|
{
|
||||||
|
@ -189,7 +215,6 @@ public:
|
||||||
QString text() const { return m_name; }
|
QString text() const { return m_name; }
|
||||||
QIcon icon() const { return Icon; }
|
QIcon icon() const { return Icon; }
|
||||||
};
|
};
|
||||||
struct BasePoolObjectNode;
|
|
||||||
struct CollectionNode : INode
|
struct CollectionNode : INode
|
||||||
{
|
{
|
||||||
QString m_name;
|
QString m_name;
|
||||||
|
@ -245,6 +270,7 @@ public:
|
||||||
|
|
||||||
bool clearProjectData();
|
bool clearProjectData();
|
||||||
bool openGroupData(const QString& groupName, UIMessenger& messenger);
|
bool openGroupData(const QString& groupName, UIMessenger& messenger);
|
||||||
|
bool openSongsData();
|
||||||
bool reloadSampleData(const QString& groupName, UIMessenger& messenger);
|
bool reloadSampleData(const QString& groupName, UIMessenger& messenger);
|
||||||
bool importGroupData(const QString& groupName, const amuse::AudioGroupData& data,
|
bool importGroupData(const QString& groupName, const amuse::AudioGroupData& data,
|
||||||
ImportMode mode, UIMessenger& messenger);
|
ImportMode mode, UIMessenger& messenger);
|
||||||
|
@ -266,9 +292,17 @@ public:
|
||||||
void _undoDel(const QModelIndex& index, amuse::ObjToken<ProjectModel::INode> node);
|
void _undoDel(const QModelIndex& index, amuse::ObjToken<ProjectModel::INode> node);
|
||||||
amuse::ObjToken<ProjectModel::INode> _redoDel(const QModelIndex& index);
|
amuse::ObjToken<ProjectModel::INode> _redoDel(const QModelIndex& index);
|
||||||
void del(const QModelIndex& index);
|
void del(const QModelIndex& index);
|
||||||
|
RootNode* rootNode() const { return m_root.get(); }
|
||||||
|
|
||||||
|
const QDir& dir() const { return m_dir; }
|
||||||
QString path() const { return m_dir.path(); }
|
QString path() const { return m_dir.path(); }
|
||||||
NullItemProxyModel* getNullProxy() { return &m_nullProxy; }
|
NullItemProxyModel* getNullProxy() { return &m_nullProxy; }
|
||||||
|
PageObjectProxyModel* getPageObjectProxy() { return &m_pageObjectProxy; }
|
||||||
|
|
||||||
|
GroupNode* getGroupOfSfx(amuse::SFXId id) const;
|
||||||
|
GroupNode* getGroupOfSong(amuse::SongId id) const;
|
||||||
|
QString getMIDIPathOfSong(amuse::SongId id) const;
|
||||||
|
void setMIDIPathOfSong(amuse::SongId id, const QString& path);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,987 @@
|
||||||
#include "SongGroupEditor.hpp"
|
#include "SongGroupEditor.hpp"
|
||||||
|
#include "MainWindow.hpp"
|
||||||
|
|
||||||
bool SongGroupEditor::loadData(ProjectModel::SongGroupNode* node)
|
PageObjectDelegate::PageObjectDelegate(QObject* parent)
|
||||||
|
: QStyledItemDelegate(parent) {}
|
||||||
|
|
||||||
|
QWidget* PageObjectDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||||
{
|
{
|
||||||
|
const PageModel* model = static_cast<const PageModel*>(index.model());
|
||||||
|
ProjectModel::GroupNode* group = g_MainWindow->projectModel()->getGroupNode(model->m_node.get());
|
||||||
|
EditorFieldPageObjectNode* cb = new EditorFieldPageObjectNode(group, parent);
|
||||||
|
connect(cb, SIGNAL(currentIndexChanged(int)), this, SLOT(objIndexChanged()));
|
||||||
|
return cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageObjectDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const
|
||||||
|
{
|
||||||
|
const PageModel* model = static_cast<const PageModel*>(index.model());
|
||||||
|
auto entry = model->m_sorted[index.row()];
|
||||||
|
ProjectModel::GroupNode* group = g_MainWindow->projectModel()->getGroupNode(model->m_node.get());
|
||||||
|
ProjectModel::BasePoolObjectNode* node = group->pageObjectNodeOfId(entry->second.objId.id);
|
||||||
|
int idx = 0;
|
||||||
|
if (node)
|
||||||
|
idx = g_MainWindow->projectModel()->getPageObjectProxy()->mapFromSource(g_MainWindow->projectModel()->index(node)).row();
|
||||||
|
static_cast<EditorFieldPageObjectNode*>(editor)->setCurrentIndex(idx);
|
||||||
|
if (static_cast<EditorFieldPageObjectNode*>(editor)->shouldPopupOpen())
|
||||||
|
static_cast<EditorFieldPageObjectNode*>(editor)->showPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageObjectDelegate::setModelData(QWidget* editor, QAbstractItemModel* m, const QModelIndex& index) const
|
||||||
|
{
|
||||||
|
const PageModel* model = static_cast<const PageModel*>(m);
|
||||||
|
auto entry = model->m_sorted[index.row()];
|
||||||
|
int idx = static_cast<EditorFieldPageObjectNode*>(editor)->currentIndex();
|
||||||
|
if (idx == 0)
|
||||||
|
{
|
||||||
|
entry->second.objId.id = amuse::ObjectId();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ProjectModel::BasePoolObjectNode* node = static_cast<ProjectModel::BasePoolObjectNode*>(
|
||||||
|
g_MainWindow->projectModel()->node(
|
||||||
|
g_MainWindow->projectModel()->getPageObjectProxy()->mapToSource(
|
||||||
|
g_MainWindow->projectModel()->getPageObjectProxy()->index(idx, 0,
|
||||||
|
static_cast<EditorFieldPageObjectNode*>(editor)->rootModelIndex()))));
|
||||||
|
entry->second.objId.id = node->id();
|
||||||
|
}
|
||||||
|
emit m->dataChanged(index, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageObjectDelegate::objIndexChanged()
|
||||||
|
{
|
||||||
|
emit commitData(static_cast<QWidget*>(sender()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MIDIFileFieldWidget::buttonPressed()
|
||||||
|
{
|
||||||
|
m_dialog.setDirectory(QFileInfo(g_MainWindow->projectModel()->dir().absoluteFilePath(m_le.text())).path());
|
||||||
|
m_dialog.open(this, SLOT(fileDialogOpened(const QString&)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MIDIFileFieldWidget::fileDialogOpened(const QString& path)
|
||||||
|
{
|
||||||
|
m_le.setText(g_MainWindow->projectModel()->dir().relativeFilePath(path));
|
||||||
|
emit pathChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
MIDIFileFieldWidget::MIDIFileFieldWidget(QWidget* parent)
|
||||||
|
: QWidget(parent), m_button(tr("Browse")),
|
||||||
|
m_dialog(this, tr("Open Song File"), {}, QStringLiteral("Songs(*.mid *.son *.sng)"))
|
||||||
|
{
|
||||||
|
QHBoxLayout* layout = new QHBoxLayout;
|
||||||
|
layout->addWidget(&m_le);
|
||||||
|
layout->addWidget(&m_button);
|
||||||
|
layout->setContentsMargins(QMargins());
|
||||||
|
layout->setSpacing(0);
|
||||||
|
setLayout(layout);
|
||||||
|
|
||||||
|
connect(&m_le, SIGNAL(returnPressed()), this, SIGNAL(pathChanged()));
|
||||||
|
connect(&m_button, SIGNAL(clicked(bool)), this, SLOT(buttonPressed()));
|
||||||
|
|
||||||
|
m_dialog.setFileMode(QFileDialog::ExistingFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget* MIDIFileDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||||
|
{
|
||||||
|
MIDIFileFieldWidget* field = new MIDIFileFieldWidget(parent);
|
||||||
|
connect(field, SIGNAL(pathChanged()), this, SLOT(pathChanged()));
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MIDIFileDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const
|
||||||
|
{
|
||||||
|
MIDIFileFieldWidget* widget = static_cast<MIDIFileFieldWidget*>(editor);
|
||||||
|
const SetupListModel* model = static_cast<const SetupListModel*>(index.model());
|
||||||
|
auto entry = model->m_sorted[index.row()];
|
||||||
|
widget->setPath(g_MainWindow->projectModel()->getMIDIPathOfSong(entry->first));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MIDIFileDelegate::setModelData(QWidget* editor, QAbstractItemModel* m, const QModelIndex& index) const
|
||||||
|
{
|
||||||
|
MIDIFileFieldWidget* widget = static_cast<MIDIFileFieldWidget*>(editor);
|
||||||
|
const SetupListModel* model = static_cast<const SetupListModel*>(index.model());
|
||||||
|
auto entry = model->m_sorted[index.row()];
|
||||||
|
g_MainWindow->projectModel()->setMIDIPathOfSong(entry->first, widget->path());
|
||||||
|
emit m->dataChanged(index, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MIDIFileDelegate::pathChanged()
|
||||||
|
{
|
||||||
|
emit commitData(static_cast<MIDIFileFieldWidget*>(sender()));
|
||||||
|
}
|
||||||
|
|
||||||
|
MIDIFileDelegate::MIDIFileDelegate(QObject* parent)
|
||||||
|
: QStyledItemDelegate(parent) {}
|
||||||
|
|
||||||
|
std::unordered_map<uint8_t, amuse::SongGroupIndex::PageEntry>& PageModel::_getMap() const
|
||||||
|
{
|
||||||
|
return m_drum ? m_node->m_index->m_drumPages : m_node->m_index->m_normPages;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageModel::_buildSortedList()
|
||||||
|
{
|
||||||
|
m_sorted.clear();
|
||||||
|
if (!m_node)
|
||||||
|
return;
|
||||||
|
auto& map = _getMap();
|
||||||
|
m_sorted.reserve(map.size());
|
||||||
|
for (auto it = map.begin() ; it != map.end() ; ++it)
|
||||||
|
m_sorted.emplace_back(it);
|
||||||
|
std::sort(m_sorted.begin(), m_sorted.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex PageModel::_indexOfProgram(uint8_t prog) const
|
||||||
|
{
|
||||||
|
auto search = std::lower_bound(m_sorted.cbegin(), m_sorted.cend(), prog);
|
||||||
|
if (search == m_sorted.cend() || search->m_it->first != prog)
|
||||||
|
return QModelIndex();
|
||||||
|
else
|
||||||
|
return createIndex(search - m_sorted.begin(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int PageModel::_hypotheticalIndexOfProgram(uint8_t prog) const
|
||||||
|
{
|
||||||
|
auto search = std::lower_bound(m_sorted.cbegin(), m_sorted.cend(), prog);
|
||||||
|
return search - m_sorted.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageModel::loadData(ProjectModel::SongGroupNode* node)
|
||||||
|
{
|
||||||
|
beginResetModel();
|
||||||
|
m_node = node;
|
||||||
|
_buildSortedList();
|
||||||
|
endResetModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageModel::unloadData()
|
||||||
|
{
|
||||||
|
beginResetModel();
|
||||||
|
m_node.reset();
|
||||||
|
m_sorted.clear();
|
||||||
|
endResetModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
int PageModel::rowCount(const QModelIndex& parent) const
|
||||||
|
{
|
||||||
|
if (parent.isValid())
|
||||||
|
return 0;
|
||||||
|
if (!m_node)
|
||||||
|
return 0;
|
||||||
|
return int(m_sorted.size()) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PageModel::columnCount(const QModelIndex& parent) const
|
||||||
|
{
|
||||||
|
if (parent.isValid())
|
||||||
|
return 0;
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant PageModel::data(const QModelIndex& index, int role) const
|
||||||
|
{
|
||||||
|
if (!m_node)
|
||||||
|
return QVariant();
|
||||||
|
if (index.row() == m_sorted.size())
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
auto entry = m_sorted[index.row()];
|
||||||
|
|
||||||
|
if (role == Qt::DisplayRole || role == Qt::EditRole)
|
||||||
|
{
|
||||||
|
switch (index.column())
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return entry->first;
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
ProjectModel::GroupNode* group = g_MainWindow->projectModel()->getGroupNode(m_node.get());
|
||||||
|
if (ProjectModel::BasePoolObjectNode* node = group->pageObjectNodeOfId(entry->second.objId.id))
|
||||||
|
return node->text();
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
return entry->second.priority;
|
||||||
|
case 3:
|
||||||
|
return entry->second.maxVoices;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PageModel::setData(const QModelIndex& index, const QVariant& value, int role)
|
||||||
|
{
|
||||||
|
if (!m_node || role != Qt::EditRole)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto& map = _getMap();
|
||||||
|
auto entry = m_sorted[index.row()];
|
||||||
|
|
||||||
|
switch (index.column())
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
if (value.toInt() == entry->first)
|
||||||
|
return false;
|
||||||
|
if (map.find(value.toInt()) != map.cend())
|
||||||
|
{
|
||||||
|
QMessageBox::critical(g_MainWindow, tr("Program Conflict"),
|
||||||
|
tr("Program %1 is already defined in table").arg(value.toInt()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
emit layoutAboutToBeChanged();
|
||||||
|
auto nh = map.extract(entry->first);
|
||||||
|
nh.key() = value.toInt();
|
||||||
|
map.insert(std::move(nh));
|
||||||
|
_buildSortedList();
|
||||||
|
QModelIndex newIndex = _indexOfProgram(value.toInt());
|
||||||
|
changePersistentIndex(index, newIndex);
|
||||||
|
emit layoutChanged();
|
||||||
|
emit dataChanged(newIndex, newIndex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
entry->second.priority = value.toInt();
|
||||||
|
emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole});
|
||||||
|
return true;
|
||||||
|
case 3:
|
||||||
|
entry->second.maxVoices = value.toInt();
|
||||||
|
emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole});
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
SongGroupEditor::SongGroupEditor(QWidget* parent)
|
QVariant PageModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||||
: EditorWidget(parent)
|
{
|
||||||
|
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
|
||||||
|
{
|
||||||
|
switch (section)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return tr("Program");
|
||||||
|
case 1:
|
||||||
|
return tr("Object");
|
||||||
|
case 2:
|
||||||
|
return tr("Priority");
|
||||||
|
case 3:
|
||||||
|
return tr("Max Voices");
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::ItemFlags PageModel::flags(const QModelIndex& index) const
|
||||||
|
{
|
||||||
|
if (!index.isValid())
|
||||||
|
return Qt::NoItemFlags;
|
||||||
|
if (index.row() == m_sorted.size())
|
||||||
|
return Qt::NoItemFlags;
|
||||||
|
return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PageModel::insertRows(int row, int count, const QModelIndex& parent)
|
||||||
|
{
|
||||||
|
if (!m_node)
|
||||||
|
return false;
|
||||||
|
if (m_sorted.size() >= 128)
|
||||||
|
return false;
|
||||||
|
auto& map = _getMap();
|
||||||
|
if (m_sorted.empty())
|
||||||
|
{
|
||||||
|
beginInsertRows(parent, 0, count - 1);
|
||||||
|
for (int i = 0; i < count; ++i)
|
||||||
|
map.emplace(std::make_pair(i, amuse::SongGroupIndex::PageEntry{}));
|
||||||
|
_buildSortedList();
|
||||||
|
endInsertRows();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
int prog = -1;
|
||||||
|
if (row < m_sorted.size())
|
||||||
|
{
|
||||||
|
prog = m_sorted[row].m_it->first;
|
||||||
|
while (prog >= 0 && _indexOfProgram(prog).isValid())
|
||||||
|
--prog;
|
||||||
|
}
|
||||||
|
if (prog == -1)
|
||||||
|
{
|
||||||
|
prog = 0;
|
||||||
|
while (prog < 128 && _indexOfProgram(prog).isValid())
|
||||||
|
++prog;
|
||||||
|
}
|
||||||
|
if (prog == 128)
|
||||||
|
return true;
|
||||||
|
int insertIdx = _hypotheticalIndexOfProgram(prog);
|
||||||
|
beginInsertRows(parent, insertIdx, insertIdx);
|
||||||
|
map.emplace(std::make_pair(prog, amuse::SongGroupIndex::PageEntry{}));
|
||||||
|
_buildSortedList();
|
||||||
|
endInsertRows();
|
||||||
|
++row;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PageModel::removeRows(int row, int count, const QModelIndex& parent)
|
||||||
|
{
|
||||||
|
if (!m_node)
|
||||||
|
return false;
|
||||||
|
auto& map = _getMap();
|
||||||
|
beginRemoveRows(parent, row, row + count - 1);
|
||||||
|
std::vector<uint8_t> removeProgs;
|
||||||
|
removeProgs.reserve(count);
|
||||||
|
for (int i = 0; i < count; ++i)
|
||||||
|
removeProgs.push_back(m_sorted[row+i].m_it->first);
|
||||||
|
for (uint8_t prog : removeProgs)
|
||||||
|
map.erase(prog);
|
||||||
|
_buildSortedList();
|
||||||
|
endRemoveRows();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
PageModel::PageModel(bool drum, QObject* parent)
|
||||||
|
: QAbstractTableModel(parent), m_drum(drum)
|
||||||
|
{}
|
||||||
|
|
||||||
|
std::unordered_map<amuse::SongId, std::array<amuse::SongGroupIndex::MIDISetup, 16>>& SetupListModel::_getMap() const
|
||||||
|
{
|
||||||
|
return m_node->m_index->m_midiSetups;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetupListModel::_buildSortedList()
|
||||||
|
{
|
||||||
|
m_sorted.clear();
|
||||||
|
if (!m_node)
|
||||||
|
return;
|
||||||
|
auto& map = _getMap();
|
||||||
|
m_sorted.reserve(map.size());
|
||||||
|
for (auto it = map.begin() ; it != map.end() ; ++it)
|
||||||
|
m_sorted.emplace_back(it);
|
||||||
|
std::sort(m_sorted.begin(), m_sorted.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex SetupListModel::_indexOfSong(amuse::SongId id) const
|
||||||
|
{
|
||||||
|
auto search = std::lower_bound(m_sorted.cbegin(), m_sorted.cend(), id);
|
||||||
|
if (search == m_sorted.cend() || search->m_it->first != id)
|
||||||
|
return QModelIndex();
|
||||||
|
else
|
||||||
|
return createIndex(search - m_sorted.begin(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int SetupListModel::_hypotheticalIndexOfSong(const std::string& songName) const
|
||||||
|
{
|
||||||
|
auto search = std::lower_bound(m_sorted.cbegin(), m_sorted.cend(), songName);
|
||||||
|
return search - m_sorted.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetupListModel::loadData(ProjectModel::SongGroupNode* node)
|
||||||
|
{
|
||||||
|
beginResetModel();
|
||||||
|
m_node = node;
|
||||||
|
g_MainWindow->projectModel()->getGroupNode(m_node.get())->getAudioGroup()->setIdDatabases();
|
||||||
|
_buildSortedList();
|
||||||
|
endResetModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetupListModel::unloadData()
|
||||||
|
{
|
||||||
|
beginResetModel();
|
||||||
|
m_node = nullptr;
|
||||||
|
m_sorted.clear();
|
||||||
|
endResetModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
int SetupListModel::rowCount(const QModelIndex& parent) const
|
||||||
|
{
|
||||||
|
if (parent.isValid())
|
||||||
|
return 0;
|
||||||
|
if (!m_node)
|
||||||
|
return 0;
|
||||||
|
return int(m_sorted.size()) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SetupListModel::columnCount(const QModelIndex& parent) const
|
||||||
|
{
|
||||||
|
if (parent.isValid())
|
||||||
|
return 0;
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant SetupListModel::data(const QModelIndex& index, int role) const
|
||||||
|
{
|
||||||
|
if (!m_node)
|
||||||
|
return QVariant();
|
||||||
|
if (index.row() == m_sorted.size())
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
auto entry = m_sorted[index.row()];
|
||||||
|
|
||||||
|
if (role == Qt::DisplayRole || role == Qt::EditRole)
|
||||||
|
{
|
||||||
|
if (index.column() == 0)
|
||||||
|
{
|
||||||
|
g_MainWindow->projectModel()->getGroupNode(m_node.get())->getAudioGroup()->setIdDatabases();
|
||||||
|
return amuse::SongId::CurNameDB->resolveNameFromId(entry->first.id).data();
|
||||||
|
}
|
||||||
|
else if (index.column() == 1)
|
||||||
|
{
|
||||||
|
return g_MainWindow->projectModel()->getMIDIPathOfSong(entry.m_it->first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SetupListModel::setData(const QModelIndex& index, const QVariant& value, int role)
|
||||||
|
{
|
||||||
|
if (!m_node || role != Qt::EditRole || index.column() != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto& map = _getMap();
|
||||||
|
auto entry = m_sorted[index.row()];
|
||||||
|
|
||||||
|
g_MainWindow->projectModel()->getGroupNode(m_node.get())->getAudioGroup()->setIdDatabases();
|
||||||
|
auto utf8key = value.toString().toUtf8();
|
||||||
|
std::unordered_map<std::string, amuse::ObjectId>::iterator idIt;
|
||||||
|
if ((idIt = amuse::SongId::CurNameDB->m_stringToId.find(utf8key.data())) != amuse::SongId::CurNameDB->m_stringToId.cend())
|
||||||
|
{
|
||||||
|
if (idIt->second == entry->first)
|
||||||
|
return false;
|
||||||
|
QMessageBox::critical(g_MainWindow, tr("Song Conflict"),
|
||||||
|
tr("Song %1 is already defined in project").arg(value.toString()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
emit layoutAboutToBeChanged();
|
||||||
|
amuse::SongId::CurNameDB->rename(entry.m_it->first, utf8key.data());
|
||||||
|
_buildSortedList();
|
||||||
|
QModelIndex newIndex = _indexOfSong(entry.m_it->first);
|
||||||
|
changePersistentIndex(index, newIndex);
|
||||||
|
emit layoutChanged();
|
||||||
|
emit dataChanged(newIndex, newIndex, {Qt::DisplayRole, Qt::EditRole});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant SetupListModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||||
|
{
|
||||||
|
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
|
||||||
|
{
|
||||||
|
switch (section)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return tr("Song");
|
||||||
|
case 1:
|
||||||
|
return tr("MIDI File");
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::ItemFlags SetupListModel::flags(const QModelIndex& index) const
|
||||||
|
{
|
||||||
|
if (index.row() == m_sorted.size())
|
||||||
|
return Qt::NoItemFlags;
|
||||||
|
return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SetupListModel::insertRows(int row, int count, const QModelIndex& parent)
|
||||||
|
{
|
||||||
|
if (!m_node)
|
||||||
|
return false;
|
||||||
|
auto& map = _getMap();
|
||||||
|
g_MainWindow->projectModel()->getGroupNode(m_node.get())->getAudioGroup()->setIdDatabases();
|
||||||
|
for (int i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
amuse::ObjectId songId = amuse::SongId::CurNameDB->generateId(amuse::NameDB::Type::Song);
|
||||||
|
std::string songName = amuse::SongId::CurNameDB->generateName(songId, amuse::NameDB::Type::Song);
|
||||||
|
int insertIdx = _hypotheticalIndexOfSong(songName);
|
||||||
|
beginInsertRows(parent, insertIdx, insertIdx);
|
||||||
|
amuse::SongId::CurNameDB->registerPair(songName, songId);
|
||||||
|
map.emplace(std::make_pair(songId, std::array<amuse::SongGroupIndex::MIDISetup, 16>{}));
|
||||||
|
_buildSortedList();
|
||||||
|
endInsertRows();
|
||||||
|
++row;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SetupListModel::removeRows(int row, int count, const QModelIndex& parent)
|
||||||
|
{
|
||||||
|
if (!m_node)
|
||||||
|
return false;
|
||||||
|
auto& map = _getMap();
|
||||||
|
g_MainWindow->projectModel()->getGroupNode(m_node.get())->getAudioGroup()->setIdDatabases();
|
||||||
|
beginRemoveRows(parent, row, row + count - 1);
|
||||||
|
std::vector<amuse::SongId> removeSongs;
|
||||||
|
removeSongs.reserve(count);
|
||||||
|
for (int i = 0; i < count; ++i)
|
||||||
|
removeSongs.push_back(m_sorted[row+i].m_it->first);
|
||||||
|
for (amuse::SongId song : removeSongs)
|
||||||
|
{
|
||||||
|
amuse::SongId::CurNameDB->remove(song);
|
||||||
|
map.erase(song);
|
||||||
|
}
|
||||||
|
_buildSortedList();
|
||||||
|
endRemoveRows();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetupListModel::SetupListModel(QObject* parent)
|
||||||
|
: QAbstractTableModel(parent)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void SetupModel::loadData(std::pair<const amuse::SongId, std::array<amuse::SongGroupIndex::MIDISetup, 16>>* data)
|
||||||
|
{
|
||||||
|
beginResetModel();
|
||||||
|
m_data = data;
|
||||||
|
endResetModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetupModel::unloadData()
|
||||||
|
{
|
||||||
|
beginResetModel();
|
||||||
|
m_data = nullptr;
|
||||||
|
endResetModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
int SetupModel::rowCount(const QModelIndex& parent) const
|
||||||
|
{
|
||||||
|
if (parent.isValid())
|
||||||
|
return 0;
|
||||||
|
if (!m_data)
|
||||||
|
return 0;
|
||||||
|
return 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SetupModel::columnCount(const QModelIndex& parent) const
|
||||||
|
{
|
||||||
|
if (parent.isValid())
|
||||||
|
return 0;
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant SetupModel::data(const QModelIndex& index, int role) const
|
||||||
|
{
|
||||||
|
if (!m_data)
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
auto& entry = m_data->second[index.row()];
|
||||||
|
|
||||||
|
if (role == Qt::DisplayRole || role == Qt::EditRole)
|
||||||
|
{
|
||||||
|
switch (index.column())
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return entry.programNo;
|
||||||
|
case 1:
|
||||||
|
return entry.volume;
|
||||||
|
case 2:
|
||||||
|
return entry.panning;
|
||||||
|
case 3:
|
||||||
|
return entry.reverb;
|
||||||
|
case 4:
|
||||||
|
return entry.chorus;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SetupModel::setData(const QModelIndex& index, const QVariant& value, int role)
|
||||||
|
{
|
||||||
|
if (!m_data || role != Qt::EditRole)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto& entry = m_data->second[index.row()];
|
||||||
|
|
||||||
|
switch (index.column())
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
entry.programNo = value.toInt();
|
||||||
|
emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole});
|
||||||
|
return true;
|
||||||
|
case 1:
|
||||||
|
entry.volume = value.toInt();
|
||||||
|
emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole});
|
||||||
|
return true;
|
||||||
|
case 2:
|
||||||
|
entry.panning = value.toInt();
|
||||||
|
emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole});
|
||||||
|
return true;
|
||||||
|
case 3:
|
||||||
|
entry.reverb = value.toInt();
|
||||||
|
emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole});
|
||||||
|
return true;
|
||||||
|
case 4:
|
||||||
|
entry.chorus = value.toInt();
|
||||||
|
emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole});
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant SetupModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||||
|
{
|
||||||
|
if (role == Qt::DisplayRole)
|
||||||
|
{
|
||||||
|
if (orientation == Qt::Horizontal)
|
||||||
|
{
|
||||||
|
switch (section)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return tr("Program");
|
||||||
|
case 1:
|
||||||
|
return tr("Volume");
|
||||||
|
case 2:
|
||||||
|
return tr("Panning");
|
||||||
|
case 3:
|
||||||
|
return tr("Reverb");
|
||||||
|
case 4:
|
||||||
|
return tr("Chorus");
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return section + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (role == Qt::BackgroundColorRole && orientation == Qt::Vertical)
|
||||||
|
{
|
||||||
|
if (section == 9)
|
||||||
|
return QColor(64, 0, 0);
|
||||||
|
return QColor(0, 64, 0);
|
||||||
|
}
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::ItemFlags SetupModel::flags(const QModelIndex& index) const
|
||||||
|
{
|
||||||
|
return Qt::ItemIsEnabled | Qt::ItemIsEditable;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetupModel::SetupModel(QObject* parent)
|
||||||
|
: QAbstractTableModel(parent)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void PageTableView::deleteSelection()
|
||||||
|
{
|
||||||
|
QModelIndexList list;
|
||||||
|
while (!(list = selectionModel()->selectedRows()).isEmpty())
|
||||||
|
model()->removeRow(list.back().row());
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageTableView::setModel(QAbstractItemModel* model)
|
||||||
|
{
|
||||||
|
QTableView::setModel(model);
|
||||||
|
horizontalHeader()->setMinimumSectionSize(75);
|
||||||
|
horizontalHeader()->setSectionResizeMode(0, QHeaderView::Fixed);
|
||||||
|
horizontalHeader()->resizeSection(0, 75);
|
||||||
|
horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch);
|
||||||
|
horizontalHeader()->setSectionResizeMode(2, QHeaderView::Fixed);
|
||||||
|
horizontalHeader()->resizeSection(2, 75);
|
||||||
|
horizontalHeader()->setSectionResizeMode(3, QHeaderView::Fixed);
|
||||||
|
horizontalHeader()->resizeSection(3, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
PageTableView::PageTableView(QWidget* parent)
|
||||||
|
: QTableView(parent)
|
||||||
|
{
|
||||||
|
setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||||
|
setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||||
|
setGridStyle(Qt::NoPen);
|
||||||
|
|
||||||
|
m_127Delegate.setItemEditorFactory(&m_127Factory);
|
||||||
|
m_255Delegate.setItemEditorFactory(&m_255Factory);
|
||||||
|
|
||||||
|
setItemDelegateForColumn(0, &m_127Delegate);
|
||||||
|
setItemDelegateForColumn(1, &m_poDelegate);
|
||||||
|
setItemDelegateForColumn(2, &m_255Delegate);
|
||||||
|
setItemDelegateForColumn(3, &m_255Delegate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetupTableView::setModel(QAbstractItemModel* list, QAbstractItemModel* table)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
m_listView.setModel(list);
|
||||||
|
auto hheader = m_listView.horizontalHeader();
|
||||||
|
hheader->setMinimumSectionSize(200);
|
||||||
|
hheader->resizeSection(0, 200);
|
||||||
|
hheader->setSectionResizeMode(1, QHeaderView::Stretch);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
m_tableView.setModel(table);
|
||||||
|
auto hheader = m_tableView.horizontalHeader();
|
||||||
|
hheader->setSectionResizeMode(QHeaderView::Stretch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetupTableView::deleteSelection()
|
||||||
|
{
|
||||||
|
QModelIndexList list;
|
||||||
|
while (!(list = m_listView.selectionModel()->selectedRows()).isEmpty())
|
||||||
|
m_listView.model()->removeRow(list.back().row());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetupTableView::showEvent(QShowEvent* event)
|
||||||
|
{
|
||||||
|
setSizes({width() - 375, 375});
|
||||||
|
}
|
||||||
|
|
||||||
|
SetupTableView::SetupTableView(QWidget* parent)
|
||||||
|
: QSplitter(parent), m_listView(this), m_tableView(this)
|
||||||
|
{
|
||||||
|
setChildrenCollapsible(false);
|
||||||
|
setStretchFactor(0, 1);
|
||||||
|
setStretchFactor(1, 0);
|
||||||
|
|
||||||
|
addWidget(&m_listView);
|
||||||
|
addWidget(&m_tableView);
|
||||||
|
|
||||||
|
m_listView.setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||||
|
m_listView.setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||||
|
m_listView.setGridStyle(Qt::NoPen);
|
||||||
|
m_listView.setItemDelegateForColumn(1, &m_midiDelegate);
|
||||||
|
|
||||||
|
m_tableView.setSelectionMode(QAbstractItemView::NoSelection);
|
||||||
|
m_tableView.setGridStyle(Qt::NoPen);
|
||||||
|
|
||||||
|
m_127Delegate.setItemEditorFactory(&m_127Factory);
|
||||||
|
|
||||||
|
m_tableView.setItemDelegateForColumn(0, &m_127Delegate);
|
||||||
|
m_tableView.setItemDelegateForColumn(1, &m_127Delegate);
|
||||||
|
m_tableView.setItemDelegateForColumn(2, &m_127Delegate);
|
||||||
|
m_tableView.setItemDelegateForColumn(3, &m_127Delegate);
|
||||||
|
m_tableView.setItemDelegateForColumn(4, &m_127Delegate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ColoredTabBarStyle::drawControl(QStyle::ControlElement element, const QStyleOption *option,
|
||||||
|
QPainter *painter, const QWidget *widget) const
|
||||||
|
{
|
||||||
|
if (element == QStyle::CE_TabBarTab)
|
||||||
|
{
|
||||||
|
QStyleOptionTab optionTab = *static_cast<const QStyleOptionTab*>(option);
|
||||||
|
switch (optionTab.position)
|
||||||
|
{
|
||||||
|
case QStyleOptionTab::Beginning:
|
||||||
|
optionTab.palette.setColor(QPalette::Button, QColor(0, 64, 0));
|
||||||
|
break;
|
||||||
|
case QStyleOptionTab::Middle:
|
||||||
|
optionTab.palette.setColor(QPalette::Button, QColor(64, 0, 0));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
QProxyStyle::drawControl(element, &optionTab, painter, widget);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
QProxyStyle::drawControl(element, option, painter, widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
ColoredTabBar::ColoredTabBar(QWidget* parent)
|
||||||
|
: QTabBar(parent), m_style(style())
|
||||||
|
{
|
||||||
|
setDrawBase(false);
|
||||||
|
setStyle(&m_style);
|
||||||
|
}
|
||||||
|
|
||||||
|
ColoredTabWidget::ColoredTabWidget(QWidget* parent)
|
||||||
|
: QTabWidget(parent)
|
||||||
|
{
|
||||||
|
setTabBar(&m_tabBar);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SongGroupEditor::loadData(ProjectModel::SongGroupNode* node)
|
||||||
|
{
|
||||||
|
m_normPages.loadData(node);
|
||||||
|
m_drumPages.loadData(node);
|
||||||
|
m_setupList.loadData(node);
|
||||||
|
m_setup.unloadData();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SongGroupEditor::unloadData()
|
||||||
|
{
|
||||||
|
m_normPages.unloadData();
|
||||||
|
m_drumPages.unloadData();
|
||||||
|
m_setupList.unloadData();
|
||||||
|
m_setup.unloadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
ProjectModel::INode* SongGroupEditor::currentNode() const
|
||||||
|
{
|
||||||
|
return m_normPages.m_node.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SongGroupEditor::resizeEvent(QResizeEvent* ev)
|
||||||
|
{
|
||||||
|
m_tabs.setGeometry(QRect({}, ev->size()));
|
||||||
|
m_addButton.move(0, ev->size().height() - 32);
|
||||||
|
m_removeButton.move(32, ev->size().height() - 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SongGroupEditor::doAdd()
|
||||||
|
{
|
||||||
|
if (PageTableView* table = qobject_cast<PageTableView*>(m_tabs.currentWidget()))
|
||||||
|
{
|
||||||
|
QModelIndex idx = table->selectionModel()->currentIndex();
|
||||||
|
if (!idx.isValid())
|
||||||
|
table->model()->insertRow(table->model()->rowCount() - 1);
|
||||||
|
else
|
||||||
|
table->model()->insertRow(idx.row());
|
||||||
|
if (PageTableView* ctable = qobject_cast<PageTableView*>(table))
|
||||||
|
m_addAction.setDisabled(ctable->model()->rowCount() >= 128);
|
||||||
|
}
|
||||||
|
else if (SetupTableView* table = qobject_cast<SetupTableView*>(m_tabs.currentWidget()))
|
||||||
|
{
|
||||||
|
QModelIndex idx = table->m_listView.selectionModel()->currentIndex();
|
||||||
|
if (!idx.isValid())
|
||||||
|
table->m_listView.model()->insertRow(table->m_listView.model()->rowCount() - 1);
|
||||||
|
else
|
||||||
|
table->m_listView.model()->insertRow(idx.row());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SongGroupEditor::doSelectionChanged(const QItemSelection& selected)
|
||||||
|
{
|
||||||
|
m_removeAction.setDisabled(selected.isEmpty());
|
||||||
|
g_MainWindow->updateFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SongGroupEditor::doSetupSelectionChanged(const QItemSelection& selected)
|
||||||
|
{
|
||||||
|
doSelectionChanged(selected);
|
||||||
|
if (selected.indexes().isEmpty() || m_setupList.m_sorted.empty())
|
||||||
|
{
|
||||||
|
m_setup.unloadData();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto entry = m_setupList.m_sorted[selected.indexes().last().row()];
|
||||||
|
m_setup.loadData(&*entry.m_it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SongGroupEditor::currentTabChanged(int idx)
|
||||||
|
{
|
||||||
|
if (PageTableView* table = qobject_cast<PageTableView*>(m_tabs.currentWidget()))
|
||||||
|
{
|
||||||
|
m_addAction.setDisabled(table->model()->rowCount() >= 128);
|
||||||
|
doSelectionChanged(table->selectionModel()->selection());
|
||||||
|
}
|
||||||
|
else if (SetupTableView* table = qobject_cast<SetupTableView*>(m_tabs.currentWidget()))
|
||||||
|
{
|
||||||
|
m_addAction.setDisabled(false);
|
||||||
|
doSelectionChanged(table->m_listView.selectionModel()->selection());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SongGroupEditor::rowsAboutToBeRemoved(const QModelIndex &parent, int first, int last)
|
||||||
|
{
|
||||||
|
for (int i = first; i <= last; ++i)
|
||||||
|
{
|
||||||
|
auto entry = m_setupList.m_sorted[i];
|
||||||
|
if (&*entry.m_it == m_setup.m_data)
|
||||||
|
{
|
||||||
|
m_setup.unloadData();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SongGroupEditor::modelAboutToBeReset()
|
||||||
|
{
|
||||||
|
m_setup.unloadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SongGroupEditor::isItemEditEnabled() const
|
||||||
|
{
|
||||||
|
if (PageTableView* table = qobject_cast<PageTableView*>(m_tabs.currentWidget()))
|
||||||
|
return table->hasFocus() && !table->selectionModel()->selectedRows().isEmpty();
|
||||||
|
else if (SetupTableView* table = qobject_cast<SetupTableView*>(m_tabs.currentWidget()))
|
||||||
|
return table->m_listView.hasFocus() && !table->m_listView.selectionModel()->selectedRows().isEmpty();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SongGroupEditor::itemCutAction()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SongGroupEditor::itemCopyAction()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SongGroupEditor::itemPasteAction()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SongGroupEditor::itemDeleteAction()
|
||||||
|
{
|
||||||
|
if (PageTableView* table = qobject_cast<PageTableView*>(m_tabs.currentWidget()))
|
||||||
|
table->deleteSelection();
|
||||||
|
else if (SetupTableView* table = qobject_cast<SetupTableView*>(m_tabs.currentWidget()))
|
||||||
|
table->deleteSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
SongGroupEditor::SongGroupEditor(QWidget* parent)
|
||||||
|
: EditorWidget(parent), m_normPages(false, this), m_drumPages(true, this), m_setup(this),
|
||||||
|
m_normTable(this), m_drumTable(this), m_setupTable(this), m_tabs(this),
|
||||||
|
m_addAction(tr("Add Row")), m_addButton(this), m_removeAction(tr("Remove Row")), m_removeButton(this)
|
||||||
|
{
|
||||||
|
m_tabs.addTab(&m_normTable, tr("Normal Pages"));
|
||||||
|
m_tabs.addTab(&m_drumTable, tr("Drum Pages"));
|
||||||
|
m_tabs.addTab(&m_setupTable, tr("MIDI Setups"));
|
||||||
|
|
||||||
|
connect(&m_tabs, SIGNAL(currentChanged(int)), this, SLOT(currentTabChanged(int)));
|
||||||
|
|
||||||
|
connect(&m_setupList, SIGNAL(rowsAboutToBeRemoved(const QModelIndex&, int, int)),
|
||||||
|
this, SLOT(rowsAboutToBeRemoved(const QModelIndex&, int, int)));
|
||||||
|
connect(&m_setupList, SIGNAL(modelAboutToBeReset()),
|
||||||
|
this, SLOT(modelAboutToBeReset()));
|
||||||
|
|
||||||
|
m_normTable.setModel(&m_normPages);
|
||||||
|
m_drumTable.setModel(&m_drumPages);
|
||||||
|
m_setupTable.setModel(&m_setupList, &m_setup);
|
||||||
|
connect(m_normTable.selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
|
||||||
|
this, SLOT(doSelectionChanged(const QItemSelection&)));
|
||||||
|
connect(m_drumTable.selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
|
||||||
|
this, SLOT(doSelectionChanged(const QItemSelection&)));
|
||||||
|
connect(m_setupTable.m_listView.selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
|
||||||
|
this, SLOT(doSetupSelectionChanged(const QItemSelection&)));
|
||||||
|
|
||||||
|
m_addAction.setIcon(QIcon(QStringLiteral(":/icons/IconAdd.svg")));
|
||||||
|
m_addButton.setDefaultAction(&m_addAction);
|
||||||
|
m_addAction.setToolTip(tr("Add new page entry"));
|
||||||
|
m_addButton.setFixedSize(32, 32);
|
||||||
|
connect(&m_addAction, SIGNAL(triggered(bool)), this, SLOT(doAdd()));
|
||||||
|
|
||||||
|
m_removeAction.setIcon(QIcon(QStringLiteral(":/icons/IconRemove.svg")));
|
||||||
|
m_removeButton.setDefaultAction(&m_removeAction);
|
||||||
|
m_removeAction.setToolTip(tr("Remove selected page entries"));
|
||||||
|
m_removeButton.setFixedSize(32, 32);
|
||||||
|
connect(&m_removeAction, SIGNAL(triggered(bool)), this, SLOT(itemDeleteAction()));
|
||||||
|
m_removeAction.setEnabled(false);
|
||||||
|
|
||||||
|
m_tabs.setCurrentIndex(0);
|
||||||
|
}
|
||||||
|
|
|
@ -2,13 +2,250 @@
|
||||||
#define AMUSE_SONG_GROUP_EDITOR_HPP
|
#define AMUSE_SONG_GROUP_EDITOR_HPP
|
||||||
|
|
||||||
#include "EditorWidget.hpp"
|
#include "EditorWidget.hpp"
|
||||||
|
#include <QTabWidget>
|
||||||
|
#include <QAbstractTableModel>
|
||||||
|
#include <QStyledItemDelegate>
|
||||||
|
#include <QTableView>
|
||||||
|
#include <QToolButton>
|
||||||
|
#include <QAction>
|
||||||
|
#include <QSplitter>
|
||||||
|
#include <QListView>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include <QProxyStyle>
|
||||||
|
|
||||||
|
class PageObjectDelegate : public QStyledItemDelegate
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit PageObjectDelegate(QObject* parent = Q_NULLPTR);
|
||||||
|
QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const;
|
||||||
|
void setEditorData(QWidget* editor, const QModelIndex& index) const;
|
||||||
|
void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const;
|
||||||
|
private slots:
|
||||||
|
void objIndexChanged();
|
||||||
|
};
|
||||||
|
|
||||||
|
class MIDIFileFieldWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
QLineEdit m_le;
|
||||||
|
QPushButton m_button;
|
||||||
|
QFileDialog m_dialog;
|
||||||
|
public:
|
||||||
|
explicit MIDIFileFieldWidget(QWidget* parent = Q_NULLPTR);
|
||||||
|
QString path() const { return m_le.text(); }
|
||||||
|
void setPath(const QString& path) { m_le.setText(path); }
|
||||||
|
public slots:
|
||||||
|
void buttonPressed();
|
||||||
|
void fileDialogOpened(const QString& path);
|
||||||
|
signals:
|
||||||
|
void pathChanged();
|
||||||
|
};
|
||||||
|
|
||||||
|
class MIDIFileDelegate : public QStyledItemDelegate
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit MIDIFileDelegate(QObject* parent = Q_NULLPTR);
|
||||||
|
QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const;
|
||||||
|
void setEditorData(QWidget* editor, const QModelIndex& index) const;
|
||||||
|
void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const;
|
||||||
|
public slots:
|
||||||
|
void pathChanged();
|
||||||
|
};
|
||||||
|
|
||||||
|
class PageModel : public QAbstractTableModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class SongGroupEditor;
|
||||||
|
friend class PageObjectDelegate;
|
||||||
|
amuse::ObjToken<ProjectModel::SongGroupNode> m_node;
|
||||||
|
struct Iterator
|
||||||
|
{
|
||||||
|
using ItTp = std::unordered_map<uint8_t, amuse::SongGroupIndex::PageEntry>::iterator;
|
||||||
|
ItTp m_it;
|
||||||
|
Iterator(ItTp it) : m_it(it) {}
|
||||||
|
ItTp::pointer operator->() { return m_it.operator->(); }
|
||||||
|
bool operator<(const Iterator& other) const { return m_it->first < other.m_it->first; }
|
||||||
|
bool operator<(uint8_t other) const { return m_it->first < other; }
|
||||||
|
};
|
||||||
|
std::vector<Iterator> m_sorted;
|
||||||
|
bool m_drum;
|
||||||
|
std::unordered_map<uint8_t, amuse::SongGroupIndex::PageEntry>& _getMap() const;
|
||||||
|
void _buildSortedList();
|
||||||
|
QModelIndex _indexOfProgram(uint8_t prog) const;
|
||||||
|
int _hypotheticalIndexOfProgram(uint8_t prog) const;
|
||||||
|
public:
|
||||||
|
explicit PageModel(bool drum, QObject* parent = Q_NULLPTR);
|
||||||
|
void loadData(ProjectModel::SongGroupNode* node);
|
||||||
|
void unloadData();
|
||||||
|
|
||||||
|
int rowCount(const QModelIndex& parent = QModelIndex()) const;
|
||||||
|
int columnCount(const QModelIndex& parent = QModelIndex()) const;
|
||||||
|
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
|
||||||
|
bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole);
|
||||||
|
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||||
|
Qt::ItemFlags flags(const QModelIndex& index) const;
|
||||||
|
|
||||||
|
bool insertRows(int row, int count, const QModelIndex& parent = QModelIndex());
|
||||||
|
bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex());
|
||||||
|
};
|
||||||
|
|
||||||
|
class SetupListModel : public QAbstractTableModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class SongGroupEditor;
|
||||||
|
friend class MIDIFileDelegate;
|
||||||
|
amuse::ObjToken<ProjectModel::SongGroupNode> m_node;
|
||||||
|
struct Iterator
|
||||||
|
{
|
||||||
|
using ItTp = std::unordered_map<amuse::SongId, std::array<amuse::SongGroupIndex::MIDISetup, 16>>::iterator;
|
||||||
|
ItTp m_it;
|
||||||
|
Iterator(ItTp it) : m_it(it) {}
|
||||||
|
ItTp::pointer operator->() { return m_it.operator->(); }
|
||||||
|
bool operator<(const Iterator& other) const
|
||||||
|
{
|
||||||
|
return amuse::SongId::CurNameDB->resolveNameFromId(m_it->first) <
|
||||||
|
amuse::SongId::CurNameDB->resolveNameFromId(other.m_it->first);
|
||||||
|
}
|
||||||
|
bool operator<(amuse::SongId other) const
|
||||||
|
{
|
||||||
|
return amuse::SongId::CurNameDB->resolveNameFromId(m_it->first) <
|
||||||
|
amuse::SongId::CurNameDB->resolveNameFromId(other);
|
||||||
|
}
|
||||||
|
bool operator<(const std::string& name) const
|
||||||
|
{
|
||||||
|
return amuse::SongId::CurNameDB->resolveNameFromId(m_it->first) < name;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
std::vector<Iterator> m_sorted;
|
||||||
|
std::unordered_map<amuse::SongId, std::array<amuse::SongGroupIndex::MIDISetup, 16>>& _getMap() const;
|
||||||
|
void _buildSortedList();
|
||||||
|
QModelIndex _indexOfSong(amuse::SongId id) const;
|
||||||
|
int _hypotheticalIndexOfSong(const std::string& songName) const;
|
||||||
|
public:
|
||||||
|
explicit SetupListModel(QObject* parent = Q_NULLPTR);
|
||||||
|
void loadData(ProjectModel::SongGroupNode* node);
|
||||||
|
void unloadData();
|
||||||
|
|
||||||
|
int rowCount(const QModelIndex& parent = QModelIndex()) const;
|
||||||
|
int columnCount(const QModelIndex& parent = QModelIndex()) const;
|
||||||
|
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
|
||||||
|
bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole);
|
||||||
|
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||||
|
Qt::ItemFlags flags(const QModelIndex& index) const;
|
||||||
|
|
||||||
|
bool insertRows(int row, int count, const QModelIndex& parent = QModelIndex());
|
||||||
|
bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex());
|
||||||
|
};
|
||||||
|
|
||||||
|
class SetupModel : public QAbstractTableModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class SongGroupEditor;
|
||||||
|
std::pair<const amuse::SongId, std::array<amuse::SongGroupIndex::MIDISetup, 16>>* m_data = nullptr;
|
||||||
|
public:
|
||||||
|
explicit SetupModel(QObject* parent = Q_NULLPTR);
|
||||||
|
void loadData(std::pair<const amuse::SongId, std::array<amuse::SongGroupIndex::MIDISetup, 16>>* data);
|
||||||
|
void unloadData();
|
||||||
|
|
||||||
|
int rowCount(const QModelIndex& parent = QModelIndex()) const;
|
||||||
|
int columnCount(const QModelIndex& parent = QModelIndex()) const;
|
||||||
|
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
|
||||||
|
bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole);
|
||||||
|
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||||
|
Qt::ItemFlags flags(const QModelIndex& index) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PageTableView : public QTableView
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
PageObjectDelegate m_poDelegate;
|
||||||
|
RangedValueFactory<0, 127> m_127Factory;
|
||||||
|
RangedValueFactory<0, 255> m_255Factory;
|
||||||
|
QStyledItemDelegate m_127Delegate, m_255Delegate;
|
||||||
|
public:
|
||||||
|
explicit PageTableView(QWidget* parent = Q_NULLPTR);
|
||||||
|
void setModel(QAbstractItemModel* model);
|
||||||
|
void deleteSelection();
|
||||||
|
};
|
||||||
|
|
||||||
|
class SetupTableView : public QSplitter
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
friend class SongGroupEditor;
|
||||||
|
QTableView m_listView;
|
||||||
|
QTableView m_tableView;
|
||||||
|
MIDIFileDelegate m_midiDelegate;
|
||||||
|
RangedValueFactory<0, 127> m_127Factory;
|
||||||
|
QStyledItemDelegate m_127Delegate;
|
||||||
|
public:
|
||||||
|
explicit SetupTableView(QWidget* parent = Q_NULLPTR);
|
||||||
|
void setModel(QAbstractItemModel* list, QAbstractItemModel* table);
|
||||||
|
void deleteSelection();
|
||||||
|
void showEvent(QShowEvent* event);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ColoredTabBarStyle : public QProxyStyle
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using QProxyStyle::QProxyStyle;
|
||||||
|
void drawControl(QStyle::ControlElement element, const QStyleOption *option,
|
||||||
|
QPainter *painter, const QWidget *widget = nullptr) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ColoredTabBar : public QTabBar
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
ColoredTabBarStyle m_style;
|
||||||
|
public:
|
||||||
|
explicit ColoredTabBar(QWidget* parent = Q_NULLPTR);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ColoredTabWidget : public QTabWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
ColoredTabBar m_tabBar;
|
||||||
|
public:
|
||||||
|
explicit ColoredTabWidget(QWidget* parent = Q_NULLPTR);
|
||||||
|
};
|
||||||
|
|
||||||
class SongGroupEditor : public EditorWidget
|
class SongGroupEditor : public EditorWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
PageModel m_normPages;
|
||||||
|
PageModel m_drumPages;
|
||||||
|
SetupListModel m_setupList;
|
||||||
|
SetupModel m_setup;
|
||||||
|
PageTableView m_normTable;
|
||||||
|
PageTableView m_drumTable;
|
||||||
|
SetupTableView m_setupTable;
|
||||||
|
ColoredTabWidget m_tabs;
|
||||||
|
QAction m_addAction;
|
||||||
|
QToolButton m_addButton;
|
||||||
|
QAction m_removeAction;
|
||||||
|
QToolButton m_removeButton;
|
||||||
public:
|
public:
|
||||||
explicit SongGroupEditor(QWidget* parent = Q_NULLPTR);
|
explicit SongGroupEditor(QWidget* parent = Q_NULLPTR);
|
||||||
bool loadData(ProjectModel::SongGroupNode* node);
|
bool loadData(ProjectModel::SongGroupNode* node);
|
||||||
|
void unloadData();
|
||||||
|
ProjectModel::INode* currentNode() const;
|
||||||
|
void resizeEvent(QResizeEvent* ev);
|
||||||
|
public slots:
|
||||||
|
void doAdd();
|
||||||
|
void doSelectionChanged(const QItemSelection& selected);
|
||||||
|
void doSetupSelectionChanged(const QItemSelection& selected);
|
||||||
|
void currentTabChanged(int idx);
|
||||||
|
void rowsAboutToBeRemoved(const QModelIndex &parent, int first, int last);
|
||||||
|
void modelAboutToBeReset();
|
||||||
|
|
||||||
|
bool isItemEditEnabled() const;
|
||||||
|
void itemCutAction();
|
||||||
|
void itemCopyAction();
|
||||||
|
void itemPasteAction();
|
||||||
|
void itemDeleteAction();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -184,214 +184,237 @@
|
||||||
<context>
|
<context>
|
||||||
<name>LayersEditor</name>
|
<name>LayersEditor</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../LayersEditor.cpp" line="442"/>
|
<location filename="../LayersEditor.cpp" line="439"/>
|
||||||
<source>Add Row</source>
|
<source>Add Row</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../LayersEditor.cpp" line="442"/>
|
<location filename="../LayersEditor.cpp" line="439"/>
|
||||||
<source>Remove Row</source>
|
<source>Remove Row</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../LayersEditor.cpp" line="446"/>
|
||||||
|
<source>Add new layer mapping</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../LayersEditor.cpp" line="452"/>
|
||||||
|
<source>Remove selected layer mappings</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>LayersModel</name>
|
<name>LayersModel</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../LayersEditor.cpp" line="186"/>
|
<location filename="../LayersEditor.cpp" line="172"/>
|
||||||
<source>SoundMacro</source>
|
<source>SoundMacro</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../LayersEditor.cpp" line="188"/>
|
<location filename="../LayersEditor.cpp" line="174"/>
|
||||||
<source>Key Lo</source>
|
<source>Key Lo</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../LayersEditor.cpp" line="190"/>
|
<location filename="../LayersEditor.cpp" line="176"/>
|
||||||
<source>Key Hi</source>
|
<source>Key Hi</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../LayersEditor.cpp" line="192"/>
|
<location filename="../LayersEditor.cpp" line="178"/>
|
||||||
<source>Transpose</source>
|
<source>Transpose</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../LayersEditor.cpp" line="194"/>
|
<location filename="../LayersEditor.cpp" line="180"/>
|
||||||
<source>Volume</source>
|
<source>Volume</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../LayersEditor.cpp" line="196"/>
|
<location filename="../LayersEditor.cpp" line="182"/>
|
||||||
<source>Prio Off</source>
|
<source>Prio Off</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../LayersEditor.cpp" line="198"/>
|
<location filename="../LayersEditor.cpp" line="184"/>
|
||||||
<source>Span</source>
|
<source>Span</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../LayersEditor.cpp" line="200"/>
|
<location filename="../LayersEditor.cpp" line="186"/>
|
||||||
<source>Pan</source>
|
<source>Pan</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>MIDIFileFieldWidget</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../SongGroupEditor.cpp" line="69"/>
|
||||||
|
<source>Browse</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../SongGroupEditor.cpp" line="70"/>
|
||||||
|
<source>Open Song File</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>MainWindow</name>
|
<name>MainWindow</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.ui" line="14"/>
|
<location filename="../MainWindow.ui" line="14"/>
|
||||||
<location filename="../MainWindow.cpp" line="181"/>
|
<location filename="../MainWindow.cpp" line="183"/>
|
||||||
<source>Amuse</source>
|
<source>Amuse</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.ui" line="306"/>
|
<location filename="../MainWindow.ui" line="277"/>
|
||||||
<source>&File</source>
|
<source>&File</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.ui" line="313"/>
|
<location filename="../MainWindow.ui" line="284"/>
|
||||||
<source>Recent &Projects</source>
|
<source>Recent &Projects</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.ui" line="328"/>
|
<location filename="../MainWindow.ui" line="299"/>
|
||||||
<source>Pro&ject</source>
|
<source>Pro&ject</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.ui" line="343"/>
|
<location filename="../MainWindow.ui" line="314"/>
|
||||||
<source>&Audio</source>
|
<source>&Audio</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.ui" line="351"/>
|
<location filename="../MainWindow.ui" line="322"/>
|
||||||
<source>&MIDI</source>
|
<source>&MIDI</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.ui" line="358"/>
|
<location filename="../MainWindow.ui" line="329"/>
|
||||||
<source>&Edit</source>
|
<source>&Edit</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.ui" line="374"/>
|
<location filename="../MainWindow.ui" line="345"/>
|
||||||
<source>&New Project</source>
|
<source>&New Project</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.ui" line="379"/>
|
<location filename="../MainWindow.ui" line="350"/>
|
||||||
<source>&Open Project</source>
|
<source>&Open Project</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.ui" line="387"/>
|
<location filename="../MainWindow.ui" line="358"/>
|
||||||
<source>&Cut</source>
|
<source>&Cut</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.ui" line="395"/>
|
<location filename="../MainWindow.ui" line="366"/>
|
||||||
<source>C&opy</source>
|
<source>C&opy</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.ui" line="403"/>
|
<location filename="../MainWindow.ui" line="374"/>
|
||||||
<source>&Paste</source>
|
<source>&Paste</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.ui" line="411"/>
|
<location filename="../MainWindow.ui" line="382"/>
|
||||||
<source>&Delete</source>
|
<source>&Delete</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.ui" line="416"/>
|
<location filename="../MainWindow.ui" line="387"/>
|
||||||
<source>&Import Groups</source>
|
<source>&Import Groups</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.ui" line="419"/>
|
<location filename="../MainWindow.ui" line="390"/>
|
||||||
<source>Ctrl+I</source>
|
<source>Ctrl+I</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.ui" line="431"/>
|
<location filename="../MainWindow.ui" line="402"/>
|
||||||
<source>New SF&X Group</source>
|
<source>New SF&X Group</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.ui" line="443"/>
|
<location filename="../MainWindow.ui" line="414"/>
|
||||||
<source>New Son&g Group</source>
|
<source>New Son&g Group</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.ui" line="455"/>
|
<location filename="../MainWindow.ui" line="426"/>
|
||||||
<source>New Sound &Macro</source>
|
<source>New Sound &Macro</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.ui" line="467"/>
|
<location filename="../MainWindow.ui" line="438"/>
|
||||||
<source>New &Keymap</source>
|
<source>New &Keymap</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.ui" line="479"/>
|
<location filename="../MainWindow.ui" line="450"/>
|
||||||
<source>New &Layers</source>
|
<source>New &Layers</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.ui" line="490"/>
|
<location filename="../MainWindow.ui" line="461"/>
|
||||||
<source>&Auto-Play</source>
|
<source>&Auto-Play</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.ui" line="498"/>
|
<location filename="../MainWindow.ui" line="469"/>
|
||||||
<source>&Output Device:</source>
|
<source>&Output Device:</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.ui" line="506"/>
|
<location filename="../MainWindow.ui" line="477"/>
|
||||||
<source>&Input Device:</source>
|
<source>&Input Device:</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.ui" line="514"/>
|
<location filename="../MainWindow.ui" line="485"/>
|
||||||
<source>&Export GameCube Groups</source>
|
<source>&Export GameCube Groups</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.ui" line="517"/>
|
<location filename="../MainWindow.ui" line="488"/>
|
||||||
<source>Ctrl+E</source>
|
<source>Ctrl+E</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.ui" line="529"/>
|
<location filename="../MainWindow.ui" line="500"/>
|
||||||
<source>&New Subproject</source>
|
<source>&New Subproject</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.ui" line="541"/>
|
<location filename="../MainWindow.ui" line="512"/>
|
||||||
<source>New &ADSR</source>
|
<source>New &ADSR</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.ui" line="553"/>
|
<location filename="../MainWindow.ui" line="524"/>
|
||||||
<source>New &Curve</source>
|
<source>New &Curve</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.ui" line="561"/>
|
<location filename="../MainWindow.ui" line="532"/>
|
||||||
<source>&Save Project</source>
|
<source>&Save Project</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.ui" line="569"/>
|
<location filename="../MainWindow.ui" line="540"/>
|
||||||
<source>&Revert Project</source>
|
<source>&Revert Project</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.ui" line="577"/>
|
<location filename="../MainWindow.ui" line="548"/>
|
||||||
<source>Reload Sample &Data</source>
|
<source>Reload Sample &Data</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -431,194 +454,194 @@
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.cpp" line="66"/>
|
<location filename="../MainWindow.cpp" line="68"/>
|
||||||
<source>Clear Recent Projects</source>
|
<source>Clear Recent Projects</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.cpp" line="72"/>
|
<location filename="../MainWindow.cpp" line="74"/>
|
||||||
<source>Quit</source>
|
<source>Quit</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.cpp" line="189"/>
|
<location filename="../MainWindow.cpp" line="191"/>
|
||||||
<source>Amuse [%1/%2/%3]</source>
|
<source>Amuse [%1/%2/%3]</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.cpp" line="194"/>
|
<location filename="../MainWindow.cpp" line="196"/>
|
||||||
<source>Amuse [%1]</source>
|
<source>Amuse [%1]</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.cpp" line="225"/>
|
<location filename="../MainWindow.cpp" line="227"/>
|
||||||
<location filename="../MainWindow.cpp" line="581"/>
|
<location filename="../MainWindow.cpp" line="585"/>
|
||||||
<source>The directory at '%1' must not be empty.</source>
|
<source>The directory at '%1' must not be empty.</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.cpp" line="226"/>
|
<location filename="../MainWindow.cpp" line="228"/>
|
||||||
<location filename="../MainWindow.cpp" line="582"/>
|
<location filename="../MainWindow.cpp" line="586"/>
|
||||||
<source>Directory empty</source>
|
<source>Directory empty</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.cpp" line="231"/>
|
<location filename="../MainWindow.cpp" line="233"/>
|
||||||
<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 type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.cpp" line="232"/>
|
<location filename="../MainWindow.cpp" line="234"/>
|
||||||
<source>Directory does not exist</source>
|
<source>Directory does not exist</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.cpp" line="235"/>
|
<location filename="../MainWindow.cpp" line="237"/>
|
||||||
<source>test</source>
|
<source>__amuse_test__</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.cpp" line="239"/>
|
<location filename="../MainWindow.cpp" line="242"/>
|
||||||
<source>The directory at '%1' must be writable for the Amuse editor.</source>
|
<source>The directory at '%1' must be writable for the Amuse editor: %2</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.cpp" line="240"/>
|
<location filename="../MainWindow.cpp" line="244"/>
|
||||||
<source>Unable to write to directory</source>
|
<source>Unable to write to directory</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.cpp" line="286"/>
|
<location filename="../MainWindow.cpp" line="290"/>
|
||||||
<source>No Audio Devices Found</source>
|
<source>No Audio Devices Found</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.cpp" line="309"/>
|
<location filename="../MainWindow.cpp" line="313"/>
|
||||||
<source>No MIDI Devices Found</source>
|
<source>No MIDI Devices Found</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.cpp" line="348"/>
|
<location filename="../MainWindow.cpp" line="352"/>
|
||||||
<source>SUSTAIN</source>
|
<source>SUSTAIN</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.cpp" line="564"/>
|
<location filename="../MainWindow.cpp" line="568"/>
|
||||||
<source>New Project</source>
|
<source>New Project</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.cpp" line="587"/>
|
<location filename="../MainWindow.cpp" line="591"/>
|
||||||
<source>The directory at '%1' does not exist.</source>
|
<source>The directory at '%1' does not exist.</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.cpp" line="588"/>
|
<location filename="../MainWindow.cpp" line="592"/>
|
||||||
<source>Bad Directory</source>
|
<source>Bad Directory</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.cpp" line="603"/>
|
<location filename="../MainWindow.cpp" line="607"/>
|
||||||
<source>Opening</source>
|
<source>Opening</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.cpp" line="603"/>
|
<location filename="../MainWindow.cpp" line="607"/>
|
||||||
<location filename="../MainWindow.cpp" line="681"/>
|
<location filename="../MainWindow.cpp" line="686"/>
|
||||||
<location filename="../MainWindow.cpp" line="764"/>
|
<location filename="../MainWindow.cpp" line="769"/>
|
||||||
<location filename="../MainWindow.cpp" line="809"/>
|
<location filename="../MainWindow.cpp" line="814"/>
|
||||||
<source>Scanning Project</source>
|
<source>Scanning Project</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.cpp" line="615"/>
|
<location filename="../MainWindow.cpp" line="619"/>
|
||||||
<source>Opening %1</source>
|
<source>Opening %1</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.cpp" line="627"/>
|
<location filename="../MainWindow.cpp" line="632"/>
|
||||||
<source>Open Project</source>
|
<source>Open Project</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.cpp" line="681"/>
|
<location filename="../MainWindow.cpp" line="686"/>
|
||||||
<source>Reloading Samples</source>
|
<source>Reloading Samples</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.cpp" line="693"/>
|
<location filename="../MainWindow.cpp" line="698"/>
|
||||||
<source>Scanning %1</source>
|
<source>Scanning %1</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.cpp" line="703"/>
|
<location filename="../MainWindow.cpp" line="708"/>
|
||||||
<source>Import Project</source>
|
<source>Import Project</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.cpp" line="712"/>
|
<location filename="../MainWindow.cpp" line="717"/>
|
||||||
<source>The file at '%1' could not be interpreted as a MusyX container.</source>
|
<source>The file at '%1' could not be interpreted as a MusyX container.</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.cpp" line="713"/>
|
<location filename="../MainWindow.cpp" line="718"/>
|
||||||
<source>Unsupported MusyX Container</source>
|
<source>Unsupported MusyX Container</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.cpp" line="718"/>
|
<location filename="../MainWindow.cpp" line="723"/>
|
||||||
<source>Sample Import Mode</source>
|
<source>Sample Import Mode</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.cpp" line="719"/>
|
<location filename="../MainWindow.cpp" line="724"/>
|
||||||
<source>Amuse can import samples as WAV files for ease of editing, import original compressed data for lossless repacking, or both. Exporting the project will prefer whichever version was modified most recently.</source>
|
<source>Amuse can import samples as WAV files for ease of editing, import original compressed data for lossless repacking, or both. Exporting the project will prefer whichever version was modified most recently.</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.cpp" line="723"/>
|
<location filename="../MainWindow.cpp" line="728"/>
|
||||||
<source>Import Compressed</source>
|
<source>Import Compressed</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.cpp" line="723"/>
|
<location filename="../MainWindow.cpp" line="728"/>
|
||||||
<source>Import WAVs</source>
|
<source>Import WAVs</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.cpp" line="723"/>
|
<location filename="../MainWindow.cpp" line="728"/>
|
||||||
<source>Import Both</source>
|
<source>Import Both</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.cpp" line="739"/>
|
<location filename="../MainWindow.cpp" line="744"/>
|
||||||
<source>Raw Import Mode</source>
|
<source>Raw Import Mode</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.cpp" line="740"/>
|
<location filename="../MainWindow.cpp" line="745"/>
|
||||||
<source>Would you like to scan for all MusyX group files in this directory?</source>
|
<source>Would you like to scan for all MusyX group files in this directory?</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.cpp" line="750"/>
|
<location filename="../MainWindow.cpp" line="755"/>
|
||||||
<source>Project Name</source>
|
<source>Project Name</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.cpp" line="750"/>
|
<location filename="../MainWindow.cpp" line="755"/>
|
||||||
<source>What should this project be named?</source>
|
<source>What should this project be named?</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.cpp" line="764"/>
|
<location filename="../MainWindow.cpp" line="769"/>
|
||||||
<location filename="../MainWindow.cpp" line="809"/>
|
<location filename="../MainWindow.cpp" line="814"/>
|
||||||
<source>Importing</source>
|
<source>Importing</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../MainWindow.cpp" line="776"/>
|
<location filename="../MainWindow.cpp" line="781"/>
|
||||||
<location filename="../MainWindow.cpp" line="818"/>
|
<location filename="../MainWindow.cpp" line="823"/>
|
||||||
<source>Importing %1</source>
|
<source>Importing %1</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -631,6 +654,57 @@
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>PageModel</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../SongGroupEditor.cpp" line="231"/>
|
||||||
|
<source>Program Conflict</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../SongGroupEditor.cpp" line="232"/>
|
||||||
|
<source>Program %1 is already defined in table</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../SongGroupEditor.cpp" line="268"/>
|
||||||
|
<source>Program</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../SongGroupEditor.cpp" line="270"/>
|
||||||
|
<source>Object</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../SongGroupEditor.cpp" line="272"/>
|
||||||
|
<source>Priority</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../SongGroupEditor.cpp" line="274"/>
|
||||||
|
<source>Max Voices</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>PageObjectProxyModel</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../ProjectModel.cpp" line="235"/>
|
||||||
|
<source>SoundMacros:</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ProjectModel.cpp" line="237"/>
|
||||||
|
<source>Keymaps:</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../ProjectModel.cpp" line="239"/>
|
||||||
|
<source>Layers:</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PaintButton</name>
|
<name>PaintButton</name>
|
||||||
<message>
|
<message>
|
||||||
|
@ -650,37 +724,37 @@
|
||||||
<context>
|
<context>
|
||||||
<name>ProjectModel</name>
|
<name>ProjectModel</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ProjectModel.cpp" line="234"/>
|
<location filename="../ProjectModel.cpp" line="501"/>
|
||||||
<source>Sound Macros</source>
|
<source>Sound Macros</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ProjectModel.cpp" line="253"/>
|
<location filename="../ProjectModel.cpp" line="520"/>
|
||||||
<source>ADSRs</source>
|
<source>ADSRs</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ProjectModel.cpp" line="264"/>
|
<location filename="../ProjectModel.cpp" line="531"/>
|
||||||
<source>Curves</source>
|
<source>Curves</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ProjectModel.cpp" line="276"/>
|
<location filename="../ProjectModel.cpp" line="543"/>
|
||||||
<source>Keymaps</source>
|
<source>Keymaps</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ProjectModel.cpp" line="283"/>
|
<location filename="../ProjectModel.cpp" line="550"/>
|
||||||
<source>Layers</source>
|
<source>Layers</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ProjectModel.cpp" line="290"/>
|
<location filename="../ProjectModel.cpp" line="557"/>
|
||||||
<source>Samples</source>
|
<source>Samples</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ProjectModel.cpp" line="442"/>
|
<location filename="../ProjectModel.cpp" line="709"/>
|
||||||
<source>Delete %1</source>
|
<source>Delete %1</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -756,6 +830,95 @@
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>SetupListModel</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../SongGroupEditor.cpp" line="460"/>
|
||||||
|
<source>Song Conflict</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../SongGroupEditor.cpp" line="461"/>
|
||||||
|
<source>Song %1 is already defined in project</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../SongGroupEditor.cpp" line="482"/>
|
||||||
|
<source>Song</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../SongGroupEditor.cpp" line="484"/>
|
||||||
|
<source>MIDI File</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>SetupModel</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../SongGroupEditor.cpp" line="649"/>
|
||||||
|
<source>Program</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../SongGroupEditor.cpp" line="651"/>
|
||||||
|
<source>Volume</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../SongGroupEditor.cpp" line="653"/>
|
||||||
|
<source>Panning</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../SongGroupEditor.cpp" line="655"/>
|
||||||
|
<source>Reverb</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../SongGroupEditor.cpp" line="657"/>
|
||||||
|
<source>Chorus</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>SongGroupEditor</name>
|
||||||
|
<message>
|
||||||
|
<location filename="../SongGroupEditor.cpp" line="975"/>
|
||||||
|
<source>Add new page entry</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../SongGroupEditor.cpp" line="981"/>
|
||||||
|
<source>Remove selected page entries</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../SongGroupEditor.cpp" line="950"/>
|
||||||
|
<source>Add Row</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../SongGroupEditor.cpp" line="950"/>
|
||||||
|
<source>Remove Row</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../SongGroupEditor.cpp" line="952"/>
|
||||||
|
<source>Normal Pages</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../SongGroupEditor.cpp" line="953"/>
|
||||||
|
<source>Drum Pages</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../SongGroupEditor.cpp" line="954"/>
|
||||||
|
<source>MIDI Setups</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>SoundMacroCatalogue</name>
|
<name>SoundMacroCatalogue</name>
|
||||||
<message>
|
<message>
|
||||||
|
|
|
@ -71,8 +71,8 @@ struct SongGroupIndex : AudioGroupIndex
|
||||||
{
|
{
|
||||||
AT_DECL_DNA_YAML
|
AT_DECL_DNA_YAML
|
||||||
PageObjectIdDNA<athena::Big> objId;
|
PageObjectIdDNA<athena::Big> objId;
|
||||||
Value<atUint8> priority;
|
Value<atUint8> priority = 0;
|
||||||
Value<atUint8> maxVoices;
|
Value<atUint8> maxVoices = 255;
|
||||||
|
|
||||||
PageEntry() = default;
|
PageEntry() = default;
|
||||||
|
|
||||||
|
@ -112,11 +112,11 @@ struct SongGroupIndex : AudioGroupIndex
|
||||||
struct MIDISetup : BigDNA
|
struct MIDISetup : BigDNA
|
||||||
{
|
{
|
||||||
AT_DECL_DNA_YAML
|
AT_DECL_DNA_YAML
|
||||||
Value<atUint8> programNo;
|
Value<atUint8> programNo = 0;
|
||||||
Value<atUint8> volume;
|
Value<atUint8> volume = 127;
|
||||||
Value<atUint8> panning;
|
Value<atUint8> panning = 64;
|
||||||
Value<atUint8> reverb;
|
Value<atUint8> reverb = 0;
|
||||||
Value<atUint8> chorus;
|
Value<atUint8> chorus = 0;
|
||||||
MIDISetup() = default;
|
MIDISetup() = default;
|
||||||
MIDISetup(const MusyX1MIDISetup& setup)
|
MIDISetup(const MusyX1MIDISetup& setup)
|
||||||
: programNo(setup.programNo), volume(setup.volume), panning(setup.panning),
|
: programNo(setup.programNo), volume(setup.volume), panning(setup.panning),
|
||||||
|
|
|
@ -620,6 +620,8 @@ struct NameDB
|
||||||
std::string_view registerPair(std::string_view str, ObjectId id);
|
std::string_view registerPair(std::string_view str, ObjectId id);
|
||||||
std::string_view resolveNameFromId(ObjectId id) const;
|
std::string_view resolveNameFromId(ObjectId id) const;
|
||||||
ObjectId resolveIdFromName(std::string_view str) const;
|
ObjectId resolveIdFromName(std::string_view str) const;
|
||||||
|
void remove(ObjectId id);
|
||||||
|
void rename(ObjectId id, std::string_view str);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -166,7 +166,15 @@ void PageObjectIdDNA<DNAE>::_read(athena::io::YAMLDocReader& r)
|
||||||
{
|
{
|
||||||
search = LayersId::CurNameDB->m_stringToId.find(name);
|
search = LayersId::CurNameDB->m_stringToId.find(name);
|
||||||
if (search == LayersId::CurNameDB->m_stringToId.cend())
|
if (search == LayersId::CurNameDB->m_stringToId.cend())
|
||||||
Log.report(logvisor::Fatal, "Unable to resolve name %s", name.c_str());
|
{
|
||||||
|
search = SoundMacroId::CurNameDB->m_stringToId.find(name);
|
||||||
|
if (search == SoundMacroId::CurNameDB->m_stringToId.cend())
|
||||||
|
{
|
||||||
|
Log.report(logvisor::Error, "Unable to resolve name %s", name.c_str());
|
||||||
|
id.id = 0xffff;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
id = search->second;
|
id = search->second;
|
||||||
}
|
}
|
||||||
|
@ -261,7 +269,11 @@ template struct SoundMacroStepDNA<athena::Little>;
|
||||||
|
|
||||||
ObjectId NameDB::generateId(Type tp) const
|
ObjectId NameDB::generateId(Type tp) const
|
||||||
{
|
{
|
||||||
uint16_t maxMatch = uint16_t(tp == Type::Layer ? 0x8000 : 0);
|
uint16_t maxMatch = 0;
|
||||||
|
if (tp == Type::Layer)
|
||||||
|
maxMatch = 0x8000;
|
||||||
|
else if (tp == Type::Keymap)
|
||||||
|
maxMatch = 0x4000;
|
||||||
for (const auto& p : m_idToString)
|
for (const auto& p : m_idToString)
|
||||||
if (p.first >= maxMatch)
|
if (p.first >= maxMatch)
|
||||||
maxMatch = p.first + 1;
|
maxMatch = p.first + 1;
|
||||||
|
@ -332,6 +344,32 @@ ObjectId NameDB::resolveIdFromName(std::string_view str) const
|
||||||
return search->second;
|
return search->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NameDB::remove(ObjectId id)
|
||||||
|
{
|
||||||
|
auto search = m_idToString.find(id);
|
||||||
|
if (search == m_idToString.cend())
|
||||||
|
return;
|
||||||
|
auto search2 = m_stringToId.find(search->second);
|
||||||
|
if (search2 == m_stringToId.cend())
|
||||||
|
return;
|
||||||
|
m_idToString.erase(search);
|
||||||
|
m_stringToId.erase(search2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NameDB::rename(ObjectId id, std::string_view str)
|
||||||
|
{
|
||||||
|
auto search = m_idToString.find(id);
|
||||||
|
if (search == m_idToString.cend())
|
||||||
|
return;
|
||||||
|
auto search2 = m_stringToId.find(search->second);
|
||||||
|
if (search2 == m_stringToId.cend())
|
||||||
|
return;
|
||||||
|
auto nh = m_stringToId.extract(search2);
|
||||||
|
nh.key() = str;
|
||||||
|
m_stringToId.insert(std::move(nh));
|
||||||
|
m_idToString[id] = str;
|
||||||
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void LittleUInt24::Enumerate<LittleDNA::Read>(athena::io::IStreamReader& reader)
|
void LittleUInt24::Enumerate<LittleDNA::Read>(athena::io::IStreamReader& reader)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue