소스 검색

Add Create a gem UI without functionality

Signed-off-by: AMZN-Phil <[email protected]>
AMZN-Phil 3 년 전
부모
커밋
598e6faea2

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

@@ -34,6 +34,24 @@ QTabBar::tab {
 QTabBar::tab:text {
 QTabBar::tab:text {
     text-align:left;
     text-align:left;
 }
 }
+
+#createAGemTab QTabBar::tab {
+    background-color: #444444;
+    font-size:16px;
+    min-height:230px;
+    margin: 0px;
+    text-align:left;
+
+}
+
+QTabWidget#createAGemTab::tab-bar {
+    left: 0px;
+}
+
+QTabBar#createAGemTab::tab:text {
+    text-align:left;
+}
+
 QTabWidget::pane {
 QTabWidget::pane {
     background-color: #333333;
     background-color: #333333;
     border:0 none;
     border:0 none;

+ 493 - 0
Code/Tools/ProjectManager/Source/CreateAGemScreen.cpp

@@ -0,0 +1,493 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include <GemCatalog/GemCatalogHeaderWidget.h>
+#include <CreateAGemScreen.h>
+#include <ProjectUtils.h>
+#include <PythonBindingsInterface.h>
+
+#include <QMessageBox>
+#include <QPushButton>
+#include <QStackedWidget>
+#include <QLabel>
+#include <QDialogButtonBox>
+
+
+namespace O3DE::ProjectManager
+{
+    CreateAGemScreen::CreateAGemScreen(QWidget* parent)
+        : ScreenWidget(parent)
+    {
+        QVBoxLayout* vLayout = new QVBoxLayout();
+        vLayout->setSpacing(0);
+        vLayout->setContentsMargins(0, 0, 0, 0);
+
+        m_tabWidget = new TabWidget();
+        
+        m_tabWidget->setObjectName("createAGemTab");
+        m_tabWidget->addTab(CreateFirstScreen(), tr("1. Gem Setup"));
+        m_tabWidget->addTab(CreateSecondScreen(), tr("2. Gem Details"));
+        m_tabWidget->addTab(CreateThirdScreen(), tr("3. Creator Details"));
+        m_tabWidget->tabBar()->setEnabled(false);
+        vLayout->addWidget(m_tabWidget);
+
+        QFrame* footerFrame = new QFrame();
+        footerFrame->setObjectName("createAGemFooter");
+        m_backNextButtons = new QDialogButtonBox();
+        m_backNextButtons->setObjectName("footer");
+        QVBoxLayout* footerLayout = new QVBoxLayout();
+        footerLayout->setContentsMargins(0, 0, 0, 0);
+        footerFrame->setLayout(footerLayout);
+        footerLayout->addWidget(m_backNextButtons);
+        vLayout->addWidget(footerFrame);
+
+        m_backButton = m_backNextButtons->addButton(tr("Back"), QDialogButtonBox::RejectRole);
+        m_backButton->setProperty("secondary", true);
+        m_nextButton = m_backNextButtons->addButton(tr("Next"), QDialogButtonBox::ApplyRole);
+
+        connect(m_tabWidget, &TabWidget::currentChanged, this, &CreateAGemScreen::UpdateNextButtonToCreate);
+        connect(m_backButton, &QPushButton::clicked, this, &CreateAGemScreen::HandleBackButton);
+        connect(m_nextButton, &QPushButton::clicked, this, &CreateAGemScreen::HandleNextButton);
+
+        setObjectName("createAGemBody");
+        setLayout(vLayout);
+    }
+
+    void CreateAGemScreen::LoadButtonsFromGemTemplatePaths([[maybe_unused]]QVBoxLayout* firstScreen)
+    {
+        QHash<QString, QString> formattedNames;
+        formattedNames.insert(QString("Prebuilt Gem Tenokate"), QString(tr("Prebuilt Gem")));
+        formattedNames.insert(QString("Asset Gem Template"), QString(tr("Asset Gem")));
+        formattedNames.insert(QString("Default Gem Template"), QString(tr("Default Gem")));
+        formattedNames.insert(QString("CppToolGem"), QString(tr("C++ Tool Gem")));
+        formattedNames.insert(QString("PythonToolGem"), QString(tr("Python Tool Gem")));
+
+        m_radioButtonGroup = new QButtonGroup();
+    }
+
+    QScrollArea* CreateAGemScreen::CreateFirstScreen()
+    {
+        QScrollArea* firstScreenScrollArea = new QScrollArea();
+        firstScreenScrollArea->setWidgetResizable(true);
+        firstScreenScrollArea->setMinimumWidth(660);
+        firstScreenScrollArea->setObjectName("createAGemRightPane");
+        QFrame* firstScreenFrame = new QFrame();
+
+        QWidget* firstScreenScrollWidget = new QWidget();
+        firstScreenScrollArea->setWidget(firstScreenScrollWidget);
+
+        QVBoxLayout* firstScreen = new QVBoxLayout();
+        firstScreen->setAlignment(Qt::AlignTop);
+        firstScreen->addWidget(firstScreenFrame);
+        firstScreenScrollWidget->setLayout(firstScreen);
+        QLabel* rightPaneHeader = new QLabel();
+        rightPaneHeader->setObjectName("rightPaneHeader");
+        rightPaneHeader->setText(tr("Please Choose a Gem Template"));
+        QLabel* rightPaneSubheader = new QLabel();
+        rightPaneSubheader->setObjectName("rightPaneSubheader");
+        rightPaneSubheader->setText(tr("Gems can contain assets such as scripts, animations, meshes, textures, and more."));
+        firstScreen->addWidget(rightPaneHeader);
+        firstScreen->addWidget(rightPaneSubheader);
+
+        LoadButtonsFromGemTemplatePaths(firstScreen);
+        m_formFolderRadioButton = new QRadioButton("Choose existing template");
+        m_formFolderRadioButton->setObjectName("createAGem");
+        m_radioButtonGroup->addButton(m_formFolderRadioButton);
+
+        m_gemTemplateLocation = new FormFolderBrowseEditWidget(tr("Gem Template Location*"), "");
+
+        firstScreen->addWidget(m_formFolderRadioButton);
+        firstScreen->addWidget(m_gemTemplateLocation);
+
+        return firstScreenScrollArea;
+    }
+
+    QScrollArea* CreateAGemScreen::CreateSecondScreen()
+    {
+        QScrollArea* secondScreenScrollArea = new QScrollArea();
+        secondScreenScrollArea->setWidgetResizable(true);
+        secondScreenScrollArea->setMinimumWidth(660);
+        secondScreenScrollArea->setObjectName("createAGemRightPane");
+        QFrame* secondScreenFrame = new QFrame();
+
+        QWidget* secondScreenScrollWidget = new QWidget();
+        secondScreenScrollArea->setWidget(secondScreenScrollWidget);
+
+        QVBoxLayout* secondScreen = new QVBoxLayout();
+        secondScreen->setAlignment(Qt::AlignTop);
+        secondScreen->addWidget(secondScreenFrame);
+        secondScreenScrollWidget->setLayout(secondScreen);
+
+        QLabel* secondRightPaneHeader = new QLabel();
+        secondRightPaneHeader->setObjectName("rightPaneHeader");
+        secondRightPaneHeader->setText(tr("Enter Gem Details"));
+        secondScreen->addWidget(secondRightPaneHeader);
+
+        m_gemDisplayName = new FormLineEditWidget(tr("Gem Display name*"), "");
+        QLineEdit* gemDisplayLineEdit = m_gemDisplayName->lineEdit();
+        gemDisplayLineEdit->setPlaceholderText(tr("The name displayed on the Gem Catalog"));
+        secondScreen->addWidget(m_gemDisplayName);
+
+        m_gemSystemName = new FormLineEditWidget(tr("Gem System name*"), "");
+        QLineEdit* gemSystemLineEdit = m_gemSystemName->lineEdit();
+        gemSystemLineEdit->setPlaceholderText(tr("The name used in the O3DE Gem System"));
+        secondScreen->addWidget(m_gemSystemName);
+
+        m_gemSummary = new FormLineEditWidget(tr("Gem Summary"), "");
+        QLineEdit* gemSummaryLineEdit = m_gemSummary->lineEdit();
+        gemSummaryLineEdit->setPlaceholderText(tr("A short description of your Gem"));
+        secondScreen->addWidget(m_gemSummary);
+
+        m_requirements = new FormLineEditWidget(tr("Requirements"), "");
+        QLineEdit* requirementsLineEdit = m_requirements->lineEdit();
+        requirementsLineEdit->setPlaceholderText(tr("Notice of any requirements your Gem. i.e. This requires X other gem"));
+        secondScreen->addWidget(m_requirements);
+
+        m_license = new FormLineEditWidget(tr("License*"), "");
+        QLineEdit* licenseLineEdit = m_license->lineEdit();
+        licenseLineEdit->setPlaceholderText(tr("License uses goes here: i.e. Apache-2.0 or MIT"));
+        secondScreen->addWidget(m_license);
+
+        m_licenseURL = new FormLineEditWidget(tr("License URL"), "");
+        QLineEdit* licenseURLLineEdit = m_licenseURL->lineEdit();
+        licenseURLLineEdit->setPlaceholderText(tr("Link to the license web site i.e. https://opensource.org/licenses/Apache-2.0"));
+        secondScreen->addWidget(m_licenseURL);
+
+        m_origin = new FormLineEditWidget(tr("Origin"), "");
+        QLineEdit* originLineEdit = m_origin->lineEdit();
+        originLineEdit->setPlaceholderText(tr("The name of the originator goes. i.e. XYZ Inc."));
+        secondScreen->addWidget(m_origin);
+
+        m_originURL = new FormLineEditWidget(tr("Origin URL"), "");
+        QLineEdit* originURLLineEdit = m_originURL->lineEdit();
+        originURLLineEdit->setPlaceholderText(tr("The primary repo for your Gem. i.e. http://www.mydomain.com"));
+        secondScreen->addWidget(m_originURL);
+
+        m_firstDropdown = new FormComboBoxWidget(tr("Global Gem Tag*"));
+        AddDropdownActions(m_firstDropdown);
+        secondScreen->addWidget(m_firstDropdown);
+
+        m_secondDropdown = new FormComboBoxWidget(tr("Optional Global Gem Tag"));
+        AddDropdownActions(m_secondDropdown);
+        secondScreen->addWidget(m_secondDropdown);
+
+        m_thirdDropdown = new FormComboBoxWidget(tr("Optional Global Gem Tag"));
+        AddDropdownActions(m_thirdDropdown);
+        secondScreen->addWidget(m_thirdDropdown);
+
+        m_userDefinedGemTags = new FormLineEditWidget(tr("User-defined Gem Tags (Comma separated list)"), "");
+        secondScreen->addWidget(m_userDefinedGemTags);
+
+        m_gemLocation = new FormFolderBrowseEditWidget(tr("Gem Location"), "");
+        QLineEdit* gemLocationLineEdit = m_gemLocation->lineEdit();
+        const char* gemLocationPlaceholderText = R"(C:\O3DE\Project\Gems\YourGem)";
+        gemLocationLineEdit->setPlaceholderText(tr(gemLocationPlaceholderText));
+        secondScreen->addWidget(m_gemLocation);
+        
+        m_gemIconPath = new FormFolderBrowseEditWidget(tr("Gem Icon Path"), "");
+        QLineEdit* gemIconPathLineEdit = m_gemIconPath->lineEdit();
+        gemIconPathLineEdit->setPlaceholderText(tr("Select Gem icon path"));
+        secondScreen->addWidget(m_gemIconPath);
+
+        m_documentationURL = new FormLineEditWidget(tr("Documentation URL"), "");
+        QLineEdit* documentationURLLineEdit = m_documentationURL->lineEdit();
+        documentationURLLineEdit->setPlaceholderText(tr("Link to any documentation of your Gem i.e. https://o3de.org/docs/user-guide/gems/..."));
+        secondScreen->addWidget(m_documentationURL);
+
+        return secondScreenScrollArea;
+    }
+
+    QScrollArea* CreateAGemScreen::CreateThirdScreen()
+    {
+        QScrollArea* thirdScreenScrollArea = new QScrollArea();
+        thirdScreenScrollArea->setWidgetResizable(true);
+        thirdScreenScrollArea->setMinimumWidth(660);
+        thirdScreenScrollArea->setObjectName("createAGemRightPane");
+        QFrame* thirdScreenFrame = new QFrame();
+
+        QWidget* thirdScreenScrollWidget = new QWidget();
+        thirdScreenScrollArea->setWidget(thirdScreenScrollWidget);
+
+        QVBoxLayout* thirdScreen = new QVBoxLayout();
+        thirdScreen->setAlignment(Qt::AlignTop);
+        thirdScreen->addWidget(thirdScreenFrame);
+        thirdScreenScrollWidget->setLayout(thirdScreen);
+
+        QLabel* thirdRightPaneHeader = new QLabel(this);
+        thirdRightPaneHeader->setObjectName("rightPaneHeader");
+        thirdRightPaneHeader->setText(tr("Enter your Details"));
+        thirdScreen->addWidget(thirdRightPaneHeader);
+
+        m_creatorName = new FormLineEditWidget(tr("Creator Name*"), "", this);
+        QLineEdit* creatorNameLineEdit = m_creatorName->lineEdit();
+        creatorNameLineEdit->setPlaceholderText(tr("John Smith"));
+        thirdScreen->addWidget(m_creatorName);
+
+        m_repositoryURL = new FormLineEditWidget(tr("Repository URL*"), "", this);
+        QLineEdit* repositoryURLLineEdit = m_repositoryURL->lineEdit();
+        repositoryURLLineEdit->setPlaceholderText(tr("https://github.com/Jane"));
+        thirdScreen->addWidget(m_repositoryURL);
+
+        return thirdScreenScrollArea;
+    }
+
+    bool CreateAGemScreen::ValidateGemTemplateLocation()
+    {
+        bool gemTemplateLocationFilled = true;
+        if (m_formFolderRadioButton->isChecked())
+        {
+            if (m_gemTemplateLocation->lineEdit()->text().isEmpty())
+            {
+                gemTemplateLocationFilled = false;
+                m_gemTemplateLocation->setErrorLabelText(tr("A path must be provided."));
+            }
+
+        }
+        m_gemTemplateLocation->setErrorLabelVisible(!gemTemplateLocationFilled);
+        return gemTemplateLocationFilled;
+    }
+
+    bool CreateAGemScreen::ValidateGemDisplayName()
+    {
+        bool gemScreenNameIsValid = true;
+        if (m_gemDisplayName->lineEdit()->text().isEmpty())
+        {
+            gemScreenNameIsValid = false;
+            m_gemDisplayName->setErrorLabelText(tr("A gem display name is required."));
+        }
+        m_gemDisplayName->setErrorLabelVisible(!gemScreenNameIsValid);
+        return gemScreenNameIsValid;
+    }
+
+    bool CreateAGemScreen::ValidateGemSystemName()
+    {
+        bool gemSystemNameIsValid = true;
+        if (m_gemSystemName->lineEdit()->text().isEmpty())
+        {
+            gemSystemNameIsValid = false;
+            m_gemSystemName->setErrorLabelText(tr("A gem system name is required."));
+        }
+        else
+        {
+            std::string gemSystemName = m_gemSystemName->lineEdit()->text().toStdString();
+            _int64 count = std::count_if(
+                gemSystemName.begin(),
+                gemSystemName.end(),
+                [](char c)
+                {
+                    return !(std::isalnum(c));
+                });
+            if (count > 0)
+            {
+                gemSystemNameIsValid = false;
+                m_gemSystemName->setErrorLabelText(tr("A gem system name can only contain alphanumeric characters."));
+            }
+        }
+        m_gemSystemName->setErrorLabelVisible(!gemSystemNameIsValid);
+        return gemSystemNameIsValid;
+    }
+
+    bool CreateAGemScreen::ValidateLicenseName()
+    {
+        bool licenseNameIsValid = true;
+        if (m_license->lineEdit()->text().isEmpty())
+        {
+            licenseNameIsValid = false;
+            m_license->setErrorLabelText(tr("License details are required."));
+        }
+
+        m_license->setErrorLabelVisible(!licenseNameIsValid);
+        return licenseNameIsValid;
+    }
+
+    bool CreateAGemScreen::ValidateGlobalGemTag()
+    {
+        bool globalGemTagIsValid = true;
+        if (m_firstDropdown->comboBox()->currentIndex() == 0)
+        {
+            globalGemTagIsValid = false;
+            m_firstDropdown->setErrorLabelText(tr("At least one global gem tag is required."));
+        }
+        m_firstDropdown->setErrorLabelVisible(!globalGemTagIsValid);
+        return globalGemTagIsValid;
+    }
+
+    bool CreateAGemScreen::ValidateOptionalGemTags()
+    {
+        bool firstOptionalGemTagIsValid = true;
+        bool secondOptionalGemTagIsValid = true;
+        if (m_secondDropdown->comboBox()->currentIndex() != 0 && m_secondDropdown->comboBox()->currentIndex() ==
+            m_firstDropdown->comboBox()->currentIndex())
+        {
+            firstOptionalGemTagIsValid = false;
+            m_secondDropdown->setErrorLabelText(tr("This gem has already been selected"));
+        }
+
+        if (m_thirdDropdown->comboBox()->currentIndex() != 0 && (m_thirdDropdown->comboBox()->currentIndex() == m_secondDropdown->comboBox()->currentIndex() ||
+            m_thirdDropdown->comboBox()->currentIndex() == m_firstDropdown->comboBox()->currentIndex()))
+        {
+            secondOptionalGemTagIsValid = false;
+            m_thirdDropdown->setErrorLabelText(tr("This gem has already been selected"));
+        }
+
+        m_secondDropdown->setErrorLabelVisible(!firstOptionalGemTagIsValid);
+        m_thirdDropdown->setErrorLabelVisible(!secondOptionalGemTagIsValid);
+        return firstOptionalGemTagIsValid && secondOptionalGemTagIsValid;
+    }
+
+
+    bool CreateAGemScreen::ValidateCreatorName()
+    {
+        bool creatorNameIsValid = true;
+        if (m_creatorName->lineEdit()->text().isEmpty())
+        {
+            creatorNameIsValid = false;
+            m_creatorName->setErrorLabelText(tr("A creator's name is required."));
+        }
+        m_creatorName->setErrorLabelVisible(!creatorNameIsValid);
+        return creatorNameIsValid;
+    }
+
+    bool CreateAGemScreen::ValidateRepositoryURL()
+    {
+        bool repositoryURLIsValid = true;
+        if (m_repositoryURL->lineEdit()->text().isEmpty())
+        {
+            repositoryURLIsValid = false;
+            m_repositoryURL->setErrorLabelText(tr("A repository URL is required."));
+        }
+        m_repositoryURL->setErrorLabelVisible(!repositoryURLIsValid);
+        return repositoryURLIsValid;
+    }
+
+    void CreateAGemScreen::HandleBackButton()
+    {
+        if (m_tabWidget->currentIndex() == 2)
+        {
+            m_tabWidget->setCurrentIndex(1);
+            m_nextButton->setText(tr("Next"));
+        }
+        else if (m_tabWidget->currentIndex() == 1)
+        {
+            m_backButton->setVisible(false);
+            m_tabWidget->setCurrentIndex(0);
+        }
+        else if (m_tabWidget->currentIndex() == 0)
+        {
+            m_backButton->setVisible(false);
+        }
+    }
+
+    void CreateAGemScreen::HandleNextButton()
+    {
+        if (m_tabWidget->currentIndex() == 0)
+        {
+            bool templateLocationIsValid = ValidateGemTemplateLocation();
+            if (!m_formFolderRadioButton->isChecked())
+            {
+                m_backButton->setVisible(true);
+                m_tabWidget->setCurrentIndex(1);
+            }
+            else if (templateLocationIsValid && m_formFolderRadioButton->isChecked())
+            {
+                m_backButton->setVisible(true);
+                m_tabWidget->setCurrentIndex(1);
+            }
+        }
+        else if (m_tabWidget->currentIndex() == 1)
+        {
+            bool displayNameIsValid = ValidateGemDisplayName();
+            bool systemNameIsValid = ValidateGemSystemName();
+            bool licenseNameIsValid = ValidateLicenseName();
+            bool globalGemTagIsValid = ValidateGlobalGemTag();
+            bool optionalGemTagsAreValid = ValidateOptionalGemTags();
+            if (systemNameIsValid && licenseNameIsValid && globalGemTagIsValid && displayNameIsValid && optionalGemTagsAreValid)
+            {
+                m_createAGemInfo.m_displayName = m_gemDisplayName->lineEdit()->text();
+                m_createAGemInfo.m_name = m_gemSystemName->lineEdit()->text();
+                m_createAGemInfo.m_summary = m_gemSummary->lineEdit()->text();
+                m_createAGemInfo.m_requirement = m_requirements->lineEdit()->text();
+                m_createAGemInfo.m_licenseText = m_license->lineEdit()->text();
+                m_createAGemInfo.m_licenseLink = m_licenseURL->lineEdit()->text();
+                m_createAGemInfo.m_licenseText = m_license->lineEdit()->text();
+                m_createAGemInfo.m_documentationLink = m_documentationURL->lineEdit()->text();
+                m_createAGemInfo.m_path = m_gemLocation->lineEdit()->text();
+
+                m_tabWidget->setCurrentIndex(2);
+                m_nextButton->setText(tr("Create"));
+
+            }
+        }
+        else if (m_tabWidget->currentIndex() == 2)
+        {
+            bool creatorNameIsValid = ValidateCreatorName();
+            bool repoURLIsValid = ValidateRepositoryURL();
+            if (creatorNameIsValid && repoURLIsValid)
+            {
+                m_createAGemInfo.m_creator = m_creatorName->lineEdit()->text();
+                m_createAGemInfo.m_repoUri = m_repositoryURL->lineEdit()->text();
+                //auto result = PythonBindingsInterface::Get()->CreateGem(m_createAGemInfo);
+                emit CreateButtonPressed();
+            }
+        }
+    }
+
+    void CreateAGemScreen::UpdateNextButtonToCreate()
+    {
+        if (m_tabWidget->currentIndex() == 2)
+        {
+            m_nextButton->setText(tr("Create"));
+        }
+        else
+        {
+            m_nextButton->setText(tr("Next"));
+        }
+    }
+
+    void CreateAGemScreen::AddDropdownActions(FormComboBoxWidget* dropdown)
+    {
+        QComboBox* comboBox = dropdown->comboBox();
+        comboBox->addItem(tr(""));
+        comboBox->addItem(tr("Achievements"));
+        comboBox->addItem(tr("Animation"));
+        comboBox->addItem(tr("Assets"));
+        comboBox->addItem(tr("Audio"));
+        comboBox->addItem(tr("Barrier"));
+        comboBox->addItem(tr("Content"));
+        comboBox->addItem(tr("Core"));
+        comboBox->addItem(tr("Creation"));
+        comboBox->addItem(tr("DCC"));
+        comboBox->addItem(tr("Debug"));
+        comboBox->addItem(tr("Design"));
+        comboBox->addItem(tr("Digital"));
+        comboBox->addItem(tr("Editor"));
+        comboBox->addItem(tr("Environment"));
+        comboBox->addItem(tr("Framework"));
+        comboBox->addItem(tr("Gameplay"));
+        comboBox->addItem(tr("Input"));
+        comboBox->addItem(tr("Materials"));
+        comboBox->addItem(tr("Multiplayer"));
+        comboBox->addItem(tr("Network"));
+        comboBox->addItem(tr("PBR"));
+        comboBox->addItem(tr("Physics"));
+        comboBox->addItem(tr("Profiler"));
+        comboBox->addItem(tr("Rendering"));
+        comboBox->addItem(tr("SDK"));
+        comboBox->addItem(tr("Sample"));
+        comboBox->addItem(tr("Scripting"));
+        comboBox->addItem(tr("Simulation"));
+        comboBox->addItem(tr("Slices"));
+        comboBox->addItem(tr("Synergy"));
+        comboBox->addItem(tr("Terrain"));
+        comboBox->addItem(tr("Tools"));
+        comboBox->addItem(tr("UI"));
+        comboBox->addItem(tr("Unity"));
+    }
+
+} // namespace O3DE::ProjectManager
+

+ 160 - 0
Code/Tools/ProjectManager/Source/CreateAGemScreen.h

@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#pragma once
+
+#if !defined(Q_MOC_RUN)
+#include <ScreenWidget.h>
+#include <FormFolderBrowseEditWidget.h>
+#include <FormLineEditWidget.h>
+#include <FormComboBoxWidget.h>
+#include <GemCatalog/GemInfo.h>
+#include <PythonBindings.h>
+
+#include <QHash>
+#include <QApplication>
+#include <QStyleOptionTab>
+#include <QStylePainter>
+#include <QTabBar>
+#include <QTabWidget>
+#include <QButtonGroup>
+#include <QDialogButtonBox>
+#include <QRadioButton>
+#include <QPushButton>
+#include <QScrollArea>
+#include <QComboBox>
+#include <QVBoxLayout>
+#endif
+
+//#define CREATE_A_GAME_ACTIVE
+
+namespace O3DE::ProjectManager
+{
+    class TabBar : public QTabBar
+    {
+    public:
+        QSize tabSizeHint(int index) const
+        {
+            QSize s = QTabBar::tabSizeHint(index);
+            s.transpose();
+            return s;
+        }
+
+    protected:
+        void paintEvent(QPaintEvent*)
+        {
+            QStylePainter painter(this);
+            QStyleOptionTab opt;
+
+            QPoint currentTopPosition(115, 175);
+
+            QStringList strs = { "1. Gem Setup", "2. Gem Details", "3. Creator Details" };
+            for (int i = 0; i < count(); i++)
+            {
+                initStyleOption(&opt, i);
+                painter.drawControl(QStyle::CE_TabBarTabShape, opt);
+                painter.save();
+                QSize s = opt.rect.size();
+                s.transpose();
+                s.setWidth(130);
+                QRect r(QPoint(), s);
+                r.moveCenter(opt.rect.center());
+                opt.rect = r;
+                QPoint c = tabRect(i).center();
+                QPoint leftJustify(currentTopPosition);
+                leftJustify.setX(30 + (int)(0.5 * opt.rect.width()));
+                painter.translate(leftJustify);
+                currentTopPosition.setY(currentTopPosition.y() + 55);
+                painter.setFont(QFont("Open Sans", 12));
+                painter.translate(-c);
+                painter.drawItemText(r, Qt::AlignLeft, QApplication::palette(), true, strs.at(i));
+                painter.restore();
+            }
+        }
+    };
+
+    class TabWidget : public QTabWidget
+    {
+    public:
+        TabWidget(QWidget* parent = 0)
+            : QTabWidget(parent)
+        {
+            setTabBar(new TabBar);
+            setTabPosition(QTabWidget::West);
+        }
+    };
+
+    class CreateAGemScreen : public ScreenWidget
+    {
+        Q_OBJECT
+    public:
+        explicit CreateAGemScreen(QWidget* parent = nullptr);
+        ~CreateAGemScreen() = default;
+
+    signals:
+        void CreateButtonPressed();
+
+    private slots:
+        void HandleBackButton();
+        void HandleNextButton();
+        void UpdateNextButtonToCreate();
+
+    private:
+        void LoadButtonsFromGemTemplatePaths(QVBoxLayout* firstScreen);
+        QScrollArea* CreateFirstScreen();
+        QScrollArea* CreateSecondScreen();
+        QScrollArea* CreateThirdScreen();
+        bool ValidateGemTemplateLocation();
+        bool ValidateGemDisplayName();
+        bool ValidateGemSystemName();
+        bool ValidateLicenseName();
+        bool ValidateGlobalGemTag();
+        bool ValidateOptionalGemTags();
+        bool ValidateCreatorName();
+        bool ValidateRepositoryURL();
+        void AddDropdownActions(FormComboBoxWidget* dropdown);
+
+        //First Screen
+        QVector<ProjectTemplateInfo> m_gemTemplates;
+        QButtonGroup* m_radioButtonGroup;
+        QRadioButton* m_formFolderRadioButton = nullptr;
+        FormFolderBrowseEditWidget* m_gemTemplateLocation = nullptr;
+
+        //Second Screen
+        FormLineEditWidget* m_gemDisplayName = nullptr;
+        FormLineEditWidget* m_gemSystemName = nullptr;
+        FormLineEditWidget* m_gemSummary = nullptr;
+        FormLineEditWidget* m_requirements = nullptr;
+        FormLineEditWidget* m_license = nullptr;
+        FormLineEditWidget* m_licenseURL = nullptr;
+        FormLineEditWidget* m_origin = nullptr;
+        FormLineEditWidget* m_originURL = nullptr;
+        FormLineEditWidget* m_userDefinedGemTags = nullptr;
+        FormFolderBrowseEditWidget* m_gemLocation = nullptr;
+        FormComboBoxWidget* m_firstDropdown = nullptr;
+        FormComboBoxWidget* m_secondDropdown = nullptr;
+        FormComboBoxWidget* m_thirdDropdown = nullptr;
+        FormFolderBrowseEditWidget* m_gemIconPath = nullptr;
+        FormLineEditWidget* m_documentationURL = nullptr;
+
+        //Third Screen
+        FormLineEditWidget* m_creatorName = nullptr;
+        FormLineEditWidget* m_repositoryURL = nullptr;
+        
+
+        TabWidget* m_tabWidget;
+
+        QDialogButtonBox* m_backNextButtons = nullptr;
+        QPushButton* m_backButton = nullptr;
+        QPushButton* m_nextButton = nullptr;
+
+        GemInfo m_createAGemInfo;
+    };
+
+
+} // namespace O3DE::ProjectManager

+ 3 - 0
Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp

@@ -523,6 +523,9 @@ namespace O3DE::ProjectManager
         gemMenu->addAction( tr("Show Gem Repos"), [this]() { emit OpenGemsRepo(); });
         gemMenu->addAction( tr("Show Gem Repos"), [this]() { emit OpenGemsRepo(); });
         gemMenu->addSeparator();
         gemMenu->addSeparator();
         gemMenu->addAction( tr("Add Existing Gem"), [this]() { emit AddGem(); });
         gemMenu->addAction( tr("Add Existing Gem"), [this]() { emit AddGem(); });
+#ifdef CREATE_A_GAME_ACTIVE
+        gemMenu->addAction( tr("Create a new Gem.."), [this]() { emit CreateANewGem(); });
+#endif
 
 
         QPushButton* gemMenuButton = new QPushButton(this);
         QPushButton* gemMenuButton = new QPushButton(this);
         gemMenuButton->setObjectName("gemCatalogMenuButton");
         gemMenuButton->setObjectName("gemCatalogMenuButton");

+ 1 - 0
Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.h

@@ -108,6 +108,7 @@ namespace O3DE::ProjectManager
 
 
     signals:
     signals:
         void AddGem();
         void AddGem();
+        void CreateANewGem();
         void OpenGemsRepo();
         void OpenGemsRepo();
         void RefreshGems();
         void RefreshGems();
         void UpdateGemCart(QWidget* gemCart);
         void UpdateGemCart(QWidget* gemCart);

+ 8 - 0
Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp

@@ -67,6 +67,7 @@ namespace O3DE::ProjectManager
         connect(m_gemModel->GetSelectionModel(), &QItemSelectionModel::selectionChanged, this, [this]{ ShowInspector(); });
         connect(m_gemModel->GetSelectionModel(), &QItemSelectionModel::selectionChanged, this, [this]{ ShowInspector(); });
         connect(m_headerWidget, &GemCatalogHeaderWidget::RefreshGems, this, &GemCatalogScreen::Refresh);
         connect(m_headerWidget, &GemCatalogHeaderWidget::RefreshGems, this, &GemCatalogScreen::Refresh);
         connect(m_headerWidget, &GemCatalogHeaderWidget::OpenGemsRepo, this, &GemCatalogScreen::HandleOpenGemRepo);
         connect(m_headerWidget, &GemCatalogHeaderWidget::OpenGemsRepo, this, &GemCatalogScreen::HandleOpenGemRepo);
+        connect(m_headerWidget, &GemCatalogHeaderWidget::CreateANewGem, this, &GemCatalogScreen::HandleCreateAGem);
         connect(m_headerWidget, &GemCatalogHeaderWidget::AddGem, this, &GemCatalogScreen::OnAddGemClicked);
         connect(m_headerWidget, &GemCatalogHeaderWidget::AddGem, this, &GemCatalogScreen::OnAddGemClicked);
         connect(m_headerWidget, &GemCatalogHeaderWidget::UpdateGemCart, this, &GemCatalogScreen::UpdateAndShowGemCart);
         connect(m_headerWidget, &GemCatalogHeaderWidget::UpdateGemCart, this, &GemCatalogScreen::UpdateAndShowGemCart);
         connect(m_downloadController, &DownloadController::Done, this, &GemCatalogScreen::OnGemDownloadResult);
         connect(m_downloadController, &DownloadController::Done, this, &GemCatalogScreen::OnGemDownloadResult);
@@ -608,6 +609,13 @@ namespace O3DE::ProjectManager
         }
         }
     }
     }
 
 
