-#include
-
-namespace O3DE::ProjectManager
-{
- FirstTimeUseScreen::FirstTimeUseScreen(QWidget* parent)
- : ScreenWidget(parent)
- {
- QVBoxLayout* vLayout = new QVBoxLayout();
- setLayout(vLayout);
- vLayout->setContentsMargins(s_contentMargins, s_contentMargins, s_contentMargins, s_contentMargins);
-
- QLabel* titleLabel = new QLabel(this);
- titleLabel->setText(tr("Ready. Set. Create!"));
- titleLabel->setStyleSheet("font-size: 60px");
- vLayout->addWidget(titleLabel);
-
- QLabel* introLabel = new QLabel(this);
- introLabel->setTextFormat(Qt::AutoText);
- introLabel->setText(tr("Welcome to O3DE! Start something new by creating a project. Not sure what to create?
Explore what\342\200\231s available by downloading our sample project.
"));
- introLabel->setStyleSheet("font-size: 14px");
- vLayout->addWidget(introLabel);
-
- QHBoxLayout* buttonLayout = new QHBoxLayout();
- buttonLayout->setSpacing(s_buttonSpacing);
-
- m_createProjectButton = CreateLargeBoxButton(QIcon(":/Add.svg"), tr("Create Project"), this);
- m_createProjectButton->setIconSize(QSize(s_iconSize, s_iconSize));
- buttonLayout->addWidget(m_createProjectButton);
-
- m_addProjectButton = CreateLargeBoxButton(QIcon(":/Select_Folder.svg"), tr("Add a Project"), this);
- m_addProjectButton->setIconSize(QSize(s_iconSize, s_iconSize));
- buttonLayout->addWidget(m_addProjectButton);
-
- QSpacerItem* buttonSpacer = new QSpacerItem(s_spacerSize, s_spacerSize, QSizePolicy::Expanding, QSizePolicy::Minimum);
- buttonLayout->addItem(buttonSpacer);
-
- vLayout->addItem(buttonLayout);
-
- QSpacerItem* verticalSpacer = new QSpacerItem(s_spacerSize, s_spacerSize, QSizePolicy::Minimum, QSizePolicy::Expanding);
- vLayout->addItem(verticalSpacer);
-
- // Using border-image allows for scaling options background-image does not support
- setStyleSheet("O3DE--ProjectManager--ScreenWidget { border-image: url(:/Backgrounds/FirstTimeBackgroundImage.jpg) repeat repeat; }");
-
- connect(m_createProjectButton, &QPushButton::pressed, this, &FirstTimeUseScreen::HandleNewProjectButton);
- connect(m_addProjectButton, &QPushButton::pressed, this, &FirstTimeUseScreen::HandleAddProjectButton);
- }
-
- ProjectManagerScreen FirstTimeUseScreen::GetScreenEnum()
- {
- return ProjectManagerScreen::FirstTimeUse;
- }
-
- void FirstTimeUseScreen::HandleNewProjectButton()
- {
- emit ResetScreenRequest(ProjectManagerScreen::CreateProject);
- emit ChangeScreenRequest(ProjectManagerScreen::CreateProject);
- }
- void FirstTimeUseScreen::HandleAddProjectButton()
- {
- emit ChangeScreenRequest(ProjectManagerScreen::ProjectsHome);
- }
-
- QPushButton* FirstTimeUseScreen::CreateLargeBoxButton(const QIcon& icon, const QString& text, QWidget* parent)
- {
- QPushButton* largeBoxButton = new QPushButton(icon, text, parent);
-
- largeBoxButton->setFixedSize(s_boxButtonWidth, s_boxButtonHeight);
- largeBoxButton->setFlat(true);
- largeBoxButton->setFocusPolicy(Qt::FocusPolicy::NoFocus);
- largeBoxButton->setStyleSheet("QPushButton { font-size: 14px; background-color: rgba(0, 0, 0, 191); }");
-
- return largeBoxButton;
- }
-
-} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/FirstTimeUseScreen.h b/Code/Tools/ProjectManager/Source/FirstTimeUseScreen.h
deleted file mode 100644
index 80a2310d7a..0000000000
--- a/Code/Tools/ProjectManager/Source/FirstTimeUseScreen.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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
-#endif
-
-QT_FORWARD_DECLARE_CLASS(QIcon)
-QT_FORWARD_DECLARE_CLASS(QPushButton)
-
-namespace O3DE::ProjectManager
-{
- class FirstTimeUseScreen
- : public ScreenWidget
- {
- public:
- explicit FirstTimeUseScreen(QWidget* parent = nullptr);
- ~FirstTimeUseScreen() = default;
- ProjectManagerScreen GetScreenEnum() override;
-
- protected slots:
- void HandleNewProjectButton();
- void HandleAddProjectButton();
-
- private:
- QPushButton* CreateLargeBoxButton(const QIcon& icon, const QString& text, QWidget* parent = nullptr);
-
- QPushButton* m_createProjectButton;
- QPushButton* m_addProjectButton;
-
- inline constexpr static int s_contentMargins = 80;
- inline constexpr static int s_buttonSpacing = 30;
- inline constexpr static int s_iconSize = 24;
- inline constexpr static int s_spacerSize = 20;
- inline constexpr static int s_boxButtonWidth = 210;
- inline constexpr static int s_boxButtonHeight = 280;
- };
-
-} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/NewProjectSettingsScreen.cpp b/Code/Tools/ProjectManager/Source/NewProjectSettingsScreen.cpp
index ffbf1bf6fe..b57a2b35b2 100644
--- a/Code/Tools/ProjectManager/Source/NewProjectSettingsScreen.cpp
+++ b/Code/Tools/ProjectManager/Source/NewProjectSettingsScreen.cpp
@@ -12,6 +12,9 @@
#include
#include
+#include
+#include
+#include
#include
#include
@@ -23,6 +26,7 @@
#include
#include
#include
+#include
namespace O3DE::ProjectManager
{
@@ -31,64 +35,81 @@ namespace O3DE::ProjectManager
NewProjectSettingsScreen::NewProjectSettingsScreen(QWidget* parent)
: ScreenWidget(parent)
{
- QHBoxLayout* hLayout = new QHBoxLayout();
- this->setLayout(hLayout);
-
+ QHBoxLayout* hLayout = new QHBoxLayout(this);
+ hLayout->setAlignment(Qt::AlignLeft);
+ hLayout->setContentsMargins(0,0,0,0);
+
+ // 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);
- QLabel* projectNameLabel = new QLabel(tr("Project Name"), this);
- vLayout->addWidget(projectNameLabel);
-
- m_projectNameLineEdit = new QLineEdit(tr("New Project"), this);
- vLayout->addWidget(m_projectNameLineEdit);
-
- QLabel* projectPathLabel = new QLabel(tr("Project Location"), this);
- vLayout->addWidget(projectPathLabel);
-
+ // you cannot remove content margins in qss
+ vLayout->setContentsMargins(0,0,0,0);
+ vLayout->setAlignment(Qt::AlignTop);
{
- QHBoxLayout* projectPathLayout = new QHBoxLayout(this);
-
- m_projectPathLineEdit = new QLineEdit(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), this);
- projectPathLayout->addWidget(m_projectPathLineEdit);
-
- QPushButton* browseButton = new QPushButton(tr("Browse"), this);
- connect(browseButton, &QPushButton::pressed, this, &NewProjectSettingsScreen::HandleBrowseButton);
- projectPathLayout->addWidget(browseButton);
-
- vLayout->addLayout(projectPathLayout);
- }
-
- QLabel* projectTemplateLabel = new QLabel(this);
- projectTemplateLabel->setText("Project Template");
- vLayout->addWidget(projectTemplateLabel);
-
- QHBoxLayout* templateLayout = new QHBoxLayout(this);
- vLayout->addItem(templateLayout);
-
- m_projectTemplateButtonGroup = new QButtonGroup(this);
- auto templatesResult = PythonBindingsInterface::Get()->GetProjectTemplates();
- if (templatesResult.IsSuccess() && !templatesResult.GetValue().isEmpty())
- {
- for (auto projectTemplate : templatesResult.GetValue())
+ m_projectName = new FormLineEditWidget(tr("Project name"), tr("New Project"), this);
+ m_projectName->setErrorLabelText(
+ tr("A project with this name already exists at this location. Please choose a new name or location."));
+ vLayout->addWidget(m_projectName);
+
+ m_projectPath =
+ new FormBrowseEditWidget(tr("Project Location"), QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), this);
+ m_projectPath->lineEdit()->setReadOnly(true);
+ m_projectPath->setErrorLabelText(tr("Please provide a valid path to a folder that exists"));
+ m_projectPath->lineEdit()->setValidator(new PathValidator(PathValidator::PathMode::ExistingFolder, this));
+ vLayout->addWidget(m_projectPath);
+
+ // 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);
{
- QRadioButton* radioButton = new QRadioButton(projectTemplate.m_name, this);
- radioButton->setProperty(k_pathProperty, projectTemplate.m_path);
- m_projectTemplateButtonGroup->addButton(radioButton);
-
- templateLayout->addWidget(radioButton);
+ 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 (auto projectTemplate : templatesResult.GetValue())
+ {
+ 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);
+ }
}
-
- m_projectTemplateButtonGroup->buttons().first()->setChecked(true);
+ projectTemplateWidget->setLayout(containerLayout);
+ vLayout->addWidget(projectTemplateWidget);
}
+ projectSettingsFrame->setLayout(vLayout);
- QSpacerItem* verticalSpacer = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding);
- vLayout->addItem(verticalSpacer);
+ hLayout->addWidget(projectSettingsFrame);
- hLayout->addItem(vLayout);
+ QWidget* projectTemplateDetails = new QWidget(this);
+ projectTemplateDetails->setObjectName("projectTemplateDetails");
+ hLayout->addWidget(projectTemplateDetails);
- QWidget* gemsListPlaceholder = new QWidget(this);
- gemsListPlaceholder->setFixedWidth(250);
- hLayout->addWidget(gemsListPlaceholder);
+ this->setLayout(hLayout);
}
ProjectManagerScreen NewProjectSettingsScreen::GetScreenEnum()
@@ -96,26 +117,12 @@ namespace O3DE::ProjectManager
return ProjectManagerScreen::NewProjectSettings;
}
- void NewProjectSettingsScreen::HandleBrowseButton()
- {
- QString defaultPath = m_projectPathLineEdit->text();
- if (defaultPath.isEmpty())
- {
- defaultPath = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
- }
-
- QString directory = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(this, tr("New project path"), defaultPath));
- if (!directory.isEmpty())
- {
- m_projectPathLineEdit->setText(directory);
- }
- }
ProjectInfo NewProjectSettingsScreen::GetProjectInfo()
{
ProjectInfo projectInfo;
- projectInfo.m_projectName = m_projectNameLineEdit->text();
- projectInfo.m_path = QDir::toNativeSeparators(m_projectPathLineEdit->text() + "/" + projectInfo.m_projectName);
+ projectInfo.m_projectName = m_projectName->lineEdit()->text();
+ projectInfo.m_path = QDir::toNativeSeparators(m_projectPath->lineEdit()->text() + "/" + projectInfo.m_projectName);
return projectInfo;
}
@@ -127,18 +134,18 @@ namespace O3DE::ProjectManager
bool NewProjectSettingsScreen::Validate()
{
bool projectNameIsValid = true;
- if (m_projectNameLineEdit->text().isEmpty())
+ if (m_projectName->lineEdit()->text().isEmpty())
{
projectNameIsValid = false;
}
bool projectPathIsValid = true;
- if (m_projectPathLineEdit->text().isEmpty())
+ if (m_projectPath->lineEdit()->text().isEmpty())
{
projectPathIsValid = false;
}
- QDir path(QDir::toNativeSeparators(m_projectPathLineEdit->text() + "/" + m_projectNameLineEdit->text()));
+ QDir path(QDir::toNativeSeparators(m_projectPath->lineEdit()->text() + "/" + m_projectName->lineEdit()->text()));
if (path.exists() && !path.isEmpty())
{
projectPathIsValid = false;
diff --git a/Code/Tools/ProjectManager/Source/NewProjectSettingsScreen.h b/Code/Tools/ProjectManager/Source/NewProjectSettingsScreen.h
index 1cfd3c9c35..f0e9609fdc 100644
--- a/Code/Tools/ProjectManager/Source/NewProjectSettingsScreen.h
+++ b/Code/Tools/ProjectManager/Source/NewProjectSettingsScreen.h
@@ -17,10 +17,12 @@
#endif
QT_FORWARD_DECLARE_CLASS(QButtonGroup)
-QT_FORWARD_DECLARE_CLASS(QLineEdit)
namespace O3DE::ProjectManager
{
+ QT_FORWARD_DECLARE_CLASS(FormLineEditWidget)
+ QT_FORWARD_DECLARE_CLASS(FormBrowseEditWidget)
+
class NewProjectSettingsScreen
: public ScreenWidget
{
@@ -38,8 +40,8 @@ namespace O3DE::ProjectManager
void HandleBrowseButton();
private:
- QLineEdit* m_projectNameLineEdit;
- QLineEdit* m_projectPathLineEdit;
+ FormLineEditWidget* m_projectName;
+ FormBrowseEditWidget* m_projectPath;
QButtonGroup* m_projectTemplateButtonGroup;
};
diff --git a/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp b/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp
index dada54b1a2..4be876e79f 100644
--- a/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp
+++ b/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp
@@ -31,6 +31,7 @@ namespace O3DE::ProjectManager
LabelButton::LabelButton(QWidget* parent)
: QLabel(parent)
{
+ setObjectName("labelButton");
m_overlayLabel = new QLabel("", this);
m_overlayLabel->setObjectName("labelButtonOverlay");
m_overlayLabel->setWordWrap(true);
@@ -75,6 +76,8 @@ namespace O3DE::ProjectManager
void ProjectButton::Setup()
{
+ setObjectName("projectButton");
+
QVBoxLayout* vLayout = new QVBoxLayout();
vLayout->setSpacing(0);
vLayout->setContentsMargins(0, 0, 0, 0);
@@ -98,14 +101,21 @@ namespace O3DE::ProjectManager
m_deleteProjectAction = newProjectMenu->addAction(tr("Delete the Project"));
#endif
- m_projectSettingsMenuButton = new QPushButton(this);
- m_projectSettingsMenuButton->setText(m_projectName);
- m_projectSettingsMenuButton->setMenu(newProjectMenu);
- m_projectSettingsMenuButton->setFocusPolicy(Qt::FocusPolicy::NoFocus);
- m_projectSettingsMenuButton->setStyleSheet("font-size: 14px; text-align:left;");
- vLayout->addWidget(m_projectSettingsMenuButton);
+ QFrame* footer = new QFrame(this);
+ QHBoxLayout* hLayout = new QHBoxLayout();
+ hLayout->setContentsMargins(0, 0, 0, 0);
+ footer->setLayout(hLayout);
+ {
+ QLabel* projectNameLabel = new QLabel(m_projectName, this);
+ hLayout->addWidget(projectNameLabel);
+
+ QPushButton* projectMenuButton = new QPushButton(this);
+ projectMenuButton->setObjectName("projectMenuButton");
+ projectMenuButton->setMenu(newProjectMenu);
+ hLayout->addWidget(projectMenuButton);
+ }
- setFixedSize(s_projectImageWidth, s_projectImageHeight + m_projectSettingsMenuButton->height());
+ vLayout->addWidget(footer);
connect(m_projectImageLabel, &LabelButton::triggered, [this]() { emit OpenProject(m_projectName); });
connect(m_editProjectAction, &QAction::triggered, [this]() { emit EditProject(m_projectName); });
diff --git a/Code/Tools/ProjectManager/Source/ProjectButtonWidget.h b/Code/Tools/ProjectManager/Source/ProjectButtonWidget.h
index 43efaa1136..671debf6d0 100644
--- a/Code/Tools/ProjectManager/Source/ProjectButtonWidget.h
+++ b/Code/Tools/ProjectManager/Source/ProjectButtonWidget.h
@@ -73,7 +73,6 @@ namespace O3DE::ProjectManager
QString m_projectName;
QString m_projectImagePath;
LabelButton* m_projectImageLabel;
- QPushButton* m_projectSettingsMenuButton;
QAction* m_editProjectAction;
QAction* m_editProjectGemsAction;
QAction* m_copyProjectAction;
diff --git a/Code/Tools/ProjectManager/Source/ProjectManagerWindow.cpp b/Code/Tools/ProjectManager/Source/ProjectManagerWindow.cpp
index eb79f2da1e..76bcc2eb99 100644
--- a/Code/Tools/ProjectManager/Source/ProjectManagerWindow.cpp
+++ b/Code/Tools/ProjectManager/Source/ProjectManagerWindow.cpp
@@ -11,52 +11,46 @@
*/
#include
-#include
+#include
#include
#include
#include
-#include
-
namespace O3DE::ProjectManager
{
ProjectManagerWindow::ProjectManagerWindow(QWidget* parent, const AZ::IO::PathView& engineRootPath)
: QMainWindow(parent)
- , m_ui(new Ui::ProjectManagerWindowClass())
{
- m_ui->setupUi(this);
- QLayout* layout = m_ui->centralWidget->layout();
- layout->setMargin(0);
- layout->setSpacing(0);
- layout->setContentsMargins(0, 0, 0, 0);
-
m_pythonBindings = AZStd::make_unique(engineRootPath);
- m_screensCtrl = new ScreensCtrl();
- m_ui->verticalLayout->addWidget(m_screensCtrl);
+ setWindowTitle(tr("O3DE Project Manager"));
- connect(m_ui->projectsMenu, &QMenu::aboutToShow, this, &ProjectManagerWindow::HandleProjectsMenu);
- connect(m_ui->engineMenu, &QMenu::aboutToShow, this, &ProjectManagerWindow::HandleEngineMenu);
+ ScreensCtrl* screensCtrl = new ScreensCtrl();
+ // currently the tab order on the home page is based on the order of this list
+ QVector screenEnums =
+ {
+ ProjectManagerScreen::Projects,
+ ProjectManagerScreen::EngineSettings,
+ ProjectManagerScreen::CreateProject,
+ ProjectManagerScreen::UpdateProject
+ };
+ screensCtrl->BuildScreens(screenEnums);
+
+ setCentralWidget(screensCtrl);
+
+ // setup stylesheets and hot reloading
QDir rootDir = QString::fromUtf8(engineRootPath.Native().data(), aznumeric_cast(engineRootPath.Native().size()));
const auto pathOnDisk = rootDir.absoluteFilePath("Code/Tools/ProjectManager/Resources");
const auto qrcPath = QStringLiteral(":/ProjectManager/style");
AzQtComponents::StyleManager::addSearchPaths("style", pathOnDisk, qrcPath, engineRootPath);
+ // set stylesheet after creating the screens or their styles won't get updated
AzQtComponents::StyleManager::setStyleSheet(this, QStringLiteral("style:ProjectManager.qss"));
- QVector screenEnums =
- {
- ProjectManagerScreen::FirstTimeUse,
- ProjectManagerScreen::CreateProject,
- ProjectManagerScreen::ProjectsHome,
- ProjectManagerScreen::UpdateProject,
- ProjectManagerScreen::EngineSettings
- };
- m_screensCtrl->BuildScreens(screenEnums);
- m_screensCtrl->ForceChangeToScreen(ProjectManagerScreen::FirstTimeUse, false);
+ screensCtrl->ForceChangeToScreen(ProjectManagerScreen::Projects, false);
}
ProjectManagerWindow::~ProjectManagerWindow()
@@ -64,13 +58,4 @@ namespace O3DE::ProjectManager
m_pythonBindings.reset();
}
- void ProjectManagerWindow::HandleProjectsMenu()
- {
- m_screensCtrl->ChangeToScreen(ProjectManagerScreen::ProjectsHome);
- }
- void ProjectManagerWindow::HandleEngineMenu()
- {
- m_screensCtrl->ChangeToScreen(ProjectManagerScreen::EngineSettings);
- }
-
} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/ProjectManagerWindow.h b/Code/Tools/ProjectManager/Source/ProjectManagerWindow.h
index d5c586e59b..74db3467c5 100644
--- a/Code/Tools/ProjectManager/Source/ProjectManagerWindow.h
+++ b/Code/Tools/ProjectManager/Source/ProjectManagerWindow.h
@@ -13,17 +13,9 @@
#if !defined(Q_MOC_RUN)
#include
-
-#include
-
#include
#endif
-namespace Ui
-{
- class ProjectManagerWindowClass;
-}
-
namespace O3DE::ProjectManager
{
class ProjectManagerWindow
@@ -35,13 +27,7 @@ namespace O3DE::ProjectManager
explicit ProjectManagerWindow(QWidget* parent, const AZ::IO::PathView& engineRootPath);
~ProjectManagerWindow();
- protected slots:
- void HandleProjectsMenu();
- void HandleEngineMenu();
-
private:
- QScopedPointer m_ui;
- ScreensCtrl* m_screensCtrl;
AZStd::unique_ptr m_pythonBindings;
};
diff --git a/Code/Tools/ProjectManager/Source/ProjectManagerWindow.ui b/Code/Tools/ProjectManager/Source/ProjectManagerWindow.ui
deleted file mode 100644
index 633cd61182..0000000000
--- a/Code/Tools/ProjectManager/Source/ProjectManagerWindow.ui
+++ /dev/null
@@ -1,67 +0,0 @@
-
-
- ProjectManagerWindowClass
-
-
-
- 0
- 0
- 1200
- 800
-
-
-
-
- 0
- 0
-
-
-
- O3DE Project Manager
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Code/Tools/ProjectManager/Source/ProjectsHomeScreen.cpp b/Code/Tools/ProjectManager/Source/ProjectsHomeScreen.cpp
deleted file mode 100644
index 6c60685358..0000000000
--- a/Code/Tools/ProjectManager/Source/ProjectsHomeScreen.cpp
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * 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
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-namespace O3DE::ProjectManager
-{
- ProjectsHomeScreen::ProjectsHomeScreen(QWidget* parent)
- : ScreenWidget(parent)
- {
- QVBoxLayout* vLayout = new QVBoxLayout();
- setLayout(vLayout);
- vLayout->setContentsMargins(s_contentMargins, s_contentMargins, s_contentMargins, s_contentMargins);
-
- QHBoxLayout* topLayout = new QHBoxLayout();
-
- QLabel* titleLabel = new QLabel(this);
- titleLabel->setText("My Projects");
- titleLabel->setStyleSheet("font-size: 24px");
- topLayout->addWidget(titleLabel);
-
- QSpacerItem* topSpacer = new QSpacerItem(s_spacerSize, s_spacerSize, QSizePolicy::Expanding, QSizePolicy::Minimum);
- topLayout->addItem(topSpacer);
-
- QMenu* newProjectMenu = new QMenu(this);
- m_createNewProjectAction = newProjectMenu->addAction("Create New Project");
- m_addExistingProjectAction = newProjectMenu->addAction("Add Existing Project");
-
- QPushButton* newProjectMenuButton = new QPushButton(this);
- newProjectMenuButton->setText("New Project...");
- newProjectMenuButton->setMenu(newProjectMenu);
- newProjectMenuButton->setFixedWidth(s_newProjectButtonWidth);
- newProjectMenuButton->setStyleSheet("font-size: 14px;");
- topLayout->addWidget(newProjectMenuButton);
-
- vLayout->addLayout(topLayout);
-
- // Get all projects and create a horizontal scrolling list of them
- auto projectsResult = PythonBindingsInterface::Get()->GetProjects();
- if (projectsResult.IsSuccess() && !projectsResult.GetValue().isEmpty())
- {
- QScrollArea* projectsScrollArea = new QScrollArea(this);
- QWidget* scrollWidget = new QWidget();
- QGridLayout* projectGridLayout = new QGridLayout();
- scrollWidget->setLayout(projectGridLayout);
- projectsScrollArea->setWidget(scrollWidget);
- projectsScrollArea->setWidgetResizable(true);
-
- int gridIndex = 0;
- for (auto project : projectsResult.GetValue())
- {
- ProjectButton* projectButton;
- QString projectPreviewPath = project.m_path + m_projectPreviewImagePath;
- QFileInfo doesPreviewExist(projectPreviewPath);
- if (doesPreviewExist.exists() && doesPreviewExist.isFile())
- {
- projectButton = new ProjectButton(project.m_projectName, projectPreviewPath, this);
- }
- else
- {
- projectButton = new ProjectButton(project.m_projectName, this);
- }
-
- // Create rows of projects buttons s_projectButtonRowCount buttons wide
- projectGridLayout->addWidget(projectButton, gridIndex / s_projectButtonRowCount, gridIndex % s_projectButtonRowCount);
-
- connect(projectButton, &ProjectButton::OpenProject, this, &ProjectsHomeScreen::HandleOpenProject);
- connect(projectButton, &ProjectButton::EditProject, this, &ProjectsHomeScreen::HandleEditProject);
-
-#ifdef SHOW_ALL_PROJECT_ACTIONS
- connect(projectButton, &ProjectButton::EditProjectGems, this, &ProjectsHomeScreen::HandleEditProjectGems);
- connect(projectButton, &ProjectButton::CopyProject, this, &ProjectsHomeScreen::HandleCopyProject);
- connect(projectButton, &ProjectButton::RemoveProject, this, &ProjectsHomeScreen::HandleRemoveProject);
- connect(projectButton, &ProjectButton::DeleteProject, this, &ProjectsHomeScreen::HandleDeleteProject);
-#endif
- ++gridIndex;
- }
-
- vLayout->addWidget(projectsScrollArea);
- }
-
- // Using border-image allows for scaling options background-image does not support
- setStyleSheet("O3DE--ProjectManager--ScreenWidget { border-image: url(:/Backgrounds/FirstTimeBackgroundImage.jpg) repeat repeat; }");
-
- connect(m_createNewProjectAction, &QAction::triggered, this, &ProjectsHomeScreen::HandleNewProjectButton);
- connect(m_addExistingProjectAction, &QAction::triggered, this, &ProjectsHomeScreen::HandleAddProjectButton);
- }
-
- ProjectManagerScreen ProjectsHomeScreen::GetScreenEnum()
- {
- return ProjectManagerScreen::ProjectsHome;
- }
-
- void ProjectsHomeScreen::HandleNewProjectButton()
- {
- emit ResetScreenRequest(ProjectManagerScreen::CreateProject);
- emit ChangeScreenRequest(ProjectManagerScreen::CreateProject);
- }
- void ProjectsHomeScreen::HandleAddProjectButton()
- {
- // Do nothing for now
- }
- void ProjectsHomeScreen::HandleOpenProject(const QString& projectPath)
- {
- if (!projectPath.isEmpty())
- {
- AZ::IO::FixedMaxPath executableDirectory = AZ::Utils::GetExecutableDirectory();
- AZStd::string executableFilename = "Editor";
- AZ::IO::FixedMaxPath editorExecutablePath = executableDirectory / (executableFilename + AZ_TRAIT_OS_EXECUTABLE_EXTENSION);
- auto cmdPath = AZ::IO::FixedMaxPathString::format("%s -regset=\"/Amazon/AzCore/Bootstrap/project_path=%s\"", editorExecutablePath.c_str(), projectPath.toStdString().c_str());
-
- AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo;
- processLaunchInfo.m_commandlineParameters = cmdPath;
- bool launchSucceeded = AzFramework::ProcessLauncher::LaunchUnwatchedProcess(processLaunchInfo);
- if (!launchSucceeded)
- {
- AZ_Error("ProjectManager", false, "Failed to launch editor");
- QMessageBox::critical( this, tr("Error"), tr("Failed to launch the Editor, please verify the project settings are valid."));
- }
- else
- {
- // prevent the user from accidentally pressing the button while the editor is launching
- // and let them know what's happening
- ProjectButton* button = qobject_cast(sender());
- if (button)
- {
- button->SetButtonEnabled(false);
- button->SetButtonOverlayText(tr("Opening Editor..."));
- }
-
- // enable the button after 3 seconds
- constexpr int waitTimeInMs = 3000;
- QTimer::singleShot(waitTimeInMs, this, [this, button] {
- if (button)
- {
- button->SetButtonEnabled(true);
- }
- });
- }
- }
- else
- {
- AZ_Error("ProjectManager", false, "Cannot open editor because an empty project path was provided");
- QMessageBox::critical( this, tr("Error"), tr("Failed to launch the Editor because the project path is invalid."));
- }
-
- }
- void ProjectsHomeScreen::HandleEditProject(const QString& projectPath)
- {
- emit NotifyCurrentProject(projectPath);
- emit ResetScreenRequest(ProjectManagerScreen::UpdateProject);
- emit ChangeScreenRequest(ProjectManagerScreen::UpdateProject);
- }
- void ProjectsHomeScreen::HandleEditProjectGems(const QString& projectPath)
- {
- emit NotifyCurrentProject(projectPath);
- emit ChangeScreenRequest(ProjectManagerScreen::GemCatalog);
- }
- void ProjectsHomeScreen::HandleCopyProject([[maybe_unused]] const QString& projectPath)
- {
- // Open file dialog and choose location for copied project then register copy with O3DE
- }
- void ProjectsHomeScreen::HandleRemoveProject([[maybe_unused]] const QString& projectPath)
- {
- // Unregister Project from O3DE
- }
- void ProjectsHomeScreen::HandleDeleteProject([[maybe_unused]] const QString& projectPath)
- {
- // Remove project from 03DE and delete from disk
- ProjectsHomeScreen::HandleRemoveProject(projectPath);
- }
-
-} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp b/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp
new file mode 100644
index 0000000000..5f1c0e2b36
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp
@@ -0,0 +1,347 @@
+/*
+ * 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
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+//#define DISPLAY_PROJECT_DEV_DATA true
+
+namespace O3DE::ProjectManager
+{
+ ProjectsScreen::ProjectsScreen(QWidget* parent)
+ : ScreenWidget(parent)
+ {
+ QVBoxLayout* vLayout = new QVBoxLayout();
+ vLayout->setAlignment(Qt::AlignTop);
+ vLayout->setContentsMargins(s_contentMargins, 0, s_contentMargins, 0);
+ setLayout(vLayout);
+
+ m_background.load(":/Backgrounds/FirstTimeBackgroundImage.jpg");
+
+ m_stack = new QStackedWidget(this);
+
+ m_firstTimeContent = CreateFirstTimeContent();
+ m_stack->addWidget(m_firstTimeContent);
+
+ m_projectsContent = CreateProjectsContent();
+ m_stack->addWidget(m_projectsContent);
+
+ vLayout->addWidget(m_stack);
+
+ connect(m_createNewProjectAction, &QAction::triggered, this, &ProjectsScreen::HandleNewProjectButton);
+ connect(m_addExistingProjectAction, &QAction::triggered, this, &ProjectsScreen::HandleAddProjectButton);
+ }
+
+ QFrame* ProjectsScreen::CreateFirstTimeContent()
+ {
+ QFrame* frame = new QFrame(this);
+ frame->setObjectName("firstTimeContent");
+ {
+ QVBoxLayout* layout = new QVBoxLayout(this);
+ layout->setContentsMargins(0, 0, 0, 0);
+ layout->setAlignment(Qt::AlignTop);
+ frame->setLayout(layout);
+
+ QLabel* titleLabel = new QLabel(tr("Ready. Set. Create."), this);
+ titleLabel->setObjectName("titleLabel");
+ layout->addWidget(titleLabel);
+
+ QLabel* introLabel = new QLabel(this);
+ introLabel->setObjectName("introLabel");
+ introLabel->setText(tr("Welcome to O3DE! Start something new by creating a project. Not sure what to create? \nExplore what's "
+ "available by downloading our sample project."));
+ layout->addWidget(introLabel);
+
+ QHBoxLayout* buttonLayout = new QHBoxLayout(this);
+ buttonLayout->setAlignment(Qt::AlignLeft);
+ buttonLayout->setSpacing(s_spacerSize);
+
+ // use a newline to force the text up
+ QPushButton* createProjectButton = new QPushButton(tr("Create a Project\n"), this);
+ createProjectButton->setObjectName("createProjectButton");
+ buttonLayout->addWidget(createProjectButton);
+
+ QPushButton* addProjectButton = new QPushButton(tr("Add a Project\n"), this);
+ addProjectButton->setObjectName("addProjectButton");
+ buttonLayout->addWidget(addProjectButton);
+
+ connect(createProjectButton, &QPushButton::clicked, this, &ProjectsScreen::HandleNewProjectButton);
+ connect(addProjectButton, &QPushButton::clicked, this, &ProjectsScreen::HandleAddProjectButton);
+
+ layout->addLayout(buttonLayout);
+ }
+
+ return frame;
+ }
+
+ QFrame* ProjectsScreen::CreateProjectsContent()
+ {
+ QFrame* frame = new QFrame(this);
+ frame->setObjectName("projectsContent");
+ {
+ QVBoxLayout* layout = new QVBoxLayout();
+ layout->setAlignment(Qt::AlignTop);
+ layout->setContentsMargins(0, 0, 0, 0);
+ frame->setLayout(layout);
+
+ QFrame* header = new QFrame(this);
+ QHBoxLayout* headerLayout = new QHBoxLayout();
+ {
+ QLabel* titleLabel = new QLabel(tr("My Projects"), this);
+ titleLabel->setObjectName("titleLabel");
+ headerLayout->addWidget(titleLabel);
+
+ QMenu* newProjectMenu = new QMenu(this);
+ m_createNewProjectAction = newProjectMenu->addAction("Create New Project");
+ m_addExistingProjectAction = newProjectMenu->addAction("Add Existing Project");
+
+ connect(m_createNewProjectAction, &QAction::triggered, this, &ProjectsScreen::HandleNewProjectButton);
+ connect(m_addExistingProjectAction, &QAction::triggered, this, &ProjectsScreen::HandleAddProjectButton);
+
+ QPushButton* newProjectMenuButton = new QPushButton(tr("New Project..."), this);
+ newProjectMenuButton->setObjectName("newProjectButton");
+ newProjectMenuButton->setMenu(newProjectMenu);
+ newProjectMenuButton->setDefault(true);
+ headerLayout->addWidget(newProjectMenuButton);
+ }
+ header->setLayout(headerLayout);
+
+ layout->addWidget(header);
+
+ // Get all projects and create a horizontal scrolling list of them
+ auto projectsResult = PythonBindingsInterface::Get()->GetProjects();
+ if (projectsResult.IsSuccess() && !projectsResult.GetValue().isEmpty())
+ {
+ QScrollArea* projectsScrollArea = new QScrollArea(this);
+ QWidget* scrollWidget = new QWidget();
+
+ FlowLayout* flowLayout = new FlowLayout(0, s_spacerSize, s_spacerSize);
+ scrollWidget->setLayout(flowLayout);
+
+ projectsScrollArea->setWidget(scrollWidget);
+ projectsScrollArea->setWidgetResizable(true);
+
+#ifndef DISPLAY_PROJECT_DEV_DATA
+ for (auto project : projectsResult.GetValue())
+#else
+ ProjectInfo project = projectsResult.GetValue().at(0);
+ for (int i = 0; i < 15; i++)
+#endif
+ {
+ ProjectButton* projectButton;
+ QString projectPreviewPath = project.m_path + m_projectPreviewImagePath;
+ QFileInfo doesPreviewExist(projectPreviewPath);
+ if (doesPreviewExist.exists() && doesPreviewExist.isFile())
+ {
+ projectButton = new ProjectButton(project.m_projectName, projectPreviewPath, this);
+ }
+ else
+ {
+ projectButton = new ProjectButton(project.m_projectName, this);
+ }
+
+ flowLayout->addWidget(projectButton);
+
+ connect(projectButton, &ProjectButton::OpenProject, this, &ProjectsScreen::HandleOpenProject);
+ connect(projectButton, &ProjectButton::EditProject, this, &ProjectsScreen::HandleEditProject);
+
+ #ifdef DISPLAY_PROJECT_DEV_DATA
+ connect(projectButton, &ProjectButton::EditProjectGems, this, &ProjectsScreen::HandleEditProjectGems);
+ connect(projectButton, &ProjectButton::CopyProject, this, &ProjectsScreen::HandleCopyProject);
+ connect(projectButton, &ProjectButton::RemoveProject, this, &ProjectsScreen::HandleRemoveProject);
+ connect(projectButton, &ProjectButton::DeleteProject, this, &ProjectsScreen::HandleDeleteProject);
+ #endif
+ }
+
+ layout->addWidget(projectsScrollArea);
+ }
+ }
+
+ return frame;
+ }
+
+ ProjectManagerScreen ProjectsScreen::GetScreenEnum()
+ {
+ return ProjectManagerScreen::Projects;
+ }
+
+ bool ProjectsScreen::IsTab()
+ {
+ return true;
+ }
+
+ QString ProjectsScreen::GetTabText()
+ {
+ return tr("Projects");
+ }
+
+ void ProjectsScreen::paintEvent([[maybe_unused]] QPaintEvent* event)
+ {
+ // we paint the background here because qss does not support background cover scaling
+ QPainter painter(this);
+
+ auto winSize = size();
+ auto pixmapRatio = (float)m_background.width() / m_background.height();
+ auto windowRatio = (float)winSize.width() / winSize.height();
+
+ if (pixmapRatio > windowRatio)
+ {
+ auto newWidth = (int)(winSize.height() * pixmapRatio);
+ auto offset = (newWidth - winSize.width()) / -2;
+ painter.drawPixmap(offset, 0, newWidth, winSize.height(), m_background);
+ }
+ else
+ {
+ auto newHeight = (int)(winSize.width() / pixmapRatio);
+ painter.drawPixmap(0, 0, winSize.width(), newHeight, m_background);
+ }
+ }
+
+ void ProjectsScreen::HandleNewProjectButton()
+ {
+ emit ResetScreenRequest(ProjectManagerScreen::CreateProject);
+ emit ChangeScreenRequest(ProjectManagerScreen::CreateProject);
+ }
+ void ProjectsScreen::HandleAddProjectButton()
+ {
+ // Do nothing for now
+ }
+ void ProjectsScreen::HandleOpenProject(const QString& projectPath)
+ {
+ if (!projectPath.isEmpty())
+ {
+ AZ::IO::FixedMaxPath executableDirectory = AZ::Utils::GetExecutableDirectory();
+ AZStd::string executableFilename = "Editor";
+ AZ::IO::FixedMaxPath editorExecutablePath = executableDirectory / (executableFilename + AZ_TRAIT_OS_EXECUTABLE_EXTENSION);
+ auto cmdPath = AZ::IO::FixedMaxPathString::format("%s -regset=\"/Amazon/AzCore/Bootstrap/project_path=%s\"", editorExecutablePath.c_str(), projectPath.toStdString().c_str());
+
+ AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo;
+ processLaunchInfo.m_commandlineParameters = cmdPath;
+ bool launchSucceeded = AzFramework::ProcessLauncher::LaunchUnwatchedProcess(processLaunchInfo);
+ if (!launchSucceeded)
+ {
+ AZ_Error("ProjectManager", false, "Failed to launch editor");
+ QMessageBox::critical( this, tr("Error"), tr("Failed to launch the Editor, please verify the project settings are valid."));
+ }
+ else
+ {
+ // prevent the user from accidentally pressing the button while the editor is launching
+ // and let them know what's happening
+ ProjectButton* button = qobject_cast(sender());
+ if (button)
+ {
+ button->SetButtonEnabled(false);
+ button->SetButtonOverlayText(tr("Opening Editor..."));
+ }
+
+ // enable the button after 3 seconds
+ constexpr int waitTimeInMs = 3000;
+ QTimer::singleShot(waitTimeInMs, this, [this, button] {
+ if (button)
+ {
+ button->SetButtonEnabled(true);
+ }
+ });
+ }
+ }
+ else
+ {
+ AZ_Error("ProjectManager", false, "Cannot open editor because an empty project path was provided");
+ QMessageBox::critical( this, tr("Error"), tr("Failed to launch the Editor because the project path is invalid."));
+ }
+
+ }
+ 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([[maybe_unused]] const QString& projectPath)
+ {
+ // Open file dialog and choose location for copied project then register copy with O3DE
+ }
+ void ProjectsScreen::HandleRemoveProject([[maybe_unused]] const QString& projectPath)
+ {
+ // Unregister Project from O3DE
+ }
+ void ProjectsScreen::HandleDeleteProject([[maybe_unused]] const QString& projectPath)
+ {
+ // Remove project from 03DE and delete from disk
+ ProjectsScreen::HandleRemoveProject(projectPath);
+ }
+
+ void ProjectsScreen::NotifyCurrentScreen()
+ {
+ if (ShouldDisplayFirstTimeContent())
+ {
+ m_stack->setCurrentWidget(m_firstTimeContent);
+ }
+ else
+ {
+ m_stack->setCurrentWidget(m_projectsContent);
+ }
+ }
+
+ bool ProjectsScreen::ShouldDisplayFirstTimeContent()
+ {
+ auto projectsResult = PythonBindingsInterface::Get()->GetProjects();
+ if (!projectsResult.IsSuccess() || projectsResult.GetValue().isEmpty())
+ {
+ return true;
+ }
+
+ QSettings settings;
+ bool displayFirstTimeContent = settings.value("displayFirstTimeContent", true).toBool();
+ if (displayFirstTimeContent)
+ {
+ settings.setValue("displayFirstTimeContent", false);
+ }
+
+ return displayFirstTimeContent;
+ }
+
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/ProjectsHomeScreen.h b/Code/Tools/ProjectManager/Source/ProjectsScreen.h
similarity index 69%
rename from Code/Tools/ProjectManager/Source/ProjectsHomeScreen.h
rename to Code/Tools/ProjectManager/Source/ProjectsScreen.h
index e8d1ac4fb5..d88ba8398d 100644
--- a/Code/Tools/ProjectManager/Source/ProjectsHomeScreen.h
+++ b/Code/Tools/ProjectManager/Source/ProjectsScreen.h
@@ -15,16 +15,26 @@
#include
#endif
+QT_FORWARD_DECLARE_CLASS(QPaintEvent)
+QT_FORWARD_DECLARE_CLASS(QFrame)
+QT_FORWARD_DECLARE_CLASS(QStackedWidget)
+
namespace O3DE::ProjectManager
{
- class ProjectsHomeScreen
+ class ProjectsScreen
: public ScreenWidget
{
public:
- explicit ProjectsHomeScreen(QWidget* parent = nullptr);
- ~ProjectsHomeScreen() = default;
+ explicit ProjectsScreen(QWidget* parent = nullptr);
+ ~ProjectsScreen() = default;
+
ProjectManagerScreen GetScreenEnum() override;
+ QString GetTabText() override;
+ bool IsTab() override;
+
+ protected:
+ void NotifyCurrentScreen() override;
protected slots:
void HandleNewProjectButton();
@@ -36,16 +46,24 @@ namespace O3DE::ProjectManager
void HandleRemoveProject(const QString& projectPath);
void HandleDeleteProject(const QString& projectPath);
+ void paintEvent(QPaintEvent* event) override;
+
private:
+ QFrame* CreateFirstTimeContent();
+ QFrame* CreateProjectsContent();
+ bool ShouldDisplayFirstTimeContent();
+
QAction* m_createNewProjectAction;
QAction* m_addExistingProjectAction;
+ QPixmap m_background;
+ QFrame* m_firstTimeContent;
+ QFrame* m_projectsContent;
+ QStackedWidget* m_stack;
const QString m_projectPreviewImagePath = "/preview.png";
+
inline constexpr static int s_contentMargins = 80;
inline constexpr static int s_spacerSize = 20;
- inline constexpr static int s_projectButtonRowCount = 4;
- inline constexpr static int s_newProjectButtonWidth = 156;
-
};
} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/ScreenDefs.h b/Code/Tools/ProjectManager/Source/ScreenDefs.h
index 13289e2481..46d243f677 100644
--- a/Code/Tools/ProjectManager/Source/ScreenDefs.h
+++ b/Code/Tools/ProjectManager/Source/ScreenDefs.h
@@ -17,11 +17,10 @@ namespace O3DE::ProjectManager
{
Invalid = -1,
Empty,
- FirstTimeUse,
CreateProject,
NewProjectSettings,
GemCatalog,
- ProjectsHome,
+ Projects,
UpdateProject,
ProjectSettings,
EngineSettings
diff --git a/Code/Tools/ProjectManager/Source/ScreenFactory.cpp b/Code/Tools/ProjectManager/Source/ScreenFactory.cpp
index d37ccdb59f..b2b4376e14 100644
--- a/Code/Tools/ProjectManager/Source/ScreenFactory.cpp
+++ b/Code/Tools/ProjectManager/Source/ScreenFactory.cpp
@@ -11,12 +11,11 @@
*/
#include
-#include
#include
#include
#include
#include
-#include
+#include
#include
#include
@@ -28,9 +27,6 @@ namespace O3DE::ProjectManager
switch(screen)
{
- case (ProjectManagerScreen::FirstTimeUse):
- newScreen = new FirstTimeUseScreen(parent);
- break;
case (ProjectManagerScreen::CreateProject):
newScreen = new CreateProjectCtrl(parent);
break;
@@ -40,8 +36,8 @@ namespace O3DE::ProjectManager
case (ProjectManagerScreen::GemCatalog):
newScreen = new GemCatalogScreen(parent);
break;
- case (ProjectManagerScreen::ProjectsHome):
- newScreen = new ProjectsHomeScreen(parent);
+ case (ProjectManagerScreen::Projects):
+ newScreen = new ProjectsScreen(parent);
break;
case (ProjectManagerScreen::UpdateProject):
newScreen = new UpdateProjectCtrl(parent);
diff --git a/Code/Tools/ProjectManager/Source/ScreenHeaderWidget.cpp b/Code/Tools/ProjectManager/Source/ScreenHeaderWidget.cpp
new file mode 100644
index 0000000000..29b1eb6ff6
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/ScreenHeaderWidget.cpp
@@ -0,0 +1,62 @@
+/*
+* 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
+#include
+#include
+#include
+
+namespace O3DE::ProjectManager
+{
+ ScreenHeader::ScreenHeader(QWidget* parent)
+ : QFrame(parent)
+ {
+ setObjectName("header");
+
+ QHBoxLayout* layout = new QHBoxLayout();
+ layout->setAlignment(Qt::AlignLeft);
+ layout->setContentsMargins(0,0,0,0);
+
+ m_backButton = new QPushButton();
+ m_backButton->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
+ layout->addWidget(m_backButton);
+
+ QVBoxLayout* titleLayout = new QVBoxLayout();
+ m_title = new QLabel();
+ m_title->setObjectName("headerTitle");
+ titleLayout->addWidget(m_title);
+
+ m_subTitle = new QLabel();
+ m_subTitle->setObjectName("headerSubTitle");
+ titleLayout->addWidget(m_subTitle);
+
+ layout->addLayout(titleLayout);
+
+ setLayout(layout);
+ }
+
+ void ScreenHeader::setTitle(const QString& text)
+ {
+ m_title->setText(text);
+ }
+
+ void ScreenHeader::setSubTitle(const QString& text)
+ {
+ m_subTitle->setText(text);
+ }
+
+ QPushButton* ScreenHeader::backButton()
+ {
+ return m_backButton;
+ }
+
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/ScreenHeaderWidget.h b/Code/Tools/ProjectManager/Source/ScreenHeaderWidget.h
new file mode 100644
index 0000000000..c5fdb56195
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/ScreenHeaderWidget.h
@@ -0,0 +1,42 @@
+/*
+* 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
+#endif
+
+QT_FORWARD_DECLARE_CLASS(QLabel)
+QT_FORWARD_DECLARE_CLASS(QPushButton)
+
+namespace O3DE::ProjectManager
+{
+ class ScreenHeader
+ : public QFrame
+ {
+ Q_OBJECT // AUTOMOC
+
+ public:
+ ScreenHeader(QWidget* parent = nullptr);
+
+ void setTitle(const QString& text);
+ void setSubTitle(const QString& text);
+
+ QPushButton* backButton();
+
+ private:
+ QLabel* m_title;
+ QLabel* m_subTitle;
+ QPushButton* m_backButton;
+ };
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/ScreenWidget.h b/Code/Tools/ProjectManager/Source/ScreenWidget.h
index e80747d67b..2ad6d30201 100644
--- a/Code/Tools/ProjectManager/Source/ScreenWidget.h
+++ b/Code/Tools/ProjectManager/Source/ScreenWidget.h
@@ -41,12 +41,27 @@ namespace O3DE::ProjectManager
{
return true;
}
+ virtual bool IsTab()
+ {
+ return false;
+ }
+ virtual QString GetTabText()
+ {
+ return tr("Missing");
+ }
+
+ //! Notify this screen it is the current screen
+ virtual void NotifyCurrentScreen()
+ {
+
+ }
signals:
void ChangeScreenRequest(ProjectManagerScreen screen);
void GotoPreviousScreenRequest();
void ResetScreenRequest(ProjectManagerScreen screen);
void NotifyCurrentProject(const QString& projectPath);
+
};
} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/ScreensCtrl.cpp b/Code/Tools/ProjectManager/Source/ScreensCtrl.cpp
index a77c434026..7d31d02f6c 100644
--- a/Code/Tools/ProjectManager/Source/ScreensCtrl.cpp
+++ b/Code/Tools/ProjectManager/Source/ScreensCtrl.cpp
@@ -14,6 +14,7 @@
#include
#include
+#include
#include
namespace O3DE::ProjectManager
@@ -21,17 +22,19 @@ namespace O3DE::ProjectManager
ScreensCtrl::ScreensCtrl(QWidget* parent)
: QWidget(parent)
{
+ setObjectName("ScreensCtrl");
+
QVBoxLayout* vLayout = new QVBoxLayout();
- vLayout->setMargin(0);
- vLayout->setSpacing(0);
vLayout->setContentsMargins(0, 0, 0, 0);
setLayout(vLayout);
m_screenStack = new QStackedWidget();
vLayout->addWidget(m_screenStack);
- //Track the bottom of the stack
- m_screenVisitOrder.push(ProjectManagerScreen::Invalid);
+ // add a tab widget at the bottom of the stack
+ m_tabWidget = new QTabWidget();
+ m_screenStack->addWidget(m_tabWidget);
+ connect(m_tabWidget, &QTabWidget::currentChanged, this, &ScreensCtrl::TabChanged);
}
void ScreensCtrl::BuildScreens(QVector screens)
@@ -57,7 +60,14 @@ namespace O3DE::ProjectManager
ScreenWidget* ScreensCtrl::GetCurrentScreen()
{
- return reinterpret_cast(m_screenStack->currentWidget());
+ if (m_screenStack->currentWidget() == m_tabWidget)
+ {
+ return reinterpret_cast(m_tabWidget->currentWidget());
+ }
+ else
+ {
+ return reinterpret_cast(m_screenStack->currentWidget());
+ }
}
bool ScreensCtrl::ChangeToScreen(ProjectManagerScreen screen)
@@ -79,13 +89,28 @@ namespace O3DE::ProjectManager
if (iterator != m_screenMap.end())
{
ScreenWidget* currentScreen = GetCurrentScreen();
- if (currentScreen != iterator.value())
+ ScreenWidget* newScreen = iterator.value();
+
+ if (currentScreen != newScreen)
{
if (addVisit)
{
- m_screenVisitOrder.push(currentScreen->GetScreenEnum());
+ ProjectManagerScreen oldScreen = currentScreen->GetScreenEnum();
+ m_screenVisitOrder.push(oldScreen);
+ }
+
+ if (newScreen->IsTab())
+ {
+ m_tabWidget->setCurrentWidget(newScreen);
+ m_screenStack->setCurrentWidget(m_tabWidget);
}
- m_screenStack->setCurrentWidget(iterator.value());
+ else
+ {
+ m_screenStack->setCurrentWidget(newScreen);
+ }
+
+ newScreen->NotifyCurrentScreen();
+
return true;
}
}
@@ -95,23 +120,46 @@ namespace O3DE::ProjectManager
bool ScreensCtrl::GotoPreviousScreen()
{
- // Don't go back if we are on the first set screen
- if (m_screenVisitOrder.top() != ProjectManagerScreen::Invalid)
+ if (!m_screenVisitOrder.isEmpty())
{
// We do not check with screen if we can go back, we should always be able to go back
- return ForceChangeToScreen(m_screenVisitOrder.pop(), false);
+ ProjectManagerScreen previousScreen = m_screenVisitOrder.pop();
+ return ForceChangeToScreen(previousScreen, false);
}
return false;
}
void ScreensCtrl::ResetScreen(ProjectManagerScreen screen)
{
+ bool shouldRestoreCurrentScreen = false;
+ if (GetCurrentScreen() && GetCurrentScreen()->GetScreenEnum() == screen)
+ {
+ shouldRestoreCurrentScreen = true;
+ }
+
// Delete old screen if it exists to start fresh
DeleteScreen(screen);
// Add new screen
ScreenWidget* newScreen = BuildScreen(this, screen);
- m_screenStack->addWidget(newScreen);
+ if (newScreen->IsTab())
+ {
+ m_tabWidget->addTab(newScreen, newScreen->GetTabText());
+ if (shouldRestoreCurrentScreen)
+ {
+ m_tabWidget->setCurrentWidget(newScreen);
+ m_screenStack->setCurrentWidget(m_tabWidget);
+ }
+ }
+ else
+ {
+ m_screenStack->addWidget(newScreen);
+ if (shouldRestoreCurrentScreen)
+ {
+ m_screenStack->setCurrentWidget(newScreen);
+ }
+ }
+
m_screenMap.insert(screen, newScreen);
connect(newScreen, &ScreenWidget::ChangeScreenRequest, this, &ScreensCtrl::ChangeToScreen);
@@ -134,8 +182,21 @@ namespace O3DE::ProjectManager
const auto iter = m_screenMap.find(screen);
if (iter != m_screenMap.end())
{
- m_screenStack->removeWidget(iter.value());
- iter.value()->deleteLater();
+ ScreenWidget* screenToDelete = iter.value();
+ if (screenToDelete->IsTab())
+ {
+ int tabIndex = m_tabWidget->indexOf(screenToDelete);
+ if (tabIndex > -1)
+ {
+ m_tabWidget->removeTab(tabIndex);
+ }
+ }
+ else
+ {
+ // if the screen we delete is the current widget, a new one will
+ // be selected automatically (randomly?)
+ m_screenStack->removeWidget(screenToDelete);
+ }
// Erase does not cause a rehash so interators remain valid
m_screenMap.erase(iter);
@@ -150,4 +211,12 @@ namespace O3DE::ProjectManager
}
}
+ void ScreensCtrl::TabChanged([[maybe_unused]] int index)
+ {
+ ScreenWidget* screen = reinterpret_cast(m_tabWidget->currentWidget());
+ if (screen)
+ {
+ screen->NotifyCurrentScreen();
+ }
+ }
} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/ScreensCtrl.h b/Code/Tools/ProjectManager/Source/ScreensCtrl.h
index a9d1023b4b..935fc78e25 100644
--- a/Code/Tools/ProjectManager/Source/ScreensCtrl.h
+++ b/Code/Tools/ProjectManager/Source/ScreensCtrl.h
@@ -18,6 +18,8 @@
#include
#endif
+QT_FORWARD_DECLARE_CLASS(QTabWidget)
+
namespace O3DE::ProjectManager
{
class ScreenWidget;
@@ -46,11 +48,13 @@ namespace O3DE::ProjectManager
void ResetAllScreens();
void DeleteScreen(ProjectManagerScreen screen);
void DeleteAllScreens();
+ void TabChanged(int index);
private:
QStackedWidget* m_screenStack;
QHash m_screenMap;
QStack m_screenVisitOrder;
+ QTabWidget* m_tabWidget;
};
} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp
index 84e3d8359d..b3180966ce 100644
--- a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp
+++ b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp
@@ -108,7 +108,7 @@ namespace O3DE::ProjectManager
auto result = PythonBindingsInterface::Get()->UpdateProject(m_projectInfo);
if (result)
{
- emit ChangeScreenRequest(ProjectManagerScreen::ProjectsHome);
+ emit ChangeScreenRequest(ProjectManagerScreen::Projects);
}
else
{
diff --git a/Code/Tools/ProjectManager/Source/main.cpp b/Code/Tools/ProjectManager/Source/main.cpp
index 3d8bb71a0c..cbeacbaf65 100644
--- a/Code/Tools/ProjectManager/Source/main.cpp
+++ b/Code/Tools/ProjectManager/Source/main.cpp
@@ -35,7 +35,6 @@ int main(int argc, char* argv[])
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
AzQtComponents::Utilities::HandleDpiAwareness(AzQtComponents::Utilities::SystemDpiAware);
-
AZ::AllocatorInstance::Create();
int runSuccess = 0;
{
@@ -55,6 +54,12 @@ int main(int argc, char* argv[])
O3DE::ProjectManager::ProjectManagerWindow window(nullptr, engineRootPath);
window.show();
+ // somethings is preventing us from moving the window to the center of the
+ // primary screen - likely an Az style or component helper
+ constexpr int width = 1200;
+ constexpr int height = 800;
+ window.resize(width, height);
+
runSuccess = app.exec();
}
AZ::AllocatorInstance::Destroy();
diff --git a/Code/Tools/ProjectManager/project_manager_files.cmake b/Code/Tools/ProjectManager/project_manager_files.cmake
index a41ddad21e..223465f3c8 100644
--- a/Code/Tools/ProjectManager/project_manager_files.cmake
+++ b/Code/Tools/ProjectManager/project_manager_files.cmake
@@ -21,8 +21,6 @@ set(FILES
Source/ScreenWidget.h
Source/EngineInfo.h
Source/EngineInfo.cpp
- Source/FirstTimeUseScreen.h
- Source/FirstTimeUseScreen.cpp
Source/FormLineEditWidget.h
Source/FormLineEditWidget.cpp
Source/FormBrowseEditWidget.h
@@ -33,7 +31,6 @@ set(FILES
Source/ProjectManagerWindow.cpp
Source/ProjectTemplateInfo.h
Source/ProjectTemplateInfo.cpp
- Source/ProjectManagerWindow.ui
Source/PythonBindings.h
Source/PythonBindings.cpp
Source/PythonBindingsInterface.h
@@ -45,8 +42,8 @@ set(FILES
Source/CreateProjectCtrl.cpp
Source/UpdateProjectCtrl.h
Source/UpdateProjectCtrl.cpp
- Source/ProjectsHomeScreen.h
- Source/ProjectsHomeScreen.cpp
+ Source/ProjectsScreen.h
+ Source/ProjectsScreen.cpp
Source/ProjectSettingsScreen.h
Source/ProjectSettingsScreen.cpp
Source/ProjectSettingsScreen.ui
@@ -54,6 +51,8 @@ set(FILES
Source/EngineSettingsScreen.cpp
Source/ProjectButtonWidget.h
Source/ProjectButtonWidget.cpp
+ Source/ScreenHeaderWidget.h
+ Source/ScreenHeaderWidget.cpp
Source/LinkWidget.h
Source/LinkWidget.cpp
Source/TagWidget.h
diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/DllMain.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/DllMain.cpp
index 3dc14814de..4ab41423fa 100644
--- a/Code/Tools/SceneAPI/FbxSceneBuilder/DllMain.cpp
+++ b/Code/Tools/SceneAPI/FbxSceneBuilder/DllMain.cpp
@@ -38,21 +38,8 @@ namespace AZ
{
namespace FbxSceneBuilder
{
- static AZ::SceneAPI::FbxSceneImporter::FbxImportRequestHandler* g_fbxImporter = nullptr;
static AZStd::vector g_componentDescriptors;
- void Initialize()
- {
- // Currently it's still needed to explicitly create an instance of this instead of letting
- // it be a normal component. This is because ResourceCompilerScene needs to return
- // the list of available extensions before it can start the application.
- if (!g_fbxImporter)
- {
- g_fbxImporter = aznew AZ::SceneAPI::FbxSceneImporter::FbxImportRequestHandler();
- g_fbxImporter->Activate();
- }
- }
-
void Reflect(AZ::SerializeContext* /*context*/)
{
// Descriptor registration is done in Reflect instead of Initialize because the ResourceCompilerScene initializes the libraries before
@@ -64,6 +51,7 @@ namespace AZ
{
// Global importer and behavior
g_componentDescriptors.push_back(FbxSceneBuilder::FbxImporter::CreateDescriptor());
+ g_componentDescriptors.push_back(FbxSceneImporter::FbxImportRequestHandler::CreateDescriptor());
// Node and attribute importers
g_componentDescriptors.push_back(AssImpBitangentStreamImporter::CreateDescriptor());
@@ -110,13 +98,6 @@ namespace AZ
g_componentDescriptors.clear();
g_componentDescriptors.shrink_to_fit();
}
-
- if (g_fbxImporter)
- {
- g_fbxImporter->Deactivate();
- delete g_fbxImporter;
- g_fbxImporter = nullptr;
- }
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
@@ -125,7 +106,6 @@ namespace AZ
extern "C" AZ_DLL_EXPORT void InitializeDynamicModule(void* env)
{
AZ::Environment::Attach(static_cast(env));
- AZ::SceneAPI::FbxSceneBuilder::Initialize();
}
extern "C" AZ_DLL_EXPORT void Reflect(AZ::SerializeContext* context)
{
diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/FbxImportRequestHandler.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/FbxImportRequestHandler.cpp
index 155209f1b5..a8b059304d 100644
--- a/Code/Tools/SceneAPI/FbxSceneBuilder/FbxImportRequestHandler.cpp
+++ b/Code/Tools/SceneAPI/FbxSceneBuilder/FbxImportRequestHandler.cpp
@@ -10,12 +10,16 @@
*
*/
+#include
+#include
#include
-#include
+#include
+#include
+#include
+#include
#include