diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp index e91b46cc65..d6f4da0051 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp @@ -7,25 +7,32 @@ */ #include +#include + #include + #include #include #include #include #include -#include #include #include #include +#include +#include namespace O3DE::ProjectManager { - CartOverlayWidget::CartOverlayWidget(GemModel* gemModel, DownloadController* downloadController, QWidget* parent) - : QWidget(parent) + GemCartWidget::GemCartWidget(GemModel* gemModel, DownloadController* downloadController, QWidget* parent) + : QScrollArea(parent) , m_gemModel(gemModel) , m_downloadController(downloadController) { setObjectName("GemCatalogCart"); + setWidgetResizable(true); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); m_layout = new QVBoxLayout(); m_layout->setSpacing(0); @@ -118,17 +125,15 @@ namespace O3DE::ProjectManager } return dependencies; }); - - setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog); } - CartOverlayWidget::~CartOverlayWidget() + GemCartWidget::~GemCartWidget() { // disconnect from all download controller signals disconnect(m_downloadController, nullptr, this, nullptr); } - void CartOverlayWidget::CreateGemSection(const QString& singularTitle, const QString& pluralTitle, GetTagIndicesCallback getTagIndices) + void GemCartWidget::CreateGemSection(const QString& singularTitle, const QString& pluralTitle, GetTagIndicesCallback getTagIndices) { QWidget* widget = new QWidget(); widget->setFixedWidth(s_width); @@ -164,12 +169,12 @@ namespace O3DE::ProjectManager update(); } - void CartOverlayWidget::OnCancelDownloadActivated(const QString& gemName) + void GemCartWidget::OnCancelDownloadActivated(const QString& gemName) { m_downloadController->CancelGemDownload(gemName); } - void CartOverlayWidget::CreateDownloadSection() + void GemCartWidget::CreateDownloadSection() { m_downloadSectionWidget = new QWidget(); m_downloadSectionWidget->setFixedWidth(s_width); @@ -223,12 +228,12 @@ namespace O3DE::ProjectManager } // connect to download controller data changed - connect(m_downloadController, &DownloadController::GemDownloadAdded, this, &CartOverlayWidget::GemDownloadAdded); - connect(m_downloadController, &DownloadController::GemDownloadRemoved, this, &CartOverlayWidget::GemDownloadRemoved); - connect(m_downloadController, &DownloadController::GemDownloadProgress, this, &CartOverlayWidget::GemDownloadProgress); + connect(m_downloadController, &DownloadController::GemDownloadAdded, this, &GemCartWidget::GemDownloadAdded); + connect(m_downloadController, &DownloadController::GemDownloadRemoved, this, &GemCartWidget::GemDownloadRemoved); + connect(m_downloadController, &DownloadController::GemDownloadProgress, this, &GemCartWidget::GemDownloadProgress); } - void CartOverlayWidget::GemDownloadAdded(const QString& gemName) + void GemCartWidget::GemDownloadAdded(const QString& gemName) { // Containing widget for the current download item QWidget* newGemDownloadWidget = new QWidget(); @@ -246,7 +251,7 @@ namespace O3DE::ProjectManager nameProgressLayout->addStretch(); QLabel* cancelText = new QLabel(tr("Cancel").arg(gemName), newGemDownloadWidget); cancelText->setTextInteractionFlags(Qt::LinksAccessibleByMouse); - connect(cancelText, &QLabel::linkActivated, this, &CartOverlayWidget::OnCancelDownloadActivated); + connect(cancelText, &QLabel::linkActivated, this, &GemCartWidget::OnCancelDownloadActivated); nameProgressLayout->addWidget(cancelText); downloadingGemLayout->addLayout(nameProgressLayout); @@ -267,7 +272,7 @@ namespace O3DE::ProjectManager m_downloadingListWidget->show(); } - void CartOverlayWidget::GemDownloadRemoved(const QString& gemName) + void GemCartWidget::GemDownloadRemoved(const QString& gemName) { QWidget* gemToRemove = m_downloadingListWidget->findChild(gemName); if (gemToRemove) @@ -289,7 +294,7 @@ namespace O3DE::ProjectManager } } - void CartOverlayWidget::GemDownloadProgress(const QString& gemName, int bytesDownloaded, int totalBytes) + void GemCartWidget::GemDownloadProgress(const QString& gemName, int bytesDownloaded, int totalBytes) { QWidget* gemToUpdate = m_downloadingListWidget->findChild(gemName); if (gemToUpdate) @@ -324,7 +329,7 @@ namespace O3DE::ProjectManager } } - QVector CartOverlayWidget::GetTagsFromModelIndices(const QVector& gems) const + QVector GemCartWidget::GetTagsFromModelIndices(const QVector& gems) const { QVector tags; tags.reserve(gems.size()); @@ -349,7 +354,7 @@ namespace O3DE::ProjectManager iconButton->setFocusPolicy(Qt::NoFocus); iconButton->setIcon(QIcon(":/Summary.svg")); iconButton->setFixedSize(s_iconSize, s_iconSize); - connect(iconButton, &QPushButton::clicked, this, &CartButton::ShowOverlay); + connect(iconButton, &QPushButton::clicked, this, &CartButton::ShowGemCart); m_layout->addWidget(iconButton); m_countLabel = new QLabel(); @@ -362,7 +367,7 @@ namespace O3DE::ProjectManager m_dropDownButton->setFocusPolicy(Qt::NoFocus); m_dropDownButton->setIcon(QIcon(":/CarrotArrowDown.svg")); m_dropDownButton->setFixedSize(s_arrowDownIconSize, s_arrowDownIconSize); - connect(m_dropDownButton, &QPushButton::clicked, this, &CartButton::ShowOverlay); + connect(m_dropDownButton, &QPushButton::clicked, this, &CartButton::ShowGemCart); m_layout->addWidget(m_dropDownButton); // Adjust the label text whenever the model gets updated. @@ -377,28 +382,28 @@ namespace O3DE::ProjectManager m_dropDownButton->setVisible(!toBeAdded.isEmpty() || !toBeRemoved.isEmpty()); // Automatically close the overlay window in case there are no gems to be activated or deactivated anymore. - if (m_cartOverlay && toBeAdded.isEmpty() && toBeRemoved.isEmpty()) + if (m_gemCart && toBeAdded.isEmpty() && toBeRemoved.isEmpty()) { - m_cartOverlay->deleteLater(); - m_cartOverlay = nullptr; + m_gemCart->deleteLater(); + m_gemCart = nullptr; } }); } void CartButton::mousePressEvent([[maybe_unused]] QMouseEvent* event) { - ShowOverlay(); + ShowGemCart(); } void CartButton::hideEvent(QHideEvent*) { - if (m_cartOverlay) + if (m_gemCart) { - m_cartOverlay->hide(); + m_gemCart->hide(); } } - void CartButton::ShowOverlay() + void CartButton::ShowGemCart() { const QVector toBeAdded = m_gemModel->GatherGemsToBeAdded(/*includeDependencies=*/true); const QVector toBeRemoved = m_gemModel->GatherGemsToBeRemoved(/*includeDependencies=*/true); @@ -407,40 +412,33 @@ namespace O3DE::ProjectManager return; } - if (m_cartOverlay) + if (m_gemCart) { // Directly delete the former overlay before creating the new one. // Don't use deleteLater() here. This might overwrite the new overlay pointer // depending on the event queue. - delete m_cartOverlay; + delete m_gemCart; } - m_cartOverlay = new CartOverlayWidget(m_gemModel, m_downloadController, this); - connect(m_cartOverlay, &QWidget::destroyed, this, [=] + m_gemCart = new GemCartWidget(m_gemModel, m_downloadController, this); + connect(m_gemCart, &QWidget::destroyed, this, [=] { // Reset the overlay pointer on destruction to prevent dangling pointers. - m_cartOverlay = nullptr; + m_gemCart = nullptr; + // Tell header gem cart is no longer open + UpdateGemCart(nullptr); }); - m_cartOverlay->show(); + m_gemCart->show(); - emit OverlayUpdate(m_cartOverlay); - /* - const QPoint parentPos = m_dropDownButton->mapToParent(m_dropDownButton->pos()); - const QPoint globalPos = m_dropDownButton->mapToGlobal(m_dropDownButton->pos()); - const QPoint offset(-4, 10); - m_cartOverlay->setGeometry(globalPos.x() - parentPos.x() - m_cartOverlay->width() + width() + offset.x(), - globalPos.y() + offset.y(), - m_cartOverlay->width(), - m_cartOverlay->height()); - */ + emit UpdateGemCart(m_gemCart); } CartButton::~CartButton() { // Make sure the overlay window is automatically closed in case the gem catalog is destroyed. - if (m_cartOverlay) + if (m_gemCart) { - m_cartOverlay->deleteLater(); + m_gemCart->deleteLater(); } } @@ -518,7 +516,16 @@ namespace O3DE::ProjectManager connect(m_downloadController, &DownloadController::GemDownloadAdded, this, &GemCatalogHeaderWidget::GemDownloadAdded); connect(m_downloadController, &DownloadController::GemDownloadRemoved, this, &GemCatalogHeaderWidget::GemDownloadRemoved); - connect(m_cartButton, &CartButton::OverlayUpdate, this, [this](QWidget* cartOverlay) { emit OverlayUpdate(cartOverlay); }); + connect( + m_cartButton, &CartButton::UpdateGemCart, this, + [this](QWidget* gemCart) + { + GemCartShown(gemCart); + if (gemCart) + { + emit UpdateGemCart(gemCart); + } + }); } void GemCatalogHeaderWidget::GemDownloadAdded(const QString& /*gemName*/) @@ -526,7 +533,7 @@ namespace O3DE::ProjectManager m_downloadSpinner->show(); m_downloadLabel->show(); m_downloadSpinnerMovie->start(); - m_cartButton->ShowOverlay(); + m_cartButton->ShowGemCart(); } void GemCatalogHeaderWidget::GemDownloadRemoved(const QString& /*gemName*/) @@ -539,8 +546,44 @@ namespace O3DE::ProjectManager } } + void GemCatalogHeaderWidget::GemCartShown(bool state) + { + m_showGemCart = state; + repaint(); + } + void GemCatalogHeaderWidget::ReinitForProject() { m_filterLineEdit->setText({}); } + + void GemCatalogHeaderWidget::paintEvent([[maybe_unused]] QPaintEvent* event) + { + // Only show triangle when cart is shown + if (!m_showGemCart) + { + return; + } + + const QPoint buttonPos = m_cartButton->pos(); + const QSize buttonSize = m_cartButton->size(); + + // Draw isosceles triangle with top point touching bottom of cartButton + // Bottom aligned with header bottom and top of right panel + const QPoint topPoint(buttonPos.x() + buttonSize.width() / 2, buttonPos.y() + buttonSize.height()); + const QPoint bottomLeftPoint(topPoint.x() - 20, height()); + const QPoint bottomRightPoint(topPoint.x() + 20, height()); + + QPainterPath trianglePath; + trianglePath.moveTo(topPoint); + trianglePath.lineTo(bottomLeftPoint); + trianglePath.lineTo(bottomRightPoint); + trianglePath.lineTo(topPoint); + + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing, true); + painter.setPen(Qt::NoPen); + painter.fillPath(trianglePath, QBrush(QColor("#555555"))); + } + } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h index 072bf27b73..b749e9831d 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h @@ -14,8 +14,10 @@ #include #include #include -#include #include + +#include +#include #endif QT_FORWARD_DECLARE_CLASS(QPushButton) @@ -28,14 +30,14 @@ QT_FORWARD_DECLARE_CLASS(QMovie) namespace O3DE::ProjectManager { - class CartOverlayWidget - : public QWidget + class GemCartWidget + : public QScrollArea { Q_OBJECT // AUTOMOC public: - CartOverlayWidget(GemModel* gemModel, DownloadController* downloadController, QWidget* parent = nullptr); - ~CartOverlayWidget(); + GemCartWidget(GemModel* gemModel, DownloadController* downloadController, QWidget* parent = nullptr); + ~GemCartWidget(); public slots: void GemDownloadAdded(const QString& gemName); @@ -68,10 +70,10 @@ namespace O3DE::ProjectManager public: CartButton(GemModel* gemModel, DownloadController* downloadController, QWidget* parent = nullptr); ~CartButton(); - void ShowOverlay(); + void ShowGemCart(); signals: - void OverlayUpdate(QWidget* cartOverlay); + void UpdateGemCart(QWidget* gemCart); private: void mousePressEvent(QMouseEvent* event) override; @@ -81,7 +83,7 @@ namespace O3DE::ProjectManager QHBoxLayout* m_layout = nullptr; QLabel* m_countLabel = nullptr; QPushButton* m_dropDownButton = nullptr; - CartOverlayWidget* m_cartOverlay = nullptr; + GemCartWidget* m_gemCart = nullptr; DownloadController* m_downloadController = nullptr; inline constexpr static int s_iconSize = 24; @@ -102,12 +104,16 @@ namespace O3DE::ProjectManager public slots: void GemDownloadAdded(const QString& gemName); void GemDownloadRemoved(const QString& gemName); + void GemCartShown(bool state = false); signals: void AddGem(); void OpenGemsRepo(); void RefreshGems(); - void OverlayUpdate(QWidget* cartOverlay); + void UpdateGemCart(QWidget* gemCart); + + protected slots: + void paintEvent(QPaintEvent* event) override; private: AzQtComponents::SearchLineEdit* m_filterLineEdit = nullptr; @@ -117,5 +123,6 @@ namespace O3DE::ProjectManager QLabel* m_downloadLabel = nullptr; QMovie* m_downloadSpinnerMovie = nullptr; CartButton* m_cartButton = nullptr; + bool m_showGemCart = false; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index 14b428a726..d610154c24 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -51,35 +51,28 @@ namespace O3DE::ProjectManager vLayout->addWidget(m_headerWidget); connect(m_gemModel, &GemModel::gemStatusChanged, this, &GemCatalogScreen::OnGemStatusChanged); + connect(m_gemModel->GetSelectionModel(), &QItemSelectionModel::selectionChanged, this, [this]{ ShowInspector(); }); connect(m_headerWidget, &GemCatalogHeaderWidget::RefreshGems, this, &GemCatalogScreen::Refresh); connect(m_headerWidget, &GemCatalogHeaderWidget::OpenGemsRepo, this, &GemCatalogScreen::HandleOpenGemRepo); connect(m_headerWidget, &GemCatalogHeaderWidget::AddGem, this, &GemCatalogScreen::OnAddGemClicked); + connect(m_headerWidget, &GemCatalogHeaderWidget::UpdateGemCart, this, &GemCatalogScreen::UpdateAndShowGemCart); connect(m_downloadController, &DownloadController::Done, this, &GemCatalogScreen::OnGemDownloadResult); QHBoxLayout* hLayout = new QHBoxLayout(); hLayout->setMargin(0); vLayout->addLayout(hLayout); + m_gemListView = new GemListView(m_proxyModel, m_proxyModel->GetSelectionModel(), this); + m_rightPanelStack = new QStackedWidget(this); m_rightPanelStack->setFixedWidth(240); - connect(m_headerWidget, &GemCatalogHeaderWidget::OverlayUpdate, this, &GemCatalogScreen::UpdateAndShowGemCart); - - m_gemListView = new GemListView(m_proxyModel, m_proxyModel->GetSelectionModel(), this); m_gemInspector = new GemInspector(m_gemModel, this); connect(m_gemInspector, &GemInspector::TagClicked, [=](const Tag& tag) { SelectGem(tag.id); }); connect(m_gemInspector, &GemInspector::UpdateGem, this, &GemCatalogScreen::UpdateGem); connect(m_gemInspector, &GemInspector::UninstallGem, this, &GemCatalogScreen::UninstallGem); - // Show the inspector if gem selection changes - connect( - m_gemModel->GetSelectionModel(), &QItemSelectionModel::selectionChanged, this, - [this] - { - m_rightPanelStack->setCurrentIndex(RightPanelWidgetOrder::Inspector); - }); - QWidget* filterWidget = new QWidget(this); filterWidget->setFixedWidth(240); m_filterWidgetLayout = new QVBoxLayout(); @@ -318,7 +311,7 @@ namespace O3DE::ProjectManager m_proxyModel->GetSelectionModel()->setCurrentIndex(proxyIndex, QItemSelectionModel::ClearAndSelect); m_gemListView->scrollTo(proxyIndex); - m_rightPanelStack->setCurrentIndex(RightPanelWidgetOrder::Inspector); + ShowInspector(); } void GemCatalogScreen::UpdateGem(const QModelIndex& modelIndex) @@ -507,6 +500,12 @@ namespace O3DE::ProjectManager } } + void GemCatalogScreen::ShowInspector() + { + m_rightPanelStack->setCurrentIndex(RightPanelWidgetOrder::Inspector); + m_headerWidget->GemCartShown(); + } + GemCatalogScreen::EnableDisableGemsResult GemCatalogScreen::EnableDisableGemsForProject(const QString& projectPath) { IPythonBindings* pythonBindings = PythonBindingsInterface::Get(); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h index 0b48ee45bd..92cf0bd5f2 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h @@ -65,6 +65,7 @@ namespace O3DE::ProjectManager private slots: void HandleOpenGemRepo(); void UpdateAndShowGemCart(QWidget* cartWidget); + void ShowInspector(); private: enum RightPanelWidgetOrder