mirror of https://github.com/AxioDL/amuse.git
Clipboard support and various bug fixes
This commit is contained in:
parent
cefa0ac18c
commit
27cdee0c14
|
@ -91,8 +91,22 @@ void FieldDoubleSlider::doValueChanged(int value)
|
|||
}
|
||||
|
||||
FieldProjectNode::FieldProjectNode(ProjectModel::CollectionNode* collection, QWidget* parent)
|
||||
: FieldComboBox(parent)
|
||||
: QWidget(parent), m_comboBox(this), m_button(this)
|
||||
{
|
||||
m_button.setDisabled(true);
|
||||
m_button.setFixedSize(30, 30);
|
||||
m_comboBox.setFixedHeight(30);
|
||||
connect(&m_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(_currentIndexChanged(int)));
|
||||
connect(&m_button, SIGNAL(clicked(bool)), this, SLOT(openCurrent()));
|
||||
QIcon icon(QStringLiteral(":/icons/IconForward.svg"));
|
||||
icon.addFile(QStringLiteral(":/icons/IconForwardDisabled.svg"), {}, QIcon::Disabled);
|
||||
m_button.setIcon(icon);
|
||||
QHBoxLayout* layout = new QHBoxLayout;
|
||||
layout->setContentsMargins({});
|
||||
layout->setSpacing(0);
|
||||
layout->addWidget(&m_comboBox);
|
||||
layout->addWidget(&m_button);
|
||||
setLayout(layout);
|
||||
setCollection(collection);
|
||||
}
|
||||
|
||||
|
@ -102,18 +116,65 @@ void FieldProjectNode::setCollection(ProjectModel::CollectionNode* collection)
|
|||
|
||||
if (!collection)
|
||||
{
|
||||
setModel(new QStandardItemModel(0, 1, this));
|
||||
m_comboBox.setModel(new QStandardItemModel(0, 1, this));
|
||||
m_button.setDisabled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
ProjectModel* model = g_MainWindow->projectModel();
|
||||
setModel(model->getNullProxy());
|
||||
setRootModelIndex(model->getNullProxy()->mapFromSource(model->index(collection)));
|
||||
m_comboBox.setModel(model->getNullProxy());
|
||||
m_comboBox.setRootModelIndex(model->getNullProxy()->mapFromSource(model->index(collection)));
|
||||
}
|
||||
|
||||
void FieldProjectNode::_currentIndexChanged(int index)
|
||||
{
|
||||
m_button.setEnabled(index != 0);
|
||||
emit currentIndexChanged(index);
|
||||
}
|
||||
|
||||
ProjectModel::BasePoolObjectNode* FieldProjectNode::currentNode() const
|
||||
{
|
||||
int index = m_comboBox.currentIndex();
|
||||
if (index == 0)
|
||||
return nullptr;
|
||||
else
|
||||
return m_collection->nodeOfIndex(index - 1);
|
||||
}
|
||||
|
||||
bool FieldProjectNode::event(QEvent* ev)
|
||||
{
|
||||
if (ev->type() == QEvent::User)
|
||||
{
|
||||
showPopup();
|
||||
return true;
|
||||
}
|
||||
return QWidget::event(ev);
|
||||
}
|
||||
|
||||
void FieldProjectNode::openCurrent()
|
||||
{
|
||||
if (ProjectModel::BasePoolObjectNode* node = currentNode())
|
||||
if (!g_MainWindow->isUiDisabled())
|
||||
g_MainWindow->openEditor(node);
|
||||
}
|
||||
|
||||
FieldPageObjectNode::FieldPageObjectNode(ProjectModel::GroupNode* group, QWidget* parent)
|
||||
: FieldComboBox(parent)
|
||||
: QWidget(parent), m_comboBox(this), m_button(this)
|
||||
{
|
||||
m_button.setDisabled(true);
|
||||
m_button.setFixedSize(30, 30);
|
||||
m_comboBox.setFixedHeight(30);
|
||||
connect(&m_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(_currentIndexChanged(int)));
|
||||
connect(&m_button, SIGNAL(clicked(bool)), this, SLOT(openCurrent()));
|
||||
QIcon icon(QStringLiteral(":/icons/IconForward.svg"));
|
||||
icon.addFile(QStringLiteral(":/icons/IconForwardDisabled.svg"), {}, QIcon::Disabled);
|
||||
m_button.setIcon(icon);
|
||||
QHBoxLayout* layout = new QHBoxLayout;
|
||||
layout->setContentsMargins({});
|
||||
layout->setSpacing(0);
|
||||
layout->addWidget(&m_comboBox);
|
||||
layout->addWidget(&m_button);
|
||||
setLayout(layout);
|
||||
setGroup(group);
|
||||
}
|
||||
|
||||
|
@ -123,13 +184,53 @@ void FieldPageObjectNode::setGroup(ProjectModel::GroupNode* group)
|
|||
|
||||
if (!group)
|
||||
{
|
||||
setModel(new QStandardItemModel(0, 1, this));
|
||||
m_comboBox.setModel(new QStandardItemModel(0, 1, this));
|
||||
m_button.setDisabled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
ProjectModel* model = g_MainWindow->projectModel();
|
||||
setModel(model->getPageObjectProxy());
|
||||
setRootModelIndex(model->getPageObjectProxy()->mapFromSource(model->index(group)));
|
||||
m_comboBox.setModel(model->getPageObjectProxy());
|
||||
m_comboBox.setRootModelIndex(model->getPageObjectProxy()->mapFromSource(model->index(group)));
|
||||
}
|
||||
|
||||
void FieldPageObjectNode::_currentIndexChanged(int index)
|
||||
{
|
||||
m_button.setEnabled(index != 0);
|
||||
emit currentIndexChanged(index);
|
||||
}
|
||||
|
||||
ProjectModel::BasePoolObjectNode* FieldPageObjectNode::currentNode() const
|
||||
{
|
||||
int index = m_comboBox.currentIndex();
|
||||
if (index == 0)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
ProjectModel* model = g_MainWindow->projectModel();
|
||||
return static_cast<ProjectModel::BasePoolObjectNode*>(
|
||||
model->node(model->getPageObjectProxy()->mapToSource(
|
||||
model->getPageObjectProxy()->index(index, 0, m_comboBox.rootModelIndex()))));
|
||||
}
|
||||
}
|
||||
|
||||
bool FieldPageObjectNode::event(QEvent* ev)
|
||||
{
|
||||
if (ev->type() == QEvent::User)
|
||||
{
|
||||
showPopup();
|
||||
return true;
|
||||
}
|
||||
return QWidget::event(ev);
|
||||
}
|
||||
|
||||
void FieldPageObjectNode::openCurrent()
|
||||
{
|
||||
if (ProjectModel::BasePoolObjectNode* node = currentNode())
|
||||
if (!g_MainWindow->isUiDisabled())
|
||||
g_MainWindow->openEditor(node);
|
||||
}
|
||||
|
||||
AddRemoveButtons::AddRemoveButtons(QWidget* parent)
|
||||
|
|
|
@ -23,7 +23,7 @@ public:
|
|||
virtual void unloadData() {}
|
||||
virtual ProjectModel::INode* currentNode() const { return nullptr; }
|
||||
virtual void setEditorEnabled(bool en) { setEnabled(en); }
|
||||
virtual bool isItemEditEnabled() const { return false; }
|
||||
virtual AmuseItemEditFlags itemEditFlags() const { return AmuseItemNone; }
|
||||
public slots:
|
||||
virtual void itemCutAction() {}
|
||||
virtual void itemCopyAction() {}
|
||||
|
@ -125,24 +125,51 @@ public:
|
|||
void wheelEvent(QWheelEvent* event) { event->ignore(); }
|
||||
};
|
||||
|
||||
class FieldProjectNode : public FieldComboBox
|
||||
class FieldProjectNode : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
ProjectModel::CollectionNode* m_collection;
|
||||
FieldComboBox m_comboBox;
|
||||
QPushButton m_button;
|
||||
public:
|
||||
explicit FieldProjectNode(ProjectModel::CollectionNode* collection = Q_NULLPTR, QWidget* parent = Q_NULLPTR);
|
||||
void setCollection(ProjectModel::CollectionNode* collection);
|
||||
ProjectModel::CollectionNode* collection() const { return m_collection; }
|
||||
int currentIndex() const { return m_comboBox.currentIndex(); }
|
||||
void setCurrentIndex(int index) { m_comboBox.setCurrentIndex(index); }
|
||||
void showPopup() { m_comboBox.showPopup(); }
|
||||
ProjectModel::BasePoolObjectNode* currentNode() const;
|
||||
bool event(QEvent* ev);
|
||||
private slots:
|
||||
void _currentIndexChanged(int);
|
||||
public slots:
|
||||
void openCurrent();
|
||||
signals:
|
||||
void currentIndexChanged(int);
|
||||
};
|
||||
|
||||
class FieldPageObjectNode : public FieldComboBox
|
||||
class FieldPageObjectNode : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
ProjectModel::GroupNode* m_group;
|
||||
FieldComboBox m_comboBox;
|
||||
QPushButton m_button;
|
||||
public:
|
||||
explicit FieldPageObjectNode(ProjectModel::GroupNode* group = Q_NULLPTR, QWidget* parent = Q_NULLPTR);
|
||||
void setGroup(ProjectModel::GroupNode* group);
|
||||
ProjectModel::GroupNode* group() const { return m_group; }
|
||||
int currentIndex() const { return m_comboBox.currentIndex(); }
|
||||
void setCurrentIndex(int index) { m_comboBox.setCurrentIndex(index); }
|
||||
QModelIndex rootModelIndex() const { return m_comboBox.rootModelIndex(); }
|
||||
void showPopup() { m_comboBox.showPopup(); }
|
||||
ProjectModel::BasePoolObjectNode* currentNode() const;
|
||||
bool event(QEvent* ev);
|
||||
private slots:
|
||||
void _currentIndexChanged(int);
|
||||
public slots:
|
||||
void openCurrent();
|
||||
signals:
|
||||
void currentIndexChanged(int);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
|
|
|
@ -118,7 +118,7 @@ void SoundMacroDelegate::setEditorData(QWidget* editor, const QModelIndex& index
|
|||
ProjectModel::CollectionNode* smColl = group->getCollectionOfType(ProjectModel::INode::Type::SoundMacro);
|
||||
static_cast<EditorFieldProjectNode*>(editor)->setCurrentIndex(smColl->indexOfId(layer.macro.id) + 1);
|
||||
if (static_cast<EditorFieldProjectNode*>(editor)->shouldPopupOpen())
|
||||
static_cast<EditorFieldProjectNode*>(editor)->showPopup();
|
||||
QApplication::postEvent(editor, new QEvent(QEvent::User));
|
||||
}
|
||||
|
||||
void SoundMacroDelegate::setModelData(QWidget* editor, QAbstractItemModel* m, const QModelIndex& index) const
|
||||
|
@ -636,24 +636,9 @@ void LayersEditor::doSelectionChanged()
|
|||
g_MainWindow->updateFocus();
|
||||
}
|
||||
|
||||
bool LayersEditor::isItemEditEnabled() const
|
||||
AmuseItemEditFlags LayersEditor::itemEditFlags() const
|
||||
{
|
||||
return !m_tableView.selectionModel()->selectedRows().isEmpty();
|
||||
}
|
||||
|
||||
void LayersEditor::itemCutAction()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void LayersEditor::itemCopyAction()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void LayersEditor::itemPasteAction()
|
||||
{
|
||||
|
||||
return m_tableView.selectionModel()->selectedRows().isEmpty() ? AmuseItemNone : AmuseItemDelete;
|
||||
}
|
||||
|
||||
void LayersEditor::itemDeleteAction()
|
||||
|
|
|
@ -78,14 +78,10 @@ public:
|
|||
void unloadData();
|
||||
ProjectModel::INode* currentNode() const;
|
||||
void resizeEvent(QResizeEvent* ev);
|
||||
bool isItemEditEnabled() const;
|
||||
AmuseItemEditFlags itemEditFlags() const;
|
||||
public slots:
|
||||
void doAdd();
|
||||
void doSelectionChanged();
|
||||
|
||||
void itemCutAction();
|
||||
void itemCopyAction();
|
||||
void itemPasteAction();
|
||||
void itemDeleteAction();
|
||||
};
|
||||
|
||||
|
|
|
@ -6,6 +6,9 @@ MIDIReader::MIDIReader(amuse::Engine& engine, bool useLock)
|
|||
|
||||
void MIDIReader::noteOff(uint8_t chan, uint8_t key, uint8_t velocity)
|
||||
{
|
||||
if (g_MainWindow->m_interactiveSeq)
|
||||
g_MainWindow->m_interactiveSeq->keyOff(chan, key, velocity);
|
||||
|
||||
auto keySearch = m_chanVoxs.find(key);
|
||||
if (keySearch == m_chanVoxs.cend())
|
||||
return;
|
||||
|
@ -19,6 +22,9 @@ void MIDIReader::noteOff(uint8_t chan, uint8_t key, uint8_t velocity)
|
|||
|
||||
void MIDIReader::noteOn(uint8_t chan, uint8_t key, uint8_t velocity)
|
||||
{
|
||||
if (g_MainWindow->m_interactiveSeq)
|
||||
g_MainWindow->m_interactiveSeq->keyOn(chan, key, velocity);
|
||||
|
||||
if (m_lastVoice && m_lastVoice->isDestroyed())
|
||||
m_lastVoice.reset();
|
||||
|
||||
|
@ -48,13 +54,19 @@ void MIDIReader::noteOn(uint8_t chan, uint8_t key, uint8_t velocity)
|
|||
|
||||
amuse::ObjToken<amuse::Voice> newVox = g_MainWindow->startEditorVoice(key, velocity);
|
||||
if (newVox)
|
||||
{
|
||||
m_chanVoxs[key] = newVox;
|
||||
m_lastVoice = newVox;
|
||||
}
|
||||
}
|
||||
|
||||
void MIDIReader::notePressure(uint8_t /*chan*/, uint8_t /*key*/, uint8_t /*pressure*/) {}
|
||||
|
||||
void MIDIReader::controlChange(uint8_t chan, uint8_t control, uint8_t value)
|
||||
{
|
||||
if (g_MainWindow->m_interactiveSeq)
|
||||
g_MainWindow->m_interactiveSeq->setCtrlValue(chan, control, value);
|
||||
|
||||
if (control == 1)
|
||||
{
|
||||
g_MainWindow->m_ui.modulationSlider->setValue(int(value));
|
||||
|
@ -71,17 +83,28 @@ void MIDIReader::controlChange(uint8_t chan, uint8_t control, uint8_t value)
|
|||
g_MainWindow->m_ctrlVals[control] = value;
|
||||
}
|
||||
|
||||
void MIDIReader::programChange(uint8_t chan, uint8_t program) {}
|
||||
void MIDIReader::programChange(uint8_t chan, uint8_t program)
|
||||
{
|
||||
if (g_MainWindow->m_interactiveSeq)
|
||||
g_MainWindow->m_interactiveSeq->setChanProgram(chan, program);
|
||||
}
|
||||
|
||||
void MIDIReader::channelPressure(uint8_t /*chan*/, uint8_t /*pressure*/) {}
|
||||
|
||||
void MIDIReader::pitchBend(uint8_t chan, int16_t pitch)
|
||||
{
|
||||
g_MainWindow->m_ui.pitchSlider->setValue(int((pitch - 0x2000) / float(0x2000) * 2048.f));
|
||||
float pWheel = (pitch - 0x2000) / float(0x2000);
|
||||
if (g_MainWindow->m_interactiveSeq)
|
||||
g_MainWindow->m_interactiveSeq->setPitchWheel(chan, pWheel);
|
||||
else
|
||||
g_MainWindow->m_ui.pitchSlider->setValue(int(pWheel * 2048.f));
|
||||
}
|
||||
|
||||
void MIDIReader::allSoundOff(uint8_t chan)
|
||||
{
|
||||
if (g_MainWindow->m_interactiveSeq)
|
||||
g_MainWindow->m_interactiveSeq->kill();
|
||||
|
||||
for (auto& v : m_engine.getActiveVoices())
|
||||
v->kill();
|
||||
}
|
||||
|
@ -92,6 +115,9 @@ void MIDIReader::localControl(uint8_t /*chan*/, bool /*on*/) {}
|
|||
|
||||
void MIDIReader::allNotesOff(uint8_t chan)
|
||||
{
|
||||
if (g_MainWindow->m_interactiveSeq)
|
||||
g_MainWindow->m_interactiveSeq->kill();
|
||||
|
||||
for (auto& v : m_engine.getActiveVoices())
|
||||
v->kill();
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <QInputDialog>
|
||||
#include <QProgressDialog>
|
||||
#include <QMouseEvent>
|
||||
#include <QClipboard>
|
||||
#include <QtSvg/QtSvg>
|
||||
#include "amuse/ContainerRegistry.hpp"
|
||||
#include "Common.hpp"
|
||||
|
@ -21,6 +22,7 @@
|
|||
|
||||
MainWindow::MainWindow(QWidget* parent)
|
||||
: QMainWindow(parent),
|
||||
m_navIt(m_navList.begin()),
|
||||
m_treeDelegate(*this, this),
|
||||
m_mainMessenger(this),
|
||||
m_filterProjectModel(this),
|
||||
|
@ -41,6 +43,17 @@ MainWindow::MainWindow(QWidget* parent)
|
|||
m_ui.projectOutline->setItemDelegate(&m_treeDelegate);
|
||||
connect(m_ui.projectOutline, SIGNAL(activated(const QModelIndex&)),
|
||||
this, SLOT(outlineItemActivated(const QModelIndex&)));
|
||||
m_goBack = new QAction(m_ui.backButton->icon(), tr("Go Back"), this);
|
||||
m_goBack->setEnabled(false);
|
||||
connect(m_goBack, SIGNAL(triggered()), this, SLOT(goBack()));
|
||||
m_goBack->setShortcut(QKeySequence::Back);
|
||||
m_ui.backButton->setDefaultAction(m_goBack);
|
||||
m_goForward = new QAction(m_ui.forwardButton->icon(), tr("Go Forward"), this);
|
||||
m_goForward->setEnabled(false);
|
||||
connect(m_goForward, SIGNAL(triggered()), this, SLOT(goForward()));
|
||||
m_goForward->setShortcut(QKeySequence::Forward);
|
||||
m_ui.forwardButton->setDefaultAction(m_goForward);
|
||||
|
||||
connectMessenger(&m_mainMessenger, Qt::DirectConnection);
|
||||
|
||||
m_ui.statusbar->connectKillClicked(this, SLOT(killSounds()));
|
||||
|
@ -71,6 +84,10 @@ MainWindow::MainWindow(QWidget* parent)
|
|||
connect(m_ui.actionImport_Groups, SIGNAL(triggered()), this, SLOT(importAction()));
|
||||
connect(m_ui.actionImport_Songs, SIGNAL(triggered()), this, SLOT(importSongsAction()));
|
||||
connect(m_ui.actionExport_GameCube_Groups, SIGNAL(triggered()), this, SLOT(exportAction()));
|
||||
connect(m_ui.actionImport_C_Headers, SIGNAL(triggered()), this, SLOT(importHeadersAction()));
|
||||
connect(m_ui.actionExport_C_Headers, SIGNAL(triggered()), this, SLOT(exportHeadersAction()));
|
||||
m_ui.actionQuit->setShortcut(QKeySequence::Quit);
|
||||
connect(m_ui.actionQuit, SIGNAL(triggered()), qApp, SLOT(quit()));
|
||||
|
||||
for (int i = 0; i < MaxRecentFiles; ++i)
|
||||
{
|
||||
|
@ -84,21 +101,16 @@ MainWindow::MainWindow(QWidget* parent)
|
|||
connect(m_clearRecentFileAct, SIGNAL(triggered()), this, SLOT(clearRecentFilesAction()));
|
||||
m_ui.menuRecent_Projects->addAction(m_clearRecentFileAct);
|
||||
|
||||
#ifndef __APPLE__
|
||||
m_ui.menuFile->addSeparator();
|
||||
QAction* quitAction = m_ui.menuFile->addAction(tr("Quit"));
|
||||
quitAction->setShortcut(QKeySequence::Quit);
|
||||
connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
|
||||
#endif
|
||||
|
||||
updateRecentFileActions();
|
||||
|
||||
connect(m_undoStack, SIGNAL(cleanChanged(bool)), this, SLOT(cleanChanged(bool)));
|
||||
QAction* undoAction = m_undoStack->createUndoAction(this);
|
||||
undoAction->setShortcut(QKeySequence::Undo);
|
||||
undoAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-undo")));
|
||||
m_ui.menuEdit->insertAction(m_ui.actionCut, undoAction);
|
||||
QAction* redoAction = m_undoStack->createRedoAction(this);
|
||||
redoAction->setShortcut(QKeySequence::Redo);
|
||||
redoAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-redo")));
|
||||
m_ui.menuEdit->insertAction(m_ui.actionCut, redoAction);
|
||||
m_ui.menuEdit->insertSeparator(m_ui.actionCut);
|
||||
m_ui.actionCut->setShortcut(QKeySequence::Cut);
|
||||
|
@ -153,6 +165,7 @@ MainWindow::MainWindow(QWidget* parent)
|
|||
connect(m_ui.menuMIDI, SIGNAL(aboutToShow()), this, SLOT(aboutToShowMIDIIOMenu()));
|
||||
|
||||
connect(qApp, SIGNAL(focusChanged(QWidget*,QWidget*)), this, SLOT(onFocusChanged(QWidget*,QWidget*)));
|
||||
connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()), this, SLOT(onClipboardChanged()));
|
||||
|
||||
m_voxEngine = boo::NewAudioVoiceEngine();
|
||||
m_voxAllocator = std::make_unique<VoiceAllocator>(*m_voxEngine);
|
||||
|
@ -233,6 +246,7 @@ void MainWindow::updateRecentFileActions()
|
|||
QString text = QStringLiteral("&%1 %2").arg(i + 1).arg(QDir(files[i]).dirName());
|
||||
m_recentFileActs[i]->setText(text);
|
||||
m_recentFileActs[i]->setData(files[i]);
|
||||
m_recentFileActs[i]->setToolTip(files[i]);
|
||||
m_recentFileActs[i]->setVisible(true);
|
||||
}
|
||||
for (int j = numRecentFiles; j < MaxRecentFiles; ++j)
|
||||
|
@ -282,11 +296,17 @@ bool MainWindow::setProjectPath(const QString& path)
|
|||
m_ui.actionReload_Sample_Data->setEnabled(true);
|
||||
m_ui.actionImport_Songs->setEnabled(true);
|
||||
m_ui.actionExport_GameCube_Groups->setEnabled(true);
|
||||
m_ui.actionImport_C_Headers->setEnabled(true);
|
||||
m_ui.actionExport_C_Headers->setEnabled(true);
|
||||
m_ui.actionNew_Subproject->setEnabled(true);
|
||||
setWindowFilePath(path);
|
||||
updateWindowTitle();
|
||||
updateFocus();
|
||||
m_undoStack->clear();
|
||||
m_navList.clear();
|
||||
m_navIt = m_navList.begin();
|
||||
|
||||
updateNavigationButtons();
|
||||
|
||||
QSettings settings;
|
||||
QStringList files = settings.value("recentFileList").toStringList();
|
||||
|
@ -399,9 +419,8 @@ void MainWindow::timerEvent(QTimerEvent* ev)
|
|||
for (int i = 0; i < songTable->model()->rowCount(); ++i)
|
||||
if (MIDIPlayerWidget* player = qobject_cast<MIDIPlayerWidget*>(
|
||||
songTable->indexWidget(songTable->model()->index(i, 1))))
|
||||
for (auto& p : m_engine->getActiveSequencers())
|
||||
if (p.get() == player->sequencer() && p->state() != amuse::SequencerState::Playing)
|
||||
player->stopped();
|
||||
if (player->sequencer() && player->sequencer()->state() != amuse::SequencerState::Playing)
|
||||
player->stopped();
|
||||
|
||||
QTableView* sfxTable = m_soundGroupEditor->getSFXListView();
|
||||
for (int i = 0; i < sfxTable->model()->rowCount(); ++i)
|
||||
|
@ -481,83 +500,119 @@ void MainWindow::startBackgroundTask(int id, const QString& windowTitle, const Q
|
|||
QMetaObject::invokeMethod(m_backgroundTask, "run", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
bool MainWindow::_setEditor(EditorWidget* editor)
|
||||
bool MainWindow::_setEditor(EditorWidget* editor, bool appendNav)
|
||||
{
|
||||
m_interactiveSeq.reset();
|
||||
if (editor != m_ui.editorContents->currentWidget() &&
|
||||
m_ui.editorContents->currentWidget() != m_faceSvg)
|
||||
getEditorWidget()->unloadData();
|
||||
if (appendNav && m_navIt != m_navList.end())
|
||||
m_navList.erase(m_navIt + 1, m_navList.end());
|
||||
if (!editor || !editor->valid())
|
||||
{
|
||||
m_ui.editorContents->setCurrentWidget(m_faceSvg);
|
||||
updateWindowTitle();
|
||||
if (appendNav)
|
||||
{
|
||||
m_navIt = m_navList.end();
|
||||
updateNavigationButtons();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
m_ui.editorContents->setCurrentWidget(editor);
|
||||
m_ui.editorContents->update();
|
||||
updateWindowTitle();
|
||||
ProjectModel::INode* currentNode = editor->currentNode();
|
||||
if (appendNav)
|
||||
{
|
||||
if (m_navIt == m_navList.end() || *m_navIt != currentNode)
|
||||
m_navIt = m_navList.insert(m_navList.end(), currentNode);
|
||||
updateNavigationButtons();
|
||||
}
|
||||
recursiveExpandAndSelectOutline(m_projectModel->index(currentNode));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MainWindow::openEditor(ProjectModel::SongGroupNode* node)
|
||||
bool MainWindow::openEditor(ProjectModel::SongGroupNode* node, bool appendNav)
|
||||
{
|
||||
return _setEditor(m_songGroupEditor->loadData(node) ? m_songGroupEditor : nullptr);
|
||||
bool ret = _setEditor(m_songGroupEditor->loadData(node) ? m_songGroupEditor : nullptr, appendNav);
|
||||
if (ProjectModel::INode* n = getEditorNode())
|
||||
{
|
||||
if (n->type() == ProjectModel::INode::Type::SongGroup)
|
||||
{
|
||||
ProjectModel::SongGroupNode* cn = static_cast<ProjectModel::SongGroupNode*>(n);
|
||||
ProjectModel::GroupNode* gn = m_projectModel->getGroupNode(n);
|
||||
m_interactiveSeq = m_engine->seqPlay(gn->getAudioGroup(), cn->m_id, {}, nullptr);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool MainWindow::openEditor(ProjectModel::SoundGroupNode* node)
|
||||
bool MainWindow::openEditor(ProjectModel::SoundGroupNode* node, bool appendNav)
|
||||
{
|
||||
return _setEditor(m_soundGroupEditor->loadData(node) ? m_soundGroupEditor : nullptr);
|
||||
bool ret = _setEditor(m_soundGroupEditor->loadData(node) ? m_soundGroupEditor : nullptr, appendNav);
|
||||
if (ProjectModel::INode* n = getEditorNode())
|
||||
{
|
||||
if (n->type() == ProjectModel::INode::Type::SoundGroup)
|
||||
{
|
||||
ProjectModel::SoundGroupNode* cn = static_cast<ProjectModel::SoundGroupNode*>(n);
|
||||
ProjectModel::GroupNode* gn = m_projectModel->getGroupNode(n);
|
||||
m_interactiveSeq = m_engine->seqPlay(gn->getAudioGroup(), cn->m_id, {}, nullptr);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool MainWindow::openEditor(ProjectModel::SoundMacroNode* node)
|
||||
bool MainWindow::openEditor(ProjectModel::SoundMacroNode* node, bool appendNav)
|
||||
{
|
||||
return _setEditor(m_soundMacroEditor->loadData(node) ? m_soundMacroEditor : nullptr);
|
||||
return _setEditor(m_soundMacroEditor->loadData(node) ? m_soundMacroEditor : nullptr, appendNav);
|
||||
}
|
||||
|
||||
bool MainWindow::openEditor(ProjectModel::ADSRNode* node)
|
||||
bool MainWindow::openEditor(ProjectModel::ADSRNode* node, bool appendNav)
|
||||
{
|
||||
return _setEditor(m_adsrEditor->loadData(node) ? m_adsrEditor : nullptr);
|
||||
return _setEditor(m_adsrEditor->loadData(node) ? m_adsrEditor : nullptr, appendNav);
|
||||
}
|
||||
|
||||
bool MainWindow::openEditor(ProjectModel::CurveNode* node)
|
||||
bool MainWindow::openEditor(ProjectModel::CurveNode* node, bool appendNav)
|
||||
{
|
||||
return _setEditor(m_curveEditor->loadData(node) ? m_curveEditor : nullptr);
|
||||
return _setEditor(m_curveEditor->loadData(node) ? m_curveEditor : nullptr, appendNav);
|
||||
}
|
||||
|
||||
bool MainWindow::openEditor(ProjectModel::KeymapNode* node)
|
||||
bool MainWindow::openEditor(ProjectModel::KeymapNode* node, bool appendNav)
|
||||
{
|
||||
return _setEditor(m_keymapEditor->loadData(node) ? m_keymapEditor : nullptr);
|
||||
return _setEditor(m_keymapEditor->loadData(node) ? m_keymapEditor : nullptr, appendNav);
|
||||
}
|
||||
|
||||
bool MainWindow::openEditor(ProjectModel::LayersNode* node)
|
||||
bool MainWindow::openEditor(ProjectModel::LayersNode* node, bool appendNav)
|
||||
{
|
||||
return _setEditor(m_layersEditor->loadData(node) ? m_layersEditor : nullptr);
|
||||
return _setEditor(m_layersEditor->loadData(node) ? m_layersEditor : nullptr, appendNav);
|
||||
}
|
||||
|
||||
bool MainWindow::openEditor(ProjectModel::SampleNode* node)
|
||||
bool MainWindow::openEditor(ProjectModel::SampleNode* node, bool appendNav)
|
||||
{
|
||||
return _setEditor(m_sampleEditor->loadData(node) ? m_sampleEditor : nullptr);
|
||||
return _setEditor(m_sampleEditor->loadData(node) ? m_sampleEditor : nullptr, appendNav);
|
||||
}
|
||||
|
||||
bool MainWindow::openEditor(ProjectModel::INode* node)
|
||||
bool MainWindow::openEditor(ProjectModel::INode* node, bool appendNav)
|
||||
{
|
||||
switch (node->type())
|
||||
{
|
||||
case ProjectModel::INode::Type::SongGroup:
|
||||
return openEditor(static_cast<ProjectModel::SongGroupNode*>(node));
|
||||
return openEditor(static_cast<ProjectModel::SongGroupNode*>(node), appendNav);
|
||||
case ProjectModel::INode::Type::SoundGroup:
|
||||
return openEditor(static_cast<ProjectModel::SoundGroupNode*>(node));
|
||||
return openEditor(static_cast<ProjectModel::SoundGroupNode*>(node), appendNav);
|
||||
case ProjectModel::INode::Type::SoundMacro:
|
||||
return openEditor(static_cast<ProjectModel::SoundMacroNode*>(node));
|
||||
return openEditor(static_cast<ProjectModel::SoundMacroNode*>(node), appendNav);
|
||||
case ProjectModel::INode::Type::ADSR:
|
||||
return openEditor(static_cast<ProjectModel::ADSRNode*>(node));
|
||||
return openEditor(static_cast<ProjectModel::ADSRNode*>(node), appendNav);
|
||||
case ProjectModel::INode::Type::Curve:
|
||||
return openEditor(static_cast<ProjectModel::CurveNode*>(node));
|
||||
return openEditor(static_cast<ProjectModel::CurveNode*>(node), appendNav);
|
||||
case ProjectModel::INode::Type::Keymap:
|
||||
return openEditor(static_cast<ProjectModel::KeymapNode*>(node));
|
||||
return openEditor(static_cast<ProjectModel::KeymapNode*>(node), appendNav);
|
||||
case ProjectModel::INode::Type::Layer:
|
||||
return openEditor(static_cast<ProjectModel::LayersNode*>(node));
|
||||
return openEditor(static_cast<ProjectModel::LayersNode*>(node), appendNav);
|
||||
case ProjectModel::INode::Type::Sample:
|
||||
return openEditor(static_cast<ProjectModel::SampleNode*>(node));
|
||||
return openEditor(static_cast<ProjectModel::SampleNode*>(node), appendNav);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -646,7 +701,7 @@ amuse::ObjToken<amuse::Sequencer> MainWindow::startSong(amuse::GroupId groupId,
|
|||
return {};
|
||||
}
|
||||
|
||||
void MainWindow::pushUndoCommand(QUndoCommand* cmd)
|
||||
void MainWindow::pushUndoCommand(EditorUndoCommand* cmd)
|
||||
{
|
||||
m_undoStack->push(cmd);
|
||||
}
|
||||
|
@ -658,6 +713,21 @@ void MainWindow::updateFocus()
|
|||
|
||||
void MainWindow::aboutToDeleteNode(ProjectModel::INode* node)
|
||||
{
|
||||
if (*m_navIt == node && m_navIt != m_navList.end())
|
||||
{
|
||||
m_navList.erase(m_navIt, m_navList.end());
|
||||
m_navIt = m_navList.end();
|
||||
}
|
||||
for (auto it = m_navList.begin(); it != m_navList.end();)
|
||||
{
|
||||
if (*it == node)
|
||||
{
|
||||
it = m_navList.erase(it);
|
||||
continue;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
updateNavigationButtons();
|
||||
if (getEditorNode() == node)
|
||||
closeEditor();
|
||||
}
|
||||
|
@ -813,6 +883,9 @@ void MainWindow::revertAction()
|
|||
QString path = m_projectModel->path();
|
||||
closeEditor();
|
||||
m_undoStack->clear();
|
||||
m_navList.clear();
|
||||
m_navIt = m_navList.begin();
|
||||
updateNavigationButtons();
|
||||
delete m_projectModel;
|
||||
m_projectModel = nullptr;
|
||||
openProject(path);
|
||||
|
@ -936,6 +1009,7 @@ void MainWindow::importAction()
|
|||
return;
|
||||
}
|
||||
}
|
||||
model->openSongsData();
|
||||
});
|
||||
|
||||
|
||||
|
@ -978,6 +1052,7 @@ void MainWindow::importAction()
|
|||
return;
|
||||
task.setValue(++curVal);
|
||||
}
|
||||
model->openSongsData();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1024,28 +1099,178 @@ void MainWindow::exportAction()
|
|||
});
|
||||
}
|
||||
|
||||
void MainWindow::importHeadersAction()
|
||||
{
|
||||
if (!m_projectModel)
|
||||
return;
|
||||
|
||||
int confirm = m_mainMessenger.warning(tr("Import C Headers"),
|
||||
tr("<p>Importing names from C headers depends on up-to-date, "
|
||||
"consistent names relative to the sound group data.</p>"
|
||||
"<p>Headers are imported on a per-subproject basis from "
|
||||
"a single directory. Headers must be named with the form "
|
||||
"<code><subproject>.h</code>.</p>"
|
||||
"<p>Group, Song and SFX definitions are matched according to the following forms:"
|
||||
"<pre>#define GRP<name> <id>\n#define SNG<name> <id>\n"
|
||||
"#define SFX<name> <id></pre></p>"
|
||||
"<p><strong>This operation cannot be undone! Is is recommended to "
|
||||
"make a backup of the project directory before proceeding.</strong></p>"
|
||||
"<p>Continue?</p>"), QMessageBox::Yes | QMessageBox::No);
|
||||
if (confirm == QMessageBox::No)
|
||||
return;
|
||||
|
||||
QString path = QFileDialog::getExistingDirectory(this, tr("Import C Headers"), m_projectModel->dir().path());
|
||||
if (path.isEmpty())
|
||||
return;
|
||||
|
||||
closeEditor();
|
||||
|
||||
for (QString group : m_projectModel->getGroupList())
|
||||
m_projectModel->importHeader(path, group, m_mainMessenger);
|
||||
m_projectModel->updateNodeNames();
|
||||
|
||||
/* Samples may have been renamed.. stay consistent! */
|
||||
saveAction();
|
||||
}
|
||||
|
||||
void MainWindow::exportHeadersAction()
|
||||
{
|
||||
if (!m_projectModel)
|
||||
return;
|
||||
|
||||
QString path = QFileDialog::getExistingDirectory(this, tr("Export C Headers"), m_projectModel->dir().path());
|
||||
if (path.isEmpty())
|
||||
return;
|
||||
|
||||
bool yesToAll = false;
|
||||
for (QString group : m_projectModel->getGroupList())
|
||||
if (!m_projectModel->exportHeader(path, group, yesToAll, m_mainMessenger))
|
||||
return;
|
||||
}
|
||||
|
||||
bool TreeDelegate::editorEvent(QEvent* event,
|
||||
QAbstractItemModel* _model,
|
||||
QAbstractItemModel* __model,
|
||||
const QStyleOptionViewItem& option,
|
||||
const QModelIndex& index)
|
||||
{
|
||||
ProjectModel* model = static_cast<ProjectModel*>(_model);
|
||||
ProjectModel::INode* node = model->node(index);
|
||||
if (!node)
|
||||
QSortFilterProxyModel* _model = static_cast<QSortFilterProxyModel*>(__model);
|
||||
ProjectModel* model = static_cast<ProjectModel*>(_model->sourceModel());
|
||||
ProjectModel::INode* node = model->node(_model->mapToSource(index));
|
||||
if (!node || !(node->flags() & Qt::ItemIsEditable))
|
||||
return false;
|
||||
AmuseItemEditFlags flags = node->editFlags();
|
||||
|
||||
#if 0
|
||||
if ((event->type() == QEvent::MouseButtonDblClick &&
|
||||
static_cast<QMouseEvent*>(event)->button() == Qt::LeftButton))
|
||||
if (event->type() == QEvent::MouseButtonPress)
|
||||
{
|
||||
// Open in editor
|
||||
return m_window.openEditor(node);
|
||||
QMouseEvent* ev = static_cast<QMouseEvent*>(event);
|
||||
if (ev->button() == Qt::RightButton)
|
||||
{
|
||||
m_window.m_ui.projectOutline->setCurrentIndex(index);
|
||||
QMenu* menu = new QMenu(g_MainWindow->m_ui.projectOutline);
|
||||
|
||||
QAction* cutAction = new QAction(tr("Cut"), menu);
|
||||
cutAction->setData(index);
|
||||
cutAction->setEnabled(flags & AmuseItemCut);
|
||||
cutAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-cut")));
|
||||
cutAction->setShortcut(QKeySequence::Cut);
|
||||
connect(cutAction, SIGNAL(triggered()), this, SLOT(doCut()));
|
||||
menu->addAction(cutAction);
|
||||
|
||||
QAction* copyAction = new QAction(tr("Copy"), menu);
|
||||
copyAction->setData(index);
|
||||
copyAction->setEnabled(flags & AmuseItemCopy);
|
||||
copyAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-copy")));
|
||||
copyAction->setShortcut(QKeySequence::Copy);
|
||||
connect(copyAction, SIGNAL(triggered()), this, SLOT(doCopy()));
|
||||
menu->addAction(copyAction);
|
||||
|
||||
QAction* pasteAction = new QAction(tr("Paste"), menu);
|
||||
pasteAction->setData(index);
|
||||
pasteAction->setEnabled(g_MainWindow->m_clipboardAmuseData && flags & AmuseItemPaste);
|
||||
pasteAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-paste")));
|
||||
pasteAction->setShortcut(QKeySequence::Paste);
|
||||
connect(pasteAction, SIGNAL(triggered()), this, SLOT(doPaste()));
|
||||
menu->addAction(pasteAction);
|
||||
|
||||
QAction* dupeAction = new QAction(tr("Duplicate"), menu);
|
||||
dupeAction->setData(index);
|
||||
connect(dupeAction, SIGNAL(triggered()), this, SLOT(doDuplicate()));
|
||||
menu->addAction(dupeAction);
|
||||
|
||||
QAction* deleteAction = new QAction(tr("Delete"), menu);
|
||||
deleteAction->setData(index);
|
||||
deleteAction->setEnabled(flags & AmuseItemDelete);
|
||||
deleteAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete")));
|
||||
deleteAction->setShortcut(QKeySequence::Delete);
|
||||
connect(deleteAction, SIGNAL(triggered()), this, SLOT(doDelete()));
|
||||
menu->addAction(deleteAction);
|
||||
|
||||
QAction* renameAction = new QAction(tr("Rename"), menu);
|
||||
renameAction->setData(index);
|
||||
renameAction->setShortcut(tr("F2"));
|
||||
connect(renameAction, SIGNAL(triggered()), this, SLOT(doRename()));
|
||||
menu->addAction(renameAction);
|
||||
|
||||
menu->popup(ev->globalPos());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void TreeDelegate::doCut()
|
||||
{
|
||||
QAction* act = qobject_cast<QAction*>(sender());
|
||||
if (!m_window.m_projectModel)
|
||||
return;
|
||||
m_window.m_projectModel->cut(m_window.m_filterProjectModel.mapToSource(act->data().toModelIndex()));
|
||||
}
|
||||
|
||||
void TreeDelegate::doCopy()
|
||||
{
|
||||
QAction* act = qobject_cast<QAction*>(sender());
|
||||
if (!m_window.m_projectModel)
|
||||
return;
|
||||
m_window.m_projectModel->copy(m_window.m_filterProjectModel.mapToSource(act->data().toModelIndex()));
|
||||
}
|
||||
|
||||
void TreeDelegate::doPaste()
|
||||
{
|
||||
QAction* act = qobject_cast<QAction*>(sender());
|
||||
if (!m_window.m_projectModel)
|
||||
return;
|
||||
m_window.m_projectModel->paste(m_window.m_filterProjectModel.mapToSource(act->data().toModelIndex()));
|
||||
}
|
||||
|
||||
void TreeDelegate::doDuplicate()
|
||||
{
|
||||
QAction* act = qobject_cast<QAction*>(sender());
|
||||
if (!m_window.m_projectModel)
|
||||
return;
|
||||
QModelIndex newIdx =
|
||||
m_window.m_projectModel->duplicate(m_window.m_filterProjectModel.mapToSource(act->data().toModelIndex()));
|
||||
if (newIdx.isValid())
|
||||
{
|
||||
newIdx = m_window.m_filterProjectModel.mapFromSource(newIdx);
|
||||
m_window.m_ui.projectOutline->edit(newIdx);
|
||||
}
|
||||
}
|
||||
|
||||
void TreeDelegate::doDelete()
|
||||
{
|
||||
QAction* act = qobject_cast<QAction*>(sender());
|
||||
if (!m_window.m_projectModel)
|
||||
return;
|
||||
m_window.m_projectModel->del(m_window.m_filterProjectModel.mapToSource(act->data().toModelIndex()));
|
||||
}
|
||||
|
||||
void TreeDelegate::doRename()
|
||||
{
|
||||
QAction* act = qobject_cast<QAction*>(sender());
|
||||
m_window.m_ui.projectOutline->edit(act->data().toModelIndex());
|
||||
}
|
||||
|
||||
QString MainWindow::getGroupName(ProjectModel::GroupNode* group) const
|
||||
{
|
||||
if (group)
|
||||
|
@ -1057,10 +1282,10 @@ ProjectModel::GroupNode* MainWindow::getSelectedGroupNode() const
|
|||
{
|
||||
if (!m_projectModel)
|
||||
return nullptr;
|
||||
if (!m_ui.projectOutline->selectionModel()->currentIndex().isValid())
|
||||
if (!m_ui.projectOutline->currentIndex().isValid())
|
||||
return nullptr;
|
||||
return m_projectModel->getGroupNode(m_projectModel->node(
|
||||
m_filterProjectModel.mapToSource(m_ui.projectOutline->selectionModel()->currentIndex())));
|
||||
m_filterProjectModel.mapToSource(m_ui.projectOutline->currentIndex())));
|
||||
}
|
||||
|
||||
QString MainWindow::getSelectedGroupName() const
|
||||
|
@ -1082,10 +1307,7 @@ void MainWindow::recursiveExpandAndSelectOutline(const QModelIndex& index) const
|
|||
QModelIndex filterIndex = m_filterProjectModel.mapFromSource(index);
|
||||
_recursiveExpandOutline(filterIndex);
|
||||
if (filterIndex.isValid())
|
||||
{
|
||||
m_ui.projectOutline->selectionModel()->setCurrentIndex(filterIndex, QItemSelectionModel::ClearAndSelect);
|
||||
m_ui.projectOutline->selectionModel()->setCurrentIndex(filterIndex, QItemSelectionModel::Current);
|
||||
}
|
||||
m_ui.projectOutline->setCurrentIndex(filterIndex);
|
||||
}
|
||||
|
||||
void MainWindow::newSubprojectAction()
|
||||
|
@ -1238,6 +1460,30 @@ void MainWindow::newLayersAction()
|
|||
openEditor(node);
|
||||
}
|
||||
|
||||
void MainWindow::updateNavigationButtons()
|
||||
{
|
||||
m_goForward->setDisabled(m_navIt == m_navList.end() || m_navIt + 1 == m_navList.end());
|
||||
m_goBack->setDisabled(m_navIt == m_navList.begin());
|
||||
}
|
||||
|
||||
void MainWindow::goForward()
|
||||
{
|
||||
if (m_navIt == m_navList.end() || m_navIt + 1 == m_navList.end())
|
||||
return;
|
||||
++m_navIt;
|
||||
openEditor(*m_navIt, false);
|
||||
updateNavigationButtons();
|
||||
}
|
||||
|
||||
void MainWindow::goBack()
|
||||
{
|
||||
if (m_navIt == m_navList.begin())
|
||||
return;
|
||||
--m_navIt;
|
||||
openEditor(*m_navIt, false);
|
||||
updateNavigationButtons();
|
||||
}
|
||||
|
||||
void MainWindow::aboutToShowAudioIOMenu()
|
||||
{
|
||||
refreshAudioIO();
|
||||
|
@ -1413,27 +1659,30 @@ void MainWindow::auxBChanged(int vol)
|
|||
|
||||
void MainWindow::outlineCutAction()
|
||||
{
|
||||
|
||||
if (!m_projectModel)
|
||||
return;
|
||||
m_projectModel->cut(m_filterProjectModel.mapToSource(m_ui.projectOutline->currentIndex()));
|
||||
}
|
||||
|
||||
void MainWindow::outlineCopyAction()
|
||||
{
|
||||
|
||||
if (!m_projectModel)
|
||||
return;
|
||||
m_projectModel->copy(m_filterProjectModel.mapToSource(m_ui.projectOutline->currentIndex()));
|
||||
}
|
||||
|
||||
void MainWindow::outlinePasteAction()
|
||||
{
|
||||
|
||||
if (!m_projectModel)
|
||||
return;
|
||||
m_projectModel->paste(m_filterProjectModel.mapToSource(m_ui.projectOutline->currentIndex()));
|
||||
}
|
||||
|
||||
void MainWindow::outlineDeleteAction()
|
||||
{
|
||||
if (!m_projectModel)
|
||||
return;
|
||||
QModelIndexList indexes = m_ui.projectOutline->selectionModel()->selectedIndexes();
|
||||
if (indexes.empty())
|
||||
return;
|
||||
m_projectModel->del(m_filterProjectModel.mapToSource(indexes.front()));
|
||||
m_projectModel->del(m_filterProjectModel.mapToSource(m_ui.projectOutline->currentIndex()));
|
||||
}
|
||||
|
||||
void MainWindow::onFocusChanged(QWidget* old, QWidget* now)
|
||||
|
@ -1460,7 +1709,10 @@ void MainWindow::onFocusChanged(QWidget* old, QWidget* now)
|
|||
|
||||
if (now == m_ui.projectOutline || m_ui.projectOutline->isAncestorOf(now))
|
||||
{
|
||||
setItemEditEnabled(canEditOutline());
|
||||
AmuseItemEditFlags editFlags = outlineEditFlags();
|
||||
if (!m_clipboardAmuseData)
|
||||
editFlags = AmuseItemEditFlags(editFlags & ~AmuseItemPaste);
|
||||
setItemEditFlags(editFlags);
|
||||
if (m_projectModel)
|
||||
{
|
||||
m_cutConn = connect(m_ui.actionCut, SIGNAL(triggered()), this, SLOT(outlineCutAction()));
|
||||
|
@ -1471,20 +1723,40 @@ void MainWindow::onFocusChanged(QWidget* old, QWidget* now)
|
|||
}
|
||||
else if (now == m_ui.editorContents || m_ui.editorContents->isAncestorOf(now))
|
||||
{
|
||||
setItemEditEnabled(false);
|
||||
if (EditorWidget* editor = getEditorWidget())
|
||||
{
|
||||
if (editor->isItemEditEnabled())
|
||||
setItemEditFlags(editor->itemEditFlags());
|
||||
m_cutConn = connect(m_ui.actionCut, SIGNAL(triggered()), editor, SLOT(itemCutAction()));
|
||||
m_copyConn = connect(m_ui.actionCopy, SIGNAL(triggered()), editor, SLOT(itemCopyAction()));
|
||||
m_pasteConn = connect(m_ui.actionPaste, SIGNAL(triggered()), editor, SLOT(itemPasteAction()));
|
||||
m_deleteConn = connect(m_ui.actionDelete, SIGNAL(triggered()), editor, SLOT(itemDeleteAction()));
|
||||
}
|
||||
else
|
||||
{
|
||||
setItemEditFlags(AmuseItemNone);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::onClipboardChanged()
|
||||
{
|
||||
if (QClipboard* cb = qobject_cast<QClipboard*>(sender()))
|
||||
{
|
||||
if (const QMimeData* md = cb->mimeData())
|
||||
{
|
||||
for (const QString& str : md->formats())
|
||||
{
|
||||
setItemEditEnabled(true);
|
||||
m_cutConn = connect(m_ui.actionCut, SIGNAL(triggered()), editor, SLOT(itemCutAction()));
|
||||
m_copyConn = connect(m_ui.actionCopy, SIGNAL(triggered()), editor, SLOT(itemCopyAction()));
|
||||
m_pasteConn = connect(m_ui.actionPaste, SIGNAL(triggered()), editor, SLOT(itemPasteAction()));
|
||||
m_deleteConn = connect(m_ui.actionDelete, SIGNAL(triggered()), editor, SLOT(itemDeleteAction()));
|
||||
if (str.startsWith(QStringLiteral("application/x-amuse-")))
|
||||
{
|
||||
m_clipboardAmuseData = true;
|
||||
updateFocus();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_clipboardAmuseData = false;
|
||||
updateFocus();
|
||||
}
|
||||
|
||||
void MainWindow::outlineItemActivated(const QModelIndex& index)
|
||||
|
@ -1495,12 +1767,12 @@ void MainWindow::outlineItemActivated(const QModelIndex& index)
|
|||
openEditor(node);
|
||||
}
|
||||
|
||||
void MainWindow::setItemEditEnabled(bool enabled)
|
||||
void MainWindow::setItemEditFlags(AmuseItemEditFlags flags)
|
||||
{
|
||||
m_ui.actionCut->setEnabled(enabled);
|
||||
m_ui.actionCopy->setEnabled(enabled);
|
||||
m_ui.actionPaste->setEnabled(enabled);
|
||||
m_ui.actionDelete->setEnabled(enabled);
|
||||
m_ui.actionCut->setEnabled(flags & AmuseItemCut);
|
||||
m_ui.actionCopy->setEnabled(flags & AmuseItemCopy);
|
||||
m_ui.actionPaste->setEnabled(flags & AmuseItemPaste);
|
||||
m_ui.actionDelete->setEnabled(flags & AmuseItemDelete);
|
||||
}
|
||||
|
||||
void MainWindow::setItemNewEnabled(bool enabled)
|
||||
|
@ -1514,25 +1786,25 @@ void MainWindow::setItemNewEnabled(bool enabled)
|
|||
m_ui.actionNew_Layers->setEnabled(enabled);
|
||||
}
|
||||
|
||||
bool MainWindow::canEditOutline()
|
||||
AmuseItemEditFlags MainWindow::outlineEditFlags()
|
||||
{
|
||||
if (!m_projectModel)
|
||||
return false;
|
||||
QModelIndex curIndex = m_ui.projectOutline->selectionModel()->currentIndex();
|
||||
return AmuseItemNone;
|
||||
QModelIndex curIndex = m_ui.projectOutline->currentIndex();
|
||||
if (!curIndex.isValid())
|
||||
return false;
|
||||
return m_projectModel->canEdit(m_filterProjectModel.mapToSource(curIndex));
|
||||
return AmuseItemNone;
|
||||
return m_projectModel->editFlags(m_filterProjectModel.mapToSource(curIndex));
|
||||
}
|
||||
|
||||
void MainWindow::onOutlineSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected)
|
||||
{
|
||||
if (!m_projectModel)
|
||||
return;
|
||||
setItemNewEnabled(m_ui.projectOutline->selectionModel()->currentIndex().isValid());
|
||||
setItemNewEnabled(m_ui.projectOutline->currentIndex().isValid());
|
||||
if (selected.indexes().empty())
|
||||
setItemEditEnabled(false);
|
||||
setItemEditFlags(AmuseItemNone);
|
||||
else
|
||||
setItemEditEnabled(m_projectModel->canEdit(m_filterProjectModel.mapToSource(selected.indexes().front())));
|
||||
setItemEditFlags(m_projectModel->editFlags(m_filterProjectModel.mapToSource(selected.indexes().front())));
|
||||
}
|
||||
|
||||
void MainWindow::onTextSelect()
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <QThread>
|
||||
#include <QStyledItemDelegate>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QLinkedList>
|
||||
#include "ui_MainWindow.h"
|
||||
#include "amuse/Engine.hpp"
|
||||
#include "amuse/BooBackend.hpp"
|
||||
|
@ -77,13 +78,27 @@ public:
|
|||
QAbstractItemModel *model,
|
||||
const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index);
|
||||
public slots:
|
||||
void doCut();
|
||||
void doCopy();
|
||||
void doPaste();
|
||||
void doDuplicate();
|
||||
void doDelete();
|
||||
void doRename();
|
||||
};
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
friend class MIDIReader;
|
||||
friend class ProjectModel;
|
||||
friend class GroupNodeUndoCommand;
|
||||
friend class TreeDelegate;
|
||||
Q_OBJECT
|
||||
Ui::MainWindow m_ui;
|
||||
QAction* m_goBack;
|
||||
QAction* m_goForward;
|
||||
QLinkedList<ProjectModel::INode*> m_navList;
|
||||
QLinkedList<ProjectModel::INode*>::iterator m_navIt;
|
||||
QAction* m_clearRecentFileAct;
|
||||
QAction* m_recentFileActs[MaxRecentFiles];
|
||||
TreeDelegate m_treeDelegate;
|
||||
|
@ -105,12 +120,14 @@ class MainWindow : public QMainWindow
|
|||
std::unique_ptr<VoiceAllocator> m_voxAllocator;
|
||||
std::unique_ptr<amuse::Engine> m_engine;
|
||||
amuse::ObjToken<amuse::Voice> m_lastSound;
|
||||
amuse::ObjToken<amuse::Sequencer> m_interactiveSeq;
|
||||
int m_velocity = 90;
|
||||
float m_pitch = 0.f;
|
||||
int8_t m_ctrlVals[128] = {};
|
||||
float m_auxAVol = 0.f;
|
||||
float m_auxBVol = 0.f;
|
||||
bool m_uiDisabled = false;
|
||||
bool m_clipboardAmuseData = false;
|
||||
|
||||
QUndoStack* m_undoStack;
|
||||
|
||||
|
@ -128,6 +145,7 @@ class MainWindow : public QMainWindow
|
|||
|
||||
void updateWindowTitle();
|
||||
void updateRecentFileActions();
|
||||
void updateNavigationButtons();
|
||||
bool setProjectPath(const QString& path);
|
||||
void refreshAudioIO();
|
||||
void refreshMIDIIO();
|
||||
|
@ -139,7 +157,7 @@ class MainWindow : public QMainWindow
|
|||
void startBackgroundTask(int id, const QString& windowTitle, const QString& label,
|
||||
std::function<void(BackgroundTask&)>&& task);
|
||||
|
||||
bool _setEditor(EditorWidget* widget);
|
||||
bool _setEditor(EditorWidget* widget, bool appendNav = true);
|
||||
|
||||
public:
|
||||
explicit MainWindow(QWidget* parent = Q_NULLPTR);
|
||||
|
@ -147,15 +165,15 @@ public:
|
|||
|
||||
bool openProject(const QString& path);
|
||||
|
||||
bool openEditor(ProjectModel::SongGroupNode* node);
|
||||
bool openEditor(ProjectModel::SoundGroupNode* node);
|
||||
bool openEditor(ProjectModel::SoundMacroNode* node);
|
||||
bool openEditor(ProjectModel::ADSRNode* node);
|
||||
bool openEditor(ProjectModel::CurveNode* node);
|
||||
bool openEditor(ProjectModel::KeymapNode* node);
|
||||
bool openEditor(ProjectModel::LayersNode* node);
|
||||
bool openEditor(ProjectModel::SampleNode* node);
|
||||
bool openEditor(ProjectModel::INode* node);
|
||||
bool openEditor(ProjectModel::SongGroupNode* node, bool appendNav = true);
|
||||
bool openEditor(ProjectModel::SoundGroupNode* node, bool appendNav = true);
|
||||
bool openEditor(ProjectModel::SoundMacroNode* node, bool appendNav = true);
|
||||
bool openEditor(ProjectModel::ADSRNode* node, bool appendNav = true);
|
||||
bool openEditor(ProjectModel::CurveNode* node, bool appendNav = true);
|
||||
bool openEditor(ProjectModel::KeymapNode* node, bool appendNav = true);
|
||||
bool openEditor(ProjectModel::LayersNode* node, bool appendNav = true);
|
||||
bool openEditor(ProjectModel::SampleNode* node, bool appendNav = true);
|
||||
bool openEditor(ProjectModel::INode* node, bool appendNav = true);
|
||||
void closeEditor();
|
||||
|
||||
ProjectModel::INode* getEditorNode() const;
|
||||
|
@ -164,7 +182,7 @@ public:
|
|||
amuse::ObjToken<amuse::Voice> startSFX(amuse::GroupId groupId, amuse::SFXId sfxId);
|
||||
amuse::ObjToken<amuse::Sequencer> startSong(amuse::GroupId groupId, amuse::SongId songId,
|
||||
const unsigned char* arrData);
|
||||
void pushUndoCommand(QUndoCommand* cmd);
|
||||
void pushUndoCommand(EditorUndoCommand* cmd);
|
||||
void updateFocus();
|
||||
void aboutToDeleteNode(ProjectModel::INode* node);
|
||||
void closeEvent(QCloseEvent* ev);
|
||||
|
@ -179,6 +197,11 @@ public:
|
|||
ProjectModel* projectModel() const { return m_projectModel; }
|
||||
UIMessenger& uiMessenger() { return m_mainMessenger; }
|
||||
|
||||
void setItemEditFlags(AmuseItemEditFlags flags);
|
||||
void setItemNewEnabled(bool enabled);
|
||||
AmuseItemEditFlags outlineEditFlags();
|
||||
bool isUiDisabled() const { return m_uiDisabled; }
|
||||
|
||||
public slots:
|
||||
void newAction();
|
||||
void openAction();
|
||||
|
@ -190,6 +213,8 @@ public slots:
|
|||
void importAction();
|
||||
void importSongsAction();
|
||||
void exportAction();
|
||||
void importHeadersAction();
|
||||
void exportHeadersAction();
|
||||
|
||||
void newSubprojectAction();
|
||||
void newSFXGroupAction();
|
||||
|
@ -200,6 +225,9 @@ public slots:
|
|||
void newKeymapAction();
|
||||
void newLayersAction();
|
||||
|
||||
void goForward();
|
||||
void goBack();
|
||||
|
||||
void aboutToShowAudioIOMenu();
|
||||
void aboutToShowMIDIIOMenu();
|
||||
|
||||
|
@ -226,10 +254,8 @@ public slots:
|
|||
void outlineDeleteAction();
|
||||
|
||||
void onFocusChanged(QWidget* old, QWidget* now);
|
||||
void onClipboardChanged();
|
||||
void outlineItemActivated(const QModelIndex& index);
|
||||
void setItemEditEnabled(bool enabled);
|
||||
void setItemNewEnabled(bool enabled);
|
||||
bool canEditOutline();
|
||||
void onOutlineSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected);
|
||||
void onTextSelect();
|
||||
void onTextDelete();
|
||||
|
|
|
@ -53,26 +53,59 @@
|
|||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="projectOutlineFilter">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
<layout class="QHBoxLayout" name="outlineLayout2">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string>Filter</string>
|
||||
</property>
|
||||
<property name="clearButtonEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="projectOutlineFilter">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string>Filter</string>
|
||||
</property>
|
||||
<property name="clearButtonEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="backButton">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="resources/resources.qrc">
|
||||
<normaloff>:/icons/IconBack.svg</normaloff>
|
||||
<disabledoff>:/icons/IconBackDisabled.svg</disabledoff>
|
||||
<disabledon>:/icons/IconBackDisabled.svg</disabledon>:/icons/IconBack.svg</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||