+    void GemCatalogScreen::HandleCreateAGem()
+    {
+#ifdef CREATE_A_GAME_ACTIVE
+        emit ChangeScreenRequest(ProjectManagerScreen::CreateAGem);
+#endif
+    }
+
     void GemCatalogScreen::UpdateAndShowGemCart(QWidget* cartWidget)
     void GemCatalogScreen::UpdateAndShowGemCart(QWidget* cartWidget)
     {
     {
         QWidget* previousCart = m_rightPanelStack->widget(RightPanelWidgetOrder::Cart);
         QWidget* previousCart = m_rightPanelStack->widget(RightPanelWidgetOrder::Cart);

+ 1 - 0
Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h

@@ -68,6 +68,7 @@ namespace O3DE::ProjectManager
 
 
     private slots:
     private slots:
         void HandleOpenGemRepo();
         void HandleOpenGemRepo();
+        void HandleCreateAGem();
         void UpdateAndShowGemCart(QWidget* cartWidget);
         void UpdateAndShowGemCart(QWidget* cartWidget);
         void ShowInspector();
         void ShowInspector();
 
 

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

@@ -27,7 +27,10 @@ namespace O3DE::ProjectManager
         Engine,
         Engine,
         EngineSettings,
         EngineSettings,
         GemRepos,
         GemRepos,
-        GemsGemRepos
+        GemsGemRepos,
+#ifdef CREATE_A_GAME_ACTIVE
+        CreateAGem
+#endif
     };
     };
 
 
     static QHash<QString, ProjectManagerScreen> s_ProjectManagerStringNames = {
     static QHash<QString, ProjectManagerScreen> s_ProjectManagerStringNames = {
@@ -42,7 +45,10 @@ namespace O3DE::ProjectManager
         { "Engine", ProjectManagerScreen::Engine},
         { "Engine", ProjectManagerScreen::Engine},
         { "EngineSettings", ProjectManagerScreen::EngineSettings},
         { "EngineSettings", ProjectManagerScreen::EngineSettings},
         { "GemRepos", ProjectManagerScreen::GemRepos},
         { "GemRepos", ProjectManagerScreen::GemRepos},
-        { "GemsGemRepos", ProjectManagerScreen::GemsGemRepos}
+        { "GemsGemRepos", ProjectManagerScreen::GemsGemRepos},
+#ifdef CREATE_A_GAME_ACTIVE
+        { "CreateAGem", ProjectManagerScreen::CreateAGem }
+#endif
     };
     };
 
 
     // need to define qHash for ProjectManagerScreen when using scoped enums
     // need to define qHash for ProjectManagerScreen when using scoped enums

