Ver código fonte

Merge branch 'main' of https://github.com/aws-lumberyard/o3de into prism/LYN-2514

# Conflicts:
#	Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp
Benjamin Jillich 4 anos atrás
pai
commit
1b96fc4361
25 arquivos alterados com 435 adições e 404 exclusões
  1. 7 9
      Code/Sandbox/Editor/CMakeLists.txt
  2. 4 0
      Code/Tools/AssetProcessor/CMakeLists.txt
  3. 0 1
      Code/Tools/ProjectManager/CMakeLists.txt
  4. 12 0
      Code/Tools/ProjectManager/Resources/ProjectManager.qss
  5. 40 122
      Code/Tools/ProjectManager/Source/NewProjectSettingsScreen.cpp
  6. 2 15
      Code/Tools/ProjectManager/Source/NewProjectSettingsScreen.h
  7. 0 10
      Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp
  8. 0 2
      Code/Tools/ProjectManager/Source/ProjectButtonWidget.h
  9. 13 0
      Code/Tools/ProjectManager/Source/ProjectInfo.cpp
  10. 2 0
      Code/Tools/ProjectManager/Source/ProjectInfo.h
  11. 102 16
      Code/Tools/ProjectManager/Source/ProjectSettingsScreen.cpp
  12. 15 9
      Code/Tools/ProjectManager/Source/ProjectSettingsScreen.h
  13. 0 113
      Code/Tools/ProjectManager/Source/ProjectSettingsScreen.ui
  14. 0 10
      Code/Tools/ProjectManager/Source/ProjectsScreen.cpp
  15. 0 1
      Code/Tools/ProjectManager/Source/ProjectsScreen.h
  16. 2 2
      Code/Tools/ProjectManager/Source/ScreenDefs.h
  17. 3 3
      Code/Tools/ProjectManager/Source/ScreenFactory.cpp
  18. 1 0
      Code/Tools/ProjectManager/Source/ScreensCtrl.cpp
  19. 113 78
      Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp
  20. 28 11
      Code/Tools/ProjectManager/Source/UpdateProjectCtrl.h
  21. 51 0
      Code/Tools/ProjectManager/Source/UpdateProjectSettingsScreen.cpp
  22. 34 0
      Code/Tools/ProjectManager/Source/UpdateProjectSettingsScreen.h
  23. 2 1
      Code/Tools/ProjectManager/project_manager_files.cmake
  24. 1 1
      Code/Tools/SceneAPI/SDKWrapper/AssImpSceneWrapper.cpp
  25. 3 0
      cmake/Projects.cmake

+ 7 - 9
Code/Sandbox/Editor/CMakeLists.txt

@@ -177,6 +177,11 @@ ly_add_target(
         Legacy::EditorLib
         ProjectManager
 )
+set_property(SOURCE
+    CryEdit.cpp
+    APPEND PROPERTY
+        COMPILE_DEFINITIONS LY_CMAKE_TARGET="Editor"
+)
 ly_add_translations(
     TARGETS Editor
     PREFIX Translations
@@ -186,15 +191,8 @@ ly_add_translations(
 )
 ly_add_dependencies(Editor AssetProcessor)
 
-if(TARGET Editor)
-    set_property(SOURCE
-        CryEdit.cpp
-        APPEND PROPERTY
-            COMPILE_DEFINITIONS LY_CMAKE_TARGET="Editor"
-    )
-else()
-    message(FATAL_ERROR "Cannot set LY_CMAKE_TARGET define to Editor as the target doesn't exist anymore."
-        " Perhaps it has been renamed")
+if(LY_FIRST_PROJECT_PATH)
+    set_property(TARGET Editor APPEND PROPERTY VS_DEBUGGER_COMMAND_ARGUMENTS "--project-path=\"${LY_FIRST_PROJECT_PATH}\"")
 endif()
 
 ################################################################################

+ 4 - 0
Code/Tools/AssetProcessor/CMakeLists.txt

@@ -125,6 +125,10 @@ ly_add_target(
             AZ::AssetProcessorBatch.Static
 )
 
+if(LY_FIRST_PROJECT_PATH)
+    set_property(TARGET AssetProcessor AssetProcessorBatch APPEND PROPERTY VS_DEBUGGER_COMMAND_ARGUMENTS "--project-path=\"${LY_FIRST_PROJECT_PATH}\"")
+endif()
+
 # Adds the AssetProcessorBatch target as a C preprocessor define so that it can be used as a Settings Registry
 # specialization in order to look up the generated .setreg which contains the dependencies
 # specified for the target.

+ 0 - 1
Code/Tools/ProjectManager/CMakeLists.txt

@@ -25,7 +25,6 @@ ly_add_target(
     OUTPUT_NAME o3de
     NAMESPACE AZ
     AUTOMOC
-    AUTOUIC
     AUTORCC
     FILES_CMAKE
         project_manager_files.cmake

+ 12 - 0
Code/Tools/ProjectManager/Resources/ProjectManager.qss

@@ -232,6 +232,18 @@ QTabBar::tab:pressed
     margin-left:30px;
 }
 
+#projectSettingsTab::tab-bar {
+    left: 60px;
+}
+
+#projectSettingsTabBar::tab {
+    height:50px;
+}
+
+#projectSettingsTopFrame {
+    background-color:#1E252F;
+}
+
 /************** Projects **************/
 #firstTimeContent > #titleLabel {
     font-size:60px;

