3
0

ATLControlsPanel.cpp 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895
  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 <ATLControlsPanel.h>
  9. #include <AzCore/StringFunc/StringFunc.h>
  10. #include <AzQtComponents/Components/Style.h>
  11. #include <ACEEnums.h>
  12. #include <ATLControlsModel.h>
  13. #include <AudioControl.h>
  14. #include <AudioControlsEditorPlugin.h>
  15. #include <IAudioSystemControl.h>
  16. #include <IAudioSystemEditor.h>
  17. #include <QAudioControlEditorIcons.h>
  18. #include <QWidgetAction>
  19. #include <QPushButton>
  20. #include <QPaintEvent>
  21. #include <QPainter>
  22. #include <QMessageBox>
  23. #include <QMimeData>
  24. #include <QStandardItemModel>
  25. #include <QStandardItem>
  26. #include <QKeyEvent>
  27. #include <QSortFilterProxyModel>
  28. #include <QModelIndex>
  29. #include <QCoreApplication>
  30. #include <QWidgetAction>
  31. #include <QIcon>
  32. namespace AudioControls
  33. {
  34. //-------------------------------------------------------------------------------------------//
  35. const QString s_addMenuStyleSheetAdjustments("QMenu::icon { left: 0px; right: 6px; }");
  36. QFilterButton::QFilterButton(const QIcon& icon, [[maybe_unused]] const QString& text, QWidget* parent)
  37. : QWidget(parent)
  38. {
  39. QHBoxLayout* mainLayout = new QHBoxLayout(this);
  40. mainLayout->setSpacing(0);
  41. mainLayout->setContentsMargins(0, 0, 0, 0);
  42. // Add the sub widgets to a parent so that the correct area is highlighted on mouseover.
  43. m_background = new QWidget(this);
  44. m_background->show();
  45. setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
  46. const QMargins margin = QMargins(5, 2, 5, 2);
  47. // Add class to fix hover state styling for WidgetAction
  48. AzQtComponents::Style::addClass(this, "WidgetAction");
  49. QHBoxLayout* layout = new QHBoxLayout(m_background);
  50. layout->setSpacing(1);
  51. QIcon* checkMarkI = new QIcon(":/stylesheet/img/UI20/checkmark-menu.svg");
  52. m_checkIcon.setPixmap(checkMarkI->pixmap(16));
  53. QSizePolicy sp = m_checkIcon.sizePolicy();
  54. sp.setRetainSizeWhenHidden(true);
  55. m_checkIcon.setSizePolicy(sp);
  56. layout->addWidget(&m_checkIcon);
  57. m_filterIcon.setPixmap(icon.pixmap(16, 16));
  58. layout->addWidget(&m_actionText);
  59. layout->addStretch();
  60. layout->addWidget(&m_filterIcon);
  61. layout->setContentsMargins(margin);
  62. m_background->setLayout(layout);
  63. mainLayout->addWidget(m_background);
  64. setLayout(mainLayout);
  65. }
  66. void QFilterButton::mousePressEvent(QMouseEvent* event)
  67. {
  68. QWidget::mousePressEvent(event);
  69. SetChecked(!m_checked);
  70. emit clicked(m_checked);
  71. }
  72. void QFilterButton::enterEvent(QEvent* /*event*/)
  73. {
  74. setStyleSheet("background-color: #444444;");
  75. }
  76. void QFilterButton::leaveEvent(QEvent* /*event*/)
  77. {
  78. setStyleSheet("background-color: transparent;");
  79. }
  80. void QFilterButton::SetChecked(bool checked)
  81. {
  82. m_checked = checked;
  83. m_checkIcon.setVisible(checked);
  84. }
  85. //-------------------------------------------------------------------------------------------//
  86. CATLControlsPanel::CATLControlsPanel(CATLControlsModel* pATLModel, QATLTreeModel* pATLControlsModel)
  87. : m_pATLModel(pATLModel)
  88. , m_pTreeModel(pATLControlsModel)
  89. , m_showUnassignedControls(false)
  90. {
  91. setupUi(this);
  92. m_pATLControlsTree->installEventFilter(this);
  93. m_pATLControlsTree->viewport()->installEventFilter(this);
  94. // ************ Context Menu ************
  95. m_addItemMenu.setStyleSheet(s_addMenuStyleSheetAdjustments);
  96. m_addItemMenu.addAction(GetControlTypeIcon(eACET_TRIGGER), tr("Trigger"), this, SLOT(CreateTriggerControl()));
  97. m_addItemMenu.addAction(GetControlTypeIcon(eACET_RTPC), tr("RTPC"), this, SLOT(CreateRTPCControl()));
  98. m_addItemMenu.addAction(GetControlTypeIcon(eACET_SWITCH), tr("Switch"), this, SLOT(CreateSwitchControl()));
  99. m_addItemMenu.addAction(GetControlTypeIcon(eACET_ENVIRONMENT), tr("Environment"), this, SLOT(CreateEnvironmentsControl()));
  100. m_addItemMenu.addAction(GetControlTypeIcon(eACET_PRELOAD), tr("Preload"), this, SLOT(CreatePreloadControl()));
  101. m_addItemMenu.addSeparator();
  102. m_addItemMenu.addAction(GetFolderIcon(), tr("Folder"), this, SLOT(CreateFolder()));
  103. m_pAddButton->setMenu(&m_addItemMenu);
  104. m_pATLControlsTree->setContextMenuPolicy(Qt::CustomContextMenu);
  105. connect(m_pATLControlsTree, SIGNAL(customContextMenuRequested(const QPoint&)), SLOT(ShowControlsContextMenu(const QPoint&)));
  106. // *********************************
  107. // ************ Filtering ************
  108. for (int i = 0; i < eACET_NUM_TYPES; ++i)
  109. {
  110. EACEControlType type = ( EACEControlType )i;
  111. QWidgetAction* pWidgetAction = new QWidgetAction(this);
  112. m_pControlTypeFilterButtons[type] = new QFilterButton(GetControlTypeIcon(type), "", this);
  113. m_pControlTypeFilterButtons[type]->SetChecked(true);
  114. if (type != eACET_SWITCH_STATE)
  115. {
  116. pWidgetAction->setDefaultWidget(m_pControlTypeFilterButtons[type]);
  117. m_filterMenu.addAction(pWidgetAction);
  118. }
  119. }
  120. QWidgetAction* pWidgetAction = new QWidgetAction(this);
  121. m_unassignedFilterButton = new QFilterButton(QIcon(":/Icons/Unassigned.svg"), "", this);
  122. m_unassignedFilterButton->SetText("Unassigned");
  123. m_unassignedFilterButton->SetChecked(m_showUnassignedControls);
  124. pWidgetAction->setDefaultWidget(m_unassignedFilterButton);
  125. m_filterMenu.addAction(pWidgetAction);
  126. m_pFiltersButton->setMenu(&m_filterMenu);
  127. m_pControlTypeFilterButtons[eACET_TRIGGER]->SetText("Triggers");
  128. m_pControlTypeFilterButtons[eACET_RTPC]->SetText("RTPCs");
  129. m_pControlTypeFilterButtons[eACET_SWITCH]->SetText("Switches");
  130. m_pControlTypeFilterButtons[eACET_SWITCH_STATE]->hide();
  131. m_pControlTypeFilterButtons[eACET_ENVIRONMENT]->SetText("Environments");
  132. m_pControlTypeFilterButtons[eACET_PRELOAD]->SetText("Preloads");
  133. connect(m_pControlTypeFilterButtons[eACET_TRIGGER], SIGNAL(clicked(bool)), this, SLOT(ShowTriggers(bool)));
  134. connect(m_pControlTypeFilterButtons[eACET_RTPC], SIGNAL(clicked(bool)), this, SLOT(ShowRTPCs(bool)));
  135. connect(m_pControlTypeFilterButtons[eACET_SWITCH], SIGNAL(clicked(bool)), this, SLOT(ShowSwitches(bool)));
  136. connect(m_pControlTypeFilterButtons[eACET_ENVIRONMENT], SIGNAL(clicked(bool)), this, SLOT(ShowEnvironments(bool)));
  137. connect(m_pControlTypeFilterButtons[eACET_PRELOAD], SIGNAL(clicked(bool)), this, SLOT(ShowPreloads(bool)));
  138. connect(m_unassignedFilterButton, SIGNAL(clicked(bool)), this, SLOT(ShowUnassigned(bool)));
  139. connect(m_pTextFilter, SIGNAL(textChanged(QString)), this, SLOT(SetFilterString(QString)));
  140. // *********************************
  141. m_pATLModel->AddListener(this);
  142. // Load data into tree control
  143. QAudioControlSortProxy* pProxyModel = new QAudioControlSortProxy(this);
  144. pProxyModel->setSourceModel(m_pTreeModel);
  145. m_pATLControlsTree->setModel(pProxyModel);
  146. m_pProxyModel = pProxyModel;
  147. QAction* pAction = new QAction(tr("Delete"), this);
  148. pAction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
  149. pAction->setShortcut(QKeySequence::Delete);
  150. connect(pAction, SIGNAL(triggered()), this, SLOT(DeleteSelectedControl()));
  151. m_pATLControlsTree->addAction(pAction);
  152. connect(m_pATLControlsTree->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), this, SIGNAL(SelectedControlChanged()));
  153. connect(m_pATLControlsTree->selectionModel(), SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)), this, SLOT(StopControlExecution()));
  154. connect(m_pTreeModel, SIGNAL(itemChanged(QStandardItem*)), this, SLOT(ItemModified(QStandardItem*)));
  155. }
  156. //-------------------------------------------------------------------------------------------//
  157. void CATLControlsPanel::ApplyFilter()
  158. {
  159. QModelIndex index = m_pProxyModel->index(0, 0);
  160. for (int i = 0; index.isValid(); ++i)
  161. {
  162. ApplyFilter(index);
  163. index = index.sibling(i, 0);
  164. }
  165. }
  166. //-------------------------------------------------------------------------------------------//
  167. void CATLControlsPanel::SetFilterString(const QString& sFilterText)
  168. {
  169. m_sFilter = sFilterText;
  170. ApplyFilter();
  171. }
  172. //-------------------------------------------------------------------------------------------//
  173. bool CATLControlsPanel::ApplyFilter(const QModelIndex parent)
  174. {
  175. if (parent.isValid())
  176. {
  177. bool bIsValid = false;
  178. bool bHasChildren = false;
  179. QModelIndex child = parent.model()->index(0, 0, parent);
  180. for (int i = 1; child.isValid(); ++i)
  181. {
  182. bHasChildren = true;
  183. if (ApplyFilter(child))
  184. {
  185. bIsValid = true;
  186. }
  187. child = parent.model()->index(i, 0, parent);
  188. }
  189. if (!bIsValid && IsValid(parent))
  190. {
  191. if (!bHasChildren || parent.data(eDR_TYPE) != eIT_FOLDER)
  192. {
  193. // we want to hide empty folders, but show controls (ie. switches) even
  194. // if their children are hidden
  195. bIsValid = true;
  196. }
  197. }
  198. m_pATLControlsTree->setRowHidden(parent.row(), parent.parent(), !bIsValid);
  199. return bIsValid;
  200. }
  201. return false;
  202. }
  203. //-------------------------------------------------------------------------------------------//
  204. bool CATLControlsPanel::IsValid(const QModelIndex index)
  205. {
  206. const QString sName = index.data(Qt::DisplayRole).toString();
  207. if (m_sFilter.isEmpty() || sName.contains(m_sFilter, Qt::CaseInsensitive))
  208. {
  209. if (index.data(eDR_TYPE) == eIT_AUDIO_CONTROL)
  210. {
  211. const CATLControl* pControl = m_pATLModel->GetControlByID(index.data(eDR_ID).toUInt());
  212. if (pControl)
  213. {
  214. // This treats switches and switchstates the same so the ATL controls panel filters work.
  215. EACEControlType eType = pControl->GetType();
  216. if (eType == eACET_SWITCH_STATE)
  217. {
  218. eType = eACET_SWITCH;
  219. }
  220. if (m_visibleTypes[eType])
  221. {
  222. if (m_showUnassignedControls)
  223. {
  224. return !pControl->IsFullyConnected();
  225. }
  226. else
  227. {
  228. return true;
  229. }
  230. }
  231. return false;
  232. }
  233. }
  234. return true;
  235. }
  236. return false;
  237. }
  238. //-------------------------------------------------------------------------------------------//
  239. CATLControlsPanel::~CATLControlsPanel()
  240. {
  241. StopControlExecution();
  242. m_pATLModel->RemoveListener(this);
  243. }
  244. //-------------------------------------------------------------------------------------------//
  245. bool CATLControlsPanel::eventFilter(QObject* pObject, QEvent* pEvent)
  246. {
  247. if (pEvent->type() == QEvent::KeyRelease)
  248. {
  249. QKeyEvent* pKeyEvent = static_cast<QKeyEvent*>(pEvent);
  250. if (pKeyEvent && !m_pATLControlsTree->IsEditing())
  251. {
  252. if (pKeyEvent->key() == Qt::Key_Delete)
  253. {
  254. DeleteSelectedControl();
  255. }
  256. else if (pKeyEvent->key() == Qt::Key_Space)
  257. {
  258. ExecuteControl();
  259. }
  260. else if (pKeyEvent->key() == Qt::Key_Escape)
  261. {
  262. DeselectAll();
  263. }
  264. }
  265. }
  266. else if (pEvent->type() == QEvent::MouseButtonRelease)
  267. {
  268. QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(pEvent);
  269. if (mouseEvent && mouseEvent->button() == Qt::LeftButton)
  270. {
  271. QModelIndex index = m_pATLControlsTree->indexAt(mouseEvent->pos());
  272. if (!index.isValid())
  273. {
  274. DeselectAll();
  275. }
  276. }
  277. }
  278. else if (pEvent->type() == QEvent::Drop)
  279. {
  280. QDropEvent* pDropEvent = static_cast<QDropEvent*>(pEvent);
  281. if (pDropEvent)
  282. {
  283. if (pDropEvent->source() != m_pATLControlsTree)
  284. {
  285. // External Drop
  286. HandleExternalDropEvent(pDropEvent);
  287. pDropEvent->accept();
  288. }
  289. }
  290. }
  291. return QWidget::eventFilter(pObject, pEvent);
  292. }
  293. //-------------------------------------------------------------------------------------------//
  294. ControlList CATLControlsPanel::GetSelectedControls()
  295. {
  296. ControlList controls;
  297. QModelIndexList indexes = m_pATLControlsTree->selectionModel()->selectedIndexes();
  298. const int size = indexes.size();
  299. for (int i = 0; i < size; ++i)
  300. {
  301. if (indexes[i].isValid())
  302. {
  303. CID nID = indexes[i].data(eDR_ID).toUInt();
  304. if (nID != ACE_INVALID_CID)
  305. {
  306. controls.push_back(nID);
  307. }
  308. }
  309. }
  310. return controls;
  311. }
  312. //-------------------------------------------------------------------------------------------//
  313. void CATLControlsPanel::Reload()
  314. {
  315. ResetFilters();
  316. }
  317. //-------------------------------------------------------------------------------------------//
  318. void CATLControlsPanel::ShowControlType(EACEControlType type, bool bShow, bool bExclusive)
  319. {
  320. if (bExclusive)
  321. {
  322. for (int i = 0; i < eACET_NUM_TYPES; ++i)
  323. {
  324. EACEControlType controlType = (EACEControlType)i;
  325. m_visibleTypes[controlType] = !bShow;
  326. ControlTypeFiltered(controlType, !bShow);
  327. m_pControlTypeFilterButtons[controlType]->SetChecked(!bShow);
  328. }
  329. }
  330. m_visibleTypes[type] = bShow;
  331. ControlTypeFiltered(type, bShow);
  332. m_pControlTypeFilterButtons[type]->SetChecked(bShow);
  333. ApplyFilter();
  334. }
  335. //-------------------------------------------------------------------------------------------//
  336. void CATLControlsPanel::ShowTriggers(bool bShow)
  337. {
  338. ShowControlType(eACET_TRIGGER, bShow, QGuiApplication::keyboardModifiers() & Qt::ControlModifier);
  339. }
  340. //-------------------------------------------------------------------------------------------//
  341. void CATLControlsPanel::ShowRTPCs(bool bShow)
  342. {
  343. ShowControlType(eACET_RTPC, bShow, QGuiApplication::keyboardModifiers() & Qt::ControlModifier);
  344. }
  345. //-------------------------------------------------------------------------------------------//
  346. void CATLControlsPanel::ShowEnvironments(bool bShow)
  347. {
  348. ShowControlType(eACET_ENVIRONMENT, bShow, QGuiApplication::keyboardModifiers() & Qt::ControlModifier);
  349. }
  350. //-------------------------------------------------------------------------------------------//
  351. void CATLControlsPanel::ShowSwitches(bool bShow)
  352. {
  353. ShowControlType(eACET_SWITCH, bShow, QGuiApplication::keyboardModifiers() & Qt::ControlModifier);
  354. }
  355. //-------------------------------------------------------------------------------------------//
  356. void CATLControlsPanel::ShowPreloads(bool bShow)
  357. {
  358. ShowControlType(eACET_PRELOAD, bShow, QGuiApplication::keyboardModifiers() & Qt::ControlModifier);
  359. }
  360. //-------------------------------------------------------------------------------------------//
  361. void CATLControlsPanel::ShowUnassigned(bool bShow)
  362. {
  363. m_showUnassignedControls = bShow;
  364. ApplyFilter();
  365. }
  366. //-------------------------------------------------------------------------------------------//
  367. void CATLControlsPanel::CreateRTPCControl()
  368. {
  369. CATLControl* pControl = m_pTreeModel->CreateControl(eACET_RTPC, "rtpc");
  370. if (pControl)
  371. {
  372. SelectItem(AddControl(pControl));
  373. m_pATLControlsTree->setFocus();
  374. m_pATLControlsTree->edit(m_pATLControlsTree->currentIndex());
  375. }
  376. }
  377. //-------------------------------------------------------------------------------------------//
  378. void CATLControlsPanel::CreateSwitchControl()
  379. {
  380. CATLControl* pControl = m_pTreeModel->CreateControl(eACET_SWITCH, "switch");
  381. if (pControl)
  382. {
  383. SelectItem(AddControl(pControl));
  384. m_pATLControlsTree->setFocus();
  385. m_pATLControlsTree->edit(m_pATLControlsTree->currentIndex());
  386. }
  387. }
  388. //-------------------------------------------------------------------------------------------//
  389. void CATLControlsPanel::CreateStateControl()
  390. {
  391. QStandardItem* pSelectedItem = GetCurrentItem();
  392. if (pSelectedItem && IsValidParent(pSelectedItem, eACET_SWITCH_STATE))
  393. {
  394. CATLControl* pControl = m_pTreeModel->CreateControl(eACET_SWITCH_STATE, "state", GetControlFromItem(pSelectedItem));
  395. if (pControl)
  396. {
  397. SelectItem(AddControl(pControl));
  398. m_pATLControlsTree->setFocus();
  399. m_pATLControlsTree->edit(m_pATLControlsTree->currentIndex());
  400. }
  401. }
  402. }
  403. //-------------------------------------------------------------------------------------------//
  404. void CATLControlsPanel::CreateTriggerControl()
  405. {
  406. CATLControl* pControl = m_pTreeModel->CreateControl(eACET_TRIGGER, "trigger");
  407. if (pControl)
  408. {
  409. SelectItem(AddControl(pControl));
  410. m_pATLControlsTree->setFocus();
  411. m_pATLControlsTree->edit(m_pATLControlsTree->currentIndex());
  412. }
  413. }
  414. //-------------------------------------------------------------------------------------------//
  415. void CATLControlsPanel::CreateEnvironmentsControl()
  416. {
  417. CATLControl* pControl = m_pTreeModel->CreateControl(eACET_ENVIRONMENT, "environment");
  418. if (pControl)
  419. {
  420. SelectItem(AddControl(pControl));
  421. m_pATLControlsTree->setFocus();
  422. m_pATLControlsTree->edit(m_pATLControlsTree->currentIndex());
  423. }
  424. }
  425. //-------------------------------------------------------------------------------------------//
  426. void CATLControlsPanel::CreatePreloadControl()
  427. {
  428. CATLControl* pControl = m_pTreeModel->CreateControl(eACET_PRELOAD, "preload");
  429. if (pControl)
  430. {
  431. SelectItem(AddControl(pControl));
  432. m_pATLControlsTree->setFocus();
  433. m_pATLControlsTree->edit(m_pATLControlsTree->currentIndex());
  434. }
  435. }
  436. //-------------------------------------------------------------------------------------------//
  437. QStandardItem* CATLControlsPanel::CreateFolder()
  438. {
  439. QModelIndex parent = m_pATLControlsTree->currentIndex();
  440. while (parent.isValid() && (parent.data(eDR_TYPE) != eIT_FOLDER))
  441. {
  442. parent = parent.parent();
  443. }
  444. QStandardItem* pParentItem = nullptr;
  445. QModelIndexList indexes = m_pATLControlsTree->selectionModel()->selectedIndexes();
  446. if (parent.isValid() && indexes.size() > 0)
  447. {
  448. pParentItem = m_pTreeModel->itemFromIndex(m_pProxyModel->mapToSource(parent));
  449. if (parent.isValid() && m_pATLControlsTree->isRowHidden(parent.row(), parent.parent()))
  450. {
  451. ResetFilters();
  452. }
  453. }
  454. else
  455. {
  456. pParentItem = m_pTreeModel->invisibleRootItem();
  457. }
  458. QStandardItem* pFolder = m_pTreeModel->CreateFolder(pParentItem, "new_folder");
  459. SelectItem(pFolder);
  460. m_pATLControlsTree->setFocus();
  461. m_pATLControlsTree->edit(m_pATLControlsTree->currentIndex());
  462. return pFolder;
  463. }
  464. //-------------------------------------------------------------------------------------------//
  465. bool CATLControlsPanel::IsValidParent(QStandardItem* pParent, const EACEControlType eControlType)
  466. {
  467. if (pParent->data(eDR_TYPE) == eIT_FOLDER)
  468. {
  469. return eControlType != eACET_SWITCH_STATE;
  470. }
  471. else if (eControlType == eACET_SWITCH_STATE)
  472. {
  473. CATLControl* pControl = GetControlFromItem(pParent);
  474. if (pControl)
  475. {
  476. return pControl->GetType() == eACET_SWITCH;
  477. }
  478. }
  479. return false;
  480. }
  481. //-------------------------------------------------------------------------------------------//
  482. QStandardItem* CATLControlsPanel::AddControl(CATLControl* pControl)
  483. {
  484. if (pControl)
  485. {
  486. // Find a suitable parent for the new control starting from the one currently selected
  487. QStandardItem* pParent = GetCurrentItem();
  488. if (pParent)
  489. {
  490. while (pParent && !IsValidParent(pParent, pControl->GetType()))
  491. {
  492. pParent = pParent->parent();
  493. }
  494. }
  495. if (!pParent)
  496. {
  497. AZ_Assert(pControl->GetType() != eACET_SWITCH_STATE, "AddControl - SwitchState control being added needs to be placed under a suitable parent (Switch)");
  498. pParent = CreateFolder();
  499. }
  500. return m_pTreeModel->AddControl(pControl, pParent);
  501. }
  502. return nullptr;
  503. }
  504. //-------------------------------------------------------------------------------------------//
  505. void CATLControlsPanel::ShowControlsContextMenu(const QPoint& pos)
  506. {
  507. QMenu contextMenu(tr("Context menu"), this);
  508. QMenu addMenu(tr("Add"));
  509. CATLControl* pControl = GetControlFromIndex(m_pATLControlsTree->currentIndex());
  510. if (pControl)
  511. {
  512. switch (pControl->GetType())
  513. {
  514. case eACET_TRIGGER:
  515. contextMenu.addAction(tr("Execute Trigger"), this, SLOT(ExecuteControl()));
  516. contextMenu.addSeparator();
  517. break;
  518. case eACET_SWITCH:
  519. case eACET_SWITCH_STATE:
  520. addMenu.addAction(GetControlTypeIcon(eACET_SWITCH_STATE), tr("State"), this, SLOT(CreateStateControl()));
  521. addMenu.addSeparator();
  522. break;
  523. }
  524. }
  525. addMenu.setStyleSheet(s_addMenuStyleSheetAdjustments);
  526. addMenu.addAction(GetControlTypeIcon(eACET_TRIGGER), tr("Trigger"), this, SLOT(CreateTriggerControl()));
  527. addMenu.addAction(GetControlTypeIcon(eACET_RTPC), tr("RTPC"), this, SLOT(CreateRTPCControl()));
  528. addMenu.addAction(GetControlTypeIcon(eACET_SWITCH), tr("Switch"), this, SLOT(CreateSwitchControl()));
  529. addMenu.addAction(GetControlTypeIcon(eACET_ENVIRONMENT), tr("Environment"), this, SLOT(CreateEnvironmentsControl()));
  530. addMenu.addAction(GetControlTypeIcon(eACET_PRELOAD), tr("Preload"), this, SLOT(CreatePreloadControl()));
  531. addMenu.addSeparator();
  532. addMenu.addAction(GetFolderIcon(), tr("Folder"), this, SLOT(CreateFolder()));
  533. contextMenu.addMenu(&addMenu);
  534. QAction* pAction = new QAction(tr("Rename"), this);
  535. connect(pAction, &QAction::triggered, m_pATLControlsTree,
  536. [&]()
  537. {
  538. m_pATLControlsTree->edit(m_pATLControlsTree->currentIndex());
  539. }
  540. );
  541. contextMenu.addAction(pAction);
  542. pAction = new QAction(tr("Delete"), this);
  543. connect(pAction, SIGNAL(triggered()), this, SLOT(DeleteSelectedControl()));
  544. contextMenu.addAction(pAction);
  545. contextMenu.addSeparator();
  546. pAction = new QAction(tr("Expand All"), this);
  547. connect(pAction, SIGNAL(triggered()), m_pATLControlsTree, SLOT(expandAll()));
  548. contextMenu.addAction(pAction);
  549. pAction = new QAction(tr("Collapse All"), this);
  550. connect(pAction, SIGNAL(triggered()), m_pATLControlsTree, SLOT(collapseAll()));
  551. contextMenu.addAction(pAction);
  552. contextMenu.exec(m_pATLControlsTree->mapToGlobal(pos));
  553. }
  554. //-------------------------------------------------------------------------------------------//
  555. void CATLControlsPanel::DeleteSelectedControl()
  556. {
  557. QMessageBox messageBox(this);
  558. QModelIndexList indexList = m_pATLControlsTree->selectionModel()->selectedIndexes();
  559. const int size = indexList.length();
  560. if (size > 0)
  561. {
  562. if (size == 1)
  563. {
  564. QModelIndex index = m_pProxyModel->mapToSource(indexList[0]);
  565. QStandardItem* pItem = m_pTreeModel->itemFromIndex(index);
  566. if (pItem)
  567. {
  568. messageBox.setText("Are you sure you want to delete \"" + pItem->text() + "\"?");
  569. }
  570. }
  571. else
  572. {
  573. messageBox.setText("Are you sure you want to delete the selected controls and folders?");
  574. }
  575. messageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
  576. messageBox.setDefaultButton(QMessageBox::Yes);
  577. messageBox.setWindowTitle("Audio Controls Editor");
  578. if (messageBox.exec() == QMessageBox::Yes)
  579. {
  580. CUndo undo("Audio Control Removed");
  581. QModelIndexList sourceIndexList;
  582. for (int i = 0; i < size; ++i)
  583. {
  584. sourceIndexList.push_back(m_pProxyModel->mapToSource(indexList[i]));
  585. }
  586. m_pTreeModel->RemoveItems(sourceIndexList);
  587. }
  588. }
  589. }
  590. //-------------------------------------------------------------------------------------------//
  591. void CATLControlsPanel::OnControlAdded(CATLControl* pControl)
  592. {
  593. // Remove filters if the control added is hidden
  594. EACEControlType controlType = pControl->GetType();
  595. if (!m_visibleTypes[controlType])
  596. {
  597. m_visibleTypes[controlType] = true;
  598. m_pControlTypeFilterButtons[controlType]->SetChecked(true);
  599. }
  600. m_pTextFilter->setText("");
  601. ApplyFilter();
  602. }
  603. //-------------------------------------------------------------------------------------------//
  604. void CATLControlsPanel::ExecuteControl()
  605. {
  606. const CATLControl* const pControl = GetControlFromIndex(m_pATLControlsTree->currentIndex());
  607. if (pControl)
  608. {
  609. CAudioControlsEditorPlugin::ExecuteTrigger(pControl->GetName());
  610. }
  611. }
  612. //-------------------------------------------------------------------------------------------//
  613. void CATLControlsPanel::StopControlExecution()
  614. {
  615. CAudioControlsEditorPlugin::StopTriggerExecution();
  616. }
  617. //-------------------------------------------------------------------------------------------//
  618. CATLControl* CATLControlsPanel::GetControlFromItem(QStandardItem* pItem)
  619. {
  620. if (pItem && (pItem->data(eDR_TYPE) == eIT_AUDIO_CONTROL))
  621. {
  622. return m_pATLModel->GetControlByID(pItem->data(eDR_ID).toUInt());
  623. }
  624. return nullptr;
  625. }
  626. //-------------------------------------------------------------------------------------------//
  627. CATLControl* CATLControlsPanel::GetControlFromIndex(QModelIndex index)
  628. {
  629. if (index.isValid() && (index.data(eDR_TYPE) == eIT_AUDIO_CONTROL))
  630. {
  631. return m_pATLModel->GetControlByID(index.data(eDR_ID).toUInt());
  632. }
  633. return nullptr;
  634. }
  635. //-------------------------------------------------------------------------------------------//
  636. void CATLControlsPanel::SelectItem(QStandardItem* pItem)
  637. {
  638. // Expand and scroll to the new item
  639. if (pItem)
  640. {
  641. QModelIndex index = m_pTreeModel->indexFromItem(pItem);
  642. if (index.isValid())
  643. {
  644. m_pATLControlsTree->selectionModel()->setCurrentIndex(m_pProxyModel->mapFromSource(index), QItemSelectionModel::ClearAndSelect);
  645. }
  646. }
  647. }
  648. //-------------------------------------------------------------------------------------------//
  649. void CATLControlsPanel::DeselectAll()
  650. {
  651. m_pATLControlsTree->selectionModel()->clear();
  652. }
  653. //-------------------------------------------------------------------------------------------//
  654. void CATLControlsPanel::HandleExternalDropEvent(QDropEvent* pDropEvent)
  655. {
  656. AudioControls::IAudioSystemEditor* pAudioSystemEditorImpl = CAudioControlsEditorPlugin::GetAudioSystemEditorImpl();
  657. if (pAudioSystemEditorImpl)
  658. {
  659. const QMimeData* pData = pDropEvent->mimeData();
  660. const QString format = "application/x-qabstractitemmodeldatalist";
  661. if (pData->hasFormat(format))
  662. {
  663. QByteArray encoded = pData->data(format);
  664. QDataStream stream(&encoded, QIODevice::ReadOnly);
  665. while (!stream.atEnd())
  666. {
  667. int row, col;
  668. QMap<int, QVariant> roleDataMap;
  669. stream >> row >> col >> roleDataMap;
  670. if (!roleDataMap.isEmpty())
  671. {
  672. // Dropped item mime data
  673. IAudioSystemControl* pAudioSystemControl = pAudioSystemEditorImpl->GetControl(roleDataMap[eMDR_ID].toUInt());
  674. if (pAudioSystemControl)
  675. {
  676. const EACEControlType eControlType = pAudioSystemEditorImpl->ImplTypeToATLType(pAudioSystemControl->GetType());
  677. // If dropped outside any folder, create a folder at the root to contain the new control
  678. const QModelIndex index = m_pProxyModel->mapToSource(m_pATLControlsTree->indexAt(pDropEvent->pos()));
  679. QStandardItem* pTargetItem = m_pTreeModel->itemFromIndex(index);
  680. if (!pTargetItem)
  681. {
  682. pTargetItem = m_pTreeModel->CreateFolder(m_pTreeModel->invisibleRootItem(), "new_folder");
  683. }
  684. // Find a suitable parent for the dropped control
  685. CATLControl* pATLParent = nullptr;
  686. CATLControl* pTargetControl = GetControlFromItem(pTargetItem);
  687. if (pTargetControl && pTargetControl->GetType() == eControlType)
  688. {
  689. // If dropped in a control of the same type, we can assume the parent is valid, so we select it
  690. pTargetItem = pTargetItem->parent();
  691. pATLParent = GetControlFromItem(pTargetItem);
  692. }
  693. else
  694. {
  695. // If the dragged control has a parent, need to find a suitable parent on the ATL side first
  696. const IAudioSystemControl* pAudioControlParent = pAudioSystemControl->GetParent();
  697. if (pAudioControlParent && pAudioControlParent->GetType() != AUDIO_IMPL_INVALID_TYPE)
  698. {
  699. // Is the place where item was dropped compatible with the parent we are looking for
  700. if (IsValidParent(pTargetItem, eControlType))
  701. {
  702. pATLParent = GetControlFromItem(pTargetItem);
  703. }
  704. else
  705. {
  706. // If place where item was dropped is not valid as a parent, we have to look for a valid control where to create one that is
  707. const EACEControlType eParentType = pAudioSystemEditorImpl->ImplTypeToATLType(pAudioControlParent->GetType());
  708. QStandardItem* pParent = pTargetItem;
  709. while (pParent && !IsValidParent(pParent, eParentType))
  710. {
  711. pParent = pParent->parent();
  712. }
  713. if (pParent)
  714. {
  715. pATLParent = m_pTreeModel->CreateControl(eParentType, pAudioControlParent->GetName());
  716. pTargetItem = m_pTreeModel->AddControl(pATLParent, pParent);
  717. }
  718. }
  719. }
  720. }
  721. if (pTargetItem)
  722. {
  723. while (pTargetItem && !IsValidParent(pTargetItem, eControlType))
  724. {
  725. pTargetItem = pTargetItem->parent();
  726. }
  727. // Create the new control and connect it to the one dragged in externally
  728. AZStd::string sControlName(roleDataMap[Qt::DisplayRole].toString().toUtf8().data());
  729. if (eControlType == eACET_PRELOAD)
  730. {
  731. AZ::StringFunc::Path::StripExtension(sControlName);
  732. }
  733. else if (eControlType == eACET_SWITCH_STATE)
  734. {
  735. if (!pATLParent->SwitchStateConnectionCheck(pAudioSystemControl))
  736. {
  737. QMessageBox messageBox(this);
  738. messageBox.setStandardButtons(QMessageBox::Ok);
  739. messageBox.setDefaultButton(QMessageBox::Ok);
  740. messageBox.setWindowTitle("Audio Controls Editor");
  741. messageBox.setText("Not in the same switch group, connection failed.");
  742. if (messageBox.exec() == QMessageBox::Ok)
  743. {
  744. return;
  745. }
  746. }
  747. }
  748. CATLControl* pTargetControl2 = m_pTreeModel->CreateControl(eControlType, sControlName, pATLParent);
  749. if (pTargetControl2)
  750. {
  751. TConnectionPtr pAudioConnection = pAudioSystemEditorImpl->CreateConnectionToControl(pTargetControl2->GetType(), pAudioSystemControl);
  752. if (pAudioConnection)
  753. {
  754. pTargetControl2->AddConnection(pAudioConnection);
  755. }
  756. pTargetItem = m_pTreeModel->AddControl(pTargetControl2, pTargetItem);
  757. SelectItem(pTargetItem);
  758. }
  759. }
  760. }
  761. }
  762. }
  763. }
  764. }
  765. }
  766. //-------------------------------------------------------------------------------------------//
  767. QStandardItem* CATLControlsPanel::GetCurrentItem()
  768. {
  769. return m_pTreeModel->itemFromIndex(m_pProxyModel->mapToSource(m_pATLControlsTree->currentIndex()));
  770. }
  771. //-------------------------------------------------------------------------------------------//
  772. void CATLControlsPanel::ResetFilters()
  773. {
  774. // Remove filters
  775. for (int i = 0; i < eACET_NUM_TYPES; ++i)
  776. {
  777. EACEControlType controlType = (EACEControlType)i;
  778. m_visibleTypes[controlType] = true;
  779. m_pControlTypeFilterButtons[controlType]->SetChecked(true);
  780. }
  781. m_pTextFilter->setText("");
  782. ApplyFilter();
  783. }
  784. //-------------------------------------------------------------------------------------------//
  785. void CATLControlsPanel::ItemModified(QStandardItem* pItem)
  786. {
  787. if (pItem)
  788. {
  789. AZStd::string sName(pItem->text().toUtf8().data());
  790. if (pItem->data(eDR_TYPE) == eIT_AUDIO_CONTROL)
  791. {
  792. CATLControl* pControl = m_pATLModel->GetControlByID(pItem->data(eDR_ID).toUInt());
  793. if (pControl)
  794. {
  795. if (pControl->GetName().compare(pItem->text().toUtf8().data()) != 0)
  796. {
  797. sName = m_pATLModel->GenerateUniqueName(sName, pControl->GetType(), pControl->GetScope(), pControl->GetParent());
  798. pControl->SetName(sName);
  799. }
  800. }
  801. m_pTreeModel->blockSignals(true);
  802. pItem->setText(QString(sName.c_str()));
  803. m_pTreeModel->blockSignals(false);
  804. }
  805. m_pTreeModel->SetItemAsDirty(pItem);
  806. }
  807. }
  808. } // namespace AudioControls
  809. #include <Source/Editor/moc_ATLControlsPanel.cpp>