AudioControlsEditorWindow.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <AudioControlsEditorWindow.h>
  9. #include <AzCore/Utils/Utils.h>
  10. #include <AzToolsFramework/API/ToolsApplicationAPI.h>
  11. #include <ATLControlsModel.h>
  12. #include <ATLControlsPanel.h>
  13. #include <AudioControlsEditorPlugin.h>
  14. #include <AudioControlsEditorUndo.h>
  15. #include <AudioFileUtils.h>
  16. #include <AudioSystemPanel.h>
  17. #include <IAudioSystem.h>
  18. #include <ImplementationManager.h>
  19. #include <InspectorPanel.h>
  20. #include <QAudioControlEditorIcons.h>
  21. #include <DockTitleBarWidget.h>
  22. #include <QPaintEvent>
  23. #include <QPushButton>
  24. #include <QApplication>
  25. #include <QPainter>
  26. #include <QMessageBox>
  27. void InitACEResources()
  28. {
  29. Q_INIT_RESOURCE(AudioControlsEditorUI);
  30. }
  31. namespace AudioControls
  32. {
  33. //-------------------------------------------------------------------------------------------//
  34. // static
  35. bool CAudioControlsEditorWindow::m_wasClosed = false;
  36. //-------------------------------------------------------------------------------------------//
  37. CAudioControlsEditorWindow::CAudioControlsEditorWindow(QWidget* parent)
  38. : QMainWindow(parent)
  39. {
  40. InitACEResources();
  41. setupUi(this);
  42. m_pATLModel = CAudioControlsEditorPlugin::GetATLModel();
  43. IAudioSystemEditor* pAudioSystemImpl = CAudioControlsEditorPlugin::GetAudioSystemEditorImpl();
  44. if (pAudioSystemImpl)
  45. {
  46. m_pATLControlsPanel = new CATLControlsPanel(m_pATLModel, CAudioControlsEditorPlugin::GetControlsTree());
  47. m_pInspectorPanel = new CInspectorPanel(m_pATLModel);
  48. m_pAudioSystemPanel = new CAudioSystemPanel();
  49. CDockTitleBarWidget* pTitleBar = new CDockTitleBarWidget(m_pATLControlsDockWidget);
  50. m_pATLControlsDockWidget->setTitleBarWidget(pTitleBar);
  51. pTitleBar = new CDockTitleBarWidget(m_pInspectorDockWidget);
  52. m_pInspectorDockWidget->setTitleBarWidget(pTitleBar);
  53. pTitleBar = new CDockTitleBarWidget(m_pMiddlewareDockWidget);
  54. m_pMiddlewareDockWidget->setTitleBarWidget(pTitleBar);
  55. // Custom title based on Middleware name
  56. m_pMiddlewareDockWidget->setWindowTitle(QString(pAudioSystemImpl->GetName().c_str()) + " Controls");
  57. m_pATLControlsDockLayout->addWidget(m_pATLControlsPanel);
  58. m_pInspectorDockLayout->addWidget(m_pInspectorPanel);
  59. m_pMiddlewareDockLayout->addWidget(m_pAudioSystemPanel);
  60. Update();
  61. connect(m_pATLControlsPanel, SIGNAL(SelectedControlChanged()), this, SLOT(UpdateInspector()));
  62. connect(m_pATLControlsPanel, SIGNAL(SelectedControlChanged()), this, SLOT(UpdateFilterFromSelection()));
  63. connect(m_pATLControlsPanel, SIGNAL(ControlTypeFiltered(EACEControlType, bool)), this, SLOT(FilterControlType(EACEControlType, bool)));
  64. connect(CAudioControlsEditorPlugin::GetImplementationManager(), SIGNAL(ImplementationChanged()), this, SLOT(Update()));
  65. connect(&m_fileSystemWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(ReloadMiddlewareData()));
  66. GetIEditor()->RegisterNotifyListener(this);
  67. // LY-11309: this call to reload middleware data will force refresh of the data when
  68. // making changes to the middleware project while the AudioControlsEditor window is closed.
  69. if (m_wasClosed)
  70. {
  71. ReloadMiddlewareData();
  72. }
  73. }
  74. }
  75. //-------------------------------------------------------------------------------------------//
  76. CAudioControlsEditorWindow::~CAudioControlsEditorWindow()
  77. {
  78. GetIEditor()->UnregisterNotifyListener(this);
  79. }
  80. //-------------------------------------------------------------------------------------------//
  81. void CAudioControlsEditorWindow::StartWatchingFolder(const AZStd::string_view folder)
  82. {
  83. m_fileSystemWatcher.addPath(folder.data());
  84. auto fileIO = AZ::IO::FileIOBase::GetInstance();
  85. auto foundFiles = Audio::FindFilesInPath(folder, "*");
  86. for (auto& file : foundFiles)
  87. {
  88. if (fileIO->IsDirectory(file.c_str()))
  89. {
  90. AZ::IO::FixedMaxPath resolvedPath;
  91. fileIO->ReplaceAlias(resolvedPath, file);
  92. StartWatchingFolder(file.Native());
  93. }
  94. }
  95. }
  96. //-------------------------------------------------------------------------------------------//
  97. void CAudioControlsEditorWindow::closeEvent(QCloseEvent* pEvent)
  98. {
  99. if (m_pATLModel && m_pATLModel->IsDirty())
  100. {
  101. QMessageBox messageBox(this);
  102. messageBox.setText(tr("There are unsaved changes."));
  103. messageBox.setInformativeText(tr("Do you want to save your changes?"));
  104. messageBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
  105. messageBox.setDefaultButton(QMessageBox::Save);
  106. messageBox.setWindowTitle("Audio Controls Editor");
  107. switch (messageBox.exec())
  108. {
  109. case QMessageBox::Save:
  110. QApplication::setOverrideCursor(Qt::WaitCursor);
  111. Save();
  112. QApplication::restoreOverrideCursor();
  113. pEvent->accept();
  114. break;
  115. case QMessageBox::Discard:
  116. pEvent->accept();
  117. break;
  118. default:
  119. pEvent->ignore();
  120. return;
  121. }
  122. }
  123. else
  124. {
  125. pEvent->accept();
  126. }
  127. // If the close event was accepted, set this flag so next time the window opens it will refresh the middleware data.
  128. m_wasClosed = true;
  129. }
  130. //-------------------------------------------------------------------------------------------//
  131. void CAudioControlsEditorWindow::Reload()
  132. {
  133. bool bReload = true;
  134. if (m_pATLModel && m_pATLModel->IsDirty())
  135. {
  136. QMessageBox messageBox(this);
  137. messageBox.setText(tr("If you reload you will lose all your unsaved changes."));
  138. messageBox.setInformativeText(tr("Are you sure you want to reload?"));
  139. messageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
  140. messageBox.setDefaultButton(QMessageBox::No);
  141. messageBox.setWindowTitle("Audio Controls Editor");
  142. bReload = (messageBox.exec() == QMessageBox::Yes);
  143. }
  144. if (bReload)
  145. {
  146. CAudioControlsEditorPlugin::ReloadModels();
  147. Update();
  148. }
  149. }
  150. //-------------------------------------------------------------------------------------------//
  151. void CAudioControlsEditorWindow::Update()
  152. {
  153. if (!m_pATLControlsPanel)
  154. {
  155. return;
  156. }
  157. m_pATLControlsPanel->Reload();
  158. m_pAudioSystemPanel->Reload();
  159. UpdateInspector();
  160. IAudioSystemEditor* pAudioSystemImpl = CAudioControlsEditorPlugin::GetAudioSystemEditorImpl();
  161. if (pAudioSystemImpl)
  162. {
  163. StartWatchingFolder(pAudioSystemImpl->GetDataPath().LexicallyNormal().Native());
  164. m_pMiddlewareDockWidget->setWindowTitle(QString(pAudioSystemImpl->GetName().c_str()) + " Controls");
  165. }
  166. }
  167. //-------------------------------------------------------------------------------------------//
  168. void CAudioControlsEditorWindow::RefreshAudioSystem()
  169. {
  170. if (auto audioSystem = AZ::Interface<Audio::IAudioSystem>::Get();
  171. audioSystem != nullptr)
  172. {
  173. QString sLevelName = GetIEditor()->GetLevelName();
  174. if (QString::compare(sLevelName, "Untitled", Qt::CaseInsensitive) == 0)
  175. {
  176. // Rather pass empty QString to indicate that no level is loaded!
  177. sLevelName = QString();
  178. }
  179. audioSystem->RefreshAudioSystem(sLevelName.toUtf8().data());
  180. }
  181. }
  182. //-------------------------------------------------------------------------------------------//
  183. void CAudioControlsEditorWindow::Save()
  184. {
  185. bool bPreloadsChanged = m_pATLModel->IsTypeDirty(eACET_PRELOAD);
  186. CAudioControlsEditorPlugin::SaveModels();
  187. UpdateAudioSystemData();
  188. // if preloads have been modified, ask the user if s/he wants to refresh the audio system
  189. if (bPreloadsChanged)
  190. {
  191. QMessageBox messageBox(this);
  192. messageBox.setText(tr("Preload requests have been modified.\n\nFor the new data to be loaded the audio system needs to be refreshed, this will stop all currently playing audio. Do you want to do this now?\n\nYou can always refresh manually at a later time through the Audio menu."));
  193. messageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
  194. messageBox.setDefaultButton(QMessageBox::No);
  195. messageBox.setWindowTitle("Audio Controls Editor");
  196. if (messageBox.exec() == QMessageBox::Yes)
  197. {
  198. RefreshAudioSystem();
  199. }
  200. }
  201. m_pATLModel->ClearDirtyFlags();
  202. }
  203. //-------------------------------------------------------------------------------------------//
  204. void CAudioControlsEditorWindow::UpdateInspector()
  205. {
  206. m_pInspectorPanel->SetSelectedControls(m_pATLControlsPanel->GetSelectedControls());
  207. }
  208. //-------------------------------------------------------------------------------------------//
  209. void CAudioControlsEditorWindow::UpdateFilterFromSelection()
  210. {
  211. bool bAllSameType = true;
  212. EACEControlType selectedType = eACET_NUM_TYPES;
  213. ControlList ids = m_pATLControlsPanel->GetSelectedControls();
  214. size_t size = ids.size();
  215. for (size_t i = 0; i < size; ++i)
  216. {
  217. CATLControl* pControl = m_pATLModel->GetControlByID(ids[i]);
  218. if (pControl)
  219. {
  220. if (selectedType == eACET_NUM_TYPES)
  221. {
  222. selectedType = pControl->GetType();
  223. }
  224. else if (selectedType != pControl->GetType())
  225. {
  226. bAllSameType = false;
  227. }
  228. }
  229. }
  230. bool bSelectedFolder = (selectedType == eACET_NUM_TYPES);
  231. for (int i = 0; i < eACET_NUM_TYPES; ++i)
  232. {
  233. EACEControlType type = (EACEControlType)i;
  234. bool bAllowed = bSelectedFolder || (bAllSameType && selectedType == type);
  235. m_pAudioSystemPanel->SetAllowedControls((EACEControlType)i, bAllowed);
  236. }
  237. }
  238. //-------------------------------------------------------------------------------------------//
  239. void CAudioControlsEditorWindow::UpdateAudioSystemData()
  240. {
  241. auto audioSystem = AZ::Interface<Audio::IAudioSystem>::Get();
  242. IAudioSystemEditor* audioSystemImpl = CAudioControlsEditorPlugin::GetAudioSystemEditorImpl();
  243. if (!audioSystemImpl || !audioSystem)
  244. {
  245. return;
  246. }
  247. // clear the AudioSystem controls data
  248. Audio::SystemRequest::UnloadControls unloadControls;
  249. unloadControls.m_scope = Audio::eADS_ALL;
  250. audioSystem->PushRequest(AZStd::move(unloadControls));
  251. // parse the AudioSystem global config data
  252. // this is technically incorrect, we should just use GetControlsPath() unmodified when loading controls.
  253. // calling GetEditingGameDataFolder ensures that the reloaded file has been written to, a temp fix.
  254. // once we can listen to delete messages from Asset system, this can be changed to an EBus handler.
  255. const char* controlsPath = audioSystem->GetControlsPath();
  256. AZ::IO::FixedMaxPath controlsFolder{ controlsPath };
  257. // load the controls again
  258. Audio::SystemRequest::LoadControls loadGlobalControls;
  259. loadGlobalControls.m_scope = Audio::eADS_GLOBAL;
  260. audioSystem->PushRequest(AZStd::move(loadGlobalControls));
  261. // parse the AudioSystem level-specific config data
  262. AZStd::string levelName;
  263. AzToolsFramework::EditorRequestBus::BroadcastResult(levelName, &AzToolsFramework::EditorRequests::GetLevelName);
  264. if (!levelName.empty() && levelName != "Untitled")
  265. {
  266. controlsFolder /= "levels";
  267. controlsFolder /= levelName;
  268. Audio::SystemRequest::LoadControls loadLevelControls;
  269. loadLevelControls.m_scope = Audio::eADS_LEVEL_SPECIFIC;
  270. audioSystem->PushRequest(AZStd::move(loadLevelControls));
  271. }
  272. // inform the middleware specific plugin that the data has been saved
  273. // to disk (in case it needs to update something)
  274. audioSystemImpl->DataSaved();
  275. }
  276. //-------------------------------------------------------------------------------------------//
  277. void CAudioControlsEditorWindow::OnEditorNotifyEvent(EEditorNotifyEvent event)
  278. {
  279. if (event == eNotify_OnEndSceneSave)
  280. {
  281. CAudioControlsEditorPlugin::ReloadScopes();
  282. m_pInspectorPanel->Reload();
  283. }
  284. }
  285. //-------------------------------------------------------------------------------------------//
  286. void CAudioControlsEditorWindow::FilterControlType(EACEControlType type, bool bShow)
  287. {
  288. m_pAudioSystemPanel->SetAllowedControls(type, bShow);
  289. }
  290. //-------------------------------------------------------------------------------------------//
  291. void CAudioControlsEditorWindow::ReloadMiddlewareData()
  292. {
  293. IAudioSystemEditor* pAudioSystemImpl = CAudioControlsEditorPlugin::GetAudioSystemEditorImpl();
  294. if (pAudioSystemImpl)
  295. {
  296. pAudioSystemImpl->Reload();
  297. }
  298. m_pAudioSystemPanel->Reload();
  299. m_pInspectorPanel->Reload();
  300. }
  301. } // namespace AudioControls
  302. #include <Source/Editor/moc_AudioControlsEditorWindow.cpp>