+ 6 - 0
Code/Tools/ProjectManager/Source/ScreenFactory.cpp

@@ -18,6 +18,7 @@
 #include <EngineScreenCtrl.h>
 #include <EngineScreenCtrl.h>
 #include <EngineSettingsScreen.h>
 #include <EngineSettingsScreen.h>
 #include <GemRepo/GemRepoScreen.h>
 #include <GemRepo/GemRepoScreen.h>
+#include <CreateAGemScreen.h>
 #include <DownloadController.h>
 #include <DownloadController.h>
 
 
 namespace O3DE::ProjectManager
 namespace O3DE::ProjectManager
@@ -61,6 +62,11 @@ namespace O3DE::ProjectManager
         case (ProjectManagerScreen::GemRepos):
         case (ProjectManagerScreen::GemRepos):
             newScreen = new GemRepoScreen(parent);
             newScreen = new GemRepoScreen(parent);
             break;
             break;
+#ifdef CREATE_A_GAME_ACTIVE
+        case (ProjectManagerScreen::CreateAGem):
+            newScreen = new CreateAGemScreen(parent);
+            break;
+#endif
         case (ProjectManagerScreen::Empty):
         case (ProjectManagerScreen::Empty):
         default:
         default:
             newScreen = new ScreenWidget(parent);
             newScreen = new ScreenWidget(parent);

