First part of UI feedback for downloading gems
Signed-off-by: AMZN-Phil <pconroy@amazon.com>
This commit is contained in:
@@ -481,6 +481,18 @@ QProgressBar::chunk {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
#GemCatalogCartOverlayGemDownloadHeader {
|
||||
margin:0;
|
||||
padding: 0px;
|
||||
background-color: #333333;
|
||||
}
|
||||
|
||||
#GemCatalogCartOverlayGemDownloadBG {
|
||||
margin:0;
|
||||
padding: 0px;
|
||||
background-color: #444444;
|
||||
}
|
||||
|
||||
#GemCatalogHeaderLabel {
|
||||
font-size: 12px;
|
||||
color: #FFFFFF;
|
||||
|
||||
@@ -12,13 +12,15 @@
|
||||
#include <QMouseEvent>
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QProgressBar>
|
||||
#include <TagWidget.h>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
CartOverlayWidget::CartOverlayWidget(GemModel* gemModel, QWidget* parent)
|
||||
CartOverlayWidget::CartOverlayWidget(GemModel* gemModel, O3DEObjectDownloadController* downloadController, QWidget* parent)
|
||||
: QWidget(parent)
|
||||
, m_gemModel(gemModel)
|
||||
, m_downloadController(downloadController)
|
||||
{
|
||||
setObjectName("GemCatalogCart");
|
||||
|
||||
@@ -42,6 +44,9 @@ namespace O3DE::ProjectManager
|
||||
hLayout->addWidget(closeButton);
|
||||
m_layout->addLayout(hLayout);
|
||||
|
||||
// downloading gems
|
||||
CreateDownloadSection();
|
||||
|
||||
// added
|
||||
CreateGemSection( tr("Gem to be activated"), tr("Gems to be activated"), [=]
|
||||
{
|
||||
@@ -149,6 +154,109 @@ namespace O3DE::ProjectManager
|
||||
update();
|
||||
}
|
||||
|
||||
void CartOverlayWidget::CreateDownloadSection()
|
||||
{
|
||||
QWidget* widget = new QWidget();
|
||||
widget->setFixedWidth(s_width);
|
||||
m_layout->addWidget(widget);
|
||||
|
||||
QVBoxLayout* layout = new QVBoxLayout();
|
||||
layout->setAlignment(Qt::AlignTop);
|
||||
widget->setLayout(layout);
|
||||
|
||||
QLabel* label = new QLabel();
|
||||
label->setObjectName("GemCatalogCartOverlaySectionLabel");
|
||||
layout->addWidget(label);
|
||||
|
||||
label->setText(tr("Gems to be installed"));
|
||||
|
||||
// Create header section
|
||||
QWidget* downloadingGemsWidget = new QWidget();
|
||||
downloadingGemsWidget->setObjectName("GemCatalogCartOverlayGemDownloadHeader");
|
||||
layout->addWidget(downloadingGemsWidget);
|
||||
QVBoxLayout* gemDownloadLayout = new QVBoxLayout();
|
||||
gemDownloadLayout->setMargin(0);
|
||||
gemDownloadLayout->setAlignment(Qt::AlignTop);
|
||||
downloadingGemsWidget->setLayout(gemDownloadLayout);
|
||||
QLabel* processingQueueLabel = new QLabel("Processing Queue");
|
||||
gemDownloadLayout->addWidget(processingQueueLabel);
|
||||
|
||||
QWidget* downloadingItemWidget = new QWidget();
|
||||
downloadingItemWidget->setObjectName("GemCatalogCartOverlayGemDownloadBG");
|
||||
gemDownloadLayout->addWidget(downloadingItemWidget);
|
||||
QVBoxLayout* downloadingItemLayout = new QVBoxLayout();
|
||||
downloadingItemLayout->setAlignment(Qt::AlignTop);
|
||||
downloadingItemWidget->setLayout(downloadingItemLayout);
|
||||
|
||||
auto update = [=](int downloadProgress)
|
||||
{
|
||||
if (m_downloadController->IsDownloadQueueEmpty())
|
||||
{
|
||||
widget->hide();
|
||||
}
|
||||
else
|
||||
{
|
||||
widget->setUpdatesEnabled(false);
|
||||
// remove items
|
||||
QLayoutItem* layoutItem = nullptr;
|
||||
while ((layoutItem = downloadingItemLayout->takeAt(0)) != nullptr)
|
||||
{
|
||||
if (layoutItem->layout())
|
||||
{
|
||||
// Gem info row
|
||||
QLayoutItem* rowLayoutItem = nullptr;
|
||||
while ((rowLayoutItem = layoutItem->layout()->takeAt(0)) != nullptr)
|
||||
{
|
||||
rowLayoutItem->widget()->deleteLater();
|
||||
}
|
||||
layoutItem->layout()->deleteLater();
|
||||
}
|
||||
if (layoutItem->widget())
|
||||
{
|
||||
layoutItem->widget()->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
// Setup gem download rows
|
||||
const AZStd::vector<QString>& downloadQueue = m_downloadController->GetDownloadQueue();
|
||||
|
||||
QLabel* downloadsInProgessLabel = new QLabel("");
|
||||
downloadsInProgessLabel->setText(
|
||||
QString("%1 %2").arg(downloadQueue.size()).arg(downloadQueue.size() == 1 ? tr("download in progress...") : tr("downloads in progress...")));
|
||||
downloadingItemLayout->addWidget(downloadsInProgessLabel);
|
||||
|
||||
for (int downloadingGemNumber = 0; downloadingGemNumber < downloadQueue.size(); ++downloadingGemNumber)
|
||||
{
|
||||
QHBoxLayout* nameProgressLayout = new QHBoxLayout();
|
||||
TagWidget* newTag = new TagWidget(downloadQueue[downloadingGemNumber]);
|
||||
nameProgressLayout->addWidget(newTag);
|
||||
QLabel* progress = new QLabel(downloadingGemNumber == 0? QString("%1%").arg(downloadProgress) : tr("Queued"));
|
||||
nameProgressLayout->addWidget(progress);
|
||||
QSpacerItem* spacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum);
|
||||
nameProgressLayout->addSpacerItem(spacer);
|
||||
QLabel* cancelText = new QLabel(tr("Cancel"));
|
||||
nameProgressLayout->addWidget(cancelText);
|
||||
downloadingItemLayout->addLayout(nameProgressLayout);
|
||||
QProgressBar* downloadProgessBar = new QProgressBar();
|
||||
downloadingItemLayout->addWidget(downloadProgessBar);
|
||||
downloadProgessBar->setValue(downloadingGemNumber == 0 ? downloadProgress : 0);
|
||||
}
|
||||
|
||||
widget->setUpdatesEnabled(true);
|
||||
widget->show();
|
||||
}
|
||||
};
|
||||
|
||||
auto downloadEnded = [=](bool /*success*/)
|
||||
{
|
||||
update(0); // update the list to remove the gem that has finished
|
||||
};
|
||||
// connect to download controller data changed
|
||||
connect(m_downloadController, &O3DEObjectDownloadController::GemDownloadProgress, this, update);
|
||||
connect(m_downloadController, &O3DEObjectDownloadController::Done, this, downloadEnded);
|
||||
update(0);
|
||||
}
|
||||
|
||||
QStringList CartOverlayWidget::ConvertFromModelIndices(const QVector<QModelIndex>& gems) const
|
||||
{
|
||||
QStringList gemNames;
|
||||
@@ -160,9 +268,10 @@ namespace O3DE::ProjectManager
|
||||
return gemNames;
|
||||
}
|
||||
|
||||
CartButton::CartButton(GemModel* gemModel, QWidget* parent)
|
||||
CartButton::CartButton(GemModel* gemModel, O3DEObjectDownloadController* downloadController, QWidget* parent)
|
||||
: QWidget(parent)
|
||||
, m_gemModel(gemModel)
|
||||
, m_downloadController(downloadController)
|
||||
{
|
||||
m_layout = new QHBoxLayout();
|
||||
m_layout->setMargin(0);
|
||||
@@ -239,7 +348,7 @@ namespace O3DE::ProjectManager
|
||||
delete m_cartOverlay;
|
||||
}
|
||||
|
||||
m_cartOverlay = new CartOverlayWidget(m_gemModel, this);
|
||||
m_cartOverlay = new CartOverlayWidget(m_gemModel, m_downloadController, this);
|
||||
connect(m_cartOverlay, &QWidget::destroyed, this, [=]
|
||||
{
|
||||
// Reset the overlay pointer on destruction to prevent dangling pointers.
|
||||
@@ -265,7 +374,7 @@ namespace O3DE::ProjectManager
|
||||
}
|
||||
}
|
||||
|
||||
GemCatalogHeaderWidget::GemCatalogHeaderWidget(GemModel* gemModel, GemSortFilterProxyModel* filterProxyModel, QWidget* parent)
|
||||
GemCatalogHeaderWidget::GemCatalogHeaderWidget(GemModel* gemModel, GemSortFilterProxyModel* filterProxyModel, O3DEObjectDownloadController* downloadController, QWidget* parent)
|
||||
: QFrame(parent)
|
||||
{
|
||||
QHBoxLayout* hLayout = new QHBoxLayout();
|
||||
@@ -293,7 +402,7 @@ namespace O3DE::ProjectManager
|
||||
hLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding));
|
||||
hLayout->addSpacerItem(new QSpacerItem(75, 0, QSizePolicy::Fixed));
|
||||
|
||||
CartButton* cartButton = new CartButton(gemModel);
|
||||
CartButton* cartButton = new CartButton(gemModel, downloadController);
|
||||
hLayout->addWidget(cartButton);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <QMoveEvent>
|
||||
#include <QHideEvent>
|
||||
#include <QVBoxLayout>
|
||||
#include <O3DEObjectDownloadController.h>
|
||||
#endif
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
@@ -31,16 +32,18 @@ namespace O3DE::ProjectManager
|
||||
Q_OBJECT // AUTOMOC
|
||||
|
||||
public:
|
||||
CartOverlayWidget(GemModel* gemModel, QWidget* parent = nullptr);
|
||||
CartOverlayWidget(GemModel* gemModel, O3DEObjectDownloadController* downloadController, QWidget* parent = nullptr);
|
||||
|
||||
private:
|
||||
QStringList ConvertFromModelIndices(const QVector<QModelIndex>& gems) const;
|
||||
|
||||
using GetTagIndicesCallback = AZStd::function<QVector<QModelIndex>()>;
|
||||
void CreateGemSection(const QString& singularTitle, const QString& pluralTitle, GetTagIndicesCallback getTagIndices);
|
||||
void CreateDownloadSection();
|
||||
|
||||
QVBoxLayout* m_layout = nullptr;
|
||||
GemModel* m_gemModel = nullptr;
|
||||
O3DEObjectDownloadController* m_downloadController = nullptr;
|
||||
|
||||
inline constexpr static int s_width = 240;
|
||||
};
|
||||
@@ -51,7 +54,7 @@ namespace O3DE::ProjectManager
|
||||
Q_OBJECT // AUTOMOC
|
||||
|
||||
public:
|
||||
CartButton(GemModel* gemModel, QWidget* parent = nullptr);
|
||||
CartButton(GemModel* gemModel, O3DEObjectDownloadController* downloadController, QWidget* parent = nullptr);
|
||||
~CartButton();
|
||||
void ShowOverlay();
|
||||
|
||||
@@ -64,6 +67,7 @@ namespace O3DE::ProjectManager
|
||||
QLabel* m_countLabel = nullptr;
|
||||
QPushButton* m_dropDownButton = nullptr;
|
||||
CartOverlayWidget* m_cartOverlay = nullptr;
|
||||
O3DEObjectDownloadController* m_downloadController = nullptr;
|
||||
|
||||
inline constexpr static int s_iconSize = 24;
|
||||
inline constexpr static int s_arrowDownIconSize = 8;
|
||||
@@ -75,7 +79,7 @@ namespace O3DE::ProjectManager
|
||||
Q_OBJECT // AUTOMOC
|
||||
|
||||
public:
|
||||
explicit GemCatalogHeaderWidget(GemModel* gemModel, GemSortFilterProxyModel* filterProxyModel, QWidget* parent = nullptr);
|
||||
explicit GemCatalogHeaderWidget(GemModel* gemModel, GemSortFilterProxyModel* filterProxyModel, O3DEObjectDownloadController* downloadController, QWidget* parent = nullptr);
|
||||
~GemCatalogHeaderWidget() = default;
|
||||
|
||||
void ReinitForProject();
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <GemCatalog/GemSortFilterProxyModel.h>
|
||||
#include <GemCatalog/GemRequirementDialog.h>
|
||||
#include <GemCatalog/GemDependenciesDialog.h>
|
||||
#include <O3DEObjectDownloadController.h>
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QPushButton>
|
||||
@@ -32,7 +33,10 @@ namespace O3DE::ProjectManager
|
||||
vLayout->setSpacing(0);
|
||||
setLayout(vLayout);
|
||||
|
||||
m_headerWidget = new GemCatalogHeaderWidget(m_gemModel, m_proxModel);
|
||||
m_downloadController = new O3DEObjectDownloadController();
|
||||
m_downloadController->Start();
|
||||
|
||||
m_headerWidget = new GemCatalogHeaderWidget(m_gemModel, m_proxModel, m_downloadController);
|
||||
vLayout->addWidget(m_headerWidget);
|
||||
|
||||
QHBoxLayout* hLayout = new QHBoxLayout();
|
||||
|
||||
@@ -39,6 +39,7 @@ namespace O3DE::ProjectManager
|
||||
EnableDisableGemsResult EnableDisableGemsForProject(const QString& projectPath);
|
||||
|
||||
GemModel* GetGemModel() const { return m_gemModel; }
|
||||
O3DEObjectDownloadController* GetDownloadController() const { return m_downloadController; }
|
||||
|
||||
private:
|
||||
void FillModel(const QString& projectPath);
|
||||
@@ -50,5 +51,6 @@ namespace O3DE::ProjectManager
|
||||
GemSortFilterProxyModel* m_proxModel = nullptr;
|
||||
QVBoxLayout* m_filterWidgetLayout = nullptr;
|
||||
GemFilterWidget* m_filterWidget = nullptr;
|
||||
O3DEObjectDownloadController* m_downloadController = nullptr;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -301,6 +301,7 @@ namespace O3DE::ProjectManager
|
||||
m_enableGemProject = pybind11::module::import("o3de.enable_gem");
|
||||
m_disableGemProject = pybind11::module::import("o3de.disable_gem");
|
||||
m_editProjectProperties = pybind11::module::import("o3de.project_properties");
|
||||
m_download = pybind11::module::import("o3de.download");
|
||||
m_pathlib = pybind11::module::import("pathlib");
|
||||
|
||||
// make sure the engine is registered
|
||||
@@ -1075,4 +1076,30 @@ namespace O3DE::ProjectManager
|
||||
std::sort(gemRepos.begin(), gemRepos.end());
|
||||
return AZ::Success(AZStd::move(gemRepos));
|
||||
}
|
||||
|
||||
AZ::Outcome<void, AZStd::string> PythonBindings::DownloadGem(const QString& gemName, std::function<void(int)> gemProgressCallback)
|
||||
{
|
||||
bool downloadSucceeded = false;
|
||||
auto result = ExecuteWithLockErrorHandling(
|
||||
[&]
|
||||
{
|
||||
auto downloadResult = m_download.attr("download_gem")(
|
||||
QString_To_Py_String(gemName), // gem name
|
||||
pybind11::none(), // destination path
|
||||
false// skip auto register
|
||||
);
|
||||
downloadSucceeded = (downloadResult.cast<int>() == 0);
|
||||
});
|
||||
|
||||
if (!result.IsSuccess())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else if (!downloadSucceeded)
|
||||
{
|
||||
return AZ::Failure<AZStd::string>("Failed to download gem.");
|
||||
}
|
||||
|
||||
return AZ::Success();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,6 +61,7 @@ namespace O3DE::ProjectManager
|
||||
bool AddGemRepo(const QString& repoUri) override;
|
||||
bool RemoveGemRepo(const QString& repoUri) override;
|
||||
AZ::Outcome<QVector<GemRepoInfo>, AZStd::string> GetAllGemRepoInfos() override;
|
||||
AZ::Outcome<void, AZStd::string> DownloadGem(const QString& gemName, std::function<void(int)> gemProgressCallback) override;
|
||||
|
||||
private:
|
||||
AZ_DISABLE_COPY_MOVE(PythonBindings);
|
||||
@@ -87,6 +88,7 @@ namespace O3DE::ProjectManager
|
||||
pybind11::handle m_enableGemProject;
|
||||
pybind11::handle m_disableGemProject;
|
||||
pybind11::handle m_editProjectProperties;
|
||||
pybind11::handle m_download;
|
||||
pybind11::handle m_pathlib;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -187,6 +187,8 @@ namespace O3DE::ProjectManager
|
||||
* @return A list of gem repo infos.
|
||||
*/
|
||||
virtual AZ::Outcome<QVector<GemRepoInfo>, AZStd::string> GetAllGemRepoInfos() = 0;
|
||||
|
||||
virtual AZ::Outcome<void, AZStd::string> DownloadGem(const QString& gemName, std::function<void(int)> gemProgressCallback) = 0;
|
||||
};
|
||||
|
||||
using PythonBindingsInterface = AZ::Interface<IPythonBindings>;
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace O3DE::ProjectManager
|
||||
vLayout->addWidget(m_header);
|
||||
|
||||
m_updateSettingsScreen = new UpdateProjectSettingsScreen();
|
||||
m_gemCatalogScreen = new GemCatalogScreen();
|
||||
m_gemCatalogScreen = new GemCatalogScreen(nullptr);
|
||||
|
||||
m_stack = new QStackedWidget(this);
|
||||
m_stack->setObjectName("body");
|
||||
@@ -136,6 +136,11 @@ namespace O3DE::ProjectManager
|
||||
}
|
||||
else if (m_stack->currentIndex() == ScreenOrder::Gems && m_gemCatalogScreen)
|
||||
{
|
||||
if (!m_gemCatalogScreen->GetDownloadController()->IsDownloadQueueEmpty())
|
||||
{
|
||||
QMessageBox::critical(this, tr("Gems downloading"), tr("You must wait for gems to finish downloading before continuing."));
|
||||
return;
|
||||
}
|
||||
// Enable or disable the gems that got adjusted in the gem catalog and apply them to the given project.
|
||||
const GemCatalogScreen::EnableDisableGemsResult result = m_gemCatalogScreen->EnableDisableGemsForProject(m_projectInfo.m_path);
|
||||
if (result == GemCatalogScreen::EnableDisableGemsResult::Failed)
|
||||
|
||||
@@ -29,6 +29,10 @@ set(FILES
|
||||
Source/FormImageBrowseEditWidget.cpp
|
||||
Source/GemsSubWidget.h
|
||||
Source/GemsSubWidget.cpp
|
||||
Source/O3DEObjectDownloadController.h
|
||||
Source/O3DEObjectDownloadController.cpp
|
||||
Source/O3DEObjectDownloadWorker.h
|
||||
Source/O3DEObjectDownloadWorker.cpp
|
||||
Source/PathValidator.h
|
||||
Source/PathValidator.cpp
|
||||
Source/ProjectManagerWindow.h
|
||||
|
||||
Reference in New Issue
Block a user