Merge branch 'main' into ftue_auto_register
This commit is contained in:
@@ -15,7 +15,6 @@
|
||||
#include <PythonBindingsInterface.h>
|
||||
#include <NewProjectSettingsScreen.h>
|
||||
#include <ScreenHeaderWidget.h>
|
||||
#include <GemCatalog/GemCatalogScreen.h>
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QHBoxLayout>
|
||||
@@ -42,9 +41,10 @@ namespace O3DE::ProjectManager
|
||||
|
||||
m_stack = new QStackedWidget(this);
|
||||
m_stack->setObjectName("body");
|
||||
m_stack->setSizePolicy(QSizePolicy(QSizePolicy::Preferred,QSizePolicy::Expanding));
|
||||
m_stack->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding));
|
||||
m_stack->addWidget(new NewProjectSettingsScreen());
|
||||
m_stack->addWidget(new GemCatalogScreen());
|
||||
m_gemCatalog = new GemCatalogScreen();
|
||||
m_stack->addWidget(m_gemCatalog);
|
||||
vLayout->addWidget(m_stack);
|
||||
|
||||
QDialogButtonBox* backNextButtons = new QDialogButtonBox();
|
||||
@@ -88,6 +88,7 @@ namespace O3DE::ProjectManager
|
||||
emit GotoPreviousScreenRequest();
|
||||
}
|
||||
}
|
||||
|
||||
void CreateProjectCtrl::HandleNextButton()
|
||||
{
|
||||
ScreenWidget* currentScreen = reinterpret_cast<ScreenWidget*>(m_stack->currentWidget());
|
||||
@@ -106,6 +107,9 @@ namespace O3DE::ProjectManager
|
||||
|
||||
m_projectInfo = newProjectScreen->GetProjectInfo();
|
||||
m_projectTemplatePath = newProjectScreen->GetProjectTemplatePath();
|
||||
|
||||
// The next page is the gem catalog. Gather the available gems that will be shown in the gem catalog.
|
||||
m_gemCatalog->ReinitForProject(m_projectInfo.m_path, /*isNewProject=*/true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,6 +133,9 @@ namespace O3DE::ProjectManager
|
||||
{
|
||||
QMessageBox::critical(this, tr("Project creation failed"), tr("Failed to create project."));
|
||||
}
|
||||
|
||||
// Enable/disable gems for the newly created project.
|
||||
m_gemCatalog->EnableDisableGemsForProject(m_projectInfo.m_path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <ScreenWidget.h>
|
||||
#include <ProjectInfo.h>
|
||||
#include <GemCatalog/GemCatalogScreen.h>
|
||||
#endif
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QStackedWidget)
|
||||
@@ -48,6 +49,8 @@ namespace O3DE::ProjectManager
|
||||
|
||||
QString m_projectTemplatePath;
|
||||
ProjectInfo m_projectInfo;
|
||||
|
||||
GemCatalogScreen* m_gemCatalog = nullptr;
|
||||
};
|
||||
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -15,13 +15,12 @@
|
||||
#include <GemCatalog/GemCatalogHeaderWidget.h>
|
||||
#include <GemCatalog/GemListHeaderWidget.h>
|
||||
#include <GemCatalog/GemSortFilterProxyModel.h>
|
||||
#include <GemCatalog/GemFilterWidget.h>
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QPushButton>
|
||||
#include <QTimer>
|
||||
|
||||
//#define USE_TESTGEMDATA
|
||||
#include <PythonBindingsInterface.h>
|
||||
#include <QMessageBox>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
@@ -29,47 +28,32 @@ namespace O3DE::ProjectManager
|
||||
: ScreenWidget(parent)
|
||||
{
|
||||
m_gemModel = new GemModel(this);
|
||||
GemSortFilterProxyModel* proxyModel = new GemSortFilterProxyModel(m_gemModel, this);
|
||||
m_proxModel = new GemSortFilterProxyModel(m_gemModel, this);
|
||||
|
||||
QVBoxLayout* vLayout = new QVBoxLayout();
|
||||
vLayout->setMargin(0);
|
||||
vLayout->setSpacing(0);
|
||||
setLayout(vLayout);
|
||||
|
||||
GemCatalogHeaderWidget* headerWidget = new GemCatalogHeaderWidget(proxyModel);
|
||||
GemCatalogHeaderWidget* headerWidget = new GemCatalogHeaderWidget(m_proxModel);
|
||||
vLayout->addWidget(headerWidget);
|
||||
|
||||
QHBoxLayout* hLayout = new QHBoxLayout();
|
||||
hLayout->setMargin(0);
|
||||
vLayout->addLayout(hLayout);
|
||||
|
||||
m_gemListView = new GemListView(proxyModel, proxyModel->GetSelectionModel(), this);
|
||||
m_gemListView = new GemListView(m_proxModel, m_proxModel->GetSelectionModel(), this);
|
||||
m_gemInspector = new GemInspector(m_gemModel, this);
|
||||
m_gemInspector->setFixedWidth(320);
|
||||
m_gemInspector->setFixedWidth(240);
|
||||
|
||||
// Start: Temporary gem test data
|
||||
#ifdef USE_TESTGEMDATA
|
||||
QVector<GemInfo> testGemData = GenerateTestData();
|
||||
for (const GemInfo& gemInfo : testGemData)
|
||||
{
|
||||
m_gemModel->AddGem(gemInfo);
|
||||
}
|
||||
#else
|
||||
// End: Temporary gem test data
|
||||
auto result = PythonBindingsInterface::Get()->GetGems();
|
||||
if (result.IsSuccess())
|
||||
{
|
||||
for (auto gemInfo : result.GetValue())
|
||||
{
|
||||
m_gemModel->AddGem(gemInfo);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
QWidget* filterWidget = new QWidget(this);
|
||||
filterWidget->setFixedWidth(240);
|
||||
m_filterWidgetLayout = new QVBoxLayout();
|
||||
m_filterWidgetLayout->setMargin(0);
|
||||
m_filterWidgetLayout->setSpacing(0);
|
||||
filterWidget->setLayout(m_filterWidgetLayout);
|
||||
|
||||
GemFilterWidget* filterWidget = new GemFilterWidget(proxyModel);
|
||||
filterWidget->setFixedWidth(250);
|
||||
|
||||
GemListHeaderWidget* listHeaderWidget = new GemListHeaderWidget(proxyModel);
|
||||
GemListHeaderWidget* listHeaderWidget = new GemListHeaderWidget(m_proxModel);
|
||||
|
||||
QVBoxLayout* middleVLayout = new QVBoxLayout();
|
||||
middleVLayout->setMargin(0);
|
||||
@@ -80,98 +64,111 @@ namespace O3DE::ProjectManager
|
||||
hLayout->addWidget(filterWidget);
|
||||
hLayout->addLayout(middleVLayout);
|
||||
hLayout->addWidget(m_gemInspector);
|
||||
|
||||
proxyModel->InvalidateFilter();
|
||||
}
|
||||
|
||||
QVector<GemInfo> GemCatalogScreen::GenerateTestData()
|
||||
void GemCatalogScreen::ReinitForProject(const QString& projectPath, bool isNewProject)
|
||||
{
|
||||
QVector<GemInfo> result;
|
||||
m_gemModel->clear();
|
||||
FillModel(projectPath, isNewProject);
|
||||
|
||||
GemInfo gem("EMotion FX",
|
||||
"O3DE Foundation",
|
||||
"EMFX is a real-time character animation system. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
|
||||
(GemInfo::Android | GemInfo::iOS | GemInfo::macOS | GemInfo::Windows | GemInfo::Linux),
|
||||
true);
|
||||
gem.m_directoryLink = "C:/";
|
||||
gem.m_documentationLink = "http://www.amazon.com";
|
||||
gem.m_dependingGemUuids = QStringList({"EMotionFX", "Atom"});
|
||||
gem.m_conflictingGemUuids = QStringList({"Vegetation", "Camera", "ScriptCanvas", "CloudCanvas", "Networking"});
|
||||
gem.m_types = (GemInfo::Code | GemInfo::Asset);
|
||||
gem.m_version = "v1.01";
|
||||
gem.m_lastUpdatedDate = "24th April 2021";
|
||||
gem.m_binarySizeInKB = 40;
|
||||
gem.m_features = QStringList({"Animation", "Assets", "Physics"});
|
||||
gem.m_gemOrigin = GemInfo::O3DEFoundation;
|
||||
result.push_back(gem);
|
||||
if (m_filterWidget)
|
||||
{
|
||||
m_filterWidget->hide();
|
||||
m_filterWidget->deleteLater();
|
||||
}
|
||||
|
||||
gem.m_name = "Atom";
|
||||
gem.m_creator = "O3DE Seattle";
|
||||
gem.m_summary = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";
|
||||
gem.m_platforms = (GemInfo::Android | GemInfo::Windows | GemInfo::Linux | GemInfo::macOS);
|
||||
gem.m_isAdded = true;
|
||||
gem.m_directoryLink = "C:/";
|
||||
gem.m_documentationLink = "https://aws.amazon.com/gametech/";
|
||||
gem.m_dependingGemUuids = QStringList({"EMotionFX", "Core", "AudioSystem", "Camera", "Particles"});
|
||||
gem.m_conflictingGemUuids = QStringList({"CloudCanvas", "NovaNet"});
|
||||
gem.m_version = "v2.31";
|
||||
gem.m_lastUpdatedDate = "24th November 2020";
|
||||
gem.m_features = QStringList({"Assets", "Rendering", "UI", "VR", "Debug", "Environment"});
|
||||
gem.m_binarySizeInKB = 2087;
|
||||
result.push_back(gem);
|
||||
m_filterWidget = new GemFilterWidget(m_proxModel);
|
||||
m_filterWidgetLayout->addWidget(m_filterWidget);
|
||||
|
||||
gem.m_name = "Physics";
|
||||
gem.m_creator = "O3DE London";
|
||||
gem.m_summary = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";
|
||||
gem.m_platforms = (GemInfo::Android | GemInfo::Linux | GemInfo::macOS);
|
||||
gem.m_isAdded = true;
|
||||
gem.m_directoryLink = "C:/";
|
||||
gem.m_documentationLink = "https://aws.amazon.com/gametech/";
|
||||
gem.m_dependingGemUuids = QStringList({"GraphCanvas", "ExpressionEvaluation", "UI Lib", "Multiplayer", "GameStateSamples"});
|
||||
gem.m_conflictingGemUuids = QStringList({"Cloud Canvas", "EMotion FX", "Streaming", "MessagePopup", "Cloth", "Graph Canvas", "Twitch Integration"});
|
||||
gem.m_version = "v1.5.102145";
|
||||
gem.m_lastUpdatedDate = "1st January 2021";
|
||||
gem.m_binarySizeInKB = 2000000;
|
||||
gem.m_features = QStringList({"Physics", "Gameplay", "Debug", "Assets"});
|
||||
result.push_back(gem);
|
||||
m_proxModel->InvalidateFilter();
|
||||
|
||||
result.push_back(O3DE::ProjectManager::GemInfo("Certificate Manager",
|
||||
"O3DE Irvine",
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
|
||||
GemInfo::Windows,
|
||||
false));
|
||||
// Select the first entry after everything got correctly sized
|
||||
QTimer::singleShot(200, [=]{
|
||||
QModelIndex firstModelIndex = m_gemListView->model()->index(0,0);
|
||||
m_gemListView->selectionModel()->select(firstModelIndex, QItemSelectionModel::ClearAndSelect);
|
||||
});
|
||||
}
|
||||
|
||||
result.push_back(O3DE::ProjectManager::GemInfo("Cloud Gem Framework",
|
||||
"O3DE Seattle",
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
|
||||
GemInfo::iOS | GemInfo::Linux,
|
||||
false));
|
||||
void GemCatalogScreen::FillModel(const QString& projectPath, bool isNewProject)
|
||||
{
|
||||
AZ::Outcome<QVector<GemInfo>, AZStd::string> allGemInfosResult;
|
||||
if (isNewProject)
|
||||
{
|
||||
allGemInfosResult = PythonBindingsInterface::Get()->GetEngineGemInfos();
|
||||
}
|
||||
else
|
||||
{
|
||||
allGemInfosResult = PythonBindingsInterface::Get()->GetAllGemInfos(projectPath);
|
||||
}
|
||||
|
||||
result.push_back(O3DE::ProjectManager::GemInfo("Cloud Gem Core",
|
||||
"O3DE Foundation",
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
||||
GemInfo::Android | GemInfo::Windows | GemInfo::Linux,
|
||||
true));
|
||||
if (allGemInfosResult.IsSuccess())
|
||||
{
|
||||
// Add all available gems to the model.
|
||||
const QVector<GemInfo> allGemInfos = allGemInfosResult.GetValue();
|
||||
for (const GemInfo& gemInfo : allGemInfos)
|
||||
{
|
||||
m_gemModel->AddGem(gemInfo);
|
||||
}
|
||||
|
||||
result.push_back(O3DE::ProjectManager::GemInfo("Gestures",
|
||||
"O3DE Foundation",
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
||||
GemInfo::Android | GemInfo::Windows | GemInfo::Linux,
|
||||
false));
|
||||
// Gather enabled gems for the given project.
|
||||
auto enabledGemNamesResult = PythonBindingsInterface::Get()->GetEnabledGemNames(projectPath);
|
||||
if (enabledGemNamesResult.IsSuccess())
|
||||
{
|
||||
const QVector<AZStd::string> enabledGemNames = enabledGemNamesResult.GetValue();
|
||||
for (const AZStd::string& enabledGemName : enabledGemNames)
|
||||
{
|
||||
const QModelIndex modelIndex = m_gemModel->FindIndexByNameString(enabledGemName.c_str());
|
||||
if (modelIndex.isValid())
|
||||
{
|
||||
GemModel::SetWasPreviouslyAdded(*m_gemModel, modelIndex, true);
|
||||
GemModel::SetIsAdded(*m_gemModel, modelIndex, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Warning("ProjectManager::GemCatalog", false,
|
||||
"Cannot find entry for gem with name '%s'. The CMake target name probably does not match the specified name in the gem.json.",
|
||||
enabledGemName.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(nullptr, tr("Operation failed"), QString("Cannot retrieve enabled gems for project %1.\n\nError:\n%2").arg(projectPath, enabledGemNamesResult.GetError().c_str()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(nullptr, tr("Operation failed"), QString("Cannot retrieve gems for %1.\n\nError:\n%2").arg(projectPath, allGemInfosResult.GetError().c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
result.push_back(O3DE::ProjectManager::GemInfo("Effects System",
|
||||
"O3DE Foundation",
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
||||
GemInfo::Android | GemInfo::Windows | GemInfo::Linux,
|
||||
true));
|
||||
void GemCatalogScreen::EnableDisableGemsForProject(const QString& projectPath)
|
||||
{
|
||||
IPythonBindings* pythonBindings = PythonBindingsInterface::Get();
|
||||
QVector<QModelIndex> toBeAdded = m_gemModel->GatherGemsToBeAdded();
|
||||
QVector<QModelIndex> toBeRemoved = m_gemModel->GatherGemsToBeRemoved();
|
||||
|
||||
result.push_back(O3DE::ProjectManager::GemInfo("Microphone",
|
||||
"O3DE Foundation",
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus euismod ligula vitae dui dictum, a sodales dolor luctus. Sed id elit dapibus, finibus neque sed, efficitur mi. Nam facilisis ligula at eleifend pellentesque. Praesent non ex consectetur, blandit tellus in, venenatis lacus. Duis nec neque in urna ullamcorper euismod id eu leo. Nam efficitur dolor sed odio vehicula venenatis. Suspendisse nec est non velit commodo cursus in sit amet dui. Ut bibendum nisl et libero hendrerit dapibus. Vestibulum ultrices ullamcorper urna, placerat porttitor est lobortis in. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer a magna ac tellus sollicitudin porttitor. Phasellus lobortis viverra justo id bibendum. Etiam ac pharetra risus. Nulla vitae justo nibh. Nulla viverra leo et molestie interdum. Duis sit amet bibendum nulla, sit amet vehicula augue.",
|
||||
GemInfo::Android | GemInfo::Windows | GemInfo::Linux,
|
||||
false));
|
||||
for (const QModelIndex& modelIndex : toBeAdded)
|
||||
{
|
||||
const QString gemPath = GemModel::GetPath(modelIndex);
|
||||
const AZ::Outcome<void, AZStd::string> result = pythonBindings->AddGemToProject(gemPath, projectPath);
|
||||
if (!result.IsSuccess())
|
||||
{
|
||||
QMessageBox::critical(nullptr, "Operation failed",
|
||||
QString("Cannot add gem %1 to project.\n\nError:\n%2").arg(GemModel::GetName(modelIndex), result.GetError().c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
for (const QModelIndex& modelIndex : toBeRemoved)
|
||||
{
|
||||
const QString gemPath = GemModel::GetPath(modelIndex);
|
||||
const AZ::Outcome<void, AZStd::string> result = pythonBindings->RemoveGemFromProject(gemPath, projectPath);
|
||||
if (!result.IsSuccess())
|
||||
{
|
||||
QMessageBox::critical(nullptr, "Operation failed",
|
||||
QString("Cannot remove gem %1 from project.\n\nError:\n%2").arg(GemModel::GetName(modelIndex), result.GetError().c_str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ProjectManagerScreen GemCatalogScreen::GetScreenEnum()
|
||||
|
||||
@@ -14,9 +14,11 @@
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <ScreenWidget.h>
|
||||
#include <GemCatalog/GemFilterWidget.h>
|
||||
#include <GemCatalog/GemListView.h>
|
||||
#include <GemCatalog/GemInspector.h>
|
||||
#include <GemCatalog/GemModel.h>
|
||||
#include <GemCatalog/GemSortFilterProxyModel.h>
|
||||
#endif
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
@@ -29,11 +31,17 @@ namespace O3DE::ProjectManager
|
||||
~GemCatalogScreen() = default;
|
||||
ProjectManagerScreen GetScreenEnum() override;
|
||||
|
||||
void ReinitForProject(const QString& projectPath, bool isNewProject);
|
||||
void EnableDisableGemsForProject(const QString& projectPath);
|
||||
|
||||
private:
|
||||
QVector<GemInfo> GenerateTestData();
|
||||
void FillModel(const QString& projectPath, bool isNewProject);
|
||||
|
||||
GemListView* m_gemListView = nullptr;
|
||||
GemInspector* m_gemInspector = nullptr;
|
||||
GemModel* m_gemModel = nullptr;
|
||||
GemSortFilterProxyModel* m_proxModel = nullptr;
|
||||
QVBoxLayout* m_filterWidgetLayout = nullptr;
|
||||
GemFilterWidget* m_filterWidget = nullptr;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -79,4 +79,9 @@ namespace O3DE::ProjectManager
|
||||
{
|
||||
return (m_platforms & platform);
|
||||
}
|
||||
|
||||
bool GemInfo::operator<(const GemInfo& gemInfo) const
|
||||
{
|
||||
return (m_displayName < gemInfo.m_displayName);
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -61,6 +61,8 @@ namespace O3DE::ProjectManager
|
||||
|
||||
bool IsValid() const;
|
||||
|
||||
bool operator<(const GemInfo& gemInfo) const;
|
||||
|
||||
QString m_path;
|
||||
QString m_name = "Unknown Gem Name";
|
||||
QString m_displayName = "Unknown Gem Name";
|
||||
|
||||
@@ -34,83 +34,57 @@ namespace O3DE::ProjectManager
|
||||
constexpr const char* k_pathProperty = "Path";
|
||||
|
||||
NewProjectSettingsScreen::NewProjectSettingsScreen(QWidget* parent)
|
||||
: ScreenWidget(parent)
|
||||
: ProjectSettingsScreen(parent)
|
||||
{
|
||||
QHBoxLayout* hLayout = new QHBoxLayout(this);
|
||||
hLayout->setAlignment(Qt::AlignLeft);
|
||||
hLayout->setContentsMargins(0,0,0,0);
|
||||
const QString defaultName{ "NewProject" };
|
||||
const QString defaultPath = QDir::toNativeSeparators(GetDefaultProjectPath() + "/" + defaultName);
|
||||
|
||||
// if we don't provide a parent for this box layout the stylesheet doesn't take
|
||||
// if we don't set this in a frame (just use a sub-layout) all the content will align incorrectly horizontally
|
||||
QFrame* projectSettingsFrame = new QFrame(this);
|
||||
projectSettingsFrame->setObjectName("projectSettings");
|
||||
QVBoxLayout* vLayout = new QVBoxLayout(this);
|
||||
m_projectName->lineEdit()->setText(defaultName);
|
||||
m_projectPath->lineEdit()->setText(defaultPath);
|
||||
|
||||
// you cannot remove content margins in qss
|
||||
vLayout->setContentsMargins(0,0,0,0);
|
||||
vLayout->setAlignment(Qt::AlignTop);
|
||||
// if we don't use a QFrame we cannot "contain" the widgets inside and move them around
|
||||
// as a group
|
||||
QFrame* projectTemplateWidget = new QFrame(this);
|
||||
projectTemplateWidget->setObjectName("projectTemplate");
|
||||
QVBoxLayout* containerLayout = new QVBoxLayout();
|
||||
containerLayout->setAlignment(Qt::AlignTop);
|
||||
{
|
||||
const QString defaultName{ "NewProject" };
|
||||
const QString defaultPath = QDir::toNativeSeparators(GetDefaultProjectPath() + "/" + defaultName);
|
||||
QLabel* projectTemplateLabel = new QLabel(tr("Select a Project Template"));
|
||||
projectTemplateLabel->setObjectName("projectTemplateLabel");
|
||||
containerLayout->addWidget(projectTemplateLabel);
|
||||
|
||||
m_projectName = new FormLineEditWidget(tr("Project name"), defaultName, this);
|
||||
connect(m_projectName->lineEdit(), &QLineEdit::textChanged, this, &NewProjectSettingsScreen::ValidateProjectPath);
|
||||
vLayout->addWidget(m_projectName);
|
||||
QLabel* projectTemplateDetailsLabel = new QLabel(tr("Project templates are pre-configured with relevant Gems that provide "
|
||||
"additional functionality and content to the project."));
|
||||
projectTemplateDetailsLabel->setWordWrap(true);
|
||||
projectTemplateDetailsLabel->setObjectName("projectTemplateDetailsLabel");
|
||||
containerLayout->addWidget(projectTemplateDetailsLabel);
|
||||
|
||||
m_projectPath = new FormBrowseEditWidget(tr("Project Location"), defaultPath, this);
|
||||
m_projectPath->lineEdit()->setReadOnly(true);
|
||||
connect(m_projectPath->lineEdit(), &QLineEdit::textChanged, this, &NewProjectSettingsScreen::ValidateProjectPath);
|
||||
vLayout->addWidget(m_projectPath);
|
||||
QHBoxLayout* templateLayout = new QHBoxLayout(this);
|
||||
containerLayout->addItem(templateLayout);
|
||||
|
||||
// if we don't use a QFrame we cannot "contain" the widgets inside and move them around
|
||||
// as a group
|
||||
QFrame* projectTemplateWidget = new QFrame(this);
|
||||
projectTemplateWidget->setObjectName("projectTemplate");
|
||||
QVBoxLayout* containerLayout = new QVBoxLayout();
|
||||
containerLayout->setAlignment(Qt::AlignTop);
|
||||
m_projectTemplateButtonGroup = new QButtonGroup(this);
|
||||
m_projectTemplateButtonGroup->setObjectName("templateButtonGroup");
|
||||
auto templatesResult = PythonBindingsInterface::Get()->GetProjectTemplates();
|
||||
if (templatesResult.IsSuccess() && !templatesResult.GetValue().isEmpty())
|
||||
{
|
||||
QLabel* projectTemplateLabel = new QLabel(tr("Select a Project Template"));
|
||||
projectTemplateLabel->setObjectName("projectTemplateLabel");
|
||||
containerLayout->addWidget(projectTemplateLabel);
|
||||
|
||||
QLabel* projectTemplateDetailsLabel = new QLabel(tr("Project templates are pre-configured with relevant Gems that provide "
|
||||
"additional functionality and content to the project."));
|
||||
projectTemplateDetailsLabel->setWordWrap(true);
|
||||
projectTemplateDetailsLabel->setObjectName("projectTemplateDetailsLabel");
|
||||
containerLayout->addWidget(projectTemplateDetailsLabel);
|
||||
|
||||
QHBoxLayout* templateLayout = new QHBoxLayout(this);
|
||||
containerLayout->addItem(templateLayout);
|
||||
|
||||
m_projectTemplateButtonGroup = new QButtonGroup(this);
|
||||
m_projectTemplateButtonGroup->setObjectName("templateButtonGroup");
|
||||
auto templatesResult = PythonBindingsInterface::Get()->GetProjectTemplates();
|
||||
if (templatesResult.IsSuccess() && !templatesResult.GetValue().isEmpty())
|
||||
for (const ProjectTemplateInfo& projectTemplate : templatesResult.GetValue())
|
||||
{
|
||||
for (auto projectTemplate : templatesResult.GetValue())
|
||||
{
|
||||
QRadioButton* radioButton = new QRadioButton(projectTemplate.m_name, this);
|
||||
radioButton->setProperty(k_pathProperty, projectTemplate.m_path);
|
||||
m_projectTemplateButtonGroup->addButton(radioButton);
|
||||
QRadioButton* radioButton = new QRadioButton(projectTemplate.m_name, this);
|
||||
radioButton->setProperty(k_pathProperty, projectTemplate.m_path);
|
||||
m_projectTemplateButtonGroup->addButton(radioButton);
|
||||
|
||||
containerLayout->addWidget(radioButton);
|
||||
}
|
||||
|
||||
m_projectTemplateButtonGroup->buttons().first()->setChecked(true);
|
||||
containerLayout->addWidget(radioButton);
|
||||
}
|
||||
}
|
||||
projectTemplateWidget->setLayout(containerLayout);
|
||||
vLayout->addWidget(projectTemplateWidget);
|
||||
}
|
||||
projectSettingsFrame->setLayout(vLayout);
|
||||
|
||||
hLayout->addWidget(projectSettingsFrame);
|
||||
m_projectTemplateButtonGroup->buttons().first()->setChecked(true);
|
||||
}
|
||||
}
|
||||
projectTemplateWidget->setLayout(containerLayout);
|
||||
m_verticalLayout->addWidget(projectTemplateWidget);
|
||||
|
||||
QWidget* projectTemplateDetails = new QWidget(this);
|
||||
projectTemplateDetails->setObjectName("projectTemplateDetails");
|
||||
hLayout->addWidget(projectTemplateDetails);
|
||||
|
||||
this->setLayout(hLayout);
|
||||
m_horizontalLayout->addWidget(projectTemplateDetails);
|
||||
}
|
||||
|
||||
QString NewProjectSettingsScreen::GetDefaultProjectPath()
|
||||
@@ -133,69 +107,13 @@ namespace O3DE::ProjectManager
|
||||
return ProjectManagerScreen::NewProjectSettings;
|
||||
}
|
||||
|
||||
void NewProjectSettingsScreen::ValidateProjectPath()
|
||||
{
|
||||
Validate();
|
||||
}
|
||||
|
||||
void NewProjectSettingsScreen::NotifyCurrentScreen()
|
||||
{
|
||||
Validate();
|
||||
}
|
||||
|
||||
ProjectInfo NewProjectSettingsScreen::GetProjectInfo()
|
||||
{
|
||||
ProjectInfo projectInfo;
|
||||
projectInfo.m_projectName = m_projectName->lineEdit()->text();
|
||||
projectInfo.m_path = m_projectPath->lineEdit()->text();
|
||||
return projectInfo;
|
||||
}
|
||||
|
||||
QString NewProjectSettingsScreen::GetProjectTemplatePath()
|
||||
{
|
||||
return m_projectTemplateButtonGroup->checkedButton()->property(k_pathProperty).toString();
|
||||
}
|
||||
|
||||
bool NewProjectSettingsScreen::Validate()
|
||||
{
|
||||
bool projectPathIsValid = true;
|
||||
if (m_projectPath->lineEdit()->text().isEmpty())
|
||||
{
|
||||
projectPathIsValid = false;
|
||||
m_projectPath->setErrorLabelText(tr("Please provide a valid location."));
|
||||
}
|
||||
else
|
||||
{
|
||||
QDir path(m_projectPath->lineEdit()->text());
|
||||
if (path.exists() && !path.isEmpty())
|
||||
{
|
||||
projectPathIsValid = false;
|
||||
m_projectPath->setErrorLabelText(tr("This folder exists and isn't empty. Please choose a different location."));
|
||||
}
|
||||
}
|
||||
|
||||
bool projectNameIsValid = true;
|
||||
if (m_projectName->lineEdit()->text().isEmpty())
|
||||
{
|
||||
projectNameIsValid = false;
|
||||
m_projectName->setErrorLabelText(tr("Please provide a project name."));
|
||||
}
|
||||
else
|
||||
{
|
||||
// this validation should roughly match the utils.validate_identifier which the cli
|
||||
// uses to validate project names
|
||||
QRegExp validProjectNameRegex("[A-Za-z][A-Za-z0-9_-]{0,63}");
|
||||
const bool result = validProjectNameRegex.exactMatch(m_projectName->lineEdit()->text());
|
||||
if (!result)
|
||||
{
|
||||
projectNameIsValid = false;
|
||||
m_projectName->setErrorLabelText(tr("Project names must start with a letter and consist of up to 64 letter, number, '_' or '-' characters"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
m_projectName->setErrorLabelVisible(!projectNameIsValid);
|
||||
m_projectPath->setErrorLabelVisible(!projectPathIsValid);
|
||||
return projectNameIsValid && projectPathIsValid;
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -12,41 +12,28 @@
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <ScreenWidget.h>
|
||||
#include <ProjectInfo.h>
|
||||
#include <ProjectSettingsScreen.h>
|
||||
#endif
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QButtonGroup)
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
QT_FORWARD_DECLARE_CLASS(FormLineEditWidget)
|
||||
QT_FORWARD_DECLARE_CLASS(FormBrowseEditWidget)
|
||||
|
||||
class NewProjectSettingsScreen
|
||||
: public ScreenWidget
|
||||
: public ProjectSettingsScreen
|
||||
{
|
||||
public:
|
||||
explicit NewProjectSettingsScreen(QWidget* parent = nullptr);
|
||||
~NewProjectSettingsScreen() = default;
|
||||
ProjectManagerScreen GetScreenEnum() override;
|
||||
|
||||
ProjectInfo GetProjectInfo();
|
||||
QString GetProjectTemplatePath();
|
||||
|
||||
bool Validate();
|
||||
|
||||
void NotifyCurrentScreen() override;
|
||||
|
||||
protected slots:
|
||||
void HandleBrowseButton();
|
||||
void ValidateProjectPath();
|
||||
|
||||
private:
|
||||
QString GetDefaultProjectPath();
|
||||
|
||||
FormLineEditWidget* m_projectName;
|
||||
FormBrowseEditWidget* m_projectPath;
|
||||
QButtonGroup* m_projectTemplateButtonGroup;
|
||||
};
|
||||
|
||||
|
||||
@@ -22,8 +22,6 @@
|
||||
#include <QMenu>
|
||||
#include <QSpacerItem>
|
||||
|
||||
//#define SHOW_ALL_PROJECT_ACTIONS
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
inline constexpr static int s_projectImageWidth = 210;
|
||||
@@ -96,10 +94,6 @@ namespace O3DE::ProjectManager
|
||||
m_removeProjectAction = newProjectMenu->addAction(tr("Remove from O3DE"));
|
||||
m_deleteProjectAction = newProjectMenu->addAction(tr("Delete this Project"));
|
||||
|
||||
#ifdef SHOW_ALL_PROJECT_ACTIONS
|
||||
m_editProjectGemsAction = newProjectMenu->addAction(tr("Cutomize Gems..."));
|
||||
#endif
|
||||
|
||||
QFrame* footer = new QFrame(this);
|
||||
QHBoxLayout* hLayout = new QHBoxLayout();
|
||||
hLayout->setContentsMargins(0, 0, 0, 0);
|
||||
@@ -121,10 +115,6 @@ namespace O3DE::ProjectManager
|
||||
connect(m_copyProjectAction, &QAction::triggered, [this]() { emit CopyProject(m_projectInfo.m_path); });
|
||||
connect(m_removeProjectAction, &QAction::triggered, [this]() { emit RemoveProject(m_projectInfo.m_path); });
|
||||
connect(m_deleteProjectAction, &QAction::triggered, [this]() { emit DeleteProject(m_projectInfo.m_path); });
|
||||
|
||||
#ifdef SHOW_ALL_PROJECT_ACTIONS
|
||||
connect(m_editProjectGemsAction, &QAction::triggered, [this]() { emit EditProjectGems(m_projectInfo.m_path); });
|
||||
#endif
|
||||
}
|
||||
|
||||
void ProjectButton::SetButtonEnabled(bool enabled)
|
||||
|
||||
@@ -62,7 +62,6 @@ namespace O3DE::ProjectManager
|
||||
signals:
|
||||
void OpenProject(const QString& projectName);
|
||||
void EditProject(const QString& projectName);
|
||||
void EditProjectGems(const QString& projectName);
|
||||
void CopyProject(const QString& projectName);
|
||||
void RemoveProject(const QString& projectName);
|
||||
void DeleteProject(const QString& projectName);
|
||||
@@ -73,7 +72,6 @@ namespace O3DE::ProjectManager
|
||||
ProjectInfo m_projectInfo;
|
||||
LabelButton* m_projectImageLabel;
|
||||
QAction* m_editProjectAction;
|
||||
QAction* m_editProjectGemsAction;
|
||||
QAction* m_copyProjectAction;
|
||||
QAction* m_removeProjectAction;
|
||||
QAction* m_deleteProjectAction;
|
||||
|
||||
@@ -25,6 +25,19 @@ namespace O3DE::ProjectManager
|
||||
{
|
||||
}
|
||||
|
||||
bool ProjectInfo::operator==(const ProjectInfo& rhs)
|
||||
{
|
||||
return m_path == rhs.m_path
|
||||
&& m_projectName == rhs.m_projectName
|
||||
&& m_imagePath == rhs.m_imagePath
|
||||
&& m_backgroundImagePath == rhs.m_backgroundImagePath;
|
||||
}
|
||||
|
||||
bool ProjectInfo::operator!=(const ProjectInfo& rhs)
|
||||
{
|
||||
return !operator==(rhs);
|
||||
}
|
||||
|
||||
bool ProjectInfo::IsValid() const
|
||||
{
|
||||
return !m_path.isEmpty() && !m_projectName.isEmpty();
|
||||
|
||||
@@ -25,6 +25,8 @@ namespace O3DE::ProjectManager
|
||||
ProjectInfo() = default;
|
||||
ProjectInfo(const QString& path, const QString& projectName, const QString& displayName,
|
||||
const QString& imagePath, const QString& backgroundImagePath, bool isNew);
|
||||
bool operator==(const ProjectInfo& rhs);
|
||||
bool operator!=(const ProjectInfo& rhs);
|
||||
|
||||
bool IsValid() const;
|
||||
|
||||
|
||||
@@ -11,45 +11,131 @@
|
||||
*/
|
||||
|
||||
#include <ProjectSettingsScreen.h>
|
||||
#include <FormBrowseEditWidget.h>
|
||||
#include <FormLineEditWidget.h>
|
||||
#include <PathValidator.h>
|
||||
#include <PythonBindingsInterface.h>
|
||||
|
||||
#include <Source/ui_ProjectSettingsScreen.h>
|
||||
#include <QFileDialog>
|
||||
#include <QFrame>
|
||||
#include <QHBoxLayout>
|
||||
#include <QVBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QStandardPaths>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
ProjectSettingsScreen::ProjectSettingsScreen(QWidget* parent)
|
||||
: ScreenWidget(parent)
|
||||
, m_ui(new Ui::ProjectSettingsClass())
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
m_horizontalLayout = new QHBoxLayout(this);
|
||||
m_horizontalLayout->setAlignment(Qt::AlignLeft);
|
||||
m_horizontalLayout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
connect(m_ui->gemsButton, &QPushButton::pressed, this, &ProjectSettingsScreen::HandleGemsButton);
|
||||
// if we don't provide a parent for this box layout the stylesheet doesn't take
|
||||
// if we don't set this in a frame (just use a sub-layout) all the content will align incorrectly horizontally
|
||||
QFrame* projectSettingsFrame = new QFrame(this);
|
||||
projectSettingsFrame->setObjectName("projectSettings");
|
||||
m_verticalLayout = new QVBoxLayout(this);
|
||||
|
||||
// you cannot remove content margins in qss
|
||||
m_verticalLayout->setContentsMargins(0, 0, 0, 0);
|
||||
m_verticalLayout->setAlignment(Qt::AlignTop);
|
||||
|
||||
m_projectName = new FormLineEditWidget(tr("Project name"), "", this);
|
||||
connect(m_projectName->lineEdit(), &QLineEdit::textChanged, this, &ProjectSettingsScreen::ValidateProjectName);
|
||||
m_verticalLayout->addWidget(m_projectName);
|
||||
|
||||
m_projectPath = new FormBrowseEditWidget(tr("Project Location"), "", this);
|
||||
m_projectPath->lineEdit()->setReadOnly(true);
|
||||
connect(m_projectPath->lineEdit(), &QLineEdit::textChanged, this, &ProjectSettingsScreen::Validate);
|
||||
m_verticalLayout->addWidget(m_projectPath);
|
||||
|
||||
projectSettingsFrame->setLayout(m_verticalLayout);
|
||||
|
||||
m_horizontalLayout->addWidget(projectSettingsFrame);
|
||||
|
||||
setLayout(m_horizontalLayout);
|
||||
}
|
||||
|
||||
ProjectManagerScreen ProjectSettingsScreen::GetScreenEnum()
|
||||
{
|
||||
return ProjectManagerScreen::ProjectSettings;
|
||||
return ProjectManagerScreen::Invalid;
|
||||
}
|
||||
|
||||
QString ProjectSettingsScreen::GetDefaultProjectPath()
|
||||
{
|
||||
QString defaultPath = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
|
||||
AZ::Outcome<EngineInfo> engineInfoResult = PythonBindingsInterface::Get()->GetEngineInfo();
|
||||
if (engineInfoResult.IsSuccess())
|
||||
{
|
||||
QDir path(QDir::toNativeSeparators(engineInfoResult.GetValue().m_defaultProjectsFolder));
|
||||
if (path.exists())
|
||||
{
|
||||
defaultPath = path.absolutePath();
|
||||
}
|
||||
}
|
||||
return defaultPath;
|
||||
}
|
||||
|
||||
ProjectInfo ProjectSettingsScreen::GetProjectInfo()
|
||||
{
|
||||
// Impl pending next PR
|
||||
return ProjectInfo();
|
||||
ProjectInfo projectInfo;
|
||||
projectInfo.m_projectName = m_projectName->lineEdit()->text();
|
||||
projectInfo.m_path = m_projectPath->lineEdit()->text();
|
||||
return projectInfo;
|
||||
}
|
||||
|
||||
void ProjectSettingsScreen::SetProjectInfo()
|
||||
bool ProjectSettingsScreen::ValidateProjectName()
|
||||
{
|
||||
// Impl pending next PR
|
||||
bool projectNameIsValid = true;
|
||||
if (m_projectName->lineEdit()->text().isEmpty())
|
||||
{
|
||||
projectNameIsValid = false;
|
||||
m_projectName->setErrorLabelText(tr("Please provide a project name."));
|
||||
}
|
||||
else
|
||||
{
|
||||
// this validation should roughly match the utils.validate_identifier which the cli
|
||||
// uses to validate project names
|
||||
QRegExp validProjectNameRegex("[A-Za-z][A-Za-z0-9_-]{0,63}");
|
||||
const bool result = validProjectNameRegex.exactMatch(m_projectName->lineEdit()->text());
|
||||
if (!result)
|
||||
{
|
||||
projectNameIsValid = false;
|
||||
m_projectName->setErrorLabelText(
|
||||
tr("Project names must start with a letter and consist of up to 64 letter, number, '_' or '-' characters"));
|
||||
}
|
||||
}
|
||||
|
||||
m_projectName->setErrorLabelVisible(!projectNameIsValid);
|
||||
return projectNameIsValid;
|
||||
}
|
||||
bool ProjectSettingsScreen::ValidateProjectPath()
|
||||
{
|
||||
bool projectPathIsValid = true;
|
||||
if (m_projectPath->lineEdit()->text().isEmpty())
|
||||
{
|
||||
projectPathIsValid = false;
|
||||
m_projectPath->setErrorLabelText(tr("Please provide a valid location."));
|
||||
}
|
||||
else
|
||||
{
|
||||
QDir path(m_projectPath->lineEdit()->text());
|
||||
if (path.exists() && !path.isEmpty())
|
||||
{
|
||||
projectPathIsValid = false;
|
||||
m_projectPath->setErrorLabelText(tr("This folder exists and isn't empty. Please choose a different location."));
|
||||
}
|
||||
}
|
||||
|
||||
m_projectPath->setErrorLabelVisible(!projectPathIsValid);
|
||||
return projectPathIsValid;
|
||||
}
|
||||
|
||||
bool ProjectSettingsScreen::Validate()
|
||||
{
|
||||
// Impl pending next PR
|
||||
return true;
|
||||
return ValidateProjectName() && ValidateProjectPath();
|
||||
}
|
||||
|
||||
void ProjectSettingsScreen::HandleGemsButton()
|
||||
{
|
||||
emit ChangeScreenRequest(ProjectManagerScreen::GemCatalog);
|
||||
}
|
||||
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -12,17 +12,18 @@
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <ScreenWidget.h>
|
||||
#include <ProjectInfo.h>
|
||||
#include <ScreenWidget.h>
|
||||
#endif
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class ProjectSettingsClass;
|
||||
}
|
||||
QT_FORWARD_DECLARE_CLASS(QHBoxLayout)
|
||||
QT_FORWARD_DECLARE_CLASS(QVBoxLayout)
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
QT_FORWARD_DECLARE_CLASS(FormLineEditWidget)
|
||||
QT_FORWARD_DECLARE_CLASS(FormBrowseEditWidget)
|
||||
|
||||
class ProjectSettingsScreen
|
||||
: public ScreenWidget
|
||||
{
|
||||
@@ -32,15 +33,20 @@ namespace O3DE::ProjectManager
|
||||
ProjectManagerScreen GetScreenEnum() override;
|
||||
|
||||
ProjectInfo GetProjectInfo();
|
||||
void SetProjectInfo();
|
||||
|
||||
bool Validate();
|
||||
|
||||
protected slots:
|
||||
void HandleGemsButton();
|
||||
virtual bool ValidateProjectName();
|
||||
virtual bool ValidateProjectPath();
|
||||
|
||||
private:
|
||||
QScopedPointer<Ui::ProjectSettingsClass> m_ui;
|
||||
protected:
|
||||
QString GetDefaultProjectPath();
|
||||
|
||||
QHBoxLayout* m_horizontalLayout;
|
||||
QVBoxLayout* m_verticalLayout;
|
||||
FormLineEditWidget* m_projectName;
|
||||
FormBrowseEditWidget* m_projectPath;
|
||||
};
|
||||
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ProjectSettingsClass</class>
|
||||
<widget class="QWidget" name="ProjectSettingsClass">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>782</width>
|
||||
<height>579</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="projectSettingsButton">
|
||||
<property name="text">
|
||||
<string>Project Settings</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="gemsButton">
|
||||
<property name="text">
|
||||
<string>Gems</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>761</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Project Name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Project Location</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineEdit_2"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Project Image Location</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineEdit_3"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Project Background Image Location</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineEdit_4"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -182,10 +182,6 @@ namespace O3DE::ProjectManager
|
||||
connect(projectButton, &ProjectButton::CopyProject, this, &ProjectsScreen::HandleCopyProject);
|
||||
connect(projectButton, &ProjectButton::RemoveProject, this, &ProjectsScreen::HandleRemoveProject);
|
||||
connect(projectButton, &ProjectButton::DeleteProject, this, &ProjectsScreen::HandleDeleteProject);
|
||||
|
||||
#ifdef SHOW_ALL_PROJECT_ACTIONS
|
||||
connect(projectButton, &ProjectButton::EditProjectGems, this, &ProjectsScreen::HandleEditProjectGems);
|
||||
#endif
|
||||
}
|
||||
|
||||
layout->addWidget(projectsScrollArea);
|
||||
@@ -293,14 +289,8 @@ namespace O3DE::ProjectManager
|
||||
void ProjectsScreen::HandleEditProject(const QString& projectPath)
|
||||
{
|
||||
emit NotifyCurrentProject(projectPath);
|
||||
emit ResetScreenRequest(ProjectManagerScreen::UpdateProject);
|
||||
emit ChangeScreenRequest(ProjectManagerScreen::UpdateProject);
|
||||
}
|
||||
void ProjectsScreen::HandleEditProjectGems(const QString& projectPath)
|
||||
{
|
||||
emit NotifyCurrentProject(projectPath);
|
||||
emit ChangeScreenRequest(ProjectManagerScreen::GemCatalog);
|
||||
}
|
||||
void ProjectsScreen::HandleCopyProject(const QString& projectPath)
|
||||
{
|
||||
// Open file dialog and choose location for copied project then register copy with O3DE
|
||||
|
||||
@@ -41,7 +41,6 @@ namespace O3DE::ProjectManager
|
||||
void HandleAddProjectButton();
|
||||
void HandleOpenProject(const QString& projectPath);
|
||||
void HandleEditProject(const QString& projectPath);
|
||||
void HandleEditProjectGems(const QString& projectPath);
|
||||
void HandleCopyProject(const QString& projectPath);
|
||||
void HandleRemoveProject(const QString& projectPath);
|
||||
void HandleDeleteProject(const QString& projectPath);
|
||||
|
||||
@@ -283,6 +283,7 @@ namespace O3DE::ProjectManager
|
||||
AZ_Warning("ProjectManagerWindow", result != -1, "Append to sys path failed");
|
||||
|
||||
// import required modules
|
||||
m_cmake = pybind11::module::import("o3de.cmake");
|
||||
m_register = pybind11::module::import("o3de.register");
|
||||
m_manifest = pybind11::module::import("o3de.manifest");
|
||||
m_engineTemplate = pybind11::module::import("o3de.engine_template");
|
||||
@@ -344,7 +345,7 @@ namespace O3DE::ProjectManager
|
||||
return finalResult;
|
||||
}
|
||||
|
||||
bool PythonBindings::ExecuteWithLock(AZStd::function<void()> executionCallback)
|
||||
AZ::Outcome<void, AZStd::string> PythonBindings::ExecuteWithLockErrorHandling(AZStd::function<void()> executionCallback)
|
||||
{
|
||||
AZStd::lock_guard<decltype(m_lock)> lock(m_lock);
|
||||
pybind11::gil_scoped_release release;
|
||||
@@ -353,13 +354,19 @@ namespace O3DE::ProjectManager
|
||||
try
|
||||
{
|
||||
executionCallback();
|
||||
return true;
|
||||
}
|
||||
catch ([[maybe_unused]] const std::exception& e)
|
||||
{
|
||||
AZ_Warning("PythonBindings", false, "Python exception %s", e.what());
|
||||
return false;
|
||||
return AZ::Failure<AZStd::string>(e.what());
|
||||
}
|
||||
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
bool PythonBindings::ExecuteWithLock(AZStd::function<void()> executionCallback)
|
||||
{
|
||||
return ExecuteWithLockErrorHandling(executionCallback).IsSuccess();
|
||||
}
|
||||
|
||||
AZ::Outcome<EngineInfo> PythonBindings::GetEngineInfo()
|
||||
@@ -452,7 +459,7 @@ namespace O3DE::ProjectManager
|
||||
return result;
|
||||
}
|
||||
|
||||
AZ::Outcome<GemInfo> PythonBindings::GetGem(const QString& path)
|
||||
AZ::Outcome<GemInfo> PythonBindings::GetGemInfo(const QString& path)
|
||||
{
|
||||
GemInfo gemInfo = GemInfoFromPath(pybind11::str(path.toStdString()));
|
||||
if (gemInfo.IsValid())
|
||||
@@ -465,32 +472,79 @@ namespace O3DE::ProjectManager
|
||||
}
|
||||
}
|
||||
|
||||
AZ::Outcome<QVector<GemInfo>> PythonBindings::GetGems()
|
||||
AZ::Outcome<QVector<GemInfo>, AZStd::string> PythonBindings::GetEngineGemInfos()
|
||||
{
|
||||
QVector<GemInfo> gems;
|
||||
|
||||
bool result = ExecuteWithLock([&] {
|
||||
// external gems
|
||||
for (auto path : m_manifest.attr("get_gems")())
|
||||
auto result = ExecuteWithLockErrorHandling([&]
|
||||
{
|
||||
gems.push_back(GemInfoFromPath(path));
|
||||
}
|
||||
for (auto path : m_manifest.attr("get_engine_gems")())
|
||||
{
|
||||
gems.push_back(GemInfoFromPath(path));
|
||||
}
|
||||
});
|
||||
if (!result.IsSuccess())
|
||||
{
|
||||
return AZ::Failure<AZStd::string>(result.GetError().c_str());
|
||||
}
|
||||
|
||||
// gems from the engine
|
||||
for (auto path : m_manifest.attr("get_engine_gems")())
|
||||
std::sort(gems.begin(), gems.end());
|
||||
return AZ::Success(AZStd::move(gems));
|
||||
}
|
||||
|
||||
AZ::Outcome<QVector<GemInfo>, AZStd::string> PythonBindings::GetAllGemInfos(const QString& projectPath)
|
||||
{
|
||||
QVector<GemInfo> gems;
|
||||
|
||||
auto result = ExecuteWithLockErrorHandling([&]
|
||||
{
|
||||
gems.push_back(GemInfoFromPath(path));
|
||||
}
|
||||
});
|
||||
pybind11::str pyProjectPath = projectPath.toStdString();
|
||||
for (auto path : m_manifest.attr("get_all_gems")(pyProjectPath))
|
||||
{
|
||||
gems.push_back(GemInfoFromPath(path));
|
||||
}
|
||||
});
|
||||
if (!result.IsSuccess())
|
||||
{
|
||||
return AZ::Failure<AZStd::string>(result.GetError().c_str());
|
||||
}
|
||||
|
||||
if (!result)
|
||||
std::sort(gems.begin(), gems.end());
|
||||
return AZ::Success(AZStd::move(gems));
|
||||
}
|
||||
|
||||
AZ::Outcome<QVector<AZStd::string>, AZStd::string> PythonBindings::GetEnabledGemNames(const QString& projectPath)
|
||||
{
|
||||
// Retrieve the path to the cmake file that lists the enabled gems.
|
||||
pybind11::str enabledGemsFilename;
|
||||
auto result = ExecuteWithLockErrorHandling([&]
|
||||
{
|
||||
const pybind11::str pyProjectPath = projectPath.toStdString();
|
||||
enabledGemsFilename = m_cmake.attr("get_enabled_gem_cmake_file")(
|
||||
pybind11::none(), // project_name
|
||||
pyProjectPath); // project_path
|
||||
});
|
||||
if (!result.IsSuccess())
|
||||
{
|
||||
return AZ::Failure();
|
||||
return AZ::Failure<AZStd::string>(result.GetError().c_str());
|
||||
}
|
||||
else
|
||||
|
||||
// Retrieve the actual list of names from the cmake file.
|
||||
QVector<AZStd::string> gemNames;
|
||||
result = ExecuteWithLockErrorHandling([&]
|
||||
{
|
||||
const auto pyGemNames = m_cmake.attr("get_enabled_gems")(enabledGemsFilename);
|
||||
for (auto gemName : pyGemNames)
|
||||
{
|
||||
gemNames.push_back(Py_To_String(gemName));
|
||||
}
|
||||
});
|
||||
if (!result.IsSuccess())
|
||||
{
|
||||
return AZ::Success(AZStd::move(gems));
|
||||
return AZ::Failure<AZStd::string>(result.GetError().c_str());
|
||||
}
|
||||
|
||||
return AZ::Success(AZStd::move(gemNames));
|
||||
}
|
||||
|
||||
bool PythonBindings::AddProject(const QString& path)
|
||||
@@ -670,38 +724,36 @@ namespace O3DE::ProjectManager
|
||||
}
|
||||
}
|
||||
|
||||
bool PythonBindings::AddGemToProject(const QString& gemPath, const QString& projectPath)
|
||||
AZ::Outcome<void, AZStd::string> PythonBindings::AddGemToProject(const QString& gemPath, const QString& projectPath)
|
||||
{
|
||||
bool result = ExecuteWithLock([&] {
|
||||
pybind11::str pyGemPath = gemPath.toStdString();
|
||||
pybind11::str pyProjectPath = projectPath.toStdString();
|
||||
return ExecuteWithLockErrorHandling([&]
|
||||
{
|
||||
pybind11::str pyGemPath = gemPath.toStdString();
|
||||
pybind11::str pyProjectPath = projectPath.toStdString();
|
||||
|
||||
m_enableGemProject.attr("enable_gem_in_project")(
|
||||
pybind11::none(), // gem_name
|
||||
pyGemPath,
|
||||
pybind11::none(), // project_name
|
||||
pyProjectPath
|
||||
);
|
||||
});
|
||||
|
||||
return result;
|
||||
m_enableGemProject.attr("enable_gem_in_project")(
|
||||
pybind11::none(), // gem name not needed as path is provided
|
||||
pyGemPath,
|
||||
pybind11::none(), // project name not needed as path is provided
|
||||
pyProjectPath
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
bool PythonBindings::RemoveGemFromProject(const QString& gemPath, const QString& projectPath)
|
||||
AZ::Outcome<void, AZStd::string> PythonBindings::RemoveGemFromProject(const QString& gemPath, const QString& projectPath)
|
||||
{
|
||||
bool result = ExecuteWithLock([&] {
|
||||
pybind11::str pyGemPath = gemPath.toStdString();
|
||||
pybind11::str pyProjectPath = projectPath.toStdString();
|
||||
return ExecuteWithLockErrorHandling([&]
|
||||
{
|
||||
pybind11::str pyGemPath = gemPath.toStdString();
|
||||
pybind11::str pyProjectPath = projectPath.toStdString();
|
||||
|
||||
m_disableGemProject.attr("disable_gem_in_project")(
|
||||
pybind11::none(), // gem_name
|
||||
pyGemPath,
|
||||
pybind11::none(), // project_name
|
||||
pyProjectPath
|
||||
);
|
||||
});
|
||||
|
||||
return result;
|
||||
m_disableGemProject.attr("disable_gem_in_project")(
|
||||
pybind11::none(), // gem name not needed as path is provided
|
||||
pyGemPath,
|
||||
pybind11::none(), // project name not needed as path is provided
|
||||
pyProjectPath
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
bool PythonBindings::UpdateProject([[maybe_unused]] const ProjectInfo& projectInfo)
|
||||
|
||||
@@ -39,8 +39,10 @@ namespace O3DE::ProjectManager
|
||||
bool SetEngineInfo(const EngineInfo& engineInfo) override;
|
||||
|
||||
// Gem
|
||||
AZ::Outcome<GemInfo> GetGem(const QString& path) override;
|
||||
AZ::Outcome<QVector<GemInfo>> GetGems() override;
|
||||
AZ::Outcome<GemInfo> GetGemInfo(const QString& path) override;
|
||||
AZ::Outcome<QVector<GemInfo>, AZStd::string> GetEngineGemInfos() override;
|
||||
AZ::Outcome<QVector<GemInfo>, AZStd::string> GetAllGemInfos(const QString& projectPath) override;
|
||||
AZ::Outcome<QVector<AZStd::string>, AZStd::string> GetEnabledGemNames(const QString& projectPath) override;
|
||||
|
||||
// Project
|
||||
AZ::Outcome<ProjectInfo> CreateProject(const QString& projectTemplatePath, const ProjectInfo& projectInfo) override;
|
||||
@@ -49,8 +51,8 @@ namespace O3DE::ProjectManager
|
||||
bool AddProject(const QString& path) override;
|
||||
bool RemoveProject(const QString& path) override;
|
||||
bool UpdateProject(const ProjectInfo& projectInfo) override;
|
||||
bool AddGemToProject(const QString& gemPath, const QString& projectPath) override;
|
||||
bool RemoveGemFromProject(const QString& gemPath, const QString& projectPath) override;
|
||||
AZ::Outcome<void, AZStd::string> AddGemToProject(const QString& gemPath, const QString& projectPath) override;
|
||||
AZ::Outcome<void, AZStd::string> RemoveGemFromProject(const QString& gemPath, const QString& projectPath) override;
|
||||
|
||||
// ProjectTemplate
|
||||
AZ::Outcome<QVector<ProjectTemplateInfo>> GetProjectTemplates() override;
|
||||
@@ -58,6 +60,7 @@ namespace O3DE::ProjectManager
|
||||
private:
|
||||
AZ_DISABLE_COPY_MOVE(PythonBindings);
|
||||
|
||||
AZ::Outcome<void, AZStd::string> ExecuteWithLockErrorHandling(AZStd::function<void()> executionCallback);
|
||||
bool ExecuteWithLock(AZStd::function<void()> executionCallback);
|
||||
GemInfo GemInfoFromPath(pybind11::handle path);
|
||||
ProjectInfo ProjectInfoFromPath(pybind11::handle path);
|
||||
@@ -70,6 +73,7 @@ namespace O3DE::ProjectManager
|
||||
AZ::IO::FixedMaxPath m_enginePath;
|
||||
pybind11::handle m_engineTemplate;
|
||||
AZStd::recursive_mutex m_lock;
|
||||
pybind11::handle m_cmake;
|
||||
pybind11::handle m_register;
|
||||
pybind11::handle m_manifest;
|
||||
pybind11::handle m_enableGemProject;
|
||||
|
||||
@@ -57,13 +57,27 @@ namespace O3DE::ProjectManager
|
||||
* @param path the absolute path to the Gem
|
||||
* @return an outcome with GemInfo on success
|
||||
*/
|
||||
virtual AZ::Outcome<GemInfo> GetGem(const QString& path) = 0;
|
||||
virtual AZ::Outcome<GemInfo> GetGemInfo(const QString& path) = 0;
|
||||
|
||||
/**
|
||||
* Get info about all known Gems
|
||||
* @return an outcome with GemInfos on success
|
||||
* Get all available gem infos. This concatenates gems registered by the engine and the project.
|
||||
* @param path The absolute path to the project.
|
||||
* @return A list of gem infos.
|
||||
*/
|
||||
virtual AZ::Outcome<QVector<GemInfo>> GetGems() = 0;
|
||||
virtual AZ::Outcome<QVector<GemInfo>, AZStd::string> GetAllGemInfos(const QString& projectPath) = 0;
|
||||
|
||||
/**
|
||||
* Get engine gem infos.
|
||||
* @return A list of all registered gem infos.
|
||||
*/
|
||||
virtual AZ::Outcome<QVector<GemInfo>, AZStd::string> GetEngineGemInfos() = 0;
|
||||
|
||||
/**
|
||||
* Get a list of all enabled gem names for a given project.
|
||||
* @param[in] projectPath Absolute file path to the project.
|
||||
* @return A list of gem names of all the enabled gems for a given project or a error message on failure.
|
||||
*/
|
||||
virtual AZ::Outcome<QVector<AZStd::string>, AZStd::string> GetEnabledGemNames(const QString& projectPath) = 0;
|
||||
|
||||
|
||||
// Projects
|
||||
@@ -114,17 +128,17 @@ namespace O3DE::ProjectManager
|
||||
* Add a gem to a project
|
||||
* @param gemPath the absolute path to the gem
|
||||
* @param projectPath the absolute path to the project
|
||||
* @return true on success, false on failure
|
||||
* @return An outcome with the success flag as well as an error message in case of a failure.
|
||||
*/
|
||||
virtual bool AddGemToProject(const QString& gemPath, const QString& projectPath) = 0;
|
||||
virtual AZ::Outcome<void, AZStd::string> AddGemToProject(const QString& gemPath, const QString& projectPath) = 0;
|
||||
|
||||
/**
|
||||
* Remove gem to a project
|
||||
* @param gemPath the absolute path to the gem
|
||||
* @param projectPath the absolute path to the project
|
||||
* @return true on success, false on failure
|
||||
* @return An outcome with the success flag as well as an error message in case of a failure.
|
||||
*/
|
||||
virtual bool RemoveGemFromProject(const QString& gemPath, const QString& projectPath) = 0;
|
||||
virtual AZ::Outcome<void, AZStd::string> RemoveGemFromProject(const QString& gemPath, const QString& projectPath) = 0;
|
||||
|
||||
|
||||
// Project Templates
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace O3DE::ProjectManager
|
||||
GemCatalog,
|
||||
Projects,
|
||||
UpdateProject,
|
||||
ProjectSettings,
|
||||
UpdateProjectSettings,
|
||||
EngineSettings
|
||||
};
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace O3DE::ProjectManager
|
||||
{ "GemCatalog", ProjectManagerScreen::GemCatalog},
|
||||
{ "Projects", ProjectManagerScreen::Projects},
|
||||
{ "UpdateProject", ProjectManagerScreen::UpdateProject},
|
||||
{ "ProjectSettings", ProjectManagerScreen::ProjectSettings},
|
||||
{ "UpdateProjectSettings", ProjectManagerScreen::UpdateProjectSettings},
|
||||
{ "EngineSettings", ProjectManagerScreen::EngineSettings}
|
||||
};
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#include <NewProjectSettingsScreen.h>
|
||||
#include <GemCatalog/GemCatalogScreen.h>
|
||||
#include <ProjectsScreen.h>
|
||||
#include <ProjectSettingsScreen.h>
|
||||
#include <UpdateProjectSettingsScreen.h>
|
||||
#include <EngineSettingsScreen.h>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
@@ -42,8 +42,8 @@ namespace O3DE::ProjectManager
|
||||
case (ProjectManagerScreen::UpdateProject):
|
||||
newScreen = new UpdateProjectCtrl(parent);
|
||||
break;
|
||||
case (ProjectManagerScreen::ProjectSettings):
|
||||
newScreen = new ProjectSettingsScreen(parent);
|
||||
case (ProjectManagerScreen::UpdateProjectSettings):
|
||||
newScreen = new UpdateProjectSettingsScreen(parent);
|
||||
break;
|
||||
case (ProjectManagerScreen::EngineSettings):
|
||||
newScreen = new EngineSettingsScreen(parent);
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <ScreensCtrl.h>
|
||||
#include <ScreenFactory.h>
|
||||
#include <ScreenWidget.h>
|
||||
#include <UpdateProjectCtrl.h>
|
||||
|
||||
#include <QTabWidget>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
@@ -10,15 +10,20 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <UpdateProjectCtrl.h>
|
||||
#include <ScreensCtrl.h>
|
||||
#include <GemCatalog/GemCatalogScreen.h>
|
||||
#include <PythonBindingsInterface.h>
|
||||
#include <ProjectSettingsScreen.h>
|
||||
#include <ScreenHeaderWidget.h>
|
||||
#include <ScreensCtrl.h>
|
||||
#include <UpdateProjectCtrl.h>
|
||||
#include <UpdateProjectSettingsScreen.h>
|
||||
#include <ProjectUtils.h>
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QVBoxLayout>
|
||||
#include <QPushButton>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <QStackedWidget>
|
||||
#include <QTabWidget>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
@@ -26,31 +31,57 @@ namespace O3DE::ProjectManager
|
||||
: ScreenWidget(parent)
|
||||
{
|
||||
QVBoxLayout* vLayout = new QVBoxLayout();
|
||||
setLayout(vLayout);
|
||||
vLayout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
m_screensCtrl = new ScreensCtrl();
|
||||
vLayout->addWidget(m_screensCtrl);
|
||||
m_header = new ScreenHeader(this);
|
||||
m_header->setTitle(tr(""));
|
||||
m_header->setSubTitle(tr("Edit Project Settings:"));
|
||||
connect(m_header->backButton(), &QPushButton::clicked, this, &UpdateProjectCtrl::HandleBackButton);
|
||||
vLayout->addWidget(m_header);
|
||||
|
||||
m_updateSettingsScreen = new UpdateProjectSettingsScreen();
|
||||
m_gemCatalogScreen = new GemCatalogScreen();
|
||||
|
||||
m_stack = new QStackedWidget(this);
|
||||
m_stack->setObjectName("body");
|
||||
m_stack->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding));
|
||||
vLayout->addWidget(m_stack);
|
||||
|
||||
QFrame* topBarFrameWidget = new QFrame(this);
|
||||
topBarFrameWidget->setObjectName("projectSettingsTopFrame");
|
||||
QHBoxLayout* topBarHLayout = new QHBoxLayout();
|
||||
topBarHLayout->setContentsMargins(0, 0, 0, 0);
|
||||
topBarFrameWidget->setLayout(topBarHLayout);
|
||||
|
||||
QTabWidget* tabWidget = new QTabWidget();
|
||||
tabWidget->setObjectName("projectSettingsTab");
|
||||
tabWidget->tabBar()->setObjectName("projectSettingsTabBar");
|
||||
tabWidget->addTab(m_updateSettingsScreen, tr("General"));
|
||||
|
||||
QPushButton* gemsButton = new QPushButton(tr("Add More Gems"), this);
|
||||
topBarHLayout->addWidget(gemsButton);
|
||||
tabWidget->setCornerWidget(gemsButton);
|
||||
|
||||
topBarHLayout->addWidget(tabWidget);
|
||||
|
||||
m_stack->addWidget(topBarFrameWidget);
|
||||
m_stack->addWidget(m_gemCatalogScreen);
|
||||
|
||||
QDialogButtonBox* backNextButtons = new QDialogButtonBox();
|
||||
backNextButtons->setObjectName("footer");
|
||||
vLayout->addWidget(backNextButtons);
|
||||
|
||||
m_backButton = backNextButtons->addButton(tr("Back"), QDialogButtonBox::RejectRole);
|
||||
m_backButton->setProperty("secondary", true);
|
||||
m_nextButton = backNextButtons->addButton(tr("Next"), QDialogButtonBox::ApplyRole);
|
||||
|
||||
connect(m_backButton, &QPushButton::pressed, this, &UpdateProjectCtrl::HandleBackButton);
|
||||
connect(m_nextButton, &QPushButton::pressed, this, &UpdateProjectCtrl::HandleNextButton);
|
||||
connect(gemsButton, &QPushButton::clicked, this, &UpdateProjectCtrl::HandleGemsButton);
|
||||
connect(m_backButton, &QPushButton::clicked, this, &UpdateProjectCtrl::HandleBackButton);
|
||||
connect(m_nextButton, &QPushButton::clicked, this, &UpdateProjectCtrl::HandleNextButton);
|
||||
connect(reinterpret_cast<ScreensCtrl*>(parent), &ScreensCtrl::NotifyCurrentProject, this, &UpdateProjectCtrl::UpdateCurrentProject);
|
||||
|
||||
m_screensOrder =
|
||||
{
|
||||
ProjectManagerScreen::ProjectSettings,
|
||||
ProjectManagerScreen::GemCatalog
|
||||
};
|
||||
m_screensCtrl->BuildScreens(m_screensOrder);
|
||||
m_screensCtrl->ForceChangeToScreen(ProjectManagerScreen::ProjectSettings, false);
|
||||
|
||||
UpdateNextButtonText();
|
||||
|
||||
Update();
|
||||
setLayout(vLayout);
|
||||
}
|
||||
|
||||
ProjectManagerScreen UpdateProjectCtrl::GetScreenEnum()
|
||||
@@ -58,63 +89,80 @@ namespace O3DE::ProjectManager
|
||||
return ProjectManagerScreen::UpdateProject;
|
||||
}
|
||||
|
||||
void UpdateProjectCtrl::NotifyCurrentScreen()
|
||||
{
|
||||
m_stack->setCurrentIndex(ScreenOrder::Settings);
|
||||
Update();
|
||||
}
|
||||
|
||||
void UpdateProjectCtrl::HandleGemsButton()
|
||||
{
|
||||
// The next page is the gem catalog. Gather the available gems that will be shown in the gem catalog.
|
||||
m_gemCatalogScreen->ReinitForProject(m_projectInfo.m_path, /*isNewProject=*/false);
|
||||
|
||||
m_stack->setCurrentWidget(m_gemCatalogScreen);
|
||||
Update();
|
||||
}
|
||||
|
||||
void UpdateProjectCtrl::HandleBackButton()
|
||||
{
|
||||
if (!m_screensCtrl->GotoPreviousScreen())
|
||||
if (m_stack->currentIndex() > 0)
|
||||
{
|
||||
emit GotoPreviousScreenRequest();
|
||||
m_stack->setCurrentIndex(m_stack->currentIndex() - 1);
|
||||
Update();
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateNextButtonText();
|
||||
emit GotoPreviousScreenRequest();
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateProjectCtrl::HandleNextButton()
|
||||
{
|
||||
ScreenWidget* currentScreen = m_screensCtrl->GetCurrentScreen();
|
||||
ProjectManagerScreen screenEnum = currentScreen->GetScreenEnum();
|
||||
auto screenOrderIter = m_screensOrder.begin();
|
||||
for (; screenOrderIter != m_screensOrder.end(); ++screenOrderIter)
|
||||
if (m_stack->currentIndex() == ScreenOrder::Settings)
|
||||
{
|
||||
if (*screenOrderIter == screenEnum)
|
||||
if (m_updateSettingsScreen)
|
||||
{
|
||||
++screenOrderIter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (screenEnum == ProjectManagerScreen::ProjectSettings)
|
||||
{
|
||||
auto projectScreen = reinterpret_cast<ProjectSettingsScreen*>(currentScreen);
|
||||
if (projectScreen)
|
||||
{
|
||||
if (!projectScreen->Validate())
|
||||
if (!m_updateSettingsScreen->Validate())
|
||||
{
|
||||
QMessageBox::critical(this, tr("Invalid project settings"), tr("Invalid project settings"));
|
||||
return;
|
||||
}
|
||||
|
||||
m_projectInfo = projectScreen->GetProjectInfo();
|
||||
ProjectInfo newProjectSettings = m_updateSettingsScreen->GetProjectInfo();
|
||||
|
||||
// Update project if settings changed
|
||||
if (m_projectInfo != newProjectSettings)
|
||||
{
|
||||
bool result = PythonBindingsInterface::Get()->UpdateProject(newProjectSettings);
|
||||
if (!result)
|
||||
{
|
||||
QMessageBox::critical(this, tr("Project update failed"), tr("Failed to update project."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if project path has changed and move it
|
||||
if (newProjectSettings.m_path != m_projectInfo.m_path)
|
||||
{
|
||||
if (!ProjectUtils::MoveProject(m_projectInfo.m_path, newProjectSettings.m_path))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Project move failed"), tr("Failed to move project."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_projectInfo = newProjectSettings;
|
||||
}
|
||||
}
|
||||
|
||||
if (screenOrderIter != m_screensOrder.end())
|
||||
if (m_stack->currentIndex() == ScreenOrder::Gems && m_gemCatalogScreen)
|
||||
{
|
||||
m_screensCtrl->ChangeToScreen(*screenOrderIter);
|
||||
UpdateNextButtonText();
|
||||
}
|
||||
else
|
||||
{
|
||||
auto result = PythonBindingsInterface::Get()->UpdateProject(m_projectInfo);
|
||||
if (result)
|
||||
{
|
||||
emit ChangeScreenRequest(ProjectManagerScreen::Projects);
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(this, tr("Project update failed"), tr("Failed to update project."));
|
||||
}
|
||||
// Enable or disable the gems that got adjusted in the gem catalog and apply them to the given project.
|
||||
m_gemCatalogScreen->EnableDisableGemsForProject(m_projectInfo.m_path);
|
||||
}
|
||||
|
||||
emit ChangeScreenRequest(ProjectManagerScreen::Projects);
|
||||
}
|
||||
|
||||
void UpdateProjectCtrl::UpdateCurrentProject(const QString& projectPath)
|
||||
@@ -124,16 +172,28 @@ namespace O3DE::ProjectManager
|
||||
{
|
||||
m_projectInfo = projectResult.GetValue();
|
||||
}
|
||||
|
||||
Update();
|
||||
UpdateSettingsScreen();
|
||||
}
|
||||
|
||||
void UpdateProjectCtrl::UpdateNextButtonText()
|
||||
void UpdateProjectCtrl::Update()
|
||||
{
|
||||
QString nextButtonText = tr("Continue");
|
||||
if (m_screensCtrl->GetCurrentScreen()->GetScreenEnum() == ProjectManagerScreen::GemCatalog)
|
||||
if (m_stack->currentIndex() == ScreenOrder::Gems)
|
||||
{
|
||||
nextButtonText = tr("Update Project");
|
||||
m_header->setSubTitle(QString(tr("Add More Gems to \"%1\"")).arg(m_projectInfo.m_projectName));
|
||||
m_nextButton->setText(tr("Confirm"));
|
||||
}
|
||||
m_nextButton->setText(nextButtonText);
|
||||
else
|
||||
{
|
||||
m_header->setSubTitle(QString(tr("Edit Project Settings: \"%1\"")).arg(m_projectInfo.m_projectName));
|
||||
m_nextButton->setText(tr("Save"));
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateProjectCtrl::UpdateSettingsScreen()
|
||||
{
|
||||
m_updateSettingsScreen->SetProjectInfo(m_projectInfo);
|
||||
}
|
||||
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -12,40 +12,57 @@
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include "ProjectInfo.h"
|
||||
#include <ProjectInfo.h>
|
||||
#include <ScreenWidget.h>
|
||||
#include <ScreensCtrl.h>
|
||||
#include <QPushButton>
|
||||
#endif
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QStackedWidget)
|
||||
QT_FORWARD_DECLARE_CLASS(QTabWidget)
|
||||
QT_FORWARD_DECLARE_CLASS(QPushButton)
|
||||
QT_FORWARD_DECLARE_CLASS(QFrame)
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
class UpdateProjectCtrl
|
||||
: public ScreenWidget
|
||||
QT_FORWARD_DECLARE_CLASS(ScreenHeader)
|
||||
QT_FORWARD_DECLARE_CLASS(UpdateProjectSettingsScreen)
|
||||
QT_FORWARD_DECLARE_CLASS(GemCatalogScreen)
|
||||
|
||||
class UpdateProjectCtrl : public ScreenWidget
|
||||
{
|
||||
public:
|
||||
explicit UpdateProjectCtrl(QWidget* parent = nullptr);
|
||||
~UpdateProjectCtrl() = default;
|
||||
ProjectManagerScreen GetScreenEnum() override;
|
||||
|
||||
protected:
|
||||
void NotifyCurrentScreen() override;
|
||||
|
||||
protected slots:
|
||||
void HandleBackButton();
|
||||
void HandleNextButton();
|
||||
void HandleGemsButton();
|
||||
void UpdateCurrentProject(const QString& projectPath);
|
||||
|
||||
private:
|
||||
void UpdateNextButtonText();
|
||||
void Update();
|
||||
void UpdateSettingsScreen();
|
||||
|
||||
ScreensCtrl* m_screensCtrl;
|
||||
QPushButton* m_backButton;
|
||||
QPushButton* m_nextButton;
|
||||
enum ScreenOrder
|
||||
{
|
||||
Settings,
|
||||
Gems
|
||||
};
|
||||
|
||||
ScreenHeader* m_header = nullptr;
|
||||
QStackedWidget* m_stack = nullptr;
|
||||
UpdateProjectSettingsScreen* m_updateSettingsScreen = nullptr;
|
||||
GemCatalogScreen* m_gemCatalogScreen = nullptr;
|
||||
|
||||
QPushButton* m_backButton = nullptr;
|
||||
QPushButton* m_nextButton = nullptr;
|
||||
QVector<ProjectManagerScreen> m_screensOrder;
|
||||
|
||||
ProjectInfo m_projectInfo;
|
||||
|
||||
ProjectManagerScreen m_screenEnum;
|
||||
};
|
||||
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <UpdateProjectSettingsScreen.h>
|
||||
#include <FormBrowseEditWidget.h>
|
||||
#include <FormLineEditWidget.h>
|
||||
|
||||
#include <QLineEdit>
|
||||
#include <QDir>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
UpdateProjectSettingsScreen::UpdateProjectSettingsScreen(QWidget* parent)
|
||||
: ProjectSettingsScreen(parent)
|
||||
{
|
||||
}
|
||||
|
||||
ProjectManagerScreen UpdateProjectSettingsScreen::GetScreenEnum()
|
||||
{
|
||||
return ProjectManagerScreen::UpdateProjectSettings;
|
||||
}
|
||||
|
||||
void UpdateProjectSettingsScreen::SetProjectInfo(const ProjectInfo& projectInfo)
|
||||
{
|
||||
m_projectName->lineEdit()->setText(projectInfo.m_projectName);
|
||||
m_projectPath->lineEdit()->setText(projectInfo.m_path);
|
||||
}
|
||||
|
||||
bool UpdateProjectSettingsScreen::ValidateProjectPath()
|
||||
{
|
||||
bool projectPathIsValid = true;
|
||||
if (m_projectPath->lineEdit()->text().isEmpty())
|
||||
{
|
||||
projectPathIsValid = false;
|
||||
m_projectPath->setErrorLabelText(tr("Please provide a valid location."));
|
||||
}
|
||||
|
||||
m_projectPath->setErrorLabelVisible(!projectPathIsValid);
|
||||
return projectPathIsValid;
|
||||
}
|
||||
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <ProjectSettingsScreen.h>
|
||||
#endif
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
class UpdateProjectSettingsScreen
|
||||
: public ProjectSettingsScreen
|
||||
{
|
||||
public:
|
||||
explicit UpdateProjectSettingsScreen(QWidget* parent = nullptr);
|
||||
~UpdateProjectSettingsScreen() = default;
|
||||
ProjectManagerScreen GetScreenEnum() override;
|
||||
|
||||
void SetProjectInfo(const ProjectInfo& projectInfo);
|
||||
|
||||
protected:
|
||||
bool ValidateProjectPath() override;
|
||||
};
|
||||
|
||||
} // namespace O3DE::ProjectManager
|
||||
Reference in New Issue
Block a user