diff --git a/Code/Tools/ProjectManager/Resources/ProjectManager.qss b/Code/Tools/ProjectManager/Resources/ProjectManager.qss index f91a597481..5f7826dbac 100644 --- a/Code/Tools/ProjectManager/Resources/ProjectManager.qss +++ b/Code/Tools/ProjectManager/Resources/ProjectManager.qss @@ -496,13 +496,34 @@ QProgressBar::chunk { background-color: #333333; } -/************** Filter tag widget **************/ +#GemDependenciesDialog QLabel { + margin-bottom:10px; +} + +#GemDependenciesDialog QCheckBox { + background-color: #333333; + border-radius: 3px; + spacing:3px; + margin-right:5px; + padding:4px; + margin-top:5px; +} + +/************** Filter Tag widget **************/ #FilterTagWidgetTextLabel { color: #94D2FF; font-size: 10px; } +#TagWidget { + background-color: #333333; + padding:3px; + font-size:12px; + border-radius: 3px; + margin-right: 3px; +} + /************** Gems SubWidget **************/ #gemSubWidgetTitleLabel { diff --git a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp index f098518fd3..84b931cb30 100644 --- a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp +++ b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp @@ -238,9 +238,13 @@ namespace O3DE::ProjectManager PythonBindingsInterface::Get()->AddProject(projectInfo.m_path); #ifdef TEMPLATE_GEM_CONFIGURATION_ENABLED - if (!m_gemCatalogScreen->EnableDisableGemsForProject(projectInfo.m_path)) + const GemCatalogScreen::EnableDisableGemsResult gemResult = m_gemCatalogScreen->EnableDisableGemsForProject(m_projectInfo.m_path); + if (gemResult == GemCatalogScreen::EnableDisableGemsResult::Failed) { QMessageBox::critical(this, tr("Failed to configure gems"), tr("Failed to configure gems for template.")); + } + if (gemResult != GemCatalogScreen::EnableDisableGemsResult::Success) + { return; } #endif // TEMPLATE_GEM_CONFIGURATION_ENABLED diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index a41a81b448..945878768d 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -134,7 +135,7 @@ namespace O3DE::ProjectManager } } - bool GemCatalogScreen::EnableDisableGemsForProject(const QString& projectPath) + GemCatalogScreen::EnableDisableGemsResult GemCatalogScreen::EnableDisableGemsForProject(const QString& projectPath) { IPythonBindings* pythonBindings = PythonBindingsInterface::Get(); QVector toBeAdded = m_gemModel->GatherGemsToBeAdded(); @@ -142,13 +143,23 @@ namespace O3DE::ProjectManager if (m_gemModel->DoGemsToBeAddedHaveRequirements()) { - GemRequirementDialog* confirmRequirementsDialog = new GemRequirementDialog(m_gemModel, toBeAdded, this); - confirmRequirementsDialog->exec(); + GemRequirementDialog* confirmRequirementsDialog = new GemRequirementDialog(m_gemModel, this); + if(confirmRequirementsDialog->exec() == QDialog::Rejected) + { + return EnableDisableGemsResult::Cancel; + } + } - if (confirmRequirementsDialog->GetButtonResult() != QDialogButtonBox::ApplyRole) + if (m_gemModel->HasDependentGemsToRemove()) + { + GemDependenciesDialog* dependenciesDialog = new GemDependenciesDialog(m_gemModel, this); + if(dependenciesDialog->exec() == QDialog::Rejected) { - return false; + return EnableDisableGemsResult::Cancel; } + + toBeAdded = m_gemModel->GatherGemsToBeAdded(); + toBeRemoved = m_gemModel->GatherGemsToBeRemoved(); } for (const QModelIndex& modelIndex : toBeAdded) @@ -160,7 +171,7 @@ namespace O3DE::ProjectManager QMessageBox::critical(nullptr, "Operation failed", QString("Cannot add gem %1 to project.\n\nError:\n%2").arg(GemModel::GetDisplayName(modelIndex), result.GetError().c_str())); - return false; + return EnableDisableGemsResult::Failed; } } @@ -173,11 +184,11 @@ namespace O3DE::ProjectManager QMessageBox::critical(nullptr, "Operation failed", QString("Cannot remove gem %1 from project.\n\nError:\n%2").arg(GemModel::GetDisplayName(modelIndex), result.GetError().c_str())); - return false; + return EnableDisableGemsResult::Failed; } } - return true; + return EnableDisableGemsResult::Success; } ProjectManagerScreen GemCatalogScreen::GetScreenEnum() diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h index 5b48b2f90e..72e8d44f65 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h @@ -29,7 +29,14 @@ namespace O3DE::ProjectManager ProjectManagerScreen GetScreenEnum() override; void ReinitForProject(const QString& projectPath); - bool EnableDisableGemsForProject(const QString& projectPath); + + enum class EnableDisableGemsResult + { + Failed = 0, + Success, + Cancel + }; + EnableDisableGemsResult EnableDisableGemsForProject(const QString& projectPath); GemModel* GetGemModel() const { return m_gemModel; } diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemDependenciesDialog.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemDependenciesDialog.cpp new file mode 100644 index 0000000000..98aebd8fab --- /dev/null +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemDependenciesDialog.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include + +#include +#include +#include +#include + +namespace O3DE::ProjectManager +{ + GemDependenciesDialog::GemDependenciesDialog(GemModel* gemModel, QWidget *parent) + : QDialog(parent) + { + setWindowTitle(tr("Dependent Gems")); + setObjectName("GemDependenciesDialog"); + setAttribute(Qt::WA_DeleteOnClose); + setModal(true); + + QVBoxLayout* layout = new QVBoxLayout(); + // layout margin/alignment cannot be set with qss + layout->setMargin(15); + layout->setAlignment(Qt::AlignTop); + setLayout(layout); + + // message + QLabel* instructionLabel = new QLabel( + tr("The following gem dependencies are no longer needed and will be deactivated.

" + "To keep these Gems enabled, select the checkbox next to it.")); + layout->addWidget(instructionLabel); + + // checkboxes + FlowLayout* flowLayout = new FlowLayout(); + QVector gemsToRemove = gemModel->GatherGemsToBeRemoved(/*includeDependencies=*/true); + for (const QModelIndex& gem : gemsToRemove) + { + if (GemModel::WasPreviouslyAddedDependency(gem)) + { + QCheckBox* checkBox = new QCheckBox(GemModel::GetName(gem)); + connect(checkBox, &QCheckBox::stateChanged, this, + [=](int state) + { + GemModel::SetIsAdded(*gemModel, gem, /*isAdded=*/state == Qt::Checked); + }); + flowLayout->addWidget(checkBox); + } + } + layout->addLayout(flowLayout); + + layout->addSpacing(10); + layout->addStretch(1); + + // buttons + QDialogButtonBox* dialogButtons = new QDialogButtonBox(QDialogButtonBox::Cancel | QDialogButtonBox::Ok); + connect(dialogButtons, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(dialogButtons, &QDialogButtonBox::rejected, this, + [=]() + { + // de-select any Gems the user selected because they're canceling + for (const QModelIndex& gem : gemsToRemove) + { + if (GemModel::WasPreviouslyAddedDependency(gem) && GemModel::IsAdded(gem)) + { + GemModel::SetIsAdded(*gemModel, gem, /*isAdded=*/false); + } + } + + reject(); + }); + layout->addWidget(dialogButtons); + } +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemDependenciesDialog.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemDependenciesDialog.h new file mode 100644 index 0000000000..df8ca6f8a2 --- /dev/null +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemDependenciesDialog.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#if !defined(Q_MOC_RUN) +#include +#endif + +namespace O3DE::ProjectManager +{ + QT_FORWARD_DECLARE_CLASS(GemModel) + + class GemDependenciesDialog + : public QDialog + { + Q_OBJECT // AUTOMOC + public: + explicit GemDependenciesDialog(GemModel* gemModel, QWidget *parent = nullptr); + ~GemDependenciesDialog() = default; + }; +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp index dc24c13009..2c7f17db32 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -16,6 +17,9 @@ #include #include #include +#include +#include +#include namespace O3DE::ProjectManager { @@ -104,22 +108,11 @@ namespace O3DE::ProjectManager painter->drawText(gemCreatorRect, Qt::TextSingleLine, gemCreator); // Gem summary - - // In case there are feature tags displayed at the bottom, decrease the size of the summary text field. const QStringList featureTags = GemModel::GetFeatures(modelIndex); - const int featureTagAreaHeight = 30; - const int summaryHeight = contentRect.height() - (!featureTags.empty() * featureTagAreaHeight); - - const int additionalSummarySpacing = s_itemMargins.right() * 3; - const QSize summarySize = QSize(contentRect.width() - s_summaryStartX - s_buttonWidth - additionalSummarySpacing, - summaryHeight); - const QRect summaryRect = QRect(/*topLeft=*/QPoint(contentRect.left() + s_summaryStartX, contentRect.top()), summarySize); - - painter->setFont(standardFont); - painter->setPen(m_textColor); - + const bool hasTags = !featureTags.isEmpty(); const QString summary = GemModel::GetSummary(modelIndex); - painter->drawText(summaryRect, Qt::AlignLeft | Qt::TextWordWrap, summary); + const QRect summaryRect = CalcSummaryRect(contentRect, hasTags); + DrawText(summary, painter, summaryRect, standardFont); DrawButton(painter, contentRect, modelIndex); DrawPlatformIcons(painter, contentRect, modelIndex); @@ -128,6 +121,17 @@ namespace O3DE::ProjectManager painter->restore(); } + QRect GemItemDelegate::CalcSummaryRect(const QRect& contentRect, bool hasTags) const + { + const int featureTagAreaHeight = 30; + const int summaryHeight = contentRect.height() - (hasTags * featureTagAreaHeight); + + const int additionalSummarySpacing = s_itemMargins.right() * 3; + const QSize summarySize = QSize(contentRect.width() - s_summaryStartX - s_buttonWidth - additionalSummarySpacing, + summaryHeight); + return QRect(QPoint(contentRect.left() + s_summaryStartX, contentRect.top()), summarySize); + } + QSize GemItemDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& modelIndex) const { QStyleOptionViewItem options(option); @@ -154,7 +158,7 @@ namespace O3DE::ProjectManager return true; } } - else if (event->type() == QEvent::MouseButtonPress ) + else if (event->type() == QEvent::MouseButtonPress) { QMouseEvent* mouseEvent = static_cast(event); @@ -168,6 +172,21 @@ namespace O3DE::ProjectManager GemModel::SetIsAdded(*model, modelIndex, !isAdded); return true; } + + // we must manually handle html links because we aren't using QLabels + const QStringList featureTags = GemModel::GetFeatures(modelIndex); + const bool hasTags = !featureTags.isEmpty(); + const QRect summaryRect = CalcSummaryRect(contentRect, hasTags); + if (summaryRect.contains(mouseEvent->pos())) + { + const QString html = GemModel::GetSummary(modelIndex); + QString anchor = anchorAt(html, mouseEvent->pos(), summaryRect); + if (!anchor.isEmpty()) + { + QDesktopServices::openUrl(QUrl(anchor)); + return true; + } + } } return QStyledItemDelegate::editorEvent(event, model, option, modelIndex); @@ -321,6 +340,44 @@ namespace O3DE::ProjectManager } } + AZStd::unique_ptr GetTextDocument(const QString& text, int width) + { + // using unique_ptr as a workaround for QTextDocument having a private copy constructor + auto doc = AZStd::make_unique(); + QTextOption textOption(doc->defaultTextOption()); + textOption.setWrapMode(QTextOption::WordWrap); + doc->setDefaultTextOption(textOption); + doc->setHtml(text); + doc->setTextWidth(width); + return doc; + } + + void GemItemDelegate::DrawText(const QString& text, QPainter* painter, const QRect& rect, const QFont& standardFont) const + { + painter->save(); + + if (text.contains('<')) + { + painter->translate(rect.topLeft()); + + // use QTextDocument because drawText does not support rich text or html + QAbstractTextDocumentLayout::PaintContext paintContext; + paintContext.clip = QRect(0, 0, rect.width(), rect.height()); + paintContext.palette.setColor(QPalette::Text, painter->pen().color()); + + AZStd::unique_ptr textDocument = GetTextDocument(text, rect.width()); + textDocument->documentLayout()->draw(painter, paintContext); + } + else + { + painter->setFont(standardFont); + painter->setPen(m_textColor); + painter->drawText(rect, Qt::AlignLeft | Qt::TextWordWrap, text); + } + + painter->restore(); + } + void GemItemDelegate::DrawButton(QPainter* painter, const QRect& contentRect, const QModelIndex& modelIndex) const { painter->save(); @@ -355,4 +412,19 @@ namespace O3DE::ProjectManager painter->restore(); } + + QString GemItemDelegate::anchorAt(const QString& html, const QPoint& position, const QRect& rect) + { + if (!html.isEmpty()) + { + AZStd::unique_ptr doc = GetTextDocument(html, rect.width()); + QAbstractTextDocumentLayout* layout = doc->documentLayout(); + if (layout) + { + return layout->anchorAt(position - rect.topLeft()); + } + } + + return QString(); + } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h index d842f63ae7..52b5a4f58e 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h @@ -30,6 +30,7 @@ namespace O3DE::ProjectManager void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& modelIndex) const override; QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& modelIndex) const override; + virtual QString anchorAt(const QString& html, const QPoint& position, const QRect& rect); // Colors const QColor m_textColor = QColor("#FFFFFF"); @@ -71,9 +72,11 @@ namespace O3DE::ProjectManager void CalcRects(const QStyleOptionViewItem& option, QRect& outFullRect, QRect& outItemRect, QRect& outContentRect) const; QRect GetTextRect(QFont& font, const QString& text, qreal fontSize) const; QRect CalcButtonRect(const QRect& contentRect) const; + QRect CalcSummaryRect(const QRect& contentRect, bool hasTags) const; void DrawPlatformIcons(QPainter* painter, const QRect& contentRect, const QModelIndex& modelIndex) const; void DrawButton(QPainter* painter, const QRect& contentRect, const QModelIndex& modelIndex) const; void DrawFeatureTags(QPainter* painter, const QRect& contentRect, const QStringList& featureTags, const QFont& standardFont, const QRect& summaryRect) const; + void DrawText(const QString& text, QPainter* painter, const QRect& rect, const QFont& standardFont) const; QAbstractItemModel* m_model = nullptr; diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.cpp index afdb9697c9..f5b54a364b 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.cpp @@ -8,27 +8,9 @@ #include #include -#include -#include namespace O3DE::ProjectManager { - class GemListViewProxyStyle : public QProxyStyle - { - public: - using QProxyStyle::QProxyStyle; - int styleHint(StyleHint hint, const QStyleOption* option = nullptr, const QWidget* widget = nullptr, QStyleHintReturn* returnData = nullptr) const override - { - if (hint == QStyle::SH_ToolTip_WakeUpDelay || hint == QStyle::SH_ToolTip_FallAsleepDelay) - { - // no delay - return 0; - } - - return QProxyStyle::styleHint(hint, option, widget, returnData); - } - }; - GemListView::GemListView(QAbstractItemModel* model, QItemSelectionModel* selectionModel, QWidget* parent) : QListView(parent) { @@ -38,8 +20,5 @@ namespace O3DE::ProjectManager setModel(model); setSelectionModel(selectionModel); setItemDelegate(new GemItemDelegate(model, this)); - - // use a custom proxy style so we get immediate tooltips for gem radio buttons - setStyle(new GemListViewProxyStyle(this->style())); } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp index 0941541793..c8911de360 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp @@ -391,6 +391,20 @@ namespace O3DE::ProjectManager return false; } + bool GemModel::HasDependentGemsToRemove() const + { + for (int row = 0; row < rowCount(); ++row) + { + const QModelIndex modelIndex = index(row, 0); + if (GemModel::NeedsToBeRemoved(modelIndex, /*includeDependencies=*/true) && + GemModel::WasPreviouslyAddedDependency(modelIndex)) + { + return true; + } + } + return false; + } + QVector GemModel::GatherGemDependencies(const QModelIndex& modelIndex) const { QVector result; diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h index 0591094c11..ef2d1a903d 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h @@ -66,6 +66,7 @@ namespace O3DE::ProjectManager static void UpdateDependencies(QAbstractItemModel& model, const QModelIndex& modelIndex); bool DoGemsToBeAddedHaveRequirements() const; + bool HasDependentGemsToRemove() const; QVector GatherGemDependencies(const QModelIndex& modelIndex) const; QVector GatherDependentGems(const QModelIndex& modelIndex, bool addedOnly = false) const; diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDelegate.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDelegate.cpp index 0ca5ca836f..f4a7148d46 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDelegate.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDelegate.cpp @@ -10,6 +10,8 @@ #include #include +#include +#include namespace O3DE::ProjectManager { @@ -38,7 +40,6 @@ namespace O3DE::ProjectManager standardFont.setPixelSize(static_cast(s_fontSize)); QFontMetrics standardFontMetrics(standardFont); - painter->save(); painter->setClipping(true); painter->setClipRect(fullRect); painter->setFont(options.font); @@ -65,25 +66,51 @@ namespace O3DE::ProjectManager painter->drawText(gemNameRect, Qt::TextSingleLine, gemName); // Gem requirement - const QSize requirementSize = QSize(contentRect.width() - s_summaryStartX - s_itemMargins.right(), contentRect.height()); - const QRect requirementRect = QRect(QPoint(contentRect.left() + s_summaryStartX, contentRect.top()), requirementSize); - - painter->setFont(standardFont); - painter->setPen(m_textColor); - + const QRect requirementRect = CalcRequirementRect(contentRect); const QString requirement = GemModel::GetRequirement(modelIndex); - painter->drawText(requirementRect, Qt::AlignLeft | Qt::TextWordWrap, requirement); + DrawText(requirement, painter, requirementRect, standardFont); painter->restore(); } + QRect GemRequirementDelegate::CalcRequirementRect(const QRect& contentRect) const + { + const QSize requirementSize = QSize(contentRect.width() - s_summaryStartX - s_itemMargins.right(), contentRect.height()); + return QRect(QPoint(contentRect.left() + s_summaryStartX, contentRect.top()), requirementSize); + } + bool GemRequirementDelegate::editorEvent( [[maybe_unused]] QEvent* event, [[maybe_unused]] QAbstractItemModel* model, [[maybe_unused]] const QStyleOptionViewItem& option, [[maybe_unused]] const QModelIndex& modelIndex) { - // Do nothing here - return false; + if (!modelIndex.isValid()) + { + return false; + } + + if (event->type() == QEvent::MouseButtonPress) + { + QMouseEvent* mouseEvent = static_cast(event); + + QRect fullRect, itemRect, contentRect; + CalcRects(option, fullRect, itemRect, contentRect); + + const QRect requirementsRect = CalcRequirementRect(contentRect); + if (requirementsRect.contains(mouseEvent->pos())) + { + const QString html = GemModel::GetRequirement(modelIndex); + QString anchor = anchorAt(html, mouseEvent->pos(), requirementsRect); + if (!anchor.isEmpty()) + { + QDesktopServices::openUrl(QUrl(anchor)); + return true; + } + } + } + + return QStyledItemDelegate::editorEvent(event, model, option, modelIndex); } + } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDelegate.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDelegate.h index a23b999ca0..e9001df7fa 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDelegate.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDelegate.h @@ -29,5 +29,8 @@ namespace O3DE::ProjectManager const QColor m_backgroundColor = QColor("#444444"); // Outside of the actual gem item const QColor m_itemBackgroundColor = QColor("#393939"); // Background color of the gem item + + private: + QRect CalcRequirementRect(const QRect& contentRect) const; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDialog.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDialog.cpp index 4740d29344..23bb776c29 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDialog.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDialog.cpp @@ -19,11 +19,12 @@ namespace O3DE::ProjectManager { - GemRequirementDialog::GemRequirementDialog(GemModel* model, const QVector& gemsToAdd, QWidget* parent) + GemRequirementDialog::GemRequirementDialog(GemModel* model, QWidget* parent) : QDialog(parent) { setWindowTitle(tr("Manual setup is required")); setModal(true); + setAttribute(Qt::WA_DeleteOnClose); QVBoxLayout* vLayout = new QVBoxLayout(); vLayout->setMargin(0); @@ -51,7 +52,7 @@ namespace O3DE::ProjectManager vLayout->addSpacing(20); - GemRequirementFilterProxyModel* proxModel = new GemRequirementFilterProxyModel(model, gemsToAdd, this); + GemRequirementFilterProxyModel* proxModel = new GemRequirementFilterProxyModel(model, this); GemRequirementListView* m_gemListView = new GemRequirementListView(proxModel, proxModel->GetSelectionModel(), this); vLayout->addWidget(m_gemListView); @@ -62,27 +63,9 @@ namespace O3DE::ProjectManager QPushButton* cancelButton = dialogButtons->addButton(tr("Cancel"), QDialogButtonBox::RejectRole); cancelButton->setProperty("secondary", true); - QPushButton* continueButton = dialogButtons->addButton(tr("Continue"), QDialogButtonBox::ApplyRole); + QPushButton* continueButton = dialogButtons->addButton(tr("Continue"), QDialogButtonBox::AcceptRole); - connect(cancelButton, &QPushButton::clicked, this, &GemRequirementDialog::CancelButtonPressed); - connect(continueButton, &QPushButton::clicked, this, &GemRequirementDialog::ContinueButtonPressed); + connect(cancelButton, &QPushButton::clicked, this, &QDialog::reject); + connect(continueButton, &QPushButton::clicked, this, &QDialog::accept); } - - QDialogButtonBox::ButtonRole GemRequirementDialog::GetButtonResult() - { - return m_buttonResult; - } - - void GemRequirementDialog::CancelButtonPressed() - { - m_buttonResult = QDialogButtonBox::RejectRole; - close(); - } - - void GemRequirementDialog::ContinueButtonPressed() - { - m_buttonResult = QDialogButtonBox::ApplyRole; - close(); - } - } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDialog.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDialog.h index 22f6977332..af8b1e2cc9 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDialog.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementDialog.h @@ -10,8 +10,6 @@ #if !defined(Q_MOC_RUN) #include - -#include #endif namespace O3DE::ProjectManager @@ -23,15 +21,7 @@ namespace O3DE::ProjectManager { Q_OBJECT // AUTOMOC public: - explicit GemRequirementDialog(GemModel* model, const QVector& gemsToAdd, QWidget *parent = nullptr); + explicit GemRequirementDialog(GemModel* model, QWidget *parent = nullptr); ~GemRequirementDialog() = default; - - QDialogButtonBox::ButtonRole GetButtonResult(); - - private: - void CancelButtonPressed(); - void ContinueButtonPressed(); - - QDialogButtonBox::ButtonRole m_buttonResult = QDialogButtonBox::RejectRole; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementFilterProxyModel.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementFilterProxyModel.cpp index 50639b7936..e89de82c6c 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementFilterProxyModel.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementFilterProxyModel.cpp @@ -13,10 +13,8 @@ namespace O3DE::ProjectManager { - GemRequirementFilterProxyModel::GemRequirementFilterProxyModel(GemModel* sourceModel, const QVector& addedGems, QObject* parent) + GemRequirementFilterProxyModel::GemRequirementFilterProxyModel(GemModel* sourceModel, QObject* parent) : QSortFilterProxyModel(parent) - , m_sourceModel(sourceModel) - , m_addedGems(addedGems) { setSourceModel(sourceModel); m_selectionProxyModel = new AzQtComponents::SelectionProxyModel(sourceModel->GetSelectionModel(), this, parent); @@ -26,22 +24,7 @@ namespace O3DE::ProjectManager { // Do not use sourceParent->child because an invalid parent does not produce valid children (which our index function does) QModelIndex sourceIndex = sourceModel()->index(sourceRow, 0, sourceParent); - if (!sourceIndex.isValid()) - { - return false; - } - - if (!m_addedGems.contains(sourceIndex)) - { - return false; - } - - if (!m_sourceModel->HasRequirement(sourceIndex)) - { - return false; - } - - return true; + return GemModel::IsAdded(sourceIndex) && GemModel::HasRequirement(sourceIndex); } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementFilterProxyModel.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementFilterProxyModel.h index a40eed9fb4..7df75f7d94 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementFilterProxyModel.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementFilterProxyModel.h @@ -25,16 +25,13 @@ namespace O3DE::ProjectManager Q_OBJECT // AUTOMOC public: - GemRequirementFilterProxyModel(GemModel* sourceModel, const QVector& addedGems, QObject* parent = nullptr); + GemRequirementFilterProxyModel(GemModel* sourceModel, QObject* parent = nullptr); AzQtComponents::SelectionProxyModel* GetSelectionModel() const { return m_selectionProxyModel; } bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const override; private: - GemModel* m_sourceModel = nullptr; AzQtComponents::SelectionProxyModel* m_selectionProxyModel = nullptr; - - QVector m_addedGems; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementListView.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementListView.cpp index daed5764ff..fd7d22cbfc 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementListView.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemRequirementListView.cpp @@ -8,7 +8,6 @@ #include #include -#include namespace O3DE::ProjectManager { diff --git a/Code/Tools/ProjectManager/Source/TagWidget.cpp b/Code/Tools/ProjectManager/Source/TagWidget.cpp index 8f433f420f..ace9d72d8f 100644 --- a/Code/Tools/ProjectManager/Source/TagWidget.cpp +++ b/Code/Tools/ProjectManager/Source/TagWidget.cpp @@ -8,87 +8,44 @@ #include #include +#include namespace O3DE::ProjectManager { TagWidget::TagWidget(const QString& text, QWidget* parent) : QLabel(text, parent) { - setFixedHeight(24); - setMargin(5); - setStyleSheet("font-size: 12px; background-color: #333333; border-radius: 3px;"); + setObjectName("TagWidget"); } TagContainerWidget::TagContainerWidget(QWidget* parent) : QWidget(parent) { - m_layout = new QVBoxLayout(); - m_layout->setAlignment(Qt::AlignTop); - m_layout->setMargin(0); - setLayout(m_layout); + setObjectName("TagWidgetContainer"); + setLayout(new FlowLayout(this)); + + // layout margins cannot be set via qss + constexpr int verticalMargin = 10; + constexpr int horizontalMargin = 0; + layout()->setContentsMargins(horizontalMargin, verticalMargin, horizontalMargin, verticalMargin); + + setAttribute(Qt::WA_StyledBackground, true); } void TagContainerWidget::Update(const QStringList& tags) { - QWidget* parentWidget = qobject_cast(parent()); - int width = 200; - if (parentWidget) - { - width = parentWidget->width(); - } + FlowLayout* flowLayout = static_cast(layout()); - if (m_widget) + // remove old tags + QLayoutItem* layoutItem = nullptr; + while ((layoutItem = layout()->takeAt(0)) != nullptr) { - // Hide the old widget and request deletion. - m_widget->hide(); - m_widget->deleteLater(); + layoutItem->widget()->deleteLater(); } - QVBoxLayout* vLayout = new QVBoxLayout(); - m_widget = new QWidget(this); - m_widget->setLayout(vLayout); - m_layout->addWidget(m_widget); - - vLayout->setAlignment(Qt::AlignTop); - vLayout->setMargin(0); - - QHBoxLayout* hLayout = nullptr; - int usedSpaceInRow = 0; - const int numTags = tags.count(); - - for (int i = 0; i < numTags; ++i) + foreach (const QString& tag, tags) { - // Create the new tag widget. - TagWidget* tagWidget = new TagWidget(tags[i]); - const int tagWidgetWidth = tagWidget->minimumSizeHint().width(); - - // Calculate the width we're currently using in the current row. Does the new tag still fit in the current row? - const bool isRowFull = width - usedSpaceInRow - tagWidgetWidth < 0; - if (isRowFull || i == 0) - { - // Add a spacer widget after the last tag widget in a row to push the tag widgets to the left. - if (i > 0) - { - QWidget* spacerWidget = new QWidget(); - spacerWidget->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); - hLayout->addWidget(spacerWidget); - } - - // Add a new row for the current tag widget. - hLayout = new QHBoxLayout(); - hLayout->setAlignment(Qt::AlignLeft); - hLayout->setMargin(0); - vLayout->addLayout(hLayout); - - // Reset the used space in the row. - usedSpaceInRow = 0; - } - - // Calculate the width of the tag widgets including the spacing between them of the current row. - usedSpaceInRow += tagWidgetWidth + hLayout->spacing(); - - // Add the tag widget to the current row. - hLayout->addWidget(tagWidget); + flowLayout->addWidget(new TagWidget(tag)); } } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/TagWidget.h b/Code/Tools/ProjectManager/Source/TagWidget.h index 16eca28fc1..0dad7468eb 100644 --- a/Code/Tools/ProjectManager/Source/TagWidget.h +++ b/Code/Tools/ProjectManager/Source/TagWidget.h @@ -14,8 +14,6 @@ #include #endif -QT_FORWARD_DECLARE_CLASS(QVBoxLayout) - namespace O3DE::ProjectManager { // Single tag @@ -40,9 +38,5 @@ namespace O3DE::ProjectManager ~TagContainerWidget() = default; void Update(const QStringList& tags); - - private: - QVBoxLayout* m_layout = nullptr; - QWidget* m_widget = nullptr; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp index 08ad7f24d9..e952ada57a 100644 --- a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp +++ b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp @@ -137,9 +137,13 @@ namespace O3DE::ProjectManager else if (m_stack->currentIndex() == ScreenOrder::Gems && m_gemCatalogScreen) { // Enable or disable the gems that got adjusted in the gem catalog and apply them to the given project. - if (!m_gemCatalogScreen->EnableDisableGemsForProject(m_projectInfo.m_path)) + const GemCatalogScreen::EnableDisableGemsResult result = m_gemCatalogScreen->EnableDisableGemsForProject(m_projectInfo.m_path); + if (result == GemCatalogScreen::EnableDisableGemsResult::Failed) { QMessageBox::critical(this, tr("Failed to configure gems"), tr("Failed to configure gems for project.")); + } + if (result != GemCatalogScreen::EnableDisableGemsResult::Success) + { return; } diff --git a/Code/Tools/ProjectManager/project_manager_files.cmake b/Code/Tools/ProjectManager/project_manager_files.cmake index 544fa2537b..fd8389ca4f 100644 --- a/Code/Tools/ProjectManager/project_manager_files.cmake +++ b/Code/Tools/ProjectManager/project_manager_files.cmake @@ -92,6 +92,8 @@ set(FILES Source/GemCatalog/GemListHeaderWidget.cpp Source/GemCatalog/GemModel.h Source/GemCatalog/GemModel.cpp + Source/GemCatalog/GemDependenciesDialog.h + Source/GemCatalog/GemDependenciesDialog.cpp Source/GemCatalog/GemRequirementDialog.h Source/GemCatalog/GemRequirementDialog.cpp Source/GemCatalog/GemRequirementDelegate.h