+ 40 - 122
Code/Tools/ProjectManager/Source/NewProjectSettingsScreen.cpp

@@ -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);
-
-        // 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);
-
-        // you cannot remove content margins in qss
-        vLayout->setContentsMargins(0,0,0,0);
-        vLayout->setAlignment(Qt::AlignTop);
+        const QString defaultName{ "NewProject" };
+        const QString defaultPath = QDir::toNativeSeparators(GetDefaultProjectPath() + "/" + defaultName);
+
+        m_projectName->lineEdit()->setText(defaultName);
+        m_projectPath->lineEdit()->setText(defaultPath);
+
+        // 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);
-
-            m_projectName = new FormLineEditWidget(tr("Project name"), defaultName, this);
-            connect(m_projectName->lineEdit(), &QLineEdit::textChanged, this, &NewProjectSettingsScreen::ValidateProjectPath);
-            vLayout->addWidget(m_projectName);
-
-            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);
-
-            // 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);
+            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())
             {
-                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);
                 }
+
+                m_projectTemplateButtonGroup->buttons().first()->setChecked(true);
             }
-            projectTemplateWidget->setLayout(containerLayout);
-            vLayout->addWidget(projectTemplateWidget);
         }
-        projectSettingsFrame->setLayout(vLayout);
-
-        hLayout->addWidget(projectSettingsFrame);
+        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

+ 2 - 15
Code/Tools/ProjectManager/Source/NewProjectSettingsScreen.h

@@ -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;
     };
 

+ 0 - 10
Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp

@@ -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)

+ 0 - 2
Code/Tools/ProjectManager/Source/ProjectButtonWidget.h

@@ -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;

+ 13 - 0
Code/Tools/ProjectManager/Source/ProjectInfo.cpp

@@ -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();

+ 2 - 0
Code/Tools/ProjectManager/Source/ProjectInfo.h

@@ -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;
 

+ 102 - 16
Code/Tools/ProjectManager/Source/ProjectSettingsScreen.cpp

@@ -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;
     }
 
-    ProjectInfo ProjectSettingsScreen::GetProjectInfo()
+    QString ProjectSettingsScreen::GetDefaultProjectPath()
     {
-        // Impl pending next PR
-        return ProjectInfo();
+        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;
     }
 
-    void ProjectSettingsScreen::SetProjectInfo()
+    ProjectInfo ProjectSettingsScreen::GetProjectInfo()
     {
-        // Impl pending next PR
+        ProjectInfo projectInfo;
+        projectInfo.m_projectName = m_projectName->lineEdit()->text();
+        projectInfo.m_path = m_projectPath->lineEdit()->text();
+        return projectInfo;
     }
 
-    bool ProjectSettingsScreen::Validate()
+    bool ProjectSettingsScreen::ValidateProjectName()
     {
-        // Impl pending next PR
-        return true;
-    }
+        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"));
+            }
+        }
 
-    void ProjectSettingsScreen::HandleGemsButton()
+        m_projectName->setErrorLabelVisible(!projectNameIsValid);
+        return projectNameIsValid;
+    }
+    bool ProjectSettingsScreen::ValidateProjectPath()
     {
-        emit ChangeScreenRequest(ProjectManagerScreen::GemCatalog);
+        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()
+    {
+        return ValidateProjectName() && ValidateProjectPath();
+    }
 } // namespace O3DE::ProjectManager