+ 17 - 0
Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp

@@ -8,6 +8,7 @@
 
 
 #include <ProjectGemCatalogScreen.h>
 #include <ProjectGemCatalogScreen.h>
 #include <GemRepo/GemRepoScreen.h>
 #include <GemRepo/GemRepoScreen.h>
+#include <CreateAGemScreen.h>
 #include <ProjectManagerDefs.h>
 #include <ProjectManagerDefs.h>
 #include <PythonBindingsInterface.h>
 #include <PythonBindingsInterface.h>
 #include <ScreenHeaderWidget.h>
 #include <ScreenHeaderWidget.h>
@@ -43,9 +44,15 @@ namespace O3DE::ProjectManager
         m_updateSettingsScreen = new UpdateProjectSettingsScreen();
         m_updateSettingsScreen = new UpdateProjectSettingsScreen();
         m_projectGemCatalogScreen = new ProjectGemCatalogScreen(downloadController);
         m_projectGemCatalogScreen = new ProjectGemCatalogScreen(downloadController);
         m_gemRepoScreen = new GemRepoScreen(this);
         m_gemRepoScreen = new GemRepoScreen(this);
+#ifdef CREATE_A_GAME_ACTIVE
+        m_createAGemScreen = new CreateAGemScreen();
+#endif
 
 
         connect(m_projectGemCatalogScreen, &ScreenWidget::ChangeScreenRequest, this, &UpdateProjectCtrl::OnChangeScreenRequest);
         connect(m_projectGemCatalogScreen, &ScreenWidget::ChangeScreenRequest, this, &UpdateProjectCtrl::OnChangeScreenRequest);
         connect(m_gemRepoScreen, &GemRepoScreen::OnRefresh, m_projectGemCatalogScreen, &ProjectGemCatalogScreen::Refresh);
         connect(m_gemRepoScreen, &GemRepoScreen::OnRefresh, m_projectGemCatalogScreen, &ProjectGemCatalogScreen::Refresh);
