2018-10-07 03:40:25 +00:00
|
|
|
#pragma once
|
2018-03-15 00:25:29 +00:00
|
|
|
|
2019-08-28 00:51:38 +00:00
|
|
|
#include <cstdint>
|
|
|
|
#include <functional>
|
|
|
|
#include <memory>
|
|
|
|
|
|
|
|
#include <QFileDialog>
|
|
|
|
#include <QLinkedList>
|
2018-07-09 18:05:31 +00:00
|
|
|
#include <QMainWindow>
|
2019-08-28 00:51:38 +00:00
|
|
|
#include <QMessageBox>
|
2018-07-18 07:39:26 +00:00
|
|
|
#include <QStyledItemDelegate>
|
2019-08-28 00:51:38 +00:00
|
|
|
#include <QThread>
|
|
|
|
|
2019-08-28 03:11:32 +00:00
|
|
|
#include "Common.hpp"
|
2018-07-18 07:39:26 +00:00
|
|
|
#include "EditorWidget.hpp"
|
2019-08-28 00:51:38 +00:00
|
|
|
#include "ProjectModel.hpp"
|
|
|
|
|
|
|
|
#include "ui_MainWindow.h"
|
|
|
|
|
|
|
|
#include <amuse/Common.hpp>
|
|
|
|
#include <amuse/Sequencer.hpp>
|
|
|
|
#include <amuse/Voice.hpp>
|
2018-07-28 04:34:29 +00:00
|
|
|
|
|
|
|
#define MaxRecentFiles 4
|
2018-07-14 06:06:33 +00:00
|
|
|
|
2019-08-28 00:51:38 +00:00
|
|
|
namespace amuse {
|
|
|
|
class Engine;
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace boo {
|
|
|
|
struct IAudioVoiceEngine;
|
|
|
|
}
|
|
|
|
|
2018-07-09 18:05:31 +00:00
|
|
|
namespace Ui {
|
|
|
|
class MainWindow;
|
|
|
|
}
|
2018-03-15 00:25:29 +00:00
|
|
|
|
2018-07-26 03:41:48 +00:00
|
|
|
class ADSREditor;
|
|
|
|
class CurveEditor;
|
|
|
|
class KeymapEditor;
|
|
|
|
class LayersEditor;
|
2019-08-28 00:51:38 +00:00
|
|
|
class MainWindow;
|
2018-07-29 03:37:06 +00:00
|
|
|
class SampleEditor;
|
2019-08-28 00:51:38 +00:00
|
|
|
class SongGroupEditor;
|
|
|
|
class SoundGroupEditor;
|
|
|
|
class SoundMacroEditor;
|
|
|
|
class StudioSetupWidget;
|
|
|
|
class VoiceAllocator;
|
|
|
|
|
|
|
|
class QProgressDialog;
|
|
|
|
class QUndoStack;
|
2018-07-14 06:06:33 +00:00
|
|
|
|
2018-12-08 05:20:09 +00:00
|
|
|
enum BackgroundTaskId { TaskOpen, TaskImport, TaskExport, TaskReloadSamples };
|
|
|
|
|
|
|
|
class BackgroundTask : public QObject {
|
|
|
|
Q_OBJECT
|
|
|
|
int m_id;
|
|
|
|
std::function<void(BackgroundTask&)> m_task;
|
|
|
|
UIMessenger m_threadMessenger;
|
|
|
|
bool m_cancelled = false;
|
2018-08-19 00:28:52 +00:00
|
|
|
|
2018-07-17 04:48:38 +00:00
|
|
|
public:
|
2018-12-08 05:20:09 +00:00
|
|
|
explicit BackgroundTask(int id, std::function<void(BackgroundTask&)>&& task)
|
|
|
|
: m_id(id), m_task(std::move(task)), m_threadMessenger(this) {}
|
|
|
|
bool isCanceled() const {
|
|
|
|
QCoreApplication::processEvents();
|
|
|
|
return m_cancelled;
|
|
|
|
}
|
|
|
|
UIMessenger& uiMessenger() { return m_threadMessenger; }
|
2018-07-17 04:48:38 +00:00
|
|
|
|
|
|
|
signals:
|
2018-12-08 05:20:09 +00:00
|
|
|
void setMinimum(int minimum);
|
|
|
|
void setMaximum(int maximum);
|
|
|
|
void setValue(int value);
|
|
|
|
void setLabelText(const QString& text);
|
|
|
|
void finished(int id);
|
2018-07-17 04:48:38 +00:00
|
|
|
|
|
|
|
public slots:
|
2018-12-08 05:20:09 +00:00
|
|
|
void run() {
|
|
|
|
m_task(*this);
|
|
|
|
emit finished(m_id);
|
|
|
|
}
|
|
|
|
void cancel() { m_cancelled = true; }
|
2018-07-17 04:48:38 +00:00
|
|
|
};
|
|
|
|
|
2018-12-08 05:20:09 +00:00
|
|
|
class TreeDelegate : public QStyledItemDelegate {
|
|
|
|
Q_OBJECT
|
|
|
|
MainWindow& m_window;
|
|
|
|
|
2018-07-18 07:39:26 +00:00
|
|
|
public:
|
2018-12-08 05:20:09 +00:00
|
|
|
explicit TreeDelegate(MainWindow& window, QObject* parent = Q_NULLPTR)
|
|
|
|
: QStyledItemDelegate(parent), m_window(window) {}
|
2018-07-18 07:39:26 +00:00
|
|
|
|
2018-12-08 05:20:09 +00:00
|
|
|
bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option,
|
2019-08-25 04:37:47 +00:00
|
|
|
const QModelIndex& index) override;
|
2018-08-25 08:34:04 +00:00
|
|
|
public slots:
|
2018-12-08 05:20:09 +00:00
|
|
|
void doExportGroup();
|
|
|
|
void doFindUsages();
|
|
|
|
void doCut();
|
|
|
|
void doCopy();
|
|
|
|
void doPaste();
|
|
|
|
void doDuplicate();
|
|
|
|
void doDelete();
|
|
|
|
void doRename();
|
2018-07-18 07:39:26 +00:00
|
|
|
};
|
|
|
|
|
2018-12-08 05:20:09 +00:00
|
|
|
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;
|
2020-09-08 23:23:55 +00:00
|
|
|
std::list<ProjectModel::INode*> m_navList;
|
|
|
|
std::list<ProjectModel::INode*>::iterator m_navIt;
|
2018-12-08 05:20:09 +00:00
|
|
|
QAction* m_clearRecentFileAct;
|
|
|
|
QAction* m_recentFileActs[MaxRecentFiles];
|
|
|
|
TreeDelegate m_treeDelegate;
|
|
|
|
UIMessenger m_mainMessenger;
|
|
|
|
ProjectModel* m_projectModel = nullptr;
|
|
|
|
QWidget* m_faceSvg;
|
|
|
|
SongGroupEditor* m_songGroupEditor = nullptr;
|
|
|
|
SoundGroupEditor* m_soundGroupEditor = nullptr;
|
|
|
|
SoundMacroEditor* m_soundMacroEditor = nullptr;
|
|
|
|
ADSREditor* m_adsrEditor = nullptr;
|
|
|
|
CurveEditor* m_curveEditor = nullptr;
|
|
|
|
KeymapEditor* m_keymapEditor = nullptr;
|
|
|
|
LayersEditor* m_layersEditor = nullptr;
|
|
|
|
SampleEditor* m_sampleEditor = nullptr;
|
|
|
|
StudioSetupWidget* m_studioSetup = nullptr;
|
|
|
|
QFileDialog m_openDirectoryDialog;
|
|
|
|
QFileDialog m_openFileDialog;
|
|
|
|
QFileDialog m_newFileDialog;
|
|
|
|
|
|
|
|
std::unique_ptr<boo::IAudioVoiceEngine> m_voxEngine;
|
|
|
|
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;
|
|
|
|
|
|
|
|
QMetaObject::Connection m_cutConn;
|
|
|
|
QMetaObject::Connection m_copyConn;
|
|
|
|
QMetaObject::Connection m_pasteConn;
|
|
|
|
QMetaObject::Connection m_deleteConn;
|
|
|
|
QMetaObject::Connection m_canEditConn;
|
|
|
|
|
|
|
|
BackgroundTask* m_backgroundTask = nullptr;
|
|
|
|
QProgressDialog* m_backgroundDialog = nullptr;
|
|
|
|
QThread m_backgroundThread;
|
|
|
|
|
|
|
|
uint64_t m_timerFireCount = 0;
|
|
|
|
int m_peakVoices = 0;
|
|
|
|
|
|
|
|
void connectMessenger(UIMessenger* messenger, Qt::ConnectionType type);
|
|
|
|
|
|
|
|
void updateWindowTitle();
|
|
|
|
void updateRecentFileActions();
|
|
|
|
void updateNavigationButtons();
|
|
|
|
bool setProjectPath(const QString& path);
|
|
|
|
void refreshAudioIO();
|
|
|
|
void refreshMIDIIO();
|
2019-08-25 04:37:47 +00:00
|
|
|
void timerEvent(QTimerEvent* ev) override;
|
2018-12-08 05:20:09 +00:00
|
|
|
void setSustain(bool sustain);
|
2019-08-25 04:37:47 +00:00
|
|
|
void keyPressEvent(QKeyEvent* ev) override;
|
|
|
|
void keyReleaseEvent(QKeyEvent* ev) override;
|
2018-12-08 05:20:09 +00:00
|
|
|
|
|
|
|
void startBackgroundTask(int id, const QString& windowTitle, const QString& label,
|
|
|
|
std::function<void(BackgroundTask&)>&& task);
|
|
|
|
|
|
|
|
bool _setEditor(EditorWidget* widget, bool appendNav = true);
|
2018-07-18 07:39:26 +00:00
|
|
|
|
2018-07-09 18:05:31 +00:00
|
|
|
public:
|
2018-12-08 05:20:09 +00:00
|
|
|
explicit MainWindow(QWidget* parent = Q_NULLPTR);
|
2019-08-25 04:37:47 +00:00
|
|
|
~MainWindow() override;
|
2018-12-08 05:20:09 +00:00
|
|
|
|
|
|
|
bool openProject(const QString& path);
|
|
|
|
|
|
|
|
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;
|
|
|
|
EditorWidget* getEditorWidget() const;
|
|
|
|
amuse::ObjToken<amuse::Voice> startEditorVoice(uint8_t key, uint8_t vel);
|
|
|
|
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(EditorUndoCommand* cmd);
|
|
|
|
void updateFocus();
|
|
|
|
void aboutToDeleteNode(ProjectModel::INode* node);
|
|
|
|
bool askAboutSave();
|
2019-08-25 04:37:47 +00:00
|
|
|
void closeEvent(QCloseEvent* ev) override;
|
|
|
|
void showEvent(QShowEvent* ev) override;
|
2018-12-08 05:20:09 +00:00
|
|
|
|
|
|
|
QString getGroupName(ProjectModel::GroupNode* group) const;
|
|
|
|
ProjectModel::GroupNode* getSelectedGroupNode() const;
|
|
|
|
QString getSelectedGroupName() const;
|
|
|
|
void _recursiveExpandOutline(const QModelIndex& filterIndex) const;
|
|
|
|
void recursiveExpandAndSelectOutline(const QModelIndex& index) const;
|
|
|
|
|
|
|
|
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; }
|
|
|
|
void findUsages(ProjectModel::INode* node);
|
2018-08-25 08:34:04 +00:00
|
|
|
|
2018-07-14 06:06:33 +00:00
|
|
|
public slots:
|
2018-12-08 05:20:09 +00:00
|
|
|
void newAction();
|
|
|
|
void _newAction(const QString& path);
|
|
|
|
void openAction();
|
|
|
|
void _openAction(const QString& path);
|
|
|
|
void openRecentFileAction();
|
|
|
|
void clearRecentFilesAction();
|
|
|
|
void saveAction();
|
|
|
|
void revertAction();
|
|
|
|
void reloadSampleDataAction();
|
|
|
|
void importAction();
|
|
|
|
void _importAction(const QString& path);
|
|
|
|
void importSongsAction();
|
|
|
|
void _importSongsAction(const QString& path);
|
|
|
|
void exportAction();
|
|
|
|
void importHeadersAction();
|
|
|
|
void _importHeadersAction(const QString& path);
|
|
|
|
void exportHeadersAction();
|
|
|
|
void _exportHeadersAction(const QString& path);
|
|
|
|
|
|
|
|
void newSubprojectAction();
|
|
|
|
void newSFXGroupAction();
|
|
|
|
void newSongGroupAction();
|
|
|
|
void newSoundMacroAction();
|
|
|
|
void newADSRAction();
|
|
|
|
void newCurveAction();
|
|
|
|
void newKeymapAction();
|
|
|
|
void newLayersAction();
|
|
|
|
|
|
|
|
void goForward();
|
|
|
|
void goBack();
|
|
|
|
|
|
|
|
void aboutToShowAudioIOMenu();
|
|
|
|
void aboutToShowMIDIIOMenu();
|
|
|
|
|
|
|
|
void setAudioIO();
|
|
|
|
void setMIDIIO(bool checked);
|
|
|
|
|
|
|
|
void aboutAmuseAction();
|
|
|
|
void aboutQtAction();
|
|
|
|
|
|
|
|
void notePressed(int key);
|
|
|
|
void noteReleased();
|
|
|
|
void velocityChanged(int vel);
|
|
|
|
void modulationChanged(int mod);
|
|
|
|
void pitchChanged(int pitch);
|
|
|
|
void killSounds();
|
|
|
|
void fxPressed();
|
|
|
|
void volumeChanged(int vol);
|
|
|
|
void auxAChanged(int vol);
|
|
|
|
void auxBChanged(int vol);
|
|
|
|
|
|
|
|
void outlineCutAction();
|
|
|
|
void outlineCopyAction();
|
|
|
|
void outlinePasteAction();
|
|
|
|
void outlineDeleteAction();
|
|
|
|
|
|
|
|
void onFocusChanged(QWidget* old, QWidget* now);
|
|
|
|
void onClipboardChanged();
|
|
|
|
void outlineItemActivated(const QModelIndex& index);
|
|
|
|
void onOutlineSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected);
|
|
|
|
void onTextSelect();
|
|
|
|
void onTextDelete();
|
|
|
|
void cleanChanged(bool clean);
|
|
|
|
|
|
|
|
void studioSetupHidden();
|
|
|
|
void studioSetupShown();
|
|
|
|
|
|
|
|
void onBackgroundTaskFinished(int id);
|
|
|
|
|
|
|
|
QMessageBox::StandardButton msgInformation(const QString& title, const QString& text,
|
|
|
|
QMessageBox::StandardButtons buttons = QMessageBox::Ok,
|
|
|
|
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
|
|
|
|
int msgQuestion(const QString& title, const QString& text, const QString& button0Text,
|
|
|
|
const QString& button1Text = QString(), const QString& button2Text = QString(),
|
|
|
|
int defaultButtonNumber = 0, int escapeButtonNumber = -1);
|
|
|
|
QMessageBox::StandardButton
|
|
|
|
msgQuestion(const QString& title, const QString& text,
|
|
|
|
QMessageBox::StandardButtons buttons = QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No),
|
|
|
|
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
|
|
|
|
QMessageBox::StandardButton msgWarning(const QString& title, const QString& text,
|
|
|
|
QMessageBox::StandardButtons buttons = QMessageBox::Ok,
|
|
|
|
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
|
|
|
|
QMessageBox::StandardButton msgCritical(const QString& title, const QString& text,
|
|
|
|
QMessageBox::StandardButtons buttons = QMessageBox::Ok,
|
|
|
|
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
|
2018-03-15 00:25:29 +00:00
|
|
|
};
|