+ 15 - 9
Code/Tools/ProjectManager/Source/ProjectSettingsScreen.h

@@ -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();
+
+    protected:
+        QString GetDefaultProjectPath();
 
-    private:
-        QScopedPointer<Ui::ProjectSettingsClass> m_ui;
+        QHBoxLayout* m_horizontalLayout;
+        QVBoxLayout* m_verticalLayout;
+        FormLineEditWidget* m_projectName;
+        FormBrowseEditWidget* m_projectPath;
     };
 
 } // namespace O3DE::ProjectManager

+ 0 - 113
Code/Tools/ProjectManager/Source/ProjectSettingsScreen.ui

@@ -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>

+ 0 - 10
Code/Tools/ProjectManager/Source/ProjectsScreen.cpp

@@ -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

+ 0 - 1
Code/Tools/ProjectManager/Source/ProjectsScreen.h

@@ -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);

+ 2 - 2
Code/Tools/ProjectManager/Source/ScreenDefs.h

@@ -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}
     };
 

+ 3 - 3
Code/Tools/ProjectManager/Source/ScreenFactory.cpp

@@ -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);

+ 1 - 0
Code/Tools/ProjectManager/Source/ScreensCtrl.cpp

@@ -13,6 +13,7 @@
 #include <ScreensCtrl.h>
 #include <ScreenFactory.h>
 #include <ScreenWidget.h>
+#include <UpdateProjectCtrl.h>
 
 #include <QTabWidget>
 #include <QVBoxLayout>

+ 113 - 78
Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp

@@ -10,16 +10,19 @@
  *
  */
 
-#include <UpdateProjectCtrl.h>
-#include <ScreensCtrl.h>
-#include <PythonBindingsInterface.h>
-#include <ProjectSettingsScreen.h>
 #include <GemCatalog/GemCatalogScreen.h>
+#include <PythonBindingsInterface.h>
+#include <ScreenHeaderWidget.h>
+#include <ScreensCtrl.h>
+#include <UpdateProjectCtrl.h>
+#include <UpdateProjectSettingsScreen.h>
 
 #include <QDialogButtonBox>
-#include <QVBoxLayout>
-#include <QPushButton>
 #include <QMessageBox>
+#include <QPushButton>
+#include <QStackedWidget>
+#include <QTabWidget>
+#include <QVBoxLayout>
 
 namespace O3DE::ProjectManager
 {
@@ -27,32 +30,57 @@ namespace O3DE::ProjectManager
         : ScreenWidget(parent)
     {
         QVBoxLayout* vLayout = new QVBoxLayout();
-        vLayout->setMargin(0);
-        setLayout(vLayout);
+        vLayout->setContentsMargins(0, 0, 0, 0);
+
+        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);
 
-        m_screensCtrl = new ScreensCtrl();
-        vLayout->addWidget(m_screensCtrl);
+        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()
@@ -60,85 +88,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 (*screenOrderIter == screenEnum)
-            {
-                ++screenOrderIter;
-                break;
-            }
-        }
-
-        if (screenEnum == ProjectManagerScreen::ProjectSettings)
+        if (m_stack->currentIndex() == ScreenOrder::Settings)
         {
-            auto projectScreen = reinterpret_cast<ProjectSettingsScreen*>(currentScreen);
-            if (projectScreen)
+            if (m_updateSettingsScreen)
             {
-                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();
 
-                // The next page is the gem catalog. Gather the available gems that will be shown in the gem catalog.
-                auto* gemCatalogScreen = reinterpret_cast<GemCatalogScreen*>(m_screensCtrl->FindScreen(ProjectManagerScreen::GemCatalog));
-                if (gemCatalogScreen)
+                // Update project if settings changed
+                if (m_projectInfo != newProjectSettings)
                 {
-                    gemCatalogScreen->ReinitForProject(m_projectInfo.m_path, /*isNewProject=*/false);
+                    bool result = PythonBindingsInterface::Get()->UpdateProject(newProjectSettings);
+                    if (!result)
+                    {
+                        QMessageBox::critical(this, tr("Project update failed"), tr("Failed to update project."));
+                        return;
+                    }
                 }
-                else
+
+                // Check if project path has changed and move it
+                if (newProjectSettings.m_path != m_projectInfo.m_path)
                 {
-                    QMessageBox::critical(this, tr("Operation failed"), tr("Cannot find gem catalog screen."));
+                    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())
-        {
-            m_screensCtrl->ChangeToScreen(*screenOrderIter);
-            UpdateNextButtonText();
-        }
-        else
+        if (m_stack->currentIndex() == ScreenOrder::Gems && m_gemCatalogScreen)
         {
-            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.
-            auto* gemCatalogScreen = reinterpret_cast<GemCatalogScreen*>(m_screensCtrl->FindScreen(ProjectManagerScreen::GemCatalog));
-            if (gemCatalogScreen)
-            {
-                gemCatalogScreen->EnableDisableGemsForProject(m_projectInfo.m_path);
-            }
-            else
-            {
-                QMessageBox::critical(this, tr("Operation failed"), tr("Cannot find gem catalog screen."));
-            }
+            m_gemCatalogScreen->EnableDisableGemsForProject(m_projectInfo.m_path);
         }
+
+        emit ChangeScreenRequest(ProjectManagerScreen::Projects);
     }
 
     void UpdateProjectCtrl::UpdateCurrentProject(const QString& projectPath)
@@ -148,16 +171,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)
+        {
+            m_header->setSubTitle(QString(tr("Add More Gems to \"%1\"")).arg(m_projectInfo.m_projectName));
+            m_nextButton->setText(tr("Confirm"));
+        }
+        else
         {
-            nextButtonText = tr("Update Project");
+            m_header->setSubTitle(QString(tr("Edit Project Settings: \"%1\"")).arg(m_projectInfo.m_projectName));
+            m_nextButton->setText(tr("Save"));
         }