+#ifdef CREATE_A_GAME_ACTIVE
+        connect(m_createAGemScreen, &CreateAGemScreen::CreateButtonPressed, this, &UpdateProjectCtrl::HandleBackButton);
+#endif
 
 
         m_stack = new QStackedWidget(this);
         m_stack = new QStackedWidget(this);
         m_stack->setObjectName("body");
         m_stack->setObjectName("body");
@@ -73,6 +80,9 @@ namespace O3DE::ProjectManager
         m_stack->addWidget(topBarFrameWidget);
         m_stack->addWidget(topBarFrameWidget);
         m_stack->addWidget(m_projectGemCatalogScreen);
         m_stack->addWidget(m_projectGemCatalogScreen);
         m_stack->addWidget(m_gemRepoScreen);
         m_stack->addWidget(m_gemRepoScreen);
+#ifdef CREATE_A_GAME_ACTIVE
+        m_stack->addWidget(m_createAGemScreen);
+#endif
 
 
         QDialogButtonBox* backNextButtons = new QDialogButtonBox();
         QDialogButtonBox* backNextButtons = new QDialogButtonBox();
         backNextButtons->setObjectName("footer");
         backNextButtons->setObjectName("footer");
@@ -133,6 +143,13 @@ namespace O3DE::ProjectManager
             m_stack->setCurrentWidget(m_updateSettingsScreen);
             m_stack->setCurrentWidget(m_updateSettingsScreen);
             Update();
             Update();
         }
         }
