3
0

AssetSelectionGrid.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  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 <AssetSelection/ui_AssetSelectionGrid.h>
  9. #include <Atom/RPI.Edit/Common/AssetUtils.h>
  10. #include <AtomToolsFramework/AssetSelection/AssetSelectionGrid.h>
  11. #include <AtomToolsFramework/Util/Util.h>
  12. #include <AzQtComponents/Components/Widgets/ElidingLabel.h>
  13. #include <AzQtComponents/Components/Widgets/LineEdit.h>
  14. #include <AzQtComponents/Components/Widgets/Text.h>
  15. #include <AzToolsFramework/API/EditorAssetSystemAPI.h>
  16. #include <AzToolsFramework/AssetBrowser/Thumbnails/SourceThumbnail.h>
  17. #include <AzToolsFramework/Thumbnails/ThumbnailWidget.h>
  18. #include <AzToolsFramework/Thumbnails/ThumbnailerBus.h>
  19. #include <QLabel>
  20. #include <QLineEdit>
  21. #include <QMenu>
  22. #include <QVBoxLayout>
  23. namespace AtomToolsFramework
  24. {
  25. AssetSelectionGrid::AssetSelectionGrid(
  26. const QString& title,
  27. const FilterFn& filterFn,
  28. const QSize& tileSize,
  29. QWidget* parent)
  30. : QDialog(parent)
  31. , m_tileSize(tileSize)
  32. , m_ui(new Ui::AssetSelectionGrid)
  33. , m_filterFn(filterFn)
  34. {
  35. m_ui->setupUi(this);
  36. QSignalBlocker signalBlocker(this);
  37. setWindowTitle(title);
  38. SetupAssetList();
  39. SetupSearchWidget();
  40. SetupDialogButtons();
  41. setModal(true);
  42. AzFramework::AssetCatalogEventBus::Handler::BusConnect();
  43. }
  44. AssetSelectionGrid::~AssetSelectionGrid()
  45. {
  46. AzFramework::AssetCatalogEventBus::Handler::BusDisconnect();
  47. }
  48. void AssetSelectionGrid::Clear()
  49. {
  50. m_ui->m_assetList->clear();
  51. }
  52. void AssetSelectionGrid::Populate()
  53. {
  54. Clear();
  55. for (const auto& path : GetPathsInSourceFoldersMatchingFilter(m_filterFn))
  56. {
  57. AddPath(path);
  58. }
  59. m_ui->m_assetList->sortItems();
  60. m_ui->m_assetList->setCurrentItem(0);
  61. }
  62. void AssetSelectionGrid::SetFilter(const FilterFn& filterFn)
  63. {
  64. m_filterFn = filterFn;
  65. }
  66. const AssetSelectionGrid::FilterFn& AssetSelectionGrid::GetFilter() const
  67. {
  68. return m_filterFn;
  69. }
  70. void AssetSelectionGrid::AddPath(const AZStd::string& path)
  71. {
  72. if(m_filterFn && !m_filterFn(path))
  73. {
  74. return;
  75. }
  76. const auto& pathWithAlias = GetPathWithAlias(path);
  77. const auto& pathWithoutAlias = GetPathWithoutAlias(path);
  78. if (!QFileInfo::exists(pathWithoutAlias.c_str()))
  79. {
  80. return;
  81. }
  82. const QVariant pathItemData(QString::fromUtf8(pathWithAlias.c_str(), static_cast<int>(pathWithAlias.size())));
  83. const QString title(GetDisplayNameFromPath(pathWithAlias).c_str());
  84. // Skip creating this list item if one with the same path is already registered
  85. for (int i = 0; i < m_ui->m_assetList->count(); ++i)
  86. {
  87. QListWidgetItem* item = m_ui->m_assetList->item(i);
  88. if (pathItemData == item->data(Qt::UserRole))
  89. {
  90. return;
  91. }
  92. }
  93. // Compare the item title against all other items and append a suffix until the new title is unique
  94. QString uniqueTitle = title;
  95. int uniqueTitleSuffix = 0;
  96. bool uniqueTitleFound = true;
  97. while (uniqueTitleFound)
  98. {
  99. uniqueTitleFound = false;
  100. for (int i = 0; i < m_ui->m_assetList->count(); ++i)
  101. {
  102. QListWidgetItem* item = m_ui->m_assetList->item(i);
  103. if (uniqueTitle == item->data(Qt::DisplayRole))
  104. {
  105. uniqueTitle = title + QString(" (%1)").arg(++uniqueTitleSuffix);
  106. uniqueTitleFound = true;
  107. break;
  108. }
  109. }
  110. }
  111. const int itemBorder =
  112. aznumeric_cast<int>(AtomToolsFramework::GetSettingsValue<AZ::u64>("/O3DE/AtomToolsFramework/AssetSelectionGrid/ItemBorder", 4));
  113. const int itemSpacing = aznumeric_cast<int>(
  114. AtomToolsFramework::GetSettingsValue<AZ::u64>("/O3DE/AtomToolsFramework/AssetSelectionGrid/ItemSpacing", 10));
  115. const int headerHeight = aznumeric_cast<int>(
  116. AtomToolsFramework::GetSettingsValue<AZ::u64>("/O3DE/AtomToolsFramework/AssetSelectionGrid/HeaderHeight", 15));
  117. const QSize gridSize = m_ui->m_assetList->gridSize();
  118. m_ui->m_assetList->setGridSize(QSize(
  119. AZStd::max(gridSize.width(), m_tileSize.width() + itemSpacing),
  120. AZStd::max(gridSize.height(), m_tileSize.height() + itemSpacing + headerHeight)));
  121. QListWidgetItem* item = new QListWidgetItem(m_ui->m_assetList);
  122. item->setData(Qt::DisplayRole, uniqueTitle);
  123. item->setData(Qt::UserRole, pathItemData);
  124. item->setData(Qt::ToolTipRole, pathWithoutAlias.c_str());
  125. item->setSizeHint(m_tileSize + QSize(itemBorder, itemBorder + headerHeight));
  126. m_ui->m_assetList->addItem(item);
  127. QWidget* itemWidget = new QWidget(m_ui->m_assetList);
  128. itemWidget->setLayout(new QVBoxLayout(itemWidget));
  129. itemWidget->layout()->setSpacing(0);
  130. itemWidget->layout()->setMargin(0);
  131. AzQtComponents::ElidingLabel* header = new AzQtComponents::ElidingLabel(itemWidget);
  132. header->setText(uniqueTitle);
  133. header->setFixedSize(QSize(m_tileSize.width(), headerHeight));
  134. header->setMargin(0);
  135. header->setStyleSheet("background-color: rgb(35, 35, 35)");
  136. AzQtComponents::Text::addPrimaryStyle(header);
  137. AzQtComponents::Text::addLabelStyle(header);
  138. itemWidget->layout()->addWidget(header);
  139. bool result = false;
  140. AZ::Data::AssetInfo assetInfo;
  141. AZStd::string watchFolder;
  142. AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
  143. result, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, pathWithoutAlias.c_str(), assetInfo, watchFolder);
  144. AzToolsFramework::Thumbnailer::ThumbnailWidget* thumbnail = new AzToolsFramework::Thumbnailer::ThumbnailWidget(itemWidget);
  145. thumbnail->setFixedSize(m_tileSize);
  146. thumbnail->SetThumbnailKey(MAKE_TKEY(AzToolsFramework::AssetBrowser::SourceThumbnailKey, assetInfo.m_assetId.m_guid));
  147. thumbnail->updateGeometry();
  148. itemWidget->layout()->addWidget(thumbnail);
  149. m_ui->m_assetList->setItemWidget(item, itemWidget);
  150. m_ui->m_assetList->sortItems();
  151. }
  152. void AssetSelectionGrid::RemovePath(const AZStd::string& path)
  153. {
  154. const auto& pathWithAlias = GetPathWithAlias(path);
  155. const QVariant pathItemData(QString::fromUtf8(pathWithAlias.c_str(), static_cast<int>(pathWithAlias.size())));
  156. for (int i = 0; i < m_ui->m_assetList->count(); ++i)
  157. {
  158. QListWidgetItem* item = m_ui->m_assetList->item(i);
  159. if (pathItemData == item->data(Qt::UserRole))
  160. {
  161. m_ui->m_assetList->removeItemWidget(item);
  162. return;
  163. }
  164. }
  165. }
  166. void AssetSelectionGrid::SelectPath(const AZStd::string& path)
  167. {
  168. const auto& pathWithAlias = GetPathWithAlias(path);
  169. const QVariant pathItemData(QString::fromUtf8(pathWithAlias.c_str(), static_cast<int>(pathWithAlias.size())));
  170. for (int i = 0; i < m_ui->m_assetList->count(); ++i)
  171. {
  172. QListWidgetItem* item = m_ui->m_assetList->item(i);
  173. if (pathItemData == item->data(Qt::UserRole))
  174. {
  175. m_ui->m_assetList->setCurrentItem(item);
  176. return;
  177. }
  178. }
  179. }
  180. AZStd::string AssetSelectionGrid::GetSelectedPath() const
  181. {
  182. auto item = m_ui->m_assetList->currentItem();
  183. return item ? AZStd::string(item->data(Qt::UserRole).toString().toUtf8().constData()) : AZStd::string();
  184. }
  185. void AssetSelectionGrid::OnCatalogAssetAdded(const AZ::Data::AssetId& assetId)
  186. {
  187. AddPath(AZ::RPI::AssetUtils::GetSourcePathByAssetId(assetId));
  188. }
  189. void AssetSelectionGrid::OnCatalogAssetRemoved(const AZ::Data::AssetId& assetId, [[maybe_unused]] const AZ::Data::AssetInfo& assetInfo)
  190. {
  191. RemovePath(AZ::RPI::AssetUtils::GetSourcePathByAssetId(assetId));
  192. }
  193. void AssetSelectionGrid::SetupAssetList()
  194. {
  195. m_ui->m_assetList->setFlow(QListView::LeftToRight);
  196. m_ui->m_assetList->setResizeMode(QListView::Adjust);
  197. m_ui->m_assetList->setGridSize(QSize(0, 0));
  198. m_ui->m_assetList->setWrapping(true);
  199. QObject::connect(m_ui->m_assetList, &QListWidget::currentItemChanged, [this](){ emit PathSelected(GetSelectedPath()); });
  200. }
  201. void AssetSelectionGrid::SetupSearchWidget()
  202. {
  203. m_ui->m_searchWidget->setReadOnly(false);
  204. m_ui->m_searchWidget->setContextMenuPolicy(Qt::CustomContextMenu);
  205. AzQtComponents::LineEdit::applySearchStyle(m_ui->m_searchWidget);
  206. connect(m_ui->m_searchWidget, &QLineEdit::textChanged, this, [this](){ ApplySearchFilter(); });
  207. connect(m_ui->m_searchWidget, &QWidget::customContextMenuRequested, this, [this](const QPoint& pos){ ShowSearchMenu(pos); });
  208. }
  209. void AssetSelectionGrid::SetupDialogButtons()
  210. {
  211. connect(m_ui->m_buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
  212. connect(m_ui->m_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
  213. connect(this, &QDialog::rejected, this, &AssetSelectionGrid::PathRejected);
  214. }
  215. void AssetSelectionGrid::ApplySearchFilter()
  216. {
  217. for (int index = 0; index < m_ui->m_assetList->count(); ++index)
  218. {
  219. QListWidgetItem* item = m_ui->m_assetList->item(index);
  220. const QString& title = item->data(Qt::DisplayRole).toString();
  221. const QString filter = m_ui->m_searchWidget->text();
  222. item->setHidden(!filter.isEmpty() && !title.contains(filter, Qt::CaseInsensitive));
  223. }
  224. }
  225. void AssetSelectionGrid::ShowSearchMenu(const QPoint& pos)
  226. {
  227. QScopedPointer<QMenu> menu(m_ui->m_searchWidget->createStandardContextMenu());
  228. menu->setStyleSheet("background-color: #333333");
  229. menu->exec(m_ui->m_searchWidget->mapToGlobal(pos));
  230. }
  231. } // namespace AtomToolsFramework
  232. #include <AtomToolsFramework/AssetSelection/moc_AssetSelectionGrid.cpp>