-        m_nextButton->setText(nextButtonText);
+    }
+
+    void UpdateProjectCtrl::UpdateSettingsScreen()
+    {
+        m_updateSettingsScreen->SetProjectInfo(m_projectInfo);
     }
 
 } // namespace O3DE::ProjectManager

+ 28 - 11
Code/Tools/ProjectManager/Source/UpdateProjectCtrl.h

@@ -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();
+
+        enum ScreenOrder
+        {
+            Settings,
+            Gems
+        };
 
-        ScreensCtrl* m_screensCtrl;
-        QPushButton* m_backButton;
-        QPushButton* m_nextButton;
+        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

+ 51 - 0
Code/Tools/ProjectManager/Source/UpdateProjectSettingsScreen.cpp

@@ -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

+ 34 - 0
Code/Tools/ProjectManager/Source/UpdateProjectSettingsScreen.h

@@ -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

+ 2 - 1
Code/Tools/ProjectManager/project_manager_files.cmake

@@ -38,6 +38,8 @@ set(FILES
     Source/ProjectInfo.cpp
     Source/ProjectUtils.h
     Source/ProjectUtils.cpp
+    Source/UpdateProjectSettingsScreen.h
+    Source/UpdateProjectSettingsScreen.cpp
     Source/NewProjectSettingsScreen.h
     Source/NewProjectSettingsScreen.cpp
     Source/CreateProjectCtrl.h
@@ -48,7 +50,6 @@ set(FILES
     Source/ProjectsScreen.cpp
     Source/ProjectSettingsScreen.h
     Source/ProjectSettingsScreen.cpp
-    Source/ProjectSettingsScreen.ui
     Source/EngineSettingsScreen.h
     Source/EngineSettingsScreen.cpp
     Source/ProjectButtonWidget.h

+ 1 - 1
Code/Tools/SceneAPI/SDKWrapper/AssImpSceneWrapper.cpp

@@ -42,7 +42,7 @@ namespace AZ
         }
 
 #if AZ_TRAIT_COMPILER_SUPPORT_CSIGNAL
-        void signal_handler(int signal) 
+        void signal_handler([[maybe_unused]] int signal) 
         {
             AZ_TracePrintf(
                 SceneAPI::Utilities::ErrorWindow,

+ 3 - 0
cmake/Projects.cmake

@@ -167,6 +167,9 @@ endfunction()
 # Add the projects here so the above function is found
 foreach(project ${LY_PROJECTS})
     file(REAL_PATH ${project} full_directory_path BASE_DIRECTORY ${CMAKE_SOURCE_DIR})
+    if(NOT LY_FIRST_PROJECT)
+        ly_set(LY_FIRST_PROJECT_PATH ${full_directory_path})
+    endif()
     string(SHA256 full_directory_hash ${full_directory_path})
 
     # Truncate the full_directory_hash down to 8 characters to avoid hitting the Windows 260 character path limit