#pragma once #include #include #include #include #include #include #include #include #include "ui_MainWindow.h" #include "amuse/Engine.hpp" #include "amuse/BooBackend.hpp" #include "boo/audiodev/IAudioVoiceEngine.hpp" #include "ProjectModel.hpp" #include "EditorWidget.hpp" #include "MIDIReader.hpp" #include "StudioSetupWidget.hpp" #define MaxRecentFiles 4 namespace Ui { class MainWindow; } class MainWindow; class SongGroupEditor; class SoundGroupEditor; class SoundMacroEditor; class ADSREditor; class CurveEditor; class KeymapEditor; class LayersEditor; class SampleEditor; enum BackgroundTaskId { TaskOpen, TaskImport, TaskExport, TaskReloadSamples }; class BackgroundTask : public QObject { Q_OBJECT int m_id; std::function m_task; UIMessenger m_threadMessenger; bool m_cancelled = false; public: explicit BackgroundTask(int id, std::function&& 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; } signals: void setMinimum(int minimum); void setMaximum(int maximum); void setValue(int value); void setLabelText(const QString& text); void finished(int id); public slots: void run() { m_task(*this); emit finished(m_id); } void cancel() { m_cancelled = true; } }; class TreeDelegate : public QStyledItemDelegate { Q_OBJECT MainWindow& m_window; public: explicit TreeDelegate(MainWindow& window, QObject* parent = Q_NULLPTR) : QStyledItemDelegate(parent), m_window(window) {} bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index) override; public slots: void doExportGroup(); void doFindUsages(); 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 m_navList; QLinkedList::iterator m_navIt; 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 m_voxEngine; std::unique_ptr m_voxAllocator; std::unique_ptr m_engine; amuse::ObjToken m_lastSound; amuse::ObjToken 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(); void timerEvent(QTimerEvent* ev) override; void setSustain(bool sustain); void keyPressEvent(QKeyEvent* ev) override; void keyReleaseEvent(QKeyEvent* ev) override; void startBackgroundTask(int id, const QString& windowTitle, const QString& label, std::function&& task); bool _setEditor(EditorWidget* widget, bool appendNav = true); public: explicit MainWindow(QWidget* parent = Q_NULLPTR); ~MainWindow() override; 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 startEditorVoice(uint8_t key, uint8_t vel); amuse::ObjToken startSFX(amuse::GroupId groupId, amuse::SFXId sfxId); amuse::ObjToken startSong(amuse::GroupId groupId, amuse::SongId songId, const unsigned char* arrData); void pushUndoCommand(EditorUndoCommand* cmd); void updateFocus(); void aboutToDeleteNode(ProjectModel::INode* node); bool askAboutSave(); void closeEvent(QCloseEvent* ev) override; void showEvent(QShowEvent* ev) override; 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); public slots: 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); };