ATLControlsResourceDialog.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  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 <ATLControlsResourceDialog.h>
  9. #include <AzCore/StringFunc/StringFunc.h>
  10. #include <ACEEnums.h>
  11. #include <ATLControlsModel.h>
  12. #include <AudioControlsEditorPlugin.h>
  13. #include <QAudioControlTreeWidget.h>
  14. #include <QDialogButtonBox>
  15. #include <QBoxLayout>
  16. #include <QApplication>
  17. #include <QHeaderView>
  18. #include <QStandardItemModel>
  19. #include <QPushButton>
  20. namespace AudioControls
  21. {
  22. //-------------------------------------------------------------------------------------------//
  23. ATLControlsDialog::ATLControlsDialog(QWidget* pParent, EACEControlType eType)
  24. : QDialog(pParent)
  25. , m_eType(eType)
  26. {
  27. AZ_Assert(CAudioControlsEditorPlugin::GetATLModel() != nullptr, "ATLControlsDialog - ATL Model is null!");
  28. setWindowTitle(GetWindowTitle(m_eType));
  29. setWindowModality(Qt::ApplicationModal);
  30. QBoxLayout* pLayout = new QBoxLayout(QBoxLayout::TopToBottom);
  31. setLayout(pLayout);
  32. m_TextFilterLineEdit = new QLineEdit(this);
  33. m_TextFilterLineEdit->setAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignVCenter);
  34. m_TextFilterLineEdit->setPlaceholderText(QApplication::translate("ATLControlsPanel", "Search", 0));
  35. connect(m_TextFilterLineEdit, &QLineEdit::textChanged, this, &ATLControlsDialog::SetTextFilter);
  36. connect(m_TextFilterLineEdit, &QLineEdit::returnPressed, this, &ATLControlsDialog::EnterPressed);
  37. pLayout->addWidget(m_TextFilterLineEdit, 0);
  38. m_pControlTree = new QAudioControlsTreeView(this);
  39. m_pControlTree->header()->setVisible(false);
  40. m_pControlTree->setEnabled(true);
  41. m_pControlTree->setAutoScroll(true);
  42. m_pControlTree->setDragEnabled(false);
  43. m_pControlTree->setDragDropMode(QAbstractItemView::NoDragDrop);
  44. m_pControlTree->setDefaultDropAction(Qt::IgnoreAction);
  45. m_pControlTree->setAlternatingRowColors(false);
  46. m_pControlTree->setSelectionMode(QAbstractItemView::SingleSelection);
  47. m_pControlTree->setRootIsDecorated(true);
  48. m_pControlTree->setSortingEnabled(true);
  49. m_pControlTree->setAnimated(false);
  50. m_pControlTree->setEditTriggers(QAbstractItemView::NoEditTriggers);
  51. pLayout->addWidget(m_pControlTree, 0);
  52. m_pATLModel = CAudioControlsEditorPlugin::GetATLModel();
  53. m_pTreeModel = CAudioControlsEditorPlugin::GetControlsTree();
  54. m_pProxyModel = new QAudioControlSortProxy(this);
  55. m_pProxyModel->setSourceModel(m_pTreeModel);
  56. m_pControlTree->setModel(m_pProxyModel);
  57. pDialogButtons = new QDialogButtonBox(this);
  58. pDialogButtons->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
  59. connect(pDialogButtons, SIGNAL(accepted()), this, SLOT(accept()));
  60. connect(pDialogButtons, SIGNAL(rejected()), this, SLOT(reject()));
  61. pLayout->addWidget(pDialogButtons, 0);
  62. connect(m_pControlTree->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), this, SLOT(UpdateSelectedControl()));
  63. ApplyFilter();
  64. UpdateSelectedControl();
  65. m_pControlTree->setFocus();
  66. m_pControlTree->installEventFilter(this);
  67. m_pControlTree->viewport()->installEventFilter(this);
  68. m_TextFilterLineEdit->installEventFilter(this);
  69. connect(m_pControlTree->selectionModel(), SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)), this, SLOT(StopTrigger()));
  70. }
  71. //-------------------------------------------------------------------------------------------//
  72. ATLControlsDialog::~ATLControlsDialog()
  73. {
  74. StopTrigger();
  75. }
  76. //-------------------------------------------------------------------------------------------//
  77. const char* ATLControlsDialog::ChooseItem(const char* currentValue)
  78. {
  79. m_sControlName = currentValue;
  80. if (m_pTreeModel && m_pProxyModel && !m_sControlName.empty())
  81. {
  82. QModelIndex index = FindItem(m_sControlName);
  83. if (index.isValid())
  84. {
  85. m_pControlTree->setCurrentIndex(index);
  86. }
  87. }
  88. if (exec() == QDialog::Accepted)
  89. {
  90. return m_sControlName.c_str();
  91. }
  92. return currentValue;
  93. }
  94. //-------------------------------------------------------------------------------------------//
  95. void ATLControlsDialog::UpdateSelectedControl()
  96. {
  97. m_sControlName.clear();
  98. if (m_pATLModel)
  99. {
  100. QModelIndexList indexes = m_pControlTree->selectionModel()->selectedIndexes();
  101. if (!indexes.empty())
  102. {
  103. const CATLControl* control = GetControlFromModelIndex(indexes[0]);
  104. if (control && IsCriteriaMatch(control))
  105. {
  106. m_sControlName = control->GetName();
  107. }
  108. }
  109. }
  110. if (QPushButton* pButton = pDialogButtons->button(QDialogButtonBox::Ok))
  111. {
  112. pButton->setEnabled(!m_sControlName.empty());
  113. }
  114. }
  115. //-------------------------------------------------------------------------------------------//
  116. void ATLControlsDialog::SetTextFilter(QString filter)
  117. {
  118. m_sFilter = filter;
  119. ApplyFilter();
  120. }
  121. //-------------------------------------------------------------------------------------------//
  122. void ATLControlsDialog::EnterPressed()
  123. {
  124. m_sFilter = m_TextFilterLineEdit->text();
  125. ApplyFilter();
  126. m_pControlTree->setFocus();
  127. }
  128. //-------------------------------------------------------------------------------------------//
  129. void ATLControlsDialog::ApplyFilter()
  130. {
  131. QModelIndex index = m_pProxyModel->index(0, 0);
  132. for (int i = 0; index.isValid(); ++i)
  133. {
  134. ApplyFilter(index);
  135. index = index.sibling(i, 0);
  136. }
  137. if (!m_sFilter.isEmpty())
  138. {
  139. m_pControlTree->expandAll();
  140. }
  141. }
  142. //-------------------------------------------------------------------------------------------//
  143. bool ATLControlsDialog::ApplyFilter(const QModelIndex parent)
  144. {
  145. if (parent.isValid())
  146. {
  147. bool bChildValid = false;
  148. QModelIndex child = parent.model()->index(0, 0, parent);
  149. for (int i = 1; child.isValid(); ++i)
  150. {
  151. if (ApplyFilter(child))
  152. {
  153. bChildValid = true;
  154. }
  155. child = parent.model()->index(i, 0, parent);
  156. }
  157. if (bChildValid || IsValid(parent))
  158. {
  159. m_pControlTree->setRowHidden(parent.row(), parent.parent(), false);
  160. return true;
  161. }
  162. else
  163. {
  164. m_pControlTree->setRowHidden(parent.row(), parent.parent(), true);
  165. }
  166. }
  167. return false;
  168. }
  169. //-------------------------------------------------------------------------------------------//
  170. bool ATLControlsDialog::IsValid(const QModelIndex index)
  171. {
  172. const QString sName = index.data(Qt::DisplayRole).toString();
  173. if (m_sFilter.isEmpty() || sName.contains(m_sFilter, Qt::CaseInsensitive))
  174. {
  175. if (index.data(eDR_TYPE) == eIT_AUDIO_CONTROL)
  176. {
  177. return IsCriteriaMatch(GetControlFromModelIndex(index));
  178. }
  179. }
  180. return false;
  181. }
  182. //-------------------------------------------------------------------------------------------//
  183. bool ATLControlsDialog::IsCriteriaMatch(const CATLControl* control) const
  184. {
  185. if (control)
  186. {
  187. AZStd::string sControlScope = control->GetScope();
  188. if (control->GetType() == m_eType && (sControlScope.empty() || AZ::StringFunc::Equal(sControlScope.c_str(), m_sScope.c_str())))
  189. {
  190. // LY-22029 - Only allow selecting Preload controls that are non-AutoLoad.
  191. // This change applies everywhere, to all Preload selectors, so if there's ever a need to select preloads
  192. // that are AutoLoad, then that option would need to be introduced to the resource selectors.
  193. // Note, there are no validation mechanisms in place if a user selects a preload, then later switches
  194. // it to be AutoLoad in the ACEditor. Any property containing that preload wouldn't know about it.
  195. // Fortunately, attempting to load one that's already been loaded won't double-dip.
  196. if (m_eType == eACET_PRELOAD && control->IsAutoLoad())
  197. {
  198. return false;
  199. }
  200. return true;
  201. }
  202. }
  203. return false;
  204. }
  205. //-------------------------------------------------------------------------------------------//
  206. const CATLControl* ATLControlsDialog::GetControlFromModelIndex(const QModelIndex index) const
  207. {
  208. CID controlId = index.isValid() ? index.data(eDR_ID).toUInt() : ACE_INVALID_CID;
  209. if (controlId != ACE_INVALID_CID)
  210. {
  211. return m_pATLModel->GetControlByID(controlId);
  212. }
  213. return nullptr;
  214. }
  215. //-------------------------------------------------------------------------------------------//
  216. QString ATLControlsDialog::GetWindowTitle(EACEControlType type) const
  217. {
  218. switch (type)
  219. {
  220. case eACET_TRIGGER:
  221. return QString(tr("Choose Trigger..."));
  222. case eACET_RTPC:
  223. return QString(tr("Choose Rtpc..."));
  224. case eACET_SWITCH:
  225. return QString(tr("Choose Switch..."));
  226. case eACET_SWITCH_STATE:
  227. return QString(tr("Choose Switch State..."));
  228. case eACET_ENVIRONMENT:
  229. return QString(tr("Choose Environment..."));
  230. case eACET_PRELOAD:
  231. return QString(tr("Choose Preload..."));
  232. default:
  233. return QString(tr("Choose..."));
  234. }
  235. }
  236. //-------------------------------------------------------------------------------------------//
  237. QSize ATLControlsDialog::sizeHint() const
  238. {
  239. return QSize(400, 900);
  240. }
  241. //-------------------------------------------------------------------------------------------//
  242. void ATLControlsDialog::SetScope(const AZStd::string& sScope)
  243. {
  244. m_sScope = sScope;
  245. ApplyFilter();
  246. }
  247. //-------------------------------------------------------------------------------------------//
  248. QModelIndex ATLControlsDialog::FindItem(const AZStd::string_view sControlName)
  249. {
  250. if (m_pTreeModel && m_pATLModel)
  251. {
  252. QModelIndexList indexes = m_pTreeModel->match(m_pTreeModel->index(0, 0, QModelIndex()), Qt::DisplayRole, QString(sControlName.data()), -1, Qt::MatchRecursive);
  253. if (!indexes.empty())
  254. {
  255. const int size = indexes.size();
  256. for (int i = 0; i < size; ++i)
  257. {
  258. QModelIndex index = indexes[i];
  259. if (index.isValid() && (index.data(eDR_TYPE) == eIT_AUDIO_CONTROL))
  260. {
  261. if (IsCriteriaMatch(GetControlFromModelIndex(index)))
  262. {
  263. return m_pProxyModel->mapFromSource(index);
  264. }
  265. }
  266. }
  267. }
  268. }
  269. return QModelIndex();
  270. }
  271. //-------------------------------------------------------------------------------------------//
  272. bool ATLControlsDialog::eventFilter(QObject* pObject, QEvent* pEvent)
  273. {
  274. if (pEvent->type() == QEvent::FocusIn && pObject == m_TextFilterLineEdit)
  275. {
  276. // Clear the selection when moving to the line edit, so that the enter key does not select the item.
  277. m_pControlTree->clearSelection();
  278. UpdateSelectedControl();
  279. }
  280. if (pEvent->type() == QEvent::KeyRelease)
  281. {
  282. QKeyEvent* pKeyEvent = static_cast<QKeyEvent*>(pEvent);
  283. if (pKeyEvent && pKeyEvent->key() == Qt::Key_Space)
  284. {
  285. QModelIndex index = m_pControlTree->currentIndex();
  286. if (index.isValid() && index.data(eDR_TYPE) == eIT_AUDIO_CONTROL)
  287. {
  288. CAudioControlsEditorPlugin::ExecuteTrigger(index.data(Qt::DisplayRole).toString().toUtf8().data());
  289. }
  290. }
  291. }
  292. // double-clicking an item will accept it when valid (not a folder, wrong type)...
  293. if (pEvent->type() == QEvent::MouseButtonDblClick)
  294. {
  295. QMouseEvent* pMouseEvent = static_cast<QMouseEvent*>(pEvent);
  296. if (pMouseEvent && pMouseEvent->button() == Qt::LeftButton)
  297. {
  298. QModelIndex index = m_pControlTree->currentIndex();
  299. if (index.isValid() && IsValid(index) && index.data(eDR_TYPE) != eIT_FOLDER)
  300. {
  301. accept();
  302. }
  303. }
  304. }
  305. return QWidget::eventFilter(pObject, pEvent);
  306. }
  307. //-------------------------------------------------------------------------------------------//
  308. void ATLControlsDialog::showEvent(QShowEvent* e)
  309. {
  310. QDialog::showEvent(e);
  311. window()->resize(sizeHint());
  312. }
  313. //-------------------------------------------------------------------------------------------//
  314. void ATLControlsDialog::StopTrigger()
  315. {
  316. CAudioControlsEditorPlugin::StopTriggerExecution();
  317. }
  318. } // namespace AudioControls
  319. #include <Source/Editor/moc_ATLControlsResourceDialog.cpp>