+#ifdef CREATE_A_GAME_ACTIVE
+        else if (screen == ProjectManagerScreen::CreateAGem)
+        {
+            m_stack->setCurrentWidget(m_createAGemScreen);
+            Update();
+        }
+#endif
         else
         else
         {
         {
             emit ChangeScreenRequest(screen);
             emit ChangeScreenRequest(screen);

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

@@ -24,6 +24,7 @@ namespace O3DE::ProjectManager
     QT_FORWARD_DECLARE_CLASS(ProjectGemCatalogScreen)
     QT_FORWARD_DECLARE_CLASS(ProjectGemCatalogScreen)
     QT_FORWARD_DECLARE_CLASS(GemRepoScreen)
     QT_FORWARD_DECLARE_CLASS(GemRepoScreen)
     QT_FORWARD_DECLARE_CLASS(DownloadController)
     QT_FORWARD_DECLARE_CLASS(DownloadController)
+    QT_FORWARD_DECLARE_CLASS(CreateAGemScreen)
 
 
     class UpdateProjectCtrl
     class UpdateProjectCtrl
         : public ScreenWidget
         : public ScreenWidget
@@ -62,6 +63,7 @@ namespace O3DE::ProjectManager
         UpdateProjectSettingsScreen* m_updateSettingsScreen = nullptr;
         UpdateProjectSettingsScreen* m_updateSettingsScreen = nullptr;
         ProjectGemCatalogScreen* m_projectGemCatalogScreen = nullptr;
         ProjectGemCatalogScreen* m_projectGemCatalogScreen = nullptr;
         GemRepoScreen* m_gemRepoScreen = nullptr;
         GemRepoScreen* m_gemRepoScreen = nullptr;
+        CreateAGemScreen* m_createAGemScreen = nullptr;
 
 
         QPushButton* m_backButton = nullptr;
         QPushButton* m_backButton = nullptr;
         QPushButton* m_nextButton = nullptr;
         QPushButton* m_nextButton = nullptr;

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

@@ -98,6 +98,8 @@ set(FILES
     Source/DownloadRemoteTemplateDialog.cpp
     Source/DownloadRemoteTemplateDialog.cpp
     Source/TextOverflowWidget.h
     Source/TextOverflowWidget.h
     Source/TextOverflowWidget.cpp
     Source/TextOverflowWidget.cpp
+    Source/CreateAGemScreen.h
+    Source/CreateAGemScreen.cpp
     Source/GemCatalog/GemCatalogHeaderWidget.h
     Source/GemCatalog/GemCatalogHeaderWidget.h
     Source/GemCatalog/GemCatalogHeaderWidget.cpp
     Source/GemCatalog/GemCatalogHeaderWidget.cpp
     Source/GemCatalog/GemCatalogScreen.h
     Source/GemCatalog/GemCatalogScreen.h