Merge branch 'main' of https://github.com/aws-lumberyard/o3de into ly-as-sdk/LYN-2948-phistere
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* 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 <CreateProjectCtrl.h>
|
||||
#include <ScreensCtrl.h>
|
||||
#include <PythonBindingsInterface.h>
|
||||
#include <NewProjectSettingsScreen.h>
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QVBoxLayout>
|
||||
#include <QPushButton>
|
||||
#include <QMessageBox>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
CreateProjectCtrl::CreateProjectCtrl(QWidget* parent)
|
||||
: ScreenWidget(parent)
|
||||
{
|
||||
QVBoxLayout* vLayout = new QVBoxLayout();
|
||||
setLayout(vLayout);
|
||||
|
||||
m_screensCtrl = new ScreensCtrl();
|
||||
vLayout->addWidget(m_screensCtrl);
|
||||
|
||||
QDialogButtonBox* backNextButtons = new QDialogButtonBox();
|
||||
vLayout->addWidget(backNextButtons);
|
||||
|
||||
m_backButton = backNextButtons->addButton(tr("Back"), QDialogButtonBox::RejectRole);
|
||||
m_nextButton = backNextButtons->addButton(tr("Next"), QDialogButtonBox::ApplyRole);
|
||||
|
||||
connect(m_backButton, &QPushButton::pressed, this, &CreateProjectCtrl::HandleBackButton);
|
||||
connect(m_nextButton, &QPushButton::pressed, this, &CreateProjectCtrl::HandleNextButton);
|
||||
|
||||
m_screensOrder =
|
||||
{
|
||||
ProjectManagerScreen::NewProjectSettings,
|
||||
ProjectManagerScreen::GemCatalog
|
||||
};
|
||||
m_screensCtrl->BuildScreens(m_screensOrder);
|
||||
m_screensCtrl->ForceChangeToScreen(ProjectManagerScreen::NewProjectSettings, false);
|
||||
|
||||
UpdateNextButtonText();
|
||||
}
|
||||
|
||||
ProjectManagerScreen CreateProjectCtrl::GetScreenEnum()
|
||||
{
|
||||
return ProjectManagerScreen::CreateProject;
|
||||
}
|
||||
|
||||
void CreateProjectCtrl::HandleBackButton()
|
||||
{
|
||||
if (!m_screensCtrl->GotoPreviousScreen())
|
||||
{
|
||||
emit GotoPreviousScreenRequest();
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateNextButtonText();
|
||||
}
|
||||
}
|
||||
void CreateProjectCtrl::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::NewProjectSettings)
|
||||
{
|
||||
auto newProjectScreen = reinterpret_cast<NewProjectSettingsScreen*>(currentScreen);
|
||||
if (newProjectScreen)
|
||||
{
|
||||
if (!newProjectScreen->Validate())
|
||||
{
|
||||
QMessageBox::critical(this, tr("Invalid project settings"), tr("Invalid project settings"));
|
||||
return;
|
||||
}
|
||||
|
||||
m_projectInfo = newProjectScreen->GetProjectInfo();
|
||||
m_projectTemplatePath = newProjectScreen->GetProjectTemplatePath();
|
||||
}
|
||||
}
|
||||
|
||||
if (screenOrderIter != m_screensOrder.end())
|
||||
{
|
||||
m_screensCtrl->ChangeToScreen(*screenOrderIter);
|
||||
UpdateNextButtonText();
|
||||
}
|
||||
else
|
||||
{
|
||||
auto result = PythonBindingsInterface::Get()->CreateProject(m_projectTemplatePath, m_projectInfo);
|
||||
if (result.IsSuccess())
|
||||
{
|
||||
// adding gems is not implemented yet because we don't know what targets to add or how to add them
|
||||
emit ChangeScreenRequest(ProjectManagerScreen::ProjectsHome);
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(this, tr("Project creation failed"), tr("Failed to create project."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CreateProjectCtrl::UpdateNextButtonText()
|
||||
{
|
||||
QString nextButtonText = tr("Next");
|
||||
if (m_screensCtrl->GetCurrentScreen()->GetScreenEnum() == ProjectManagerScreen::GemCatalog)
|
||||
{
|
||||
nextButtonText = tr("Create Project");
|
||||
}
|
||||
m_nextButton->setText(nextButtonText);
|
||||
}
|
||||
|
||||
} // namespace O3DE::ProjectManager
|
||||
+8
-5
@@ -12,21 +12,21 @@
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include "ProjectInfo.h"
|
||||
#include <ScreenWidget.h>
|
||||
|
||||
#include <ScreensCtrl.h>
|
||||
|
||||
#include <QPushButton>
|
||||
#endif
|
||||
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
class ProjectSettingsCtrl
|
||||
class CreateProjectCtrl
|
||||
: public ScreenWidget
|
||||
{
|
||||
public:
|
||||
explicit ProjectSettingsCtrl(QWidget* parent = nullptr);
|
||||
~ProjectSettingsCtrl() = default;
|
||||
explicit CreateProjectCtrl(QWidget* parent = nullptr);
|
||||
~CreateProjectCtrl() = default;
|
||||
ProjectManagerScreen GetScreenEnum() override;
|
||||
|
||||
protected slots:
|
||||
@@ -40,6 +40,9 @@ namespace O3DE::ProjectManager
|
||||
QPushButton* m_backButton;
|
||||
QPushButton* m_nextButton;
|
||||
QVector<ProjectManagerScreen> m_screensOrder;
|
||||
|
||||
QString m_projectTemplatePath;
|
||||
ProjectInfo m_projectInfo;
|
||||
};
|
||||
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -14,8 +14,16 @@
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
EngineInfo::EngineInfo(const QString& path)
|
||||
EngineInfo::EngineInfo(const QString& path, const QString& name, const QString& version, const QString& thirdPartyPath)
|
||||
: m_path(path)
|
||||
, m_name(name)
|
||||
, m_version(version)
|
||||
, m_thirdPartyPath(thirdPartyPath)
|
||||
{
|
||||
}
|
||||
|
||||
bool EngineInfo::IsValid() const
|
||||
{
|
||||
return !m_path.isEmpty();
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -22,8 +22,20 @@ namespace O3DE::ProjectManager
|
||||
{
|
||||
public:
|
||||
EngineInfo() = default;
|
||||
EngineInfo(const QString& path);
|
||||
EngineInfo(const QString& path, const QString& name, const QString& version, const QString& thirdPartyPath);
|
||||
|
||||
// from engine.json
|
||||
QString m_version;
|
||||
QString m_name;
|
||||
QString m_thirdPartyPath;
|
||||
|
||||
// from o3de_manifest.json
|
||||
QString m_path;
|
||||
QString m_defaultProjectsFolder;
|
||||
QString m_defaultGemsFolder;
|
||||
QString m_defaultTemplatesFolder;
|
||||
QString m_defaultRestrictedFolder;
|
||||
|
||||
bool IsValid() const;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -11,20 +11,99 @@
|
||||
*/
|
||||
|
||||
#include <EngineSettingsScreen.h>
|
||||
|
||||
#include <Source/ui_EngineSettingsScreen.h>
|
||||
#include <QVBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QMessageBox>
|
||||
#include <FormLineEditWidget.h>
|
||||
#include <FormBrowseEditWidget.h>
|
||||
#include <PythonBindingsInterface.h>
|
||||
#include <PathValidator.h>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
EngineSettingsScreen::EngineSettingsScreen(QWidget* parent)
|
||||
: ScreenWidget(parent)
|
||||
, m_ui(new Ui::EngineSettingsClass())
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
auto* layout = new QVBoxLayout(this);
|
||||
layout->setAlignment(Qt::AlignTop);
|
||||
|
||||
setObjectName("engineSettingsScreen");
|
||||
|
||||
EngineInfo engineInfo;
|
||||
|
||||
AZ::Outcome<EngineInfo> engineInfoResult = PythonBindingsInterface::Get()->GetEngineInfo();
|
||||
if (engineInfoResult.IsSuccess())
|
||||
{
|
||||
engineInfo = engineInfoResult.GetValue();
|
||||
}
|
||||
|
||||
QLabel* formTitleLabel = new QLabel(tr("O3DE Settings"), this);
|
||||
formTitleLabel->setObjectName("formTitleLabel");
|
||||
layout->addWidget(formTitleLabel);
|
||||
|
||||
m_engineVersion = new FormLineEditWidget(tr("Engine Version"), engineInfo.m_version, this);
|
||||
m_engineVersion->lineEdit()->setReadOnly(true);
|
||||
layout->addWidget(m_engineVersion);
|
||||
|
||||
m_thirdParty = new FormBrowseEditWidget(tr("3rd Party Software Folder"), engineInfo.m_thirdPartyPath, this);
|
||||
m_thirdParty->lineEdit()->setValidator(new PathValidator(PathValidator::PathMode::ExistingFolder, this));
|
||||
m_thirdParty->lineEdit()->setReadOnly(true);
|
||||
m_thirdParty->setErrorLabelText(tr("Please provide a valid path to a folder that exists"));
|
||||
connect(m_thirdParty->lineEdit(), &QLineEdit::textChanged, this, &EngineSettingsScreen::OnTextChanged);
|
||||
layout->addWidget(m_thirdParty);
|
||||
|
||||
m_defaultProjects = new FormBrowseEditWidget(tr("Default Projects Folder"), engineInfo.m_defaultProjectsFolder, this);
|
||||
m_defaultProjects->lineEdit()->setValidator(new PathValidator(PathValidator::PathMode::ExistingFolder, this));
|
||||
m_defaultProjects->lineEdit()->setReadOnly(true);
|
||||
m_defaultProjects->setErrorLabelText(tr("Please provide a valid path to a folder that exists"));
|
||||
connect(m_defaultProjects->lineEdit(), &QLineEdit::textChanged, this, &EngineSettingsScreen::OnTextChanged);
|
||||
layout->addWidget(m_defaultProjects);
|
||||
|
||||
m_defaultGems = new FormBrowseEditWidget(tr("Default Gems Folder"), engineInfo.m_defaultGemsFolder, this);
|
||||
m_defaultGems->lineEdit()->setValidator(new PathValidator(PathValidator::PathMode::ExistingFolder, this));
|
||||
m_defaultGems->lineEdit()->setReadOnly(true);
|
||||
m_defaultGems->setErrorLabelText(tr("Please provide a valid path to a folder that exists"));
|
||||
connect(m_defaultGems->lineEdit(), &QLineEdit::textChanged, this, &EngineSettingsScreen::OnTextChanged);
|
||||
layout->addWidget(m_defaultGems);
|
||||
|
||||
m_defaultProjectTemplates = new FormBrowseEditWidget(tr("Default Project Templates Folder"), engineInfo.m_defaultTemplatesFolder, this);
|
||||
m_defaultProjectTemplates->lineEdit()->setValidator(new PathValidator(PathValidator::PathMode::ExistingFolder, this));
|
||||
m_defaultProjectTemplates->lineEdit()->setReadOnly(true);
|
||||
m_defaultProjectTemplates->setErrorLabelText(tr("Please provide a valid path to a folder that exists"));
|
||||
connect(m_defaultProjectTemplates->lineEdit(), &QLineEdit::textChanged, this, &EngineSettingsScreen::OnTextChanged);
|
||||
layout->addWidget(m_defaultProjectTemplates);
|
||||
|
||||
setLayout(layout);
|
||||
}
|
||||
|
||||
ProjectManagerScreen EngineSettingsScreen::GetScreenEnum()
|
||||
{
|
||||
return ProjectManagerScreen::EngineSettings;
|
||||
}
|
||||
|
||||
void EngineSettingsScreen::OnTextChanged()
|
||||
{
|
||||
// save engine settings
|
||||
auto engineInfoResult = PythonBindingsInterface::Get()->GetEngineInfo();
|
||||
if (engineInfoResult.IsSuccess())
|
||||
{
|
||||
EngineInfo engineInfo;
|
||||
engineInfo = engineInfoResult.GetValue();
|
||||
engineInfo.m_thirdPartyPath = m_thirdParty->lineEdit()->text();
|
||||
engineInfo.m_defaultProjectsFolder = m_defaultProjects->lineEdit()->text();
|
||||
engineInfo.m_defaultGemsFolder = m_defaultGems->lineEdit()->text();
|
||||
engineInfo.m_defaultTemplatesFolder = m_defaultProjectTemplates->lineEdit()->text();
|
||||
|
||||
bool result = PythonBindingsInterface::Get()->SetEngineInfo(engineInfo);
|
||||
if (!result)
|
||||
{
|
||||
QMessageBox::critical(this, tr("Engine Settings"), tr("Failed to save engine settings."));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(this, tr("Engine Settings"), tr("Failed to get engine settings."));
|
||||
}
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -15,13 +15,11 @@
|
||||
#include <ScreenWidget.h>
|
||||
#endif
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class EngineSettingsClass;
|
||||
}
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
QT_FORWARD_DECLARE_CLASS(FormLineEditWidget)
|
||||
QT_FORWARD_DECLARE_CLASS(FormBrowseEditWidget)
|
||||
|
||||
class EngineSettingsScreen
|
||||
: public ScreenWidget
|
||||
{
|
||||
@@ -30,8 +28,15 @@ namespace O3DE::ProjectManager
|
||||
~EngineSettingsScreen() = default;
|
||||
ProjectManagerScreen GetScreenEnum() override;
|
||||
|
||||
protected slots:
|
||||
void OnTextChanged();
|
||||
|
||||
private:
|
||||
QScopedPointer<Ui::EngineSettingsClass> m_ui;
|
||||
FormLineEditWidget* m_engineVersion;
|
||||
FormBrowseEditWidget* m_thirdParty;
|
||||
FormBrowseEditWidget* m_defaultProjects;
|
||||
FormBrowseEditWidget* m_defaultGems;
|
||||
FormBrowseEditWidget* m_defaultProjectTemplates;
|
||||
};
|
||||
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>EngineSettingsClass</class>
|
||||
<widget class="QWidget" name="EngineSettingsClass">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>839</width>
|
||||
<height>597</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>O3DE Settings</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Engine Version</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>v1.01</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>3rd Party Software Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Restricted Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineEdit_2"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Default Gems Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineEdit_3"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Default Project Templates Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineEdit_4"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -12,18 +12,57 @@
|
||||
|
||||
#include <FirstTimeUseScreen.h>
|
||||
|
||||
#include <Source/ui_FirstTimeUseScreen.h>
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QIcon>
|
||||
#include <QSpacerItem>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
FirstTimeUseScreen::FirstTimeUseScreen(QWidget* parent)
|
||||
: ScreenWidget(parent)
|
||||
, m_ui(new Ui::FirstTimeUseClass())
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
QVBoxLayout* vLayout = new QVBoxLayout();
|
||||
setLayout(vLayout);
|
||||
vLayout->setContentsMargins(s_contentMargins, s_contentMargins, s_contentMargins, s_contentMargins);
|
||||
|
||||
connect(m_ui->createProjectButton, &QPushButton::pressed, this, &FirstTimeUseScreen::HandleNewProjectButton);
|
||||
connect(m_ui->openProjectButton, &QPushButton::pressed, this, &FirstTimeUseScreen::HandleOpenProjectButton);
|
||||
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("<html><head/><body><p>Welcome to O3DE! Start something new by creating a project. Not sure what to create? </p><p>Explore what\342\200\231s available by downloading our sample project.</p></body></html>"));
|
||||
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()
|
||||
@@ -33,12 +72,24 @@ namespace O3DE::ProjectManager
|
||||
|
||||
void FirstTimeUseScreen::HandleNewProjectButton()
|
||||
{
|
||||
emit ResetScreenRequest(ProjectManagerScreen::NewProjectSettingsCore);
|
||||
emit ChangeScreenRequest(ProjectManagerScreen::NewProjectSettingsCore);
|
||||
emit ResetScreenRequest(ProjectManagerScreen::CreateProject);
|
||||
emit ChangeScreenRequest(ProjectManagerScreen::CreateProject);
|
||||
}
|
||||
void FirstTimeUseScreen::HandleOpenProjectButton()
|
||||
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
|
||||
|
||||
@@ -15,10 +15,8 @@
|
||||
#include <ScreenWidget.h>
|
||||
#endif
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class FirstTimeUseClass;
|
||||
}
|
||||
QT_FORWARD_DECLARE_CLASS(QIcon)
|
||||
QT_FORWARD_DECLARE_CLASS(QPushButton)
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
@@ -32,10 +30,20 @@ namespace O3DE::ProjectManager
|
||||
|
||||
protected slots:
|
||||
void HandleNewProjectButton();
|
||||
void HandleOpenProjectButton();
|
||||
void HandleAddProjectButton();
|
||||
|
||||
private:
|
||||
QScopedPointer<Ui::FirstTimeUseClass> m_ui;
|
||||
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
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>FirstTimeUseClass</class>
|
||||
<widget class="QWidget" name="FirstTimeUseClass">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>881</width>
|
||||
<height>555</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>30</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>READY. SET. CREATE!</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>Welcome to O3DE! Start something new by creating a project. Not sure what to create? </p><p>Explore what’s available by downloading our sample project.</p></body></html></string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::AutoText</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||
<item>
|
||||
<widget class="QPushButton" name="createProjectButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Create Project</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../project_manager.qrc">
|
||||
<normaloff>:/Resources/Add.svg</normaloff>:/Resources/Add.svg</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>16</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="openProjectButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Open a Project</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../project_manager.qrc">
|
||||
<normaloff>:/Resources/Select_Folder.svg</normaloff>:/Resources/Select_Folder.svg</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../project_manager.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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 <FormBrowseEditWidget.h>
|
||||
#include <AzQtComponents/Components/StyledLineEdit.h>
|
||||
#include <QPushButton>
|
||||
#include <QHBoxLayout>
|
||||
#include <QFileDialog>
|
||||
#include <QLineEdit>
|
||||
#include <QStandardPaths>
|
||||
#include <QIcon>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
FormBrowseEditWidget::FormBrowseEditWidget(const QString& labelText, const QString& valueText, QWidget* parent)
|
||||
: FormLineEditWidget(labelText, valueText, parent)
|
||||
{
|
||||
setObjectName("formBrowseEditWidget");
|
||||
|
||||
QPushButton* browseButton = new QPushButton(this);
|
||||
connect(browseButton, &QPushButton::pressed, this, &FormBrowseEditWidget::HandleBrowseButton);
|
||||
m_frameLayout->addWidget(browseButton);
|
||||
}
|
||||
|
||||
void FormBrowseEditWidget::HandleBrowseButton()
|
||||
{
|
||||
QString defaultPath = m_lineEdit->text();
|
||||
if (defaultPath.isEmpty())
|
||||
{
|
||||
defaultPath = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
|
||||
}
|
||||
|
||||
QString directory = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(this, tr("Browse"), defaultPath));
|
||||
if (!directory.isEmpty())
|
||||
{
|
||||
m_lineEdit->setText(directory);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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 <FormLineEditWidget.h>
|
||||
#endif
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
class FormBrowseEditWidget
|
||||
: public FormLineEditWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit FormBrowseEditWidget(const QString& labelText, const QString& valueText = "", QWidget* parent = nullptr);
|
||||
~FormBrowseEditWidget() = default;
|
||||
|
||||
private slots:
|
||||
void HandleBrowseButton();
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* 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 <FormLineEditWidget.h>
|
||||
#include <AzQtComponents/Components/StyledLineEdit.h>
|
||||
#include <AzQtComponents/Components/Widgets/LineEdit.h>
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLineEdit>
|
||||
#include <QLabel>
|
||||
#include <QFrame>
|
||||
#include <QValidator>
|
||||
#include <QStyle>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
FormLineEditWidget::FormLineEditWidget(const QString& labelText, const QString& valueText, QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
setObjectName("formLineEditWidget");
|
||||
|
||||
QVBoxLayout* mainLayout = new QVBoxLayout();
|
||||
mainLayout->setAlignment(Qt::AlignTop);
|
||||
{
|
||||
m_frame = new QFrame(this);
|
||||
m_frame->setObjectName("formFrame");
|
||||
|
||||
// use a horizontal box layout so buttons can be added to the right of the field
|
||||
m_frameLayout = new QHBoxLayout();
|
||||
{
|
||||
QVBoxLayout* fieldLayout = new QVBoxLayout();
|
||||
|
||||
QLabel* label = new QLabel(labelText, this);
|
||||
fieldLayout->addWidget(label);
|
||||
|
||||
m_lineEdit = new AzQtComponents::StyledLineEdit(this);
|
||||
m_lineEdit->setFlavor(AzQtComponents::StyledLineEdit::Question);
|
||||
AzQtComponents::LineEdit::setErrorIconEnabled(m_lineEdit, false);
|
||||
m_lineEdit->setText(valueText);
|
||||
|
||||
connect(m_lineEdit, &AzQtComponents::StyledLineEdit::flavorChanged, this, &FormLineEditWidget::flavorChanged);
|
||||
connect(m_lineEdit, &AzQtComponents::StyledLineEdit::onFocus, this, &FormLineEditWidget::onFocus);
|
||||
connect(m_lineEdit, &AzQtComponents::StyledLineEdit::onFocusOut, this, &FormLineEditWidget::onFocusOut);
|
||||
|
||||
m_lineEdit->setFrame(false);
|
||||
fieldLayout->addWidget(m_lineEdit);
|
||||
|
||||
m_frameLayout->addLayout(fieldLayout);
|
||||
|
||||
QWidget* emptyWidget = new QWidget(this);
|
||||
m_frameLayout->addWidget(emptyWidget);
|
||||
}
|
||||
|
||||
m_frame->setLayout(m_frameLayout);
|
||||
|
||||
mainLayout->addWidget(m_frame);
|
||||
|
||||
m_errorLabel = new QLabel(this);
|
||||
m_errorLabel->setObjectName("formErrorLabel");
|
||||
m_errorLabel->setVisible(false);
|
||||
mainLayout->addWidget(m_errorLabel);
|
||||
}
|
||||
|
||||
setLayout(mainLayout);
|
||||
}
|
||||
|
||||
void FormLineEditWidget::setErrorLabelText(const QString& labelText)
|
||||
{
|
||||
m_errorLabel->setText(labelText);
|
||||
}
|
||||
|
||||
QLineEdit* FormLineEditWidget::lineEdit() const
|
||||
{
|
||||
return m_lineEdit;
|
||||
}
|
||||
|
||||
void FormLineEditWidget::flavorChanged()
|
||||
{
|
||||
if (m_lineEdit->flavor() == AzQtComponents::StyledLineEdit::Flavor::Invalid)
|
||||
{
|
||||
m_frame->setProperty("Valid", false);
|
||||
m_errorLabel->setVisible(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_frame->setProperty("Valid", true);
|
||||
m_errorLabel->setVisible(false);
|
||||
}
|
||||
refreshStyle();
|
||||
}
|
||||
|
||||
void FormLineEditWidget::onFocus()
|
||||
{
|
||||
m_frame->setProperty("Focus", true);
|
||||
refreshStyle();
|
||||
}
|
||||
|
||||
void FormLineEditWidget::onFocusOut()
|
||||
{
|
||||
m_frame->setProperty("Focus", false);
|
||||
refreshStyle();
|
||||
}
|
||||
|
||||
void FormLineEditWidget::refreshStyle()
|
||||
{
|
||||
// we must unpolish/polish every child after changing a property
|
||||
// or else they won't use the correct stylesheet selector
|
||||
for (auto child : findChildren<QWidget*>())
|
||||
{
|
||||
child->style()->unpolish(child);
|
||||
child->style()->polish(child);
|
||||
}
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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 <QWidget>
|
||||
#endif
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QLineEdit)
|
||||
QT_FORWARD_DECLARE_CLASS(QLabel)
|
||||
QT_FORWARD_DECLARE_CLASS(QFrame)
|
||||
QT_FORWARD_DECLARE_CLASS(QHBoxLayout)
|
||||
|
||||
namespace AzQtComponents
|
||||
{
|
||||
class StyledLineEdit;
|
||||
}
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
class FormLineEditWidget
|
||||
: public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit FormLineEditWidget(const QString& labelText, const QString& valueText = "", QWidget* parent = nullptr);
|
||||
~FormLineEditWidget() = default;
|
||||
|
||||
//! Set the error message for to display when invalid.
|
||||
void setErrorLabelText(const QString& labelText);
|
||||
|
||||
//! Returns a pointer to the underlying LineEdit.
|
||||
QLineEdit* lineEdit() const;
|
||||
|
||||
protected:
|
||||
QLabel* m_errorLabel = nullptr;
|
||||
QFrame* m_frame = nullptr;
|
||||
QHBoxLayout* m_frameLayout = nullptr;
|
||||
AzQtComponents::StyledLineEdit* m_lineEdit = nullptr;
|
||||
|
||||
private slots:
|
||||
void flavorChanged();
|
||||
void onFocus();
|
||||
void onFocusOut();
|
||||
|
||||
private:
|
||||
void refreshStyle();
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -11,10 +11,15 @@
|
||||
*/
|
||||
|
||||
#include <GemCatalog/GemCatalogScreen.h>
|
||||
#include <PythonBindingsInterface.h>
|
||||
#include <GemCatalog/GemSortFilterProxyModel.h>
|
||||
#include <GemCatalog/GemFilterWidget.h>
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QPushButton>
|
||||
#include <PythonBindingsInterface.h>
|
||||
#include <QTimer>
|
||||
|
||||
//#define USE_TESTGEMDATA
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
@@ -22,62 +27,29 @@ namespace O3DE::ProjectManager
|
||||
: ScreenWidget(parent)
|
||||
{
|
||||
m_gemModel = new GemModel(this);
|
||||
GemSortFilterProxyModel* proxyModel = new GemSortFilterProxyModel(m_gemModel, this);
|
||||
|
||||
QVBoxLayout* vLayout = new QVBoxLayout();
|
||||
vLayout->setMargin(0);
|
||||
vLayout->setSpacing(0);
|
||||
setLayout(vLayout);
|
||||
|
||||
QHBoxLayout* hLayout = new QHBoxLayout();
|
||||
hLayout->setMargin(0);
|
||||
vLayout->addLayout(hLayout);
|
||||
|
||||
QWidget* filterPlaceholderWidget = new QWidget();
|
||||
filterPlaceholderWidget->setFixedWidth(250);
|
||||
hLayout->addWidget(filterPlaceholderWidget);
|
||||
|
||||
m_gemListView = new GemListView(m_gemModel, this);
|
||||
hLayout->addWidget(m_gemListView);
|
||||
|
||||
QWidget* inspectorPlaceholderWidget = new QWidget();
|
||||
inspectorPlaceholderWidget->setFixedWidth(250);
|
||||
hLayout->addWidget(inspectorPlaceholderWidget);
|
||||
m_gemListView = new GemListView(proxyModel, proxyModel->GetSelectionModel(), this);
|
||||
m_gemInspector = new GemInspector(m_gemModel, this);
|
||||
m_gemInspector->setFixedWidth(320);
|
||||
|
||||
// Start: Temporary gem test data
|
||||
#ifdef USE_TESTGEMDATA
|
||||
QVector<GemInfo> testGemData = GenerateTestData();
|
||||
for (const GemInfo& gemInfo : testGemData)
|
||||
{
|
||||
m_gemModel->AddGem(GemInfo("EMotion FX",
|
||||
"O3DE Foundation",
|
||||
"EMFX is a real-time character animation system. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
|
||||
(GemInfo::Android | GemInfo::iOS | GemInfo::macOS | GemInfo::Windows | GemInfo::Linux),
|
||||
true));
|
||||
|
||||
m_gemModel->AddGem(O3DE::ProjectManager::GemInfo("Atom",
|
||||
"O3DE Foundation",
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
|
||||
GemInfo::Android | GemInfo::Windows | GemInfo::Linux | GemInfo::macOS,
|
||||
true));
|
||||
|
||||
m_gemModel->AddGem(O3DE::ProjectManager::GemInfo("PhysX",
|
||||
"O3DE London",
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
|
||||
GemInfo::Android | GemInfo::Linux | GemInfo::macOS,
|
||||
false));
|
||||
|
||||
m_gemModel->AddGem(O3DE::ProjectManager::GemInfo("Certificate Manager",
|
||||
"O3DE Irvine",
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
|
||||
GemInfo::Windows,
|
||||
false));
|
||||
|
||||
m_gemModel->AddGem(O3DE::ProjectManager::GemInfo("Cloud Gem Framework",
|
||||
"O3DE Seattle",
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
|
||||
GemInfo::iOS | GemInfo::Linux,
|
||||
false));
|
||||
|
||||
m_gemModel->AddGem(O3DE::ProjectManager::GemInfo("Achievements",
|
||||
"O3DE Foundation",
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
||||
GemInfo::Android | GemInfo::Windows | GemInfo::Linux,
|
||||
false));
|
||||
m_gemModel->AddGem(gemInfo);
|
||||
}
|
||||
#else
|
||||
// End: Temporary gem test data
|
||||
auto result = PythonBindingsInterface::Get()->GetGems();
|
||||
if (result.IsSuccess())
|
||||
@@ -87,15 +59,115 @@ namespace O3DE::ProjectManager
|
||||
m_gemModel->AddGem(gemInfo);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
GemFilterWidget* filterWidget = new GemFilterWidget(proxyModel);
|
||||
filterWidget->setFixedWidth(250);
|
||||
|
||||
QVBoxLayout* middleVLayout = new QVBoxLayout();
|
||||
middleVLayout->setMargin(0);
|
||||
middleVLayout->setSpacing(0);
|
||||
middleVLayout->addWidget(m_gemListView);
|
||||
|
||||
hLayout->addWidget(filterWidget);
|
||||
hLayout->addLayout(middleVLayout);
|
||||
hLayout->addWidget(m_gemInspector);
|
||||
|
||||
proxyModel->InvalidateFilter();
|
||||
}
|
||||
|
||||
QVector<GemInfo> GemCatalogScreen::GenerateTestData()
|
||||
{
|
||||
QVector<GemInfo> result;
|
||||
|
||||
GemInfo gem("EMotion FX",
|
||||
"O3DE Foundation",
|
||||
"EMFX is a real-time character animation system. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
|
||||
(GemInfo::Android | GemInfo::iOS | GemInfo::macOS | GemInfo::Windows | GemInfo::Linux),
|
||||
true);
|
||||
gem.m_directoryLink = "C:/";
|
||||
gem.m_documentationLink = "http://www.amazon.com";
|
||||
gem.m_dependingGemUuids = QStringList({"EMotionFX", "Atom"});
|
||||
gem.m_conflictingGemUuids = QStringList({"Vegetation", "Camera", "ScriptCanvas", "CloudCanvas", "Networking"});
|
||||
gem.m_types = (GemInfo::Code | GemInfo::Asset);
|
||||
gem.m_version = "v1.01";
|
||||
gem.m_lastUpdatedDate = "24th April 2021";
|
||||
gem.m_binarySizeInKB = 40;
|
||||
gem.m_features = QStringList({"Animation", "Assets", "Physics"});
|
||||
gem.m_gemOrigin = GemInfo::O3DEFoundation;
|
||||
result.push_back(gem);
|
||||
|
||||
gem.m_name = "Atom";
|
||||
gem.m_creator = "O3DE Seattle";
|
||||
gem.m_summary = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";
|
||||
gem.m_platforms = (GemInfo::Android | GemInfo::Windows | GemInfo::Linux | GemInfo::macOS);
|
||||
gem.m_isAdded = true;
|
||||
gem.m_directoryLink = "C:/";
|
||||
gem.m_documentationLink = "https://aws.amazon.com/gametech/";
|
||||
gem.m_dependingGemUuids = QStringList({"EMotionFX", "Core", "AudioSystem", "Camera", "Particles"});
|
||||
gem.m_conflictingGemUuids = QStringList({"CloudCanvas", "NovaNet"});
|
||||
gem.m_version = "v2.31";
|
||||
gem.m_lastUpdatedDate = "24th November 2020";
|
||||
gem.m_features = QStringList({"Assets", "Rendering", "UI", "VR", "Debug", "Environment"});
|
||||
gem.m_binarySizeInKB = 2087;
|
||||
result.push_back(gem);
|
||||
|
||||
gem.m_name = "Physics";
|
||||
gem.m_creator = "O3DE London";
|
||||
gem.m_summary = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";
|
||||
gem.m_platforms = (GemInfo::Android | GemInfo::Linux | GemInfo::macOS);
|
||||
gem.m_isAdded = true;
|
||||
gem.m_directoryLink = "C:/";
|
||||
gem.m_documentationLink = "https://aws.amazon.com/gametech/";
|
||||
gem.m_dependingGemUuids = QStringList({"GraphCanvas", "ExpressionEvaluation", "UI Lib", "Multiplayer", "GameStateSamples"});
|
||||
gem.m_conflictingGemUuids = QStringList({"Cloud Canvas", "EMotion FX", "Streaming", "MessagePopup", "Cloth", "Graph Canvas", "Twitch Integration"});
|
||||
gem.m_version = "v1.5.102145";
|
||||
gem.m_lastUpdatedDate = "1st January 2021";
|
||||
gem.m_binarySizeInKB = 2000000;
|
||||
gem.m_features = QStringList({"Physics", "Gameplay", "Debug", "Assets"});
|
||||
result.push_back(gem);
|
||||
|
||||
result.push_back(O3DE::ProjectManager::GemInfo("Certificate Manager",
|
||||
"O3DE Irvine",
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
|
||||
GemInfo::Windows,
|
||||
false));
|
||||
|
||||
result.push_back(O3DE::ProjectManager::GemInfo("Cloud Gem Framework",
|
||||
"O3DE Seattle",
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
|
||||
GemInfo::iOS | GemInfo::Linux,
|
||||
false));
|
||||
|
||||
result.push_back(O3DE::ProjectManager::GemInfo("Cloud Gem Core",
|
||||
"O3DE Foundation",
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
||||
GemInfo::Android | GemInfo::Windows | GemInfo::Linux,
|
||||
true));
|
||||
|
||||
result.push_back(O3DE::ProjectManager::GemInfo("Gestures",
|
||||
"O3DE Foundation",
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
||||
GemInfo::Android | GemInfo::Windows | GemInfo::Linux,
|
||||
false));
|
||||
|
||||
result.push_back(O3DE::ProjectManager::GemInfo("Effects System",
|
||||
"O3DE Foundation",
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
||||
GemInfo::Android | GemInfo::Windows | GemInfo::Linux,
|
||||
true));
|
||||
|
||||
result.push_back(O3DE::ProjectManager::GemInfo("Microphone",
|
||||
"O3DE Foundation",
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus euismod ligula vitae dui dictum, a sodales dolor luctus. Sed id elit dapibus, finibus neque sed, efficitur mi. Nam facilisis ligula at eleifend pellentesque. Praesent non ex consectetur, blandit tellus in, venenatis lacus. Duis nec neque in urna ullamcorper euismod id eu leo. Nam efficitur dolor sed odio vehicula venenatis. Suspendisse nec est non velit commodo cursus in sit amet dui. Ut bibendum nisl et libero hendrerit dapibus. Vestibulum ultrices ullamcorper urna, placerat porttitor est lobortis in. Interdum et malesuada fames ac ante ipsum primis in faucibus. Integer a magna ac tellus sollicitudin porttitor. Phasellus lobortis viverra justo id bibendum. Etiam ac pharetra risus. Nulla vitae justo nibh. Nulla viverra leo et molestie interdum. Duis sit amet bibendum nulla, sit amet vehicula augue.",
|
||||
GemInfo::Android | GemInfo::Windows | GemInfo::Linux,
|
||||
false));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ProjectManagerScreen GemCatalogScreen::GetScreenEnum()
|
||||
{
|
||||
return ProjectManagerScreen::GemCatalog;
|
||||
}
|
||||
|
||||
QString GemCatalogScreen::GetNextButtonText()
|
||||
{
|
||||
return "Create Project";
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -9,11 +9,13 @@
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <ScreenWidget.h>
|
||||
#include <GemCatalog/GemListView.h>
|
||||
#include <GemCatalog/GemInspector.h>
|
||||
#include <GemCatalog/GemModel.h>
|
||||
#endif
|
||||
|
||||
@@ -26,10 +28,12 @@ namespace O3DE::ProjectManager
|
||||
explicit GemCatalogScreen(QWidget* parent = nullptr);
|
||||
~GemCatalogScreen() = default;
|
||||
ProjectManagerScreen GetScreenEnum() override;
|
||||
QString GetNextButtonText() override;
|
||||
|
||||
private:
|
||||
QVector<GemInfo> GenerateTestData();
|
||||
|
||||
GemListView* m_gemListView = nullptr;
|
||||
GemInspector* m_gemInspector = nullptr;
|
||||
GemModel* m_gemModel = nullptr;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -0,0 +1,412 @@
|
||||
/*
|
||||
* 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 <GemCatalog/GemFilterWidget.h>
|
||||
#include <QButtonGroup>
|
||||
#include <QCheckBox>
|
||||
#include <QLabel>
|
||||
#include <QMap>
|
||||
#include <QLineEdit>
|
||||
#include <QHBoxLayout>
|
||||
#include <QVBoxLayout>
|
||||
#include <QPushButton>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
FilterCategoryWidget::FilterCategoryWidget(const QString& header,
|
||||
const QVector<QString>& elementNames,
|
||||
const QVector<int>& elementCounts,
|
||||
bool showAllLessButton,
|
||||
int defaultShowCount,
|
||||
QWidget* parent)
|
||||
: QWidget(parent)
|
||||
, m_defaultShowCount(defaultShowCount)
|
||||
{
|
||||
AZ_Assert(elementNames.size() == elementCounts.size(), "Number of element names needs to match the counts.");
|
||||
|
||||
QVBoxLayout* vLayout = new QVBoxLayout();
|
||||
setLayout(vLayout);
|
||||
|
||||
// Collapse button
|
||||
QHBoxLayout* collapseLayout = new QHBoxLayout();
|
||||
m_collapseButton = new QPushButton();
|
||||
m_collapseButton->setCheckable(true);
|
||||
m_collapseButton->setFlat(true);
|
||||
m_collapseButton->setFocusPolicy(Qt::NoFocus);
|
||||
m_collapseButton->setFixedWidth(s_collapseButtonSize);
|
||||
m_collapseButton->setStyleSheet("border: 0px; border-radius: 0px;");
|
||||
connect(m_collapseButton, &QPushButton::clicked, this, [=]()
|
||||
{
|
||||
UpdateCollapseState();
|
||||
});
|
||||
collapseLayout->addWidget(m_collapseButton);
|
||||
|
||||
// Category title
|
||||
QLabel* headerLabel = new QLabel(header);
|
||||
headerLabel->setStyleSheet("font-size: 11pt;");
|
||||
collapseLayout->addWidget(headerLabel);
|
||||
vLayout->addLayout(collapseLayout);
|
||||
|
||||
vLayout->addSpacing(5);
|
||||
|
||||
// Everything in the main widget will be collapsed/uncollapsed
|
||||
{
|
||||
m_mainWidget = new QWidget();
|
||||
vLayout->addWidget(m_mainWidget);
|
||||
|
||||
QVBoxLayout* mainLayout = new QVBoxLayout();
|
||||
mainLayout->setMargin(0);
|
||||
mainLayout->setAlignment(Qt::AlignTop);
|
||||
m_mainWidget->setLayout(mainLayout);
|
||||
|
||||
// Elements
|
||||
m_buttonGroup = new QButtonGroup();
|
||||
m_buttonGroup->setExclusive(false);
|
||||
for (int i = 0; i < elementNames.size(); ++i)
|
||||
{
|
||||
QWidget* elementWidget = new QWidget();
|
||||
QHBoxLayout* elementLayout = new QHBoxLayout();
|
||||
elementLayout->setMargin(0);
|
||||
elementWidget->setLayout(elementLayout);
|
||||
|
||||
QCheckBox* checkbox = new QCheckBox(elementNames[i]);
|
||||
checkbox->setStyleSheet("font-size: 11pt;");
|
||||
m_buttonGroup->addButton(checkbox);
|
||||
elementLayout->addWidget(checkbox);
|
||||
|
||||
elementLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding));
|
||||
|
||||
QLabel* countLabel = new QLabel(QString::number(elementCounts[i]));
|
||||
countLabel->setStyleSheet("font-size: 11pt; background-color: #333333; border-radius: 3px; color: #94D2FF;");
|
||||
elementLayout->addWidget(countLabel);
|
||||
|
||||
m_elementWidgets.push_back(elementWidget);
|
||||
mainLayout->addWidget(elementWidget);
|
||||
}
|
||||
|
||||
// See more / less
|
||||
if (showAllLessButton)
|
||||
{
|
||||
m_seeAllLessLabel = new LinkLabel();
|
||||
connect(m_seeAllLessLabel, &LinkLabel::clicked, this, [=]()
|
||||
{
|
||||
m_seeAll = !m_seeAll;
|
||||
UpdateSeeMoreLess();
|
||||
});
|
||||
mainLayout->addWidget(m_seeAllLessLabel);
|
||||
}
|
||||
else
|
||||
{
|
||||
mainLayout->addSpacing(5);
|
||||
}
|
||||
}
|
||||
|
||||
// Separating line
|
||||
QFrame* hLine = new QFrame();
|
||||
hLine->setFrameShape(QFrame::HLine);
|
||||
hLine->setStyleSheet("color: #666666;");
|
||||
vLayout->addWidget(hLine);
|
||||
|
||||
UpdateCollapseState();
|
||||
UpdateSeeMoreLess();
|
||||
}
|
||||
|
||||
void FilterCategoryWidget::UpdateCollapseState()
|
||||
{
|
||||
if (m_collapseButton->isChecked())
|
||||
{
|
||||
m_collapseButton->setIcon(QIcon(":/Resources/ArrowDownLine.svg"));
|
||||
m_mainWidget->hide();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_collapseButton->setIcon(QIcon(":/Resources/ArrowUpLine.svg"));
|
||||
m_mainWidget->show();
|
||||
}
|
||||
}
|
||||
|
||||
void FilterCategoryWidget::UpdateSeeMoreLess()
|
||||
{
|
||||
if (!m_seeAllLessLabel)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_elementWidgets.isEmpty())
|
||||
{
|
||||
m_seeAllLessLabel->hide();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_seeAllLessLabel->show();
|
||||
}
|
||||
|
||||
if (!m_seeAll)
|
||||
{
|
||||
m_seeAllLessLabel->setText("See all");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_seeAllLessLabel->setText("See less");
|
||||
}
|
||||
|
||||
int showCount = m_seeAll ? m_elementWidgets.size() : m_defaultShowCount;
|
||||
showCount = AZ::GetMin(showCount, m_elementWidgets.size());
|
||||
for (int i = 0; i < showCount; ++i)
|
||||
{
|
||||
m_elementWidgets[i]->show();
|
||||
}
|
||||
for (int i = showCount; i < m_elementWidgets.size(); ++i)
|
||||
{
|
||||
m_elementWidgets[i]->hide();
|
||||
}
|
||||
}
|
||||
|
||||
QButtonGroup* FilterCategoryWidget::GetButtonGroup()
|
||||
{
|
||||
return m_buttonGroup;
|
||||
}
|
||||
|
||||
GemFilterWidget::GemFilterWidget(GemSortFilterProxyModel* filterProxyModel, QWidget* parent)
|
||||
: QScrollArea(parent)
|
||||
, m_filterProxyModel(filterProxyModel)
|
||||
{
|
||||
m_gemModel = m_filterProxyModel->GetSourceModel();
|
||||
|
||||
setWidgetResizable(true);
|
||||
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||
|
||||
QWidget* mainWidget = new QWidget();
|
||||
setWidget(mainWidget);
|
||||
|
||||
m_mainLayout = new QVBoxLayout();
|
||||
m_mainLayout->setAlignment(Qt::AlignTop);
|
||||
mainWidget->setLayout(m_mainLayout);
|
||||
|
||||
QLabel* filterByLabel = new QLabel("Filter by");
|
||||
filterByLabel->setStyleSheet("font-size: 15pt;");
|
||||
m_mainLayout->addWidget(filterByLabel);
|
||||
|
||||
AddGemOriginFilter();
|
||||
AddTypeFilter();
|
||||
AddPlatformFilter();
|
||||
AddFeatureFilter();
|
||||
}
|
||||
|
||||
void GemFilterWidget::AddGemOriginFilter()
|
||||
{
|
||||
QVector<QString> elementNames;
|
||||
QVector<int> elementCounts;
|
||||
const int numGems = m_gemModel->rowCount();
|
||||
for (int originIndex = 0; originIndex < GemInfo::NumGemOrigins; ++originIndex)
|
||||
{
|
||||
const GemInfo::GemOrigin gemOriginToBeCounted = static_cast<GemInfo::GemOrigin>(1 << originIndex);
|
||||
|
||||
int gemOriginCount = 0;
|
||||
for (int gemIndex = 0; gemIndex < numGems; ++gemIndex)
|
||||
{
|
||||
const GemInfo::GemOrigin gemOrigin = m_gemModel->GetGemOrigin(m_gemModel->index(gemIndex, 0));
|
||||
|
||||
// Is the gem of the given origin?
|
||||
if (gemOriginToBeCounted == gemOrigin)
|
||||
{
|
||||
gemOriginCount++;
|
||||
}
|
||||
}
|
||||
|
||||
elementNames.push_back(GemInfo::GetGemOriginString(gemOriginToBeCounted));
|
||||
elementCounts.push_back(gemOriginCount);
|
||||
}
|
||||
|
||||
FilterCategoryWidget* filterWidget = new FilterCategoryWidget("Provider", elementNames, elementCounts, /*showAllLessButton=*/false);
|
||||
m_mainLayout->addWidget(filterWidget);
|
||||
|
||||
const QList<QAbstractButton*> buttons = filterWidget->GetButtonGroup()->buttons();
|
||||
for (int i = 0; i < buttons.size(); ++i)
|
||||
{
|
||||
const GemInfo::GemOrigin gemOrigin = static_cast<GemInfo::GemOrigin>(1 << i);
|
||||
QAbstractButton* button = buttons[i];
|
||||
|
||||
connect(button, &QAbstractButton::toggled, this, [=](bool checked)
|
||||
{
|
||||
GemInfo::GemOrigins gemOrigins = m_filterProxyModel->GetGemOrigins();
|
||||
if (checked)
|
||||
{
|
||||
gemOrigins |= gemOrigin;
|
||||
}
|
||||
else
|
||||
{
|
||||
gemOrigins &= ~gemOrigin;
|
||||
}
|
||||
m_filterProxyModel->SetGemOrigins(gemOrigins);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void GemFilterWidget::AddTypeFilter()
|
||||
{
|
||||
QVector<QString> elementNames;
|
||||
QVector<int> elementCounts;
|
||||
const int numGems = m_gemModel->rowCount();
|
||||
for (int typeIndex = 0; typeIndex < GemInfo::NumTypes; ++typeIndex)
|
||||
{
|
||||
const GemInfo::Type type = static_cast<GemInfo::Type>(1 << typeIndex);
|
||||
|
||||
int typeGemCount = 0;
|
||||
for (int gemIndex = 0; gemIndex < numGems; ++gemIndex)
|
||||
{
|
||||
const GemInfo::Types types = m_gemModel->GetTypes(m_gemModel->index(gemIndex, 0));
|
||||
|
||||
// Is type (Asset, Code, Tool) part of the gem?
|
||||
if (types & type)
|
||||
{
|
||||
typeGemCount++;
|
||||
}
|
||||
}
|
||||
|
||||
elementNames.push_back(GemInfo::GetTypeString(type));
|
||||
elementCounts.push_back(typeGemCount);
|
||||
}
|
||||
|
||||
FilterCategoryWidget* filterWidget = new FilterCategoryWidget("Type", elementNames, elementCounts, /*showAllLessButton=*/false);
|
||||
m_mainLayout->addWidget(filterWidget);
|
||||
|
||||
const QList<QAbstractButton*> buttons = filterWidget->GetButtonGroup()->buttons();
|
||||
for (int i = 0; i < buttons.size(); ++i)
|
||||
{
|
||||
const GemInfo::Type type = static_cast<GemInfo::Type>(1 << i);
|
||||
QAbstractButton* button = buttons[i];
|
||||
|
||||
connect(button, &QAbstractButton::toggled, this, [=](bool checked)
|
||||
{
|
||||
GemInfo::Types types = m_filterProxyModel->GetTypes();
|
||||
if (checked)
|
||||
{
|
||||
types |= type;
|
||||
}
|
||||
else
|
||||
{
|
||||
types &= ~type;
|
||||
}
|
||||
m_filterProxyModel->SetTypes(types);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void GemFilterWidget::AddPlatformFilter()
|
||||
{
|
||||
QVector<QString> elementNames;
|
||||
QVector<int> elementCounts;
|
||||
const int numGems = m_gemModel->rowCount();
|
||||
for (int platformIndex = 0; platformIndex < GemInfo::NumPlatforms; ++platformIndex)
|
||||
{
|
||||
const GemInfo::Platform platform = static_cast<GemInfo::Platform>(1 << platformIndex);
|
||||
|
||||
int platformGemCount = 0;
|
||||
for (int gemIndex = 0; gemIndex < numGems; ++gemIndex)
|
||||
{
|
||||
const GemInfo::Platforms platforms = m_gemModel->GetPlatforms(m_gemModel->index(gemIndex, 0));
|
||||
|
||||
// Is platform supported?
|
||||
if (platforms & platform)
|
||||
{
|
||||
platformGemCount++;
|
||||
}
|
||||
}
|
||||
|
||||
elementNames.push_back(GemInfo::GetPlatformString(platform));
|
||||
elementCounts.push_back(platformGemCount);
|
||||
}
|
||||
|
||||
FilterCategoryWidget* filterWidget = new FilterCategoryWidget("Supported Platforms", elementNames, elementCounts, /*showAllLessButton=*/false);
|
||||
m_mainLayout->addWidget(filterWidget);
|
||||
|
||||
const QList<QAbstractButton*> buttons = filterWidget->GetButtonGroup()->buttons();
|
||||
for (int i = 0; i < buttons.size(); ++i)
|
||||
{
|
||||
const GemInfo::Platform platform = static_cast<GemInfo::Platform>(1 << i);
|
||||
QAbstractButton* button = buttons[i];
|
||||
|
||||
connect(button, &QAbstractButton::toggled, this, [=](bool checked)
|
||||
{
|
||||
GemInfo::Platforms platforms = m_filterProxyModel->GetPlatforms();
|
||||
if (checked)
|
||||
{
|
||||
platforms |= platform;
|
||||
}
|
||||
else
|
||||
{
|
||||
platforms &= ~platform;
|
||||
}
|
||||
m_filterProxyModel->SetPlatforms(platforms);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void GemFilterWidget::AddFeatureFilter()
|
||||
{
|
||||
// Alphabetically sorted, unique features and their number of occurrences in the gem database.
|
||||
QMap<QString, int> uniqueFeatureCounts;
|
||||
const int numGems = m_gemModel->rowCount();
|
||||
for (int gemIndex = 0; gemIndex < numGems; ++gemIndex)
|
||||
{
|
||||
const QStringList features = m_gemModel->GetFeatures(m_gemModel->index(gemIndex, 0));
|
||||
for (const QString& feature : features)
|
||||
{
|
||||
if (!uniqueFeatureCounts.contains(feature))
|
||||
{
|
||||
uniqueFeatureCounts.insert(feature, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
int& featureeCount = uniqueFeatureCounts[feature];
|
||||
featureeCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QVector<QString> elementNames;
|
||||
QVector<int> elementCounts;
|
||||
for (auto iterator = uniqueFeatureCounts.begin(); iterator != uniqueFeatureCounts.end(); iterator++)
|
||||
{
|
||||
elementNames.push_back(iterator.key());
|
||||
elementCounts.push_back(iterator.value());
|
||||
}
|
||||
|
||||
FilterCategoryWidget* filterWidget = new FilterCategoryWidget("Features", elementNames, elementCounts,
|
||||
/*showAllLessButton=*/true, /*defaultShowCount=*/5);
|
||||
m_mainLayout->addWidget(filterWidget);
|
||||
|
||||
const QList<QAbstractButton*> buttons = filterWidget->GetButtonGroup()->buttons();
|
||||
for (int i = 0; i < buttons.size(); ++i)
|
||||
{
|
||||
const QString& feature = elementNames[i];
|
||||
QAbstractButton* button = buttons[i];
|
||||
|
||||
connect(button, &QAbstractButton::toggled, this, [=](bool checked)
|
||||
{
|
||||
QSet<QString> features = m_filterProxyModel->GetFeatures();
|
||||
if (checked)
|
||||
{
|
||||
features.insert(feature);
|
||||
}
|
||||
else
|
||||
{
|
||||
features.remove(feature);
|
||||
}
|
||||
m_filterProxyModel->SetFeatures(features);
|
||||
});
|
||||
}
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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 <LinkWidget.h>
|
||||
#include <GemCatalog/GemSortFilterProxyModel.h>
|
||||
#include <QScrollArea>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
#include <QCheckBox>
|
||||
#include <QVector>
|
||||
#include <QPushButton>
|
||||
#endif
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QButtonGroup)
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
class FilterCategoryWidget
|
||||
: public QWidget
|
||||
{
|
||||
Q_OBJECT // AUTOMOC
|
||||
|
||||
public:
|
||||
explicit FilterCategoryWidget(const QString& header,
|
||||
const QVector<QString>& elementNames,
|
||||
const QVector<int>& elementCounts,
|
||||
bool showAllLessButton = true,
|
||||
int defaultShowCount = 4,
|
||||
QWidget* parent = nullptr);
|
||||
|
||||
QButtonGroup* GetButtonGroup();
|
||||
|
||||
private:
|
||||
void UpdateCollapseState();
|
||||
void UpdateSeeMoreLess();
|
||||
|
||||
inline constexpr static int s_collapseButtonSize = 16;
|
||||
QPushButton* m_collapseButton = nullptr;
|
||||
|
||||
QWidget* m_mainWidget = nullptr;
|
||||
QButtonGroup* m_buttonGroup = nullptr;
|
||||
QVector<QWidget*> m_elementWidgets; //! Includes checkbox and the count labl.
|
||||
LinkLabel* m_seeAllLessLabel = nullptr;
|
||||
int m_defaultShowCount = 0;
|
||||
bool m_seeAll = false;
|
||||
};
|
||||
|
||||
class GemFilterWidget
|
||||
: public QScrollArea
|
||||
{
|
||||
Q_OBJECT // AUTOMOC
|
||||
|
||||
public:
|
||||
explicit GemFilterWidget(GemSortFilterProxyModel* filterProxyModel, QWidget* parent = nullptr);
|
||||
~GemFilterWidget() = default;
|
||||
|
||||
private:
|
||||
void AddGemOriginFilter();
|
||||
void AddTypeFilter();
|
||||
void AddPlatformFilter();
|
||||
void AddFeatureFilter();
|
||||
|
||||
QVBoxLayout* m_mainLayout = nullptr;
|
||||
GemModel* m_gemModel = nullptr;
|
||||
GemSortFilterProxyModel* m_filterProxyModel = nullptr;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -22,10 +22,61 @@ namespace O3DE::ProjectManager
|
||||
, m_isAdded(isAdded)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool GemInfo::IsValid() const
|
||||
{
|
||||
return !m_path.isEmpty();
|
||||
}
|
||||
|
||||
QString GemInfo::GetPlatformString(Platform platform)
|
||||
{
|
||||
switch (platform)
|
||||
{
|
||||
case Android:
|
||||
return "Android";
|
||||
case iOS:
|
||||
return "iOS";
|
||||
case Linux:
|
||||
return "Linux";
|
||||
case macOS:
|
||||
return "macOS";
|
||||
case Windows:
|
||||
return "Windows";
|
||||
default:
|
||||
return "<Unknown Platform>";
|
||||
}
|
||||
}
|
||||
|
||||
QString GemInfo::GetTypeString(Type type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case Asset:
|
||||
return "Asset";
|
||||
case Code:
|
||||
return "Code";
|
||||
case Tool:
|
||||
return "Tool";
|
||||
default:
|
||||
return "<Unknown Type>";
|
||||
}
|
||||
}
|
||||
|
||||
QString GemInfo::GetGemOriginString(GemOrigin origin)
|
||||
{
|
||||
switch (origin)
|
||||
{
|
||||
case O3DEFoundation:
|
||||
return "Open 3D Foundation";
|
||||
case Local:
|
||||
return "Local";
|
||||
default:
|
||||
return "<Unknown Gem Origin>";
|
||||
}
|
||||
}
|
||||
|
||||
bool GemInfo::IsPlatformSupported(Platform platform) const
|
||||
{
|
||||
return (m_platforms & platform);
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -34,9 +34,30 @@ namespace O3DE::ProjectManager
|
||||
NumPlatforms = 5
|
||||
};
|
||||
Q_DECLARE_FLAGS(Platforms, Platform)
|
||||
static QString GetPlatformString(Platform platform);
|
||||
|
||||
enum Type
|
||||
{
|
||||
Asset = 1 << 0,
|
||||
Code = 1 << 1,
|
||||
Tool = 1 << 2,
|
||||
NumTypes = 3
|
||||
};
|
||||
Q_DECLARE_FLAGS(Types, Type)
|
||||
static QString GetTypeString(Type type);
|
||||
|
||||
enum GemOrigin
|
||||
{
|
||||
O3DEFoundation = 1 << 0,
|
||||
Local = 1 << 1,
|
||||
NumGemOrigins = 2
|
||||
};
|
||||
Q_DECLARE_FLAGS(GemOrigins, GemOrigin)
|
||||
static QString GetGemOriginString(GemOrigin origin);
|
||||
|
||||
GemInfo() = default;
|
||||
GemInfo(const QString& name, const QString& creator, const QString& summary, Platforms platforms, bool isAdded);
|
||||
bool IsPlatformSupported(Platform platform) const;
|
||||
|
||||
bool IsValid() const;
|
||||
|
||||
@@ -44,16 +65,22 @@ namespace O3DE::ProjectManager
|
||||
QString m_name;
|
||||
QString m_displayName;
|
||||
QString m_creator;
|
||||
GemOrigin m_gemOrigin = Local;
|
||||
bool m_isAdded = false; //! Is the gem currently added and enabled in the project?
|
||||
QString m_summary;
|
||||
Platforms m_platforms;
|
||||
Types m_types; //! Asset and/or Code and/or Tool
|
||||
QStringList m_features;
|
||||
QString m_directoryLink;
|
||||
QString m_documentationLink;
|
||||
QString m_version;
|
||||
QString m_lastUpdatedDate;
|
||||
QString m_documentationUrl;
|
||||
QVector<AZ::Uuid> m_dependingGemUuids;
|
||||
QVector<AZ::Uuid> m_conflictingGemUuids;
|
||||
int m_binarySizeInKB = 0;
|
||||
QStringList m_dependingGemUuids;
|
||||
QStringList m_conflictingGemUuids;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(O3DE::ProjectManager::GemInfo::Platforms)
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(O3DE::ProjectManager::GemInfo::Types)
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(O3DE::ProjectManager::GemInfo::GemOrigins)
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* 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 <GemCatalog/GemInspector.h>
|
||||
#include <GemCatalog/GemItemDelegate.h>
|
||||
#include <QFrame>
|
||||
#include <QLabel>
|
||||
#include <QSpacerItem>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
GemInspector::GemInspector(GemModel* model, QWidget* parent)
|
||||
: QScrollArea(parent)
|
||||
, m_model(model)
|
||||
{
|
||||
setWidgetResizable(true);
|
||||
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||
|
||||
m_mainWidget = new QWidget();
|
||||
setWidget(m_mainWidget);
|
||||
|
||||
m_mainLayout = new QVBoxLayout();
|
||||
m_mainLayout->setMargin(15);
|
||||
m_mainLayout->setAlignment(Qt::AlignTop);
|
||||
m_mainWidget->setLayout(m_mainLayout);
|
||||
|
||||
InitMainWidget();
|
||||
|
||||
connect(m_model->GetSelectionModel(), &QItemSelectionModel::selectionChanged, this, &GemInspector::OnSelectionChanged);
|
||||
Update({});
|
||||
}
|
||||
|
||||
void GemInspector::OnSelectionChanged(const QItemSelection& selected, [[maybe_unused]] const QItemSelection& deselected)
|
||||
{
|
||||
const QModelIndexList selectedIndices = selected.indexes();
|
||||
if (selectedIndices.empty())
|
||||
{
|
||||
Update({});
|
||||
return;
|
||||
}
|
||||
|
||||
Update(selectedIndices[0]);
|
||||
}
|
||||
|
||||
void GemInspector::Update(const QModelIndex& modelIndex)
|
||||
{
|
||||
if (!modelIndex.isValid())
|
||||
{
|
||||
m_mainWidget->hide();
|
||||
}
|
||||
|
||||
m_nameLabel->setText(m_model->GetName(modelIndex));
|
||||
m_creatorLabel->setText(m_model->GetCreator(modelIndex));
|
||||
|
||||
m_summaryLabel->setText(m_model->GetSummary(modelIndex));
|
||||
m_summaryLabel->adjustSize();
|
||||
|
||||
m_directoryLinkLabel->SetUrl(m_model->GetDirectoryLink(modelIndex));
|
||||
m_documentationLinkLabel->SetUrl(m_model->GetDocLink(modelIndex));
|
||||
|
||||
// Depending and conflicting gems
|
||||
m_dependingGems->Update("Depending Gems", "The following Gems will be automatically enabled with this Gem.", m_model->GetDependingGemNames(modelIndex));
|
||||
m_conflictingGems->Update("Conflicting Gems", "The following Gems will be automatically disabled with this Gem.", m_model->GetConflictingGemNames(modelIndex));
|
||||
|
||||
// Additional information
|
||||
m_versionLabel->setText(QString("Gem Version: %1").arg(m_model->GetVersion(modelIndex)));
|
||||
m_lastUpdatedLabel->setText(QString("Last Updated: %1").arg(m_model->GetLastUpdated(modelIndex)));
|
||||
m_binarySizeLabel->setText(QString("Binary Size: %1 KB").arg(QString::number(m_model->GetBinarySizeInKB(modelIndex))));
|
||||
|
||||
m_mainWidget->adjustSize();
|
||||
m_mainWidget->show();
|
||||
}
|
||||
|
||||
QLabel* GemInspector::CreateStyledLabel(QLayout* layout, int fontSize, const QString& colorCodeString)
|
||||
{
|
||||
QLabel* result = new QLabel();
|
||||
result->setStyleSheet(QString("font-size: %1pt; color: %2;").arg(QString::number(fontSize), colorCodeString));
|
||||
layout->addWidget(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void GemInspector::InitMainWidget()
|
||||
{
|
||||
// Gem name, creator and summary
|
||||
m_nameLabel = CreateStyledLabel(m_mainLayout, 17, s_headerColor);
|
||||
m_creatorLabel = CreateStyledLabel(m_mainLayout, 12, s_creatorColor);
|
||||
m_mainLayout->addSpacing(5);
|
||||
|
||||
// TODO: QLabel seems to have issues determining the right sizeHint() for our font with the given font size.
|
||||
// This results into squeezed elements in the layout in case the text is a little longer than a sentence.
|
||||
m_summaryLabel = new QLabel();//CreateLabel(m_mainLayout, 12, s_textColor);
|
||||
m_mainLayout->addWidget(m_summaryLabel);
|
||||
m_summaryLabel->setWordWrap(true);
|
||||
m_mainLayout->addSpacing(5);
|
||||
|
||||
// Directory and documentation links
|
||||
{
|
||||
QHBoxLayout* linksHLayout = new QHBoxLayout();
|
||||
linksHLayout->setMargin(0);
|
||||
m_mainLayout->addLayout(linksHLayout);
|
||||
|
||||
QSpacerItem* spacerLeft = new QSpacerItem(0, 0, QSizePolicy::Expanding);
|
||||
linksHLayout->addSpacerItem(spacerLeft);
|
||||
|
||||
m_directoryLinkLabel = new LinkLabel("View in Directory");
|
||||
linksHLayout->addWidget(m_directoryLinkLabel);
|
||||
linksHLayout->addWidget(new QLabel("|"));
|
||||
m_documentationLinkLabel = new LinkLabel("Read Documentation");
|
||||
linksHLayout->addWidget(m_documentationLinkLabel);
|
||||
|
||||
QSpacerItem* spacerRight = new QSpacerItem(0, 0, QSizePolicy::Expanding);
|
||||
linksHLayout->addSpacerItem(spacerRight);
|
||||
|
||||
m_mainLayout->addSpacing(8);
|
||||
}
|
||||
|
||||
// Separating line
|
||||
QFrame* hLine = new QFrame();
|
||||
hLine->setFrameShape(QFrame::HLine);
|
||||
hLine->setStyleSheet("color: #666666;");
|
||||
m_mainLayout->addWidget(hLine);
|
||||
|
||||
m_mainLayout->addSpacing(10);
|
||||
|
||||
// Depending and conflicting gems
|
||||
m_dependingGems = new GemsSubWidget();
|
||||
m_mainLayout->addWidget(m_dependingGems);
|
||||
m_mainLayout->addSpacing(20);
|
||||
|
||||
m_conflictingGems = new GemsSubWidget();
|
||||
m_mainLayout->addWidget(m_conflictingGems);
|
||||
m_mainLayout->addSpacing(20);
|
||||
|
||||
// Additional information
|
||||
QLabel* additionalInfoLabel = CreateStyledLabel(m_mainLayout, 14, s_headerColor);
|
||||
additionalInfoLabel->setText("Additional Information");
|
||||
|
||||
m_versionLabel = CreateStyledLabel(m_mainLayout, 11, s_textColor);
|
||||
m_lastUpdatedLabel = CreateStyledLabel(m_mainLayout, 11, s_textColor);
|
||||
m_binarySizeLabel = CreateStyledLabel(m_mainLayout, 11, s_textColor);
|
||||
}
|
||||
|
||||
GemInspector::GemsSubWidget::GemsSubWidget(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
m_layout = new QVBoxLayout();
|
||||
m_layout->setAlignment(Qt::AlignTop);
|
||||
m_layout->setMargin(0);
|
||||
setLayout(m_layout);
|
||||
|
||||
m_titleLabel = GemInspector::CreateStyledLabel(m_layout, 15, s_headerColor);
|
||||
m_textLabel = GemInspector::CreateStyledLabel(m_layout, 9, s_textColor);
|
||||
m_textLabel->setWordWrap(true);
|
||||
|
||||
m_tagWidget = new TagContainerWidget();
|
||||
m_layout->addWidget(m_tagWidget);
|
||||
}
|
||||
|
||||
void GemInspector::GemsSubWidget::Update(const QString& title, const QString& text, const QStringList& gemNames)
|
||||
{
|
||||
m_titleLabel->setText(title);
|
||||
m_textLabel->setText(text);
|
||||
m_tagWidget->Update(gemNames);
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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 <LinkWidget.h>
|
||||
#include <TagWidget.h>
|
||||
#include <GemCatalog/GemInfo.h>
|
||||
#include <GemCatalog/GemModel.h>
|
||||
#include <QItemSelection>
|
||||
#include <QScrollArea>
|
||||
#include <QWidget>
|
||||
#endif
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QVBoxLayout)
|
||||
QT_FORWARD_DECLARE_CLASS(QLabel)
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
class GemInspector
|
||||
: public QScrollArea
|
||||
{
|
||||
Q_OBJECT // AUTOMOC
|
||||
|
||||
public:
|
||||
explicit GemInspector(GemModel* model, QWidget* parent = nullptr);
|
||||
~GemInspector() = default;
|
||||
|
||||
void Update(const QModelIndex& modelIndex);
|
||||
static QLabel* CreateStyledLabel(QLayout* layout, int fontSize, const QString& colorCodeString);
|
||||
|
||||
// Colors
|
||||
inline constexpr static const char* s_headerColor = "#FFFFFF";
|
||||
inline constexpr static const char* s_textColor = "#DDDDDD";
|
||||
inline constexpr static const char* s_creatorColor = "#94D2FF";
|
||||
|
||||
private slots:
|
||||
void OnSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected);
|
||||
|
||||
private:
|
||||
// Title, description and tag widget container used for the depending and conflicting gems
|
||||
class GemsSubWidget
|
||||
: public QWidget
|
||||
{
|
||||
public:
|
||||
GemsSubWidget(QWidget* parent = nullptr);
|
||||
void Update(const QString& title, const QString& text, const QStringList& gemNames);
|
||||
|
||||
private:
|
||||
QLabel* m_titleLabel = nullptr;
|
||||
QLabel* m_textLabel = nullptr;
|
||||
QVBoxLayout* m_layout = nullptr;
|
||||
TagContainerWidget* m_tagWidget = nullptr;
|
||||
};
|
||||
|
||||
void InitMainWidget();
|
||||
|
||||
GemModel* m_model = nullptr;
|
||||
QWidget* m_mainWidget = nullptr;
|
||||
QVBoxLayout* m_mainLayout = nullptr;
|
||||
|
||||
// General info (top) section
|
||||
QLabel* m_nameLabel = nullptr;
|
||||
QLabel* m_creatorLabel = nullptr;
|
||||
QLabel* m_summaryLabel = nullptr;
|
||||
LinkLabel* m_directoryLinkLabel = nullptr;
|
||||
LinkLabel* m_documentationLinkLabel = nullptr;
|
||||
|
||||
// Depending and conflicting gems
|
||||
GemsSubWidget* m_dependingGems = nullptr;
|
||||
GemsSubWidget* m_conflictingGems = nullptr;
|
||||
|
||||
// Additional information
|
||||
QLabel* m_versionLabel = nullptr;
|
||||
QLabel* m_lastUpdatedLabel = nullptr;
|
||||
QLabel* m_binarySizeLabel = nullptr;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -10,7 +10,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "GemItemDelegate.h"
|
||||
#include <GemCatalog/GemItemDelegate.h>
|
||||
#include "GemModel.h"
|
||||
#include <QEvent>
|
||||
#include <QPainter>
|
||||
@@ -18,15 +18,15 @@
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
GemItemDelegate::GemItemDelegate(GemModel* gemModel, QObject* parent)
|
||||
GemItemDelegate::GemItemDelegate(QAbstractItemModel* model, QObject* parent)
|
||||
: QStyledItemDelegate(parent)
|
||||
, m_gemModel(gemModel)
|
||||
, m_model(model)
|
||||
{
|
||||
AddPlatformIcon(GemInfo::Android, ":/Resources/Android.svg");
|
||||
AddPlatformIcon(GemInfo::iOS, ":/Resources/iOS.svg");
|
||||
AddPlatformIcon(GemInfo::Linux, ":/Resources/Linux.svg");
|
||||
AddPlatformIcon(GemInfo::macOS, ":/Resources/macOS.svg");
|
||||
AddPlatformIcon(GemInfo::Windows, ":/Resources/Windows.svg");
|
||||
AddPlatformIcon(GemInfo::Android, ":/Android.svg");
|
||||
AddPlatformIcon(GemInfo::iOS, ":/iOS.svg");
|
||||
AddPlatformIcon(GemInfo::Linux, ":/Linux.svg");
|
||||
AddPlatformIcon(GemInfo::macOS, ":/macOS.svg");
|
||||
AddPlatformIcon(GemInfo::Windows, ":/Windows.svg");
|
||||
}
|
||||
|
||||
void GemItemDelegate::AddPlatformIcon(GemInfo::Platform platform, const QString& iconPath)
|
||||
@@ -78,7 +78,7 @@ namespace O3DE::ProjectManager
|
||||
}
|
||||
|
||||
// Gem name
|
||||
const QString gemName = m_gemModel->GetName(modelIndex);
|
||||
const QString gemName = GemModel::GetName(modelIndex);
|
||||
QFont gemNameFont(options.font);
|
||||
gemNameFont.setPixelSize(s_gemNameFontSize);
|
||||
gemNameFont.setBold(true);
|
||||
@@ -90,7 +90,7 @@ namespace O3DE::ProjectManager
|
||||
painter->drawText(gemNameRect, Qt::TextSingleLine, gemName);
|
||||
|
||||
// Gem creator
|
||||
const QString gemCreator = m_gemModel->GetCreator(modelIndex);
|
||||
const QString gemCreator = GemModel::GetCreator(modelIndex);
|
||||
QRect gemCreatorRect = GetTextRect(standardFont, gemCreator, s_fontSize);
|
||||
gemCreatorRect.moveTo(contentRect.left(), contentRect.top() + gemNameRect.height());
|
||||
|
||||
@@ -105,7 +105,7 @@ namespace O3DE::ProjectManager
|
||||
painter->setFont(standardFont);
|
||||
painter->setPen(m_textColor);
|
||||
|
||||
const QString summary = m_gemModel->GetSummary(modelIndex);
|
||||
const QString summary = GemModel::GetSummary(modelIndex);
|
||||
painter->drawText(summaryRect, Qt::AlignLeft | Qt::TextWordWrap, summary);
|
||||
|
||||
|
||||
@@ -158,7 +158,7 @@ namespace O3DE::ProjectManager
|
||||
|
||||
void GemItemDelegate::DrawPlatformIcons(QPainter* painter, const QRect& contentRect, const QModelIndex& modelIndex) const
|
||||
{
|
||||
const GemInfo::Platforms platforms = m_gemModel->GetPlatforms(modelIndex);
|
||||
const GemInfo::Platforms platforms = GemModel::GetPlatforms(modelIndex);
|
||||
int startX = 0;
|
||||
|
||||
// Iterate and draw the platforms in the order they are defined in the enum.
|
||||
@@ -188,7 +188,7 @@ namespace O3DE::ProjectManager
|
||||
QPoint circleCenter;
|
||||
QString buttonText;
|
||||
|
||||
const bool isAdded = m_gemModel->IsAdded(modelIndex);
|
||||
const bool isAdded = GemModel::IsAdded(modelIndex);
|
||||
if (isAdded)
|
||||
{
|
||||
painter->setBrush(m_buttonEnabledColor);
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <QStyledItemDelegate>
|
||||
#include "GemInfo.h"
|
||||
#include "GemModel.h"
|
||||
#include <QAbstractItemModel>
|
||||
#include <QHash>
|
||||
#endif
|
||||
|
||||
@@ -29,22 +29,13 @@ namespace O3DE::ProjectManager
|
||||
Q_OBJECT // AUTOMOC
|
||||
|
||||
public:
|
||||
explicit GemItemDelegate(GemModel* gemModel, QObject* parent = nullptr);
|
||||
explicit GemItemDelegate(QAbstractItemModel* model, QObject* parent = nullptr);
|
||||
~GemItemDelegate() = default;
|
||||
|
||||
void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& modelIndex) const override;
|
||||
bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& modelIndex) override;
|
||||
QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& modelIndex) const override;
|
||||
|
||||
private:
|
||||
void CalcRects(const QStyleOptionViewItem& option, const QModelIndex& modelIndex, QRect& outFullRect, QRect& outItemRect, QRect& outContentRect) const;
|
||||
QRect GetTextRect(QFont& font, const QString& text, qreal fontSize) const;
|
||||
QRect CalcButtonRect(const QRect& contentRect) const;
|
||||
void DrawPlatformIcons(QPainter* painter, const QRect& contentRect, const QModelIndex& modelIndex) const;
|
||||
void DrawButton(QPainter* painter, const QRect& contentRect, const QModelIndex& modelIndex) const;
|
||||
|
||||
GemModel* m_gemModel = nullptr;
|
||||
|
||||
// Colors
|
||||
const QColor m_textColor = QColor("#FFFFFF");
|
||||
const QColor m_linkColor = QColor("#94D2FF");
|
||||
@@ -71,6 +62,15 @@ namespace O3DE::ProjectManager
|
||||
inline constexpr static int s_buttonCircleRadius = s_buttonBorderRadius - 3;
|
||||
inline constexpr static qreal s_buttonFontSize = 12.0;
|
||||
|
||||
private:
|
||||
void CalcRects(const QStyleOptionViewItem& option, const QModelIndex& modelIndex, QRect& outFullRect, QRect& outItemRect, QRect& outContentRect) const;
|
||||
QRect GetTextRect(QFont& font, const QString& text, qreal fontSize) const;
|
||||
QRect CalcButtonRect(const QRect& contentRect) const;
|
||||
void DrawPlatformIcons(QPainter* painter, const QRect& contentRect, const QModelIndex& modelIndex) const;
|
||||
void DrawButton(QPainter* painter, const QRect& contentRect, const QModelIndex& modelIndex) const;
|
||||
|
||||
QAbstractItemModel* m_model = nullptr;
|
||||
|
||||
// Platform icons
|
||||
void AddPlatformIcon(GemInfo::Platform platform, const QString& iconPath);
|
||||
inline constexpr static int s_platformIconSize = 16;
|
||||
|
||||
@@ -18,17 +18,15 @@
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
GemListView::GemListView(GemModel* model, QWidget *parent) :
|
||||
QListView(parent)
|
||||
GemListView::GemListView(QAbstractItemModel* model, QItemSelectionModel* selectionModel, QWidget* parent)
|
||||
: QListView(parent)
|
||||
{
|
||||
setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
|
||||
|
||||
QPalette palette;
|
||||
palette.setColor(QPalette::Window, QColor("#333333"));
|
||||
setPalette(palette);
|
||||
setStyleSheet("background-color: #333333;");
|
||||
|
||||
setModel(model);
|
||||
setSelectionModel(model->GetSelectionModel());
|
||||
setSelectionModel(selectionModel);
|
||||
setItemDelegate(new GemItemDelegate(model, this));
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include "GemInfo.h"
|
||||
#include "GemModel.h"
|
||||
#include <QAbstractItemModel>
|
||||
#include <QItemSelectionModel>
|
||||
#include <QListView>
|
||||
#endif
|
||||
|
||||
@@ -24,8 +25,9 @@ namespace O3DE::ProjectManager
|
||||
: public QListView
|
||||
{
|
||||
Q_OBJECT // AUTOMOC
|
||||
|
||||
public:
|
||||
explicit GemListView(GemModel* model, QWidget *parent = nullptr);
|
||||
explicit GemListView(QAbstractItemModel* model, QItemSelectionModel* selectionModel, QWidget* parent = nullptr);
|
||||
~GemListView() = default;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "GemModel.h"
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <GemCatalog/GemModel.h>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
@@ -32,12 +33,27 @@ namespace O3DE::ProjectManager
|
||||
item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
|
||||
|
||||
item->setData(gemInfo.m_name, RoleName);
|
||||
const QString uuidString = gemInfo.m_uuid.ToString<AZStd::string>().c_str();
|
||||
item->setData(uuidString, RoleUuid);
|
||||
item->setData(gemInfo.m_creator, RoleCreator);
|
||||
item->setData(static_cast<int>(gemInfo.m_platforms), RolePlatforms);
|
||||
item->setData(gemInfo.m_gemOrigin, RoleGemOrigin);
|
||||
item->setData(aznumeric_cast<int>(gemInfo.m_platforms), RolePlatforms);
|
||||
item->setData(aznumeric_cast<int>(gemInfo.m_types), RoleTypes);
|
||||
item->setData(gemInfo.m_summary, RoleSummary);
|
||||
item->setData(gemInfo.m_isAdded, RoleIsAdded);
|
||||
item->setData(gemInfo.m_directoryLink, RoleDirectoryLink);
|
||||
item->setData(gemInfo.m_documentationLink, RoleDocLink);
|
||||
item->setData(gemInfo.m_dependingGemUuids, RoleDependingGems);
|
||||
item->setData(gemInfo.m_conflictingGemUuids, RoleConflictingGems);
|
||||
item->setData(gemInfo.m_version, RoleVersion);
|
||||
item->setData(gemInfo.m_lastUpdatedDate, RoleLastUpdated);
|
||||
item->setData(gemInfo.m_binarySizeInKB, RoleBinarySize);
|
||||
item->setData(gemInfo.m_features, RoleFeatures);
|
||||
|
||||
appendRow(item);
|
||||
|
||||
const QModelIndex modelIndex = index(rowCount()-1, 0);
|
||||
m_uuidToIndexMap[uuidString] = modelIndex;
|
||||
}
|
||||
|
||||
void GemModel::Clear()
|
||||
@@ -45,28 +61,130 @@ namespace O3DE::ProjectManager
|
||||
clear();
|
||||
}
|
||||
|
||||
QString GemModel::GetName(const QModelIndex& modelIndex) const
|
||||
QString GemModel::GetName(const QModelIndex& modelIndex)
|
||||
{
|
||||
return modelIndex.data(RoleName).toString();
|
||||
}
|
||||
|
||||
QString GemModel::GetCreator(const QModelIndex& modelIndex) const
|
||||
QString GemModel::GetCreator(const QModelIndex& modelIndex)
|
||||
{
|
||||
return modelIndex.data(RoleCreator).toString();
|
||||
}
|
||||
|
||||
GemInfo::Platforms GemModel::GetPlatforms(const QModelIndex& modelIndex) const
|
||||
GemInfo::GemOrigin GemModel::GetGemOrigin(const QModelIndex& modelIndex)
|
||||
{
|
||||
return static_cast<GemInfo::GemOrigin>(modelIndex.data(RoleGemOrigin).toInt());
|
||||
}
|
||||
|
||||
QString GemModel::GetUuidString(const QModelIndex& modelIndex)
|
||||
{
|
||||
return modelIndex.data(RoleUuid).toString();
|
||||
}
|
||||
|
||||
GemInfo::Platforms GemModel::GetPlatforms(const QModelIndex& modelIndex)
|
||||
{
|
||||
return static_cast<GemInfo::Platforms>(modelIndex.data(RolePlatforms).toInt());
|
||||
}
|
||||
|
||||
QString GemModel::GetSummary(const QModelIndex& modelIndex) const
|
||||
GemInfo::Types GemModel::GetTypes(const QModelIndex& modelIndex)
|
||||
{
|
||||
return static_cast<GemInfo::Types>(modelIndex.data(RoleTypes).toInt());
|
||||
}
|
||||
|
||||
QString GemModel::GetSummary(const QModelIndex& modelIndex)
|
||||
{
|
||||
return modelIndex.data(RoleSummary).toString();
|
||||
}
|
||||
|
||||
bool GemModel::IsAdded(const QModelIndex& modelIndex) const
|
||||
bool GemModel::IsAdded(const QModelIndex& modelIndex)
|
||||
{
|
||||
return modelIndex.data(RoleIsAdded).toBool();
|
||||
}
|
||||
|
||||
QString GemModel::GetDirectoryLink(const QModelIndex& modelIndex)
|
||||
{
|
||||
return modelIndex.data(RoleDirectoryLink).toString();
|
||||
}
|
||||
|
||||
QString GemModel::GetDocLink(const QModelIndex& modelIndex)
|
||||
{
|
||||
return modelIndex.data(RoleDocLink).toString();
|
||||
}
|
||||
|
||||
QModelIndex GemModel::FindIndexByUuidString(const QString& uuidString) const
|
||||
{
|
||||
const auto iterator = m_uuidToIndexMap.find(uuidString);
|
||||
if (iterator != m_uuidToIndexMap.end())
|
||||
{
|
||||
return iterator.value();
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void GemModel::FindGemNamesByUuidStrings(QStringList& inOutGemNames)
|
||||
{
|
||||
for (QString& dependingGemString : inOutGemNames)
|
||||
{
|
||||
QModelIndex modelIndex = FindIndexByUuidString(dependingGemString);
|
||||
if (modelIndex.isValid())
|
||||
{
|
||||
dependingGemString = GetName(modelIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QStringList GemModel::GetDependingGemUuids(const QModelIndex& modelIndex)
|
||||
{
|
||||
return modelIndex.data(RoleDependingGems).toStringList();
|
||||
}
|
||||
|
||||
QStringList GemModel::GetDependingGemNames(const QModelIndex& modelIndex)
|
||||
{
|
||||
QStringList result = GetDependingGemUuids(modelIndex);
|
||||
if (result.isEmpty())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
FindGemNamesByUuidStrings(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
QStringList GemModel::GetConflictingGemUuids(const QModelIndex& modelIndex)
|
||||
{
|
||||
return modelIndex.data(RoleConflictingGems).toStringList();
|
||||
}
|
||||
|
||||
QStringList GemModel::GetConflictingGemNames(const QModelIndex& modelIndex)
|
||||
{
|
||||
QStringList result = GetConflictingGemUuids(modelIndex);
|
||||
if (result.isEmpty())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
FindGemNamesByUuidStrings(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
QString GemModel::GetVersion(const QModelIndex& modelIndex)
|
||||
{
|
||||
return modelIndex.data(RoleVersion).toString();
|
||||
}
|
||||
|
||||
QString GemModel::GetLastUpdated(const QModelIndex& modelIndex)
|
||||
{
|
||||
return modelIndex.data(RoleLastUpdated).toString();
|
||||
}
|
||||
|
||||
int GemModel::GetBinarySizeInKB(const QModelIndex& modelIndex)
|
||||
{
|
||||
return modelIndex.data(RoleBinarySize).toInt();
|
||||
}
|
||||
|
||||
QStringList GemModel::GetFeatures(const QModelIndex& modelIndex)
|
||||
{
|
||||
return modelIndex.data(RoleFeatures).toStringList();
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include "GemInfo.h"
|
||||
#include <GemCatalog/GemInfo.h>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QStandardItemModel>
|
||||
#include <QItemSelectionModel>
|
||||
#endif
|
||||
@@ -32,22 +33,50 @@ namespace O3DE::ProjectManager
|
||||
void AddGem(const GemInfo& gemInfo);
|
||||
void Clear();
|
||||
|
||||
QString GetName(const QModelIndex& modelIndex) const;
|
||||
QString GetCreator(const QModelIndex& modelIndex) const;
|
||||
GemInfo::Platforms GetPlatforms(const QModelIndex& modelIndex) const;
|
||||
QString GetSummary(const QModelIndex& modelIndex) const;
|
||||
bool IsAdded(const QModelIndex& modelIndex) const;
|
||||
QModelIndex FindIndexByUuidString(const QString& uuidString) const;
|
||||
void FindGemNamesByUuidStrings(QStringList& inOutGemNames);
|
||||
QStringList GetDependingGemUuids(const QModelIndex& modelIndex);
|
||||
QStringList GetDependingGemNames(const QModelIndex& modelIndex);
|
||||
QStringList GetConflictingGemUuids(const QModelIndex& modelIndex);
|
||||
QStringList GetConflictingGemNames(const QModelIndex& modelIndex);
|
||||
|
||||
static QString GetName(const QModelIndex& modelIndex);
|
||||
static QString GetCreator(const QModelIndex& modelIndex);
|
||||
static GemInfo::GemOrigin GetGemOrigin(const QModelIndex& modelIndex);
|
||||
static QString GetUuidString(const QModelIndex& modelIndex);
|
||||
static GemInfo::Platforms GetPlatforms(const QModelIndex& modelIndex);
|
||||
static GemInfo::Types GetTypes(const QModelIndex& modelIndex);
|
||||
static QString GetSummary(const QModelIndex& modelIndex);
|
||||
static bool IsAdded(const QModelIndex& modelIndex);
|
||||
static QString GetDirectoryLink(const QModelIndex& modelIndex);
|
||||
static QString GetDocLink(const QModelIndex& modelIndex);
|
||||
static QString GetVersion(const QModelIndex& modelIndex);
|
||||
static QString GetLastUpdated(const QModelIndex& modelIndex);
|
||||
static int GetBinarySizeInKB(const QModelIndex& modelIndex);
|
||||
static QStringList GetFeatures(const QModelIndex& modelIndex);
|
||||
|
||||
private:
|
||||
enum UserRole
|
||||
{
|
||||
RoleName = Qt::UserRole,
|
||||
RoleUuid,
|
||||
RoleCreator,
|
||||
RoleGemOrigin,
|
||||
RolePlatforms,
|
||||
RoleSummary,
|
||||
RoleIsAdded
|
||||
RoleIsAdded,
|
||||
RoleDirectoryLink,
|
||||
RoleDocLink,
|
||||
RoleDependingGems,
|
||||
RoleConflictingGems,
|
||||
RoleVersion,
|
||||
RoleLastUpdated,
|
||||
RoleBinarySize,
|
||||
RoleFeatures,
|
||||
RoleTypes
|
||||
};
|
||||
|
||||
QHash<QString, QModelIndex> m_uuidToIndexMap;
|
||||
QItemSelectionModel* m_selectionModel = nullptr;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* 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 <GemCatalog/GemSortFilterProxyModel.h>
|
||||
#include <QItemSelectionModel>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
GemSortFilterProxyModel::GemSortFilterProxyModel(GemModel* sourceModel, QObject* parent)
|
||||
: QSortFilterProxyModel(parent)
|
||||
, m_sourceModel(sourceModel)
|
||||
{
|
||||
setSourceModel(sourceModel);
|
||||
m_selectionProxyModel = new AzQtComponents::SelectionProxyModel(sourceModel->GetSelectionModel(), this, parent);
|
||||
}
|
||||
|
||||
bool GemSortFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const
|
||||
{
|
||||
// Do not use sourceParent->child because an invalid parent does not produce valid children (which our index function does)
|
||||
QModelIndex sourceIndex = sourceModel()->index(sourceRow, 0, sourceParent);
|
||||
if (!sourceIndex.isValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_sourceModel->GetName(sourceIndex).contains(m_searchString, Qt::CaseInsensitive))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Gem origins
|
||||
if (m_gemOriginFilter)
|
||||
{
|
||||
bool supportsAnyFilteredGemOrigin = false;
|
||||
for (int i = 0; i < GemInfo::NumGemOrigins; ++i)
|
||||
{
|
||||
const GemInfo::GemOrigin filteredGemOrigin = static_cast<GemInfo::GemOrigin>(1 << i);
|
||||
if (m_gemOriginFilter & filteredGemOrigin)
|
||||
{
|
||||
if ((GemModel::GetGemOrigin(sourceIndex) == filteredGemOrigin))
|
||||
{
|
||||
supportsAnyFilteredGemOrigin = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!supportsAnyFilteredGemOrigin)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Platform
|
||||
if (m_platformFilter)
|
||||
{
|
||||
bool supportsAnyFilteredPlatform = false;
|
||||
for (int i = 0; i < GemInfo::NumPlatforms; ++i)
|
||||
{
|
||||
const GemInfo::Platform filteredPlatform = static_cast<GemInfo::Platform>(1 << i);
|
||||
if (m_platformFilter & filteredPlatform)
|
||||
{
|
||||
if ((GemModel::GetPlatforms(sourceIndex) & filteredPlatform))
|
||||
{
|
||||
supportsAnyFilteredPlatform = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!supportsAnyFilteredPlatform)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Types (Asset, Code, Tool)
|
||||
if (m_typeFilter)
|
||||
{
|
||||
bool supportsAnyFilteredType = false;
|
||||
for (int i = 0; i < GemInfo::NumTypes; ++i)
|
||||
{
|
||||
const GemInfo::Type filteredType = static_cast<GemInfo::Type>(1 << i);
|
||||
if (m_typeFilter & filteredType)
|
||||
{
|
||||
if ((GemModel::GetTypes(sourceIndex) & filteredType))
|
||||
{
|
||||
supportsAnyFilteredType = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!supportsAnyFilteredType)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Features
|
||||
if (!m_featureFilter.isEmpty())
|
||||
{
|
||||
bool containsFilterFeature = false;
|
||||
const QStringList features = m_sourceModel->GetFeatures(sourceIndex);
|
||||
for (const QString& feature : features)
|
||||
{
|
||||
if (m_featureFilter.contains(feature))
|
||||
{
|
||||
containsFilterFeature = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!containsFilterFeature)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GemSortFilterProxyModel::InvalidateFilter()
|
||||
{
|
||||
invalidate();
|
||||
emit OnInvalidated();
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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 <AzQtComponents/Utilities/SelectionProxyModel.h>
|
||||
#include <GemCatalog/GemModel.h>
|
||||
#include <QtCore/QSortFilterProxyModel>
|
||||
#include <QSet>
|
||||
#endif
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QItemSelectionModel)
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
class GemSortFilterProxyModel
|
||||
: public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT // AUTOMOC
|
||||
|
||||
public:
|
||||
GemSortFilterProxyModel(GemModel* sourceModel, QObject* parent = nullptr);
|
||||
|
||||
bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const override;
|
||||
|
||||
GemModel* GetSourceModel() const { return m_sourceModel; }
|
||||
AzQtComponents::SelectionProxyModel* GetSelectionModel() const { return m_selectionProxyModel; }
|
||||
|
||||
void SetSearchString(const QString& searchString) { m_searchString = searchString; InvalidateFilter(); }
|
||||
|
||||
GemInfo::GemOrigins GetGemOrigins() const { return m_gemOriginFilter; }
|
||||
void SetGemOrigins(const GemInfo::GemOrigins& gemOrigins) { m_gemOriginFilter = gemOrigins; InvalidateFilter(); }
|
||||
|
||||
GemInfo::Platforms GetPlatforms() const { return m_platformFilter; }
|
||||
void SetPlatforms(const GemInfo::Platforms& platforms) { m_platformFilter = platforms; InvalidateFilter(); }
|
||||
|
||||
GemInfo::Types GetTypes() const { return m_typeFilter; }
|
||||
void SetTypes(const GemInfo::Types& types) { m_typeFilter = types; InvalidateFilter(); }
|
||||
|
||||
const QSet<QString>& GetFeatures() const { return m_featureFilter; }
|
||||
void SetFeatures(const QSet<QString>& features) { m_featureFilter = features; InvalidateFilter(); }
|
||||
|
||||
void InvalidateFilter();
|
||||
|
||||
signals:
|
||||
void OnInvalidated();
|
||||
|
||||
private:
|
||||
GemModel* m_sourceModel = nullptr;
|
||||
AzQtComponents::SelectionProxyModel* m_selectionProxyModel = nullptr;
|
||||
|
||||
QString m_searchString;
|
||||
GemInfo::GemOrigins m_gemOriginFilter = {};
|
||||
GemInfo::Platforms m_platformFilter = {};
|
||||
GemInfo::Types m_typeFilter = {};
|
||||
QSet<QString> m_featureFilter;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -27,7 +27,12 @@ namespace O3DE::ProjectManager
|
||||
|
||||
void LinkLabel::mousePressEvent([[maybe_unused]] QMouseEvent* event)
|
||||
{
|
||||
QDesktopServices::openUrl(m_url);
|
||||
if (m_url.isValid())
|
||||
{
|
||||
QDesktopServices::openUrl(m_url);
|
||||
}
|
||||
|
||||
emit clicked();
|
||||
}
|
||||
|
||||
void LinkLabel::enterEvent([[maybe_unused]] QEvent* event)
|
||||
|
||||
@@ -26,10 +26,16 @@ namespace O3DE::ProjectManager
|
||||
class LinkLabel
|
||||
: public QLabel
|
||||
{
|
||||
Q_OBJECT // AUTOMOC
|
||||
|
||||
public:
|
||||
LinkLabel(const QString& text, const QUrl& url = {}, QWidget* parent = nullptr);
|
||||
LinkLabel(const QString& text = {}, const QUrl& url = {}, QWidget* parent = nullptr);
|
||||
|
||||
void SetUrl(const QUrl& url);
|
||||
|
||||
signals:
|
||||
void clicked();
|
||||
|
||||
private:
|
||||
void mousePressEvent(QMouseEvent* event) override;
|
||||
void enterEvent(QEvent* event) override;
|
||||
|
||||
@@ -11,16 +11,23 @@
|
||||
*/
|
||||
|
||||
#include <NewProjectSettingsScreen.h>
|
||||
#include <PythonBindingsInterface.h>
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QFileDialog>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QRadioButton>
|
||||
#include <QButtonGroup>
|
||||
#include <QPushButton>
|
||||
#include <QSpacerItem>
|
||||
#include <QStandardPaths>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
constexpr const char* k_pathProperty = "Path";
|
||||
|
||||
NewProjectSettingsScreen::NewProjectSettingsScreen(QWidget* parent)
|
||||
: ScreenWidget(parent)
|
||||
{
|
||||
@@ -29,19 +36,27 @@ namespace O3DE::ProjectManager
|
||||
|
||||
QVBoxLayout* vLayout = new QVBoxLayout(this);
|
||||
|
||||
QLabel* projectNameLabel = new QLabel(this);
|
||||
projectNameLabel->setText("Project Name");
|
||||
QLabel* projectNameLabel = new QLabel(tr("Project Name"), this);
|
||||
vLayout->addWidget(projectNameLabel);
|
||||
|
||||
QLineEdit* projectNameLineEdit = new QLineEdit(this);
|
||||
vLayout->addWidget(projectNameLineEdit);
|
||||
m_projectNameLineEdit = new QLineEdit(tr("New Project"), this);
|
||||
vLayout->addWidget(m_projectNameLineEdit);
|
||||
|
||||
QLabel* projectPathLabel = new QLabel(this);
|
||||
projectPathLabel->setText("Project Location");
|
||||
QLabel* projectPathLabel = new QLabel(tr("Project Location"), this);
|
||||
vLayout->addWidget(projectPathLabel);
|
||||
|
||||
QLineEdit* projectPathLineEdit = new QLineEdit(this);
|
||||
vLayout->addWidget(projectPathLineEdit);
|
||||
{
|
||||
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");
|
||||
@@ -50,14 +65,21 @@ namespace O3DE::ProjectManager
|
||||
QHBoxLayout* templateLayout = new QHBoxLayout(this);
|
||||
vLayout->addItem(templateLayout);
|
||||
|
||||
QRadioButton* projectTemplateStandardRadioButton = new QRadioButton(this);
|
||||
projectTemplateStandardRadioButton->setText("Standard (Recommened)");
|
||||
projectTemplateStandardRadioButton->setChecked(true);
|
||||
templateLayout->addWidget(projectTemplateStandardRadioButton);
|
||||
m_projectTemplateButtonGroup = new QButtonGroup(this);
|
||||
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);
|
||||
|
||||
QRadioButton* projectTemplateEmptyRadioButton = new QRadioButton(this);
|
||||
projectTemplateEmptyRadioButton->setText("Empty");
|
||||
templateLayout->addWidget(projectTemplateEmptyRadioButton);
|
||||
templateLayout->addWidget(radioButton);
|
||||
}
|
||||
|
||||
m_projectTemplateButtonGroup->buttons().first()->setChecked(true);
|
||||
}
|
||||
|
||||
QSpacerItem* verticalSpacer = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding);
|
||||
vLayout->addItem(verticalSpacer);
|
||||
@@ -74,9 +96,54 @@ namespace O3DE::ProjectManager
|
||||
return ProjectManagerScreen::NewProjectSettings;
|
||||
}
|
||||
|
||||
QString NewProjectSettingsScreen::GetNextButtonText()
|
||||
void NewProjectSettingsScreen::HandleBrowseButton()
|
||||
{
|
||||
return "Create Project";
|
||||
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);
|
||||
return projectInfo;
|
||||
}
|
||||
|
||||
QString NewProjectSettingsScreen::GetProjectTemplatePath()
|
||||
{
|
||||
return m_projectTemplateButtonGroup->checkedButton()->property(k_pathProperty).toString();
|
||||
}
|
||||
|
||||
bool NewProjectSettingsScreen::Validate()
|
||||
{
|
||||
bool projectNameIsValid = true;
|
||||
if (m_projectNameLineEdit->text().isEmpty())
|
||||
{
|
||||
projectNameIsValid = false;
|
||||
}
|
||||
|
||||
bool projectPathIsValid = true;
|
||||
if (m_projectPathLineEdit->text().isEmpty())
|
||||
{
|
||||
projectPathIsValid = false;
|
||||
}
|
||||
|
||||
QDir path(QDir::toNativeSeparators(m_projectPathLineEdit->text() + "/" + m_projectNameLineEdit->text()));
|
||||
if (path.exists() && !path.isEmpty())
|
||||
{
|
||||
projectPathIsValid = false;
|
||||
}
|
||||
|
||||
return projectNameIsValid && projectPathIsValid;
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -13,8 +13,12 @@
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <ScreenWidget.h>
|
||||
#include <ProjectInfo.h>
|
||||
#endif
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QButtonGroup)
|
||||
QT_FORWARD_DECLARE_CLASS(QLineEdit)
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
class NewProjectSettingsScreen
|
||||
@@ -24,7 +28,19 @@ namespace O3DE::ProjectManager
|
||||
explicit NewProjectSettingsScreen(QWidget* parent = nullptr);
|
||||
~NewProjectSettingsScreen() = default;
|
||||
ProjectManagerScreen GetScreenEnum() override;
|
||||
QString GetNextButtonText() override;
|
||||
|
||||
ProjectInfo GetProjectInfo();
|
||||
QString GetProjectTemplatePath();
|
||||
|
||||
bool Validate();
|
||||
|
||||
protected slots:
|
||||
void HandleBrowseButton();
|
||||
|
||||
private:
|
||||
QLineEdit* m_projectNameLineEdit;
|
||||
QLineEdit* m_projectPathLineEdit;
|
||||
QButtonGroup* m_projectTemplateButtonGroup;
|
||||
};
|
||||
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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 "PathValidator.h"
|
||||
|
||||
#include <QWidget>
|
||||
#include <QFileInfo>
|
||||
#include <QDir>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
PathValidator::PathValidator(PathMode pathMode, QWidget* parent)
|
||||
: QValidator(parent)
|
||||
, m_pathMode(pathMode)
|
||||
{
|
||||
}
|
||||
|
||||
void PathValidator::setAllowEmpty(bool allowEmpty)
|
||||
{
|
||||
m_allowEmpty = allowEmpty;
|
||||
}
|
||||
|
||||
void PathValidator::setPathMode(PathMode pathMode)
|
||||
{
|
||||
m_pathMode = pathMode;
|
||||
}
|
||||
|
||||
QValidator::State PathValidator::validate(QString &text, int &) const
|
||||
{
|
||||
if(text.isEmpty())
|
||||
{
|
||||
return m_allowEmpty ? QValidator::Acceptable : QValidator::Intermediate;
|
||||
}
|
||||
|
||||
QFileInfo pathInfo(text);
|
||||
if(!pathInfo.dir().exists())
|
||||
{
|
||||
return QValidator::Intermediate;
|
||||
}
|
||||
|
||||
switch(m_pathMode)
|
||||
{
|
||||
case PathMode::AnyFile://acceptable, as long as it's not an directoy
|
||||
return pathInfo.isDir() ? QValidator::Intermediate : QValidator::Acceptable;
|
||||
case PathMode::ExistingFile://must be an existing file
|
||||
return pathInfo.exists() && pathInfo.isFile() ? QValidator::Acceptable : QValidator::Intermediate;
|
||||
case PathMode::ExistingFolder://must be an existing folder
|
||||
return pathInfo.exists() && pathInfo.isDir() ? QValidator::Acceptable : QValidator::Intermediate;
|
||||
default:
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
return QValidator::Invalid;
|
||||
}
|
||||
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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 <QValidator>
|
||||
#endif
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QWidget)
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
class PathValidator
|
||||
: public QValidator
|
||||
{
|
||||
public:
|
||||
enum class PathMode {
|
||||
ExistingFile, //!< A single, existings file. Useful for "Open file"
|
||||
ExistingFolder, //!< A single, existing directory. Useful for "Open Folder"
|
||||
AnyFile //!< A single, valid file, doesn't have to exist but the directory must. Useful for "Save File"
|
||||
};
|
||||
|
||||
explicit PathValidator(PathMode pathMode, QWidget* parent = nullptr);
|
||||
~PathValidator() = default;
|
||||
|
||||
void setAllowEmpty(bool allowEmpty);
|
||||
void setPathMode(PathMode pathMode);
|
||||
|
||||
QValidator::State validate(QString &text, int &) const override;
|
||||
|
||||
private:
|
||||
PathMode m_pathMode = PathMode::AnyFile;
|
||||
bool m_allowEmpty = false;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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 <ProjectButtonWidget.h>
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QResizeEvent>
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QPixmap>
|
||||
#include <QMenu>
|
||||
#include <QSpacerItem>
|
||||
|
||||
//#define SHOW_ALL_PROJECT_ACTIONS
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
inline constexpr static int s_projectImageWidth = 210;
|
||||
inline constexpr static int s_projectImageHeight = 280;
|
||||
|
||||
LabelButton::LabelButton(QWidget* parent)
|
||||
: QLabel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void LabelButton::mousePressEvent([[maybe_unused]] QMouseEvent* event)
|
||||
{
|
||||
emit triggered();
|
||||
}
|
||||
|
||||
ProjectButton::ProjectButton(const QString& projectName, QWidget* parent)
|
||||
: QFrame(parent)
|
||||
, m_projectName(projectName)
|
||||
, m_projectImagePath(":/Resources/DefaultProjectImage.png")
|
||||
{
|
||||
Setup();
|
||||
}
|
||||
|
||||
ProjectButton::ProjectButton(const QString& projectName, const QString& projectImage, QWidget* parent)
|
||||
: QFrame(parent)
|
||||
, m_projectName(projectName)
|
||||
, m_projectImagePath(projectImage)
|
||||
{
|
||||
Setup();
|
||||
}
|
||||
|
||||
void ProjectButton::Setup()
|
||||
{
|
||||
QVBoxLayout* vLayout = new QVBoxLayout();
|
||||
vLayout->setSpacing(0);
|
||||
vLayout->setContentsMargins(0, 0, 0, 0);
|
||||
setLayout(vLayout);
|
||||
|
||||
m_projectImageLabel = new LabelButton(this);
|
||||
m_projectImageLabel->setFixedSize(s_projectImageWidth, s_projectImageHeight);
|
||||
vLayout->addWidget(m_projectImageLabel);
|
||||
|
||||
m_projectImageLabel->setPixmap(QPixmap(m_projectImagePath).scaled(m_projectImageLabel->size(), Qt::KeepAspectRatioByExpanding));
|
||||
|
||||
QMenu* newProjectMenu = new QMenu(this);
|
||||
m_editProjectAction = newProjectMenu->addAction(tr("Edit Project Settings..."));
|
||||
|
||||
#ifdef SHOW_ALL_PROJECT_ACTIONS
|
||||
m_editProjectGemsAction = newProjectMenu->addAction(tr("Cutomize Gems..."));
|
||||
newProjectMenu->addSeparator();
|
||||
m_copyProjectAction = newProjectMenu->addAction(tr("Duplicate"));
|
||||
newProjectMenu->addSeparator();
|
||||
m_removeProjectAction = newProjectMenu->addAction(tr("Remove from O3DE"));
|
||||
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);
|
||||
|
||||
setFixedSize(s_projectImageWidth, s_projectImageHeight + m_projectSettingsMenuButton->height());
|
||||
|
||||
connect(m_projectImageLabel, &LabelButton::triggered, [this]() { emit OpenProject(m_projectName); });
|
||||
connect(m_editProjectAction, &QAction::triggered, [this]() { emit EditProject(m_projectName); });
|
||||
|
||||
#ifdef SHOW_ALL_PROJECT_ACTIONS
|
||||
connect(m_editProjectGemsAction, &QAction::triggered, [this]() { emit EditProjectGems(m_projectName); });
|
||||
connect(m_copyProjectAction, &QAction::triggered, [this]() { emit CopyProject(m_projectName); });
|
||||
connect(m_removeProjectAction, &QAction::triggered, [this]() { emit RemoveProject(m_projectName); });
|
||||
connect(m_deleteProjectAction, &QAction::triggered, [this]() { emit DeleteProject(m_projectName); });
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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 <QFrame>
|
||||
#include <QLabel>
|
||||
#endif
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QPixmap)
|
||||
QT_FORWARD_DECLARE_CLASS(QPushButton)
|
||||
QT_FORWARD_DECLARE_CLASS(QAction)
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
class LabelButton
|
||||
: public QLabel
|
||||
{
|
||||
Q_OBJECT // AUTOMOC
|
||||
|
||||
public:
|
||||
explicit LabelButton(QWidget* parent = nullptr);
|
||||
~LabelButton() = default;
|
||||
|
||||
signals:
|
||||
void triggered();
|
||||
|
||||
public slots:
|
||||
void mousePressEvent(QMouseEvent* event) override;
|
||||
};
|
||||
|
||||
class ProjectButton
|
||||
: public QFrame
|
||||
{
|
||||
Q_OBJECT // AUTOMOC
|
||||
|
||||
public:
|
||||
explicit ProjectButton(const QString& projectName, QWidget* parent = nullptr);
|
||||
explicit ProjectButton(const QString& projectName, const QString& projectImage, QWidget* parent = nullptr);
|
||||
~ProjectButton() = default;
|
||||
|
||||
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);
|
||||
|
||||
private:
|
||||
void Setup();
|
||||
|
||||
QString m_projectName;
|
||||
QString m_projectImagePath;
|
||||
LabelButton* m_projectImageLabel;
|
||||
QPushButton* m_projectSettingsMenuButton;
|
||||
QAction* m_editProjectAction;
|
||||
QAction* m_editProjectGemsAction;
|
||||
QAction* m_copyProjectAction;
|
||||
QAction* m_removeProjectAction;
|
||||
QAction* m_deleteProjectAction;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -14,12 +14,11 @@
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
ProjectInfo::ProjectInfo(const QString& path, const QString& projectName, const QString& productName, const AZ::Uuid projectId,
|
||||
ProjectInfo::ProjectInfo(const QString& path, const QString& projectName, const QString& displayName,
|
||||
const QString& imagePath, const QString& backgroundImagePath, bool isNew)
|
||||
: m_path(path)
|
||||
, m_projectName(projectName)
|
||||
, m_productName(productName)
|
||||
, m_projectId(projectId)
|
||||
, m_displayName(displayName)
|
||||
, m_imagePath(imagePath)
|
||||
, m_backgroundImagePath(backgroundImagePath)
|
||||
, m_isNew(isNew)
|
||||
@@ -28,6 +27,6 @@ namespace O3DE::ProjectManager
|
||||
|
||||
bool ProjectInfo::IsValid() const
|
||||
{
|
||||
return !m_path.isEmpty() && !m_projectId.IsNull();
|
||||
return !m_path.isEmpty() && !m_projectName.isEmpty();
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace O3DE::ProjectManager
|
||||
{
|
||||
public:
|
||||
ProjectInfo() = default;
|
||||
ProjectInfo(const QString& path, const QString& projectName, const QString& productName, const AZ::Uuid projectId,
|
||||
ProjectInfo(const QString& path, const QString& projectName, const QString& displayName,
|
||||
const QString& imagePath, const QString& backgroundImagePath, bool isNew);
|
||||
|
||||
bool IsValid() const;
|
||||
@@ -33,8 +33,7 @@ namespace O3DE::ProjectManager
|
||||
|
||||
// From project.json
|
||||
QString m_projectName;
|
||||
QString m_productName;
|
||||
AZ::Uuid m_projectId;
|
||||
QString m_displayName;
|
||||
|
||||
// Used on projects home screen
|
||||
QString m_imagePath;
|
||||
|
||||
@@ -27,6 +27,10 @@ namespace O3DE::ProjectManager
|
||||
, 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<PythonBindings>(engineRootPath);
|
||||
|
||||
@@ -38,17 +42,17 @@ namespace O3DE::ProjectManager
|
||||
|
||||
QDir rootDir = QString::fromUtf8(engineRootPath.Native().data(), aznumeric_cast<int>(engineRootPath.Native().size()));
|
||||
const auto pathOnDisk = rootDir.absoluteFilePath("Code/Tools/ProjectManager/Resources");
|
||||
const auto qrcPath = QStringLiteral(":/ProjectManagerWindow");
|
||||
AzQtComponents::StyleManager::addSearchPaths("projectmanagerwindow", pathOnDisk, qrcPath, engineRootPath);
|
||||
const auto qrcPath = QStringLiteral(":/ProjectManager/style");
|
||||
AzQtComponents::StyleManager::addSearchPaths("style", pathOnDisk, qrcPath, engineRootPath);
|
||||
|
||||
AzQtComponents::StyleManager::setStyleSheet(this, QStringLiteral("projectlauncherwindow:ProjectManagerWindow.qss"));
|
||||
AzQtComponents::StyleManager::setStyleSheet(this, QStringLiteral("style:ProjectManager.qss"));
|
||||
|
||||
QVector<ProjectManagerScreen> screenEnums =
|
||||
{
|
||||
ProjectManagerScreen::FirstTimeUse,
|
||||
ProjectManagerScreen::NewProjectSettingsCore,
|
||||
ProjectManagerScreen::CreateProject,
|
||||
ProjectManagerScreen::ProjectsHome,
|
||||
ProjectManagerScreen::ProjectSettings,
|
||||
ProjectManagerScreen::UpdateProject,
|
||||
ProjectManagerScreen::EngineSettings
|
||||
};
|
||||
m_screensCtrl->BuildScreens(screenEnums);
|
||||
|
||||
@@ -6,10 +6,16 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
<width>1200</width>
|
||||
<height>800</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>O3DE Project Manager</string>
|
||||
</property>
|
||||
@@ -21,7 +27,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<width>1200</width>
|
||||
<height>36</height>
|
||||
</rect>
|
||||
</property>
|
||||
@@ -35,8 +41,8 @@
|
||||
<string>Icon</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../project_manager.qrc">
|
||||
<normaloff>:/Resources/o3de_editor.ico</normaloff>:/Resources/o3de_editor.ico</iconset>
|
||||
<iconset resource="../Resources/ProjectManager.qrc">
|
||||
<normaloff>:/o3de_editor.ico</normaloff>:/o3de_editor.ico</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QMenu" name="projectsMenu">
|
||||
@@ -55,7 +61,7 @@
|
||||
</widget>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../project_manager.qrc"/>
|
||||
<include location="../Resources/ProjectManager.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
||||
@@ -1,95 +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 <ProjectSettingsCtrl.h>
|
||||
#include <ScreensCtrl.h>
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QVBoxLayout>
|
||||
#include <QPushButton>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
ProjectSettingsCtrl::ProjectSettingsCtrl(QWidget* parent)
|
||||
: ScreenWidget(parent)
|
||||
{
|
||||
QVBoxLayout* vLayout = new QVBoxLayout();
|
||||
setLayout(vLayout);
|
||||
|
||||
m_screensCtrl = new ScreensCtrl();
|
||||
vLayout->addWidget(m_screensCtrl);
|
||||
|
||||
QDialogButtonBox* backNextButtons = new QDialogButtonBox();
|
||||
vLayout->addWidget(backNextButtons);
|
||||
|
||||
m_backButton = backNextButtons->addButton("Back", QDialogButtonBox::RejectRole);
|
||||
m_nextButton = backNextButtons->addButton("Next", QDialogButtonBox::ApplyRole);
|
||||
|
||||
connect(m_backButton, &QPushButton::pressed, this, &ProjectSettingsCtrl::HandleBackButton);
|
||||
connect(m_nextButton, &QPushButton::pressed, this, &ProjectSettingsCtrl::HandleNextButton);
|
||||
|
||||
m_screensOrder =
|
||||
{
|
||||
ProjectManagerScreen::NewProjectSettings,
|
||||
ProjectManagerScreen::GemCatalog
|
||||
};
|
||||
m_screensCtrl->BuildScreens(m_screensOrder);
|
||||
m_screensCtrl->ForceChangeToScreen(ProjectManagerScreen::NewProjectSettings, false);
|
||||
UpdateNextButtonText();
|
||||
}
|
||||
|
||||
ProjectManagerScreen ProjectSettingsCtrl::GetScreenEnum()
|
||||
{
|
||||
return ProjectManagerScreen::NewProjectSettingsCore;
|
||||
}
|
||||
|
||||
void ProjectSettingsCtrl::HandleBackButton()
|
||||
{
|
||||
if (!m_screensCtrl->GotoPreviousScreen())
|
||||
{
|
||||
emit GotoPreviousScreenRequest();
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateNextButtonText();
|
||||
}
|
||||
}
|
||||
void ProjectSettingsCtrl::HandleNextButton()
|
||||
{
|
||||
ProjectManagerScreen screenEnum = m_screensCtrl->GetCurrentScreen()->GetScreenEnum();
|
||||
auto screenOrderIter = m_screensOrder.begin();
|
||||
for (; screenOrderIter != m_screensOrder.end(); ++screenOrderIter)
|
||||
{
|
||||
if (*screenOrderIter == screenEnum)
|
||||
{
|
||||
++screenOrderIter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (screenOrderIter != m_screensOrder.end())
|
||||
{
|
||||
m_screensCtrl->ChangeToScreen(*screenOrderIter);
|
||||
UpdateNextButtonText();
|
||||
}
|
||||
else
|
||||
{
|
||||
emit ChangeScreenRequest(ProjectManagerScreen::ProjectsHome);
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectSettingsCtrl::UpdateNextButtonText()
|
||||
{
|
||||
m_nextButton->setText(m_screensCtrl->GetCurrentScreen()->GetNextButtonText());
|
||||
}
|
||||
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -30,6 +30,23 @@ namespace O3DE::ProjectManager
|
||||
return ProjectManagerScreen::ProjectSettings;
|
||||
}
|
||||
|
||||
ProjectInfo ProjectSettingsScreen::GetProjectInfo()
|
||||
{
|
||||
// Impl pending next PR
|
||||
return ProjectInfo();
|
||||
}
|
||||
|
||||
void ProjectSettingsScreen::SetProjectInfo()
|
||||
{
|
||||
// Impl pending next PR
|
||||
}
|
||||
|
||||
bool ProjectSettingsScreen::Validate()
|
||||
{
|
||||
// Impl pending next PR
|
||||
return true;
|
||||
}
|
||||
|
||||
void ProjectSettingsScreen::HandleGemsButton()
|
||||
{
|
||||
emit ChangeScreenRequest(ProjectManagerScreen::GemCatalog);
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <ScreenWidget.h>
|
||||
#include <ProjectInfo.h>
|
||||
#endif
|
||||
|
||||
namespace Ui
|
||||
@@ -30,6 +31,11 @@ namespace O3DE::ProjectManager
|
||||
~ProjectSettingsScreen() = default;
|
||||
ProjectManagerScreen GetScreenEnum() override;
|
||||
|
||||
ProjectInfo GetProjectInfo();
|
||||
void SetProjectInfo();
|
||||
|
||||
bool Validate();
|
||||
|
||||
protected slots:
|
||||
void HandleGemsButton();
|
||||
|
||||
|
||||
@@ -12,21 +12,103 @@
|
||||
|
||||
#include <ProjectsHomeScreen.h>
|
||||
|
||||
#include <Source/ui_ProjectsHomeScreen.h>
|
||||
|
||||
#include <ProjectButtonWidget.h>
|
||||
#include <PythonBindingsInterface.h>
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QGridLayout>
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QMenu>
|
||||
#include <QListView>
|
||||
#include <QSpacerItem>
|
||||
#include <QListWidget>
|
||||
#include <QListWidgetItem>
|
||||
#include <QFileInfo>
|
||||
#include <QScrollArea>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
ProjectsHomeScreen::ProjectsHomeScreen(QWidget* parent)
|
||||
: ScreenWidget(parent)
|
||||
, m_ui(new Ui::ProjectsHomeClass())
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
QVBoxLayout* vLayout = new QVBoxLayout();
|
||||
setLayout(vLayout);
|
||||
vLayout->setContentsMargins(s_contentMargins, s_contentMargins, s_contentMargins, s_contentMargins);
|
||||
|
||||
connect(m_ui->newProjectButton, &QPushButton::pressed, this, &ProjectsHomeScreen::HandleNewProjectButton);
|
||||
connect(m_ui->addProjectButton, &QPushButton::pressed, this, &ProjectsHomeScreen::HandleAddProjectButton);
|
||||
connect(m_ui->editProjectButton, &QPushButton::pressed, this, &ProjectsHomeScreen::HandleEditProjectButton);
|
||||
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()
|
||||
@@ -36,16 +118,41 @@ namespace O3DE::ProjectManager
|
||||
|
||||
void ProjectsHomeScreen::HandleNewProjectButton()
|
||||
{
|
||||
emit ResetScreenRequest(ProjectManagerScreen::NewProjectSettingsCore);
|
||||
emit ChangeScreenRequest(ProjectManagerScreen::NewProjectSettingsCore);
|
||||
emit ResetScreenRequest(ProjectManagerScreen::CreateProject);
|
||||
emit ChangeScreenRequest(ProjectManagerScreen::CreateProject);
|
||||
}
|
||||
void ProjectsHomeScreen::HandleAddProjectButton()
|
||||
{
|
||||
// Do nothing for now
|
||||
}
|
||||
void ProjectsHomeScreen::HandleEditProjectButton()
|
||||
void ProjectsHomeScreen::HandleOpenProject(const QString& projectPath)
|
||||
{
|
||||
emit ChangeScreenRequest(ProjectManagerScreen::ProjectSettings);
|
||||
// Open the editor with this project open
|
||||
emit NotifyCurrentProject(projectPath);
|
||||
}
|
||||
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
|
||||
|
||||
@@ -15,11 +15,6 @@
|
||||
#include <ScreenWidget.h>
|
||||
#endif
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class ProjectsHomeClass;
|
||||
}
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
class ProjectsHomeScreen
|
||||
@@ -34,10 +29,23 @@ namespace O3DE::ProjectManager
|
||||
protected slots:
|
||||
void HandleNewProjectButton();
|
||||
void HandleAddProjectButton();
|
||||
void HandleEditProjectButton();
|
||||
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);
|
||||
|
||||
private:
|
||||
QScopedPointer<Ui::ProjectsHomeClass> m_ui;
|
||||
QAction* m_createNewProjectAction;
|
||||
QAction* m_addExistingProjectAction;
|
||||
|
||||
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
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ProjectsHomeClass</class>
|
||||
<widget class="QWidget" name="ProjectsHomeClass">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>826</width>
|
||||
<height>585</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>My Projects</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="currentProjectButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="newProjectButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../project_manager.qrc">
|
||||
<normaloff>:/Resources/Add.svg</normaloff>:/Resources/Add.svg</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="addProjectButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../project_manager.qrc">
|
||||
<normaloff>:/Resources/Select_Folder.svg</normaloff>:/Resources/Select_Folder.svg</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="editProjectButton">
|
||||
<property name="text">
|
||||
<string>Edit Project</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Open a Project</string>
|
||||
</property>
|
||||
</widget>
|
||||
</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>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../project_manager.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -53,6 +53,173 @@ namespace Platform
|
||||
#define Py_To_String(obj) obj.cast<std::string>().c_str()
|
||||
#define Py_To_String_Optional(dict, key, default_string) dict.contains(key) ? Py_To_String(dict[key]) : default_string
|
||||
|
||||
namespace RedirectOutput
|
||||
{
|
||||
using RedirectOutputFunc = AZStd::function<void(const char*)>;
|
||||
|
||||
struct RedirectOutput
|
||||
{
|
||||
PyObject_HEAD RedirectOutputFunc write;
|
||||
};
|
||||
|
||||
PyObject* RedirectWrite(PyObject* self, PyObject* args)
|
||||
{
|
||||
std::size_t written(0);
|
||||
RedirectOutput* selfimpl = reinterpret_cast<RedirectOutput*>(self);
|
||||
if (selfimpl->write)
|
||||
{
|
||||
char* data;
|
||||
if (!PyArg_ParseTuple(args, "s", &data))
|
||||
{
|
||||
return PyLong_FromSize_t(0);
|
||||
}
|
||||
selfimpl->write(data);
|
||||
written = strlen(data);
|
||||
}
|
||||
return PyLong_FromSize_t(written);
|
||||
}
|
||||
|
||||
PyObject* RedirectFlush([[maybe_unused]] PyObject* self,[[maybe_unused]] PyObject* args)
|
||||
{
|
||||
// no-op
|
||||
return Py_BuildValue("");
|
||||
}
|
||||
|
||||
PyMethodDef RedirectMethods[] = {
|
||||
{"write", RedirectWrite, METH_VARARGS, "sys.stdout.write"},
|
||||
{"flush", RedirectFlush, METH_VARARGS, "sys.stdout.flush"},
|
||||
{"write", RedirectWrite, METH_VARARGS, "sys.stderr.write"},
|
||||
{"flush", RedirectFlush, METH_VARARGS, "sys.stderr.flush"},
|
||||
{0, 0, 0, 0} // sentinel
|
||||
};
|
||||
|
||||
PyTypeObject RedirectOutputType = {
|
||||
PyVarObject_HEAD_INIT(0, 0) "azlmbr_redirect.RedirectOutputType", // tp_name
|
||||
sizeof(RedirectOutput), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
0, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_reserved */
|
||||
0, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
0, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
0, /* tp_str */
|
||||
0, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||
"azlmbr_redirect objects", /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
RedirectMethods, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
0, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
0 /* tp_new */
|
||||
};
|
||||
|
||||
PyModuleDef RedirectOutputModule = {
|
||||
PyModuleDef_HEAD_INIT, "azlmbr_redirect", 0, -1, 0,
|
||||
};
|
||||
|
||||
// Internal state
|
||||
PyObject* g_redirect_stdout = nullptr;
|
||||
PyObject* g_redirect_stdout_saved = nullptr;
|
||||
PyObject* g_redirect_stderr = nullptr;
|
||||
PyObject* g_redirect_stderr_saved = nullptr;
|
||||
|
||||
PyMODINIT_FUNC PyInit_RedirectOutput(void)
|
||||
{
|
||||
g_redirect_stdout = nullptr;
|
||||
g_redirect_stdout_saved = nullptr;
|
||||
g_redirect_stderr = nullptr;
|
||||
g_redirect_stderr_saved = nullptr;
|
||||
|
||||
RedirectOutputType.tp_new = PyType_GenericNew;
|
||||
if (PyType_Ready(&RedirectOutputType) < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyObject* redirectModule = PyModule_Create(&RedirectOutputModule);
|
||||
if (redirectModule)
|
||||
{
|
||||
Py_INCREF(&RedirectOutputType);
|
||||
PyModule_AddObject(redirectModule, "Redirect", reinterpret_cast<PyObject*>(&RedirectOutputType));
|
||||
}
|
||||
return redirectModule;
|
||||
}
|
||||
|
||||
void SetRedirection(const char* funcname, PyObject*& saved, PyObject*& current, RedirectOutputFunc func)
|
||||
{
|
||||
if (PyType_Ready(&RedirectOutputType) < 0)
|
||||
{
|
||||
AZ_Warning("python", false, "RedirectOutputType not ready!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!current)
|
||||
{
|
||||
saved = PySys_GetObject(funcname); // borrowed
|
||||
current = RedirectOutputType.tp_new(&RedirectOutputType, 0, 0);
|
||||
}
|
||||
|
||||
RedirectOutput* redirectOutput = reinterpret_cast<RedirectOutput*>(current);
|
||||
redirectOutput->write = func;
|
||||
PySys_SetObject(funcname, current);
|
||||
}
|
||||
|
||||
void ResetRedirection(const char* funcname, PyObject*& saved, PyObject*& current)
|
||||
{
|
||||
if (current)
|
||||
{
|
||||
PySys_SetObject(funcname, saved);
|
||||
}
|
||||
Py_XDECREF(current);
|
||||
current = nullptr;
|
||||
}
|
||||
|
||||
PyObject* s_RedirectModule = nullptr;
|
||||
|
||||
void Intialize(PyObject* module)
|
||||
{
|
||||
s_RedirectModule = module;
|
||||
|
||||
SetRedirection("stdout", g_redirect_stdout_saved, g_redirect_stdout, []([[maybe_unused]] const char* msg) {
|
||||
AZ_TracePrintf("Python", msg);
|
||||
});
|
||||
|
||||
SetRedirection("stderr", g_redirect_stderr_saved, g_redirect_stderr, []([[maybe_unused]] const char* msg) {
|
||||
AZ_TracePrintf("Python", msg);
|
||||
});
|
||||
|
||||
PySys_WriteStdout("RedirectOutput installed");
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
{
|
||||
ResetRedirection("stdout", g_redirect_stdout_saved, g_redirect_stdout);
|
||||
ResetRedirection("stderr", g_redirect_stderr_saved, g_redirect_stderr);
|
||||
Py_XDECREF(s_RedirectModule);
|
||||
s_RedirectModule = nullptr;
|
||||
}
|
||||
} // namespace RedirectOutput
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
PythonBindings::PythonBindings(const AZ::IO::PathView& enginePath)
|
||||
@@ -92,6 +259,8 @@ namespace O3DE::ProjectManager
|
||||
AZ_TracePrintf("python", "Py_GetExecPrefix=%ls \n", Py_GetExecPrefix());
|
||||
AZ_TracePrintf("python", "Py_GetProgramFullPath=%ls \n", Py_GetProgramFullPath());
|
||||
|
||||
PyImport_AppendInittab("azlmbr_redirect", RedirectOutput::PyInit_RedirectOutput);
|
||||
|
||||
try
|
||||
{
|
||||
// ignore system location for sites site-packages
|
||||
@@ -101,6 +270,8 @@ namespace O3DE::ProjectManager
|
||||
const bool initializeSignalHandlers = true;
|
||||
pybind11::initialize_interpreter(initializeSignalHandlers);
|
||||
|
||||
RedirectOutput::Intialize(PyImport_ImportModule("azlmbr_redirect"));
|
||||
|
||||
// Acquire GIL before calling Python code
|
||||
AZStd::lock_guard<decltype(m_lock)> lock(m_lock);
|
||||
pybind11::gil_scoped_acquire acquire;
|
||||
@@ -112,7 +283,9 @@ namespace O3DE::ProjectManager
|
||||
AZ_Warning("ProjectManagerWindow", result != -1, "Append to sys path failed");
|
||||
|
||||
// import required modules
|
||||
m_registration = pybind11::module::import("o3de.manifest");
|
||||
m_register= pybind11::module::import("o3de.register");
|
||||
m_manifest = pybind11::module::import("o3de.manifest");
|
||||
m_engineTemplate = pybind11::module::import("o3de.engine_template");
|
||||
|
||||
return result == 0 && !PyErr_Occurred();
|
||||
} catch ([[maybe_unused]] const std::exception& e)
|
||||
@@ -126,6 +299,7 @@ namespace O3DE::ProjectManager
|
||||
{
|
||||
if (Py_IsInitialized())
|
||||
{
|
||||
RedirectOutput::Shutdown();
|
||||
pybind11::finalize_interpreter();
|
||||
}
|
||||
else
|
||||
@@ -155,12 +329,91 @@ namespace O3DE::ProjectManager
|
||||
|
||||
AZ::Outcome<EngineInfo> PythonBindings::GetEngineInfo()
|
||||
{
|
||||
EngineInfo engineInfo;
|
||||
bool result = ExecuteWithLock([&] {
|
||||
pybind11::str enginePath = m_registration.attr("get_this_engine_path")();
|
||||
|
||||
auto o3deData = m_registration.attr("load_o3de_manifest")();
|
||||
if (pybind11::isinstance<pybind11::dict>(o3deData))
|
||||
{
|
||||
engineInfo.m_path = Py_To_String(enginePath);
|
||||
engineInfo.m_defaultGemsFolder = Py_To_String(o3deData["default_gems_folder"]);
|
||||
engineInfo.m_defaultProjectsFolder = Py_To_String(o3deData["default_projects_folder"]);
|
||||
engineInfo.m_defaultRestrictedFolder = Py_To_String(o3deData["default_restricted_folder"]);
|
||||
engineInfo.m_defaultTemplatesFolder = Py_To_String(o3deData["default_templates_folder"]);
|
||||
engineInfo.m_thirdPartyPath = Py_To_String_Optional(o3deData,"third_party_path","");
|
||||
}
|
||||
|
||||
auto engineData = m_registration.attr("get_engine_json_data")(pybind11::none(), enginePath);
|
||||
if (pybind11::isinstance<pybind11::dict>(engineData))
|
||||
{
|
||||
try
|
||||
{
|
||||
engineInfo.m_version = Py_To_String_Optional(engineData,"O3DEVersion","0.0.0.0");
|
||||
engineInfo.m_name = Py_To_String_Optional(engineData,"engine_name","O3DE");
|
||||
}
|
||||
catch ([[maybe_unused]] const std::exception& e)
|
||||
{
|
||||
AZ_Warning("PythonBindings", false, "Failed to get EngineInfo from %s", Py_To_String(enginePath));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!result || !engineInfo.IsValid())
|
||||
{
|
||||
return AZ::Failure();
|
||||
}
|
||||
else
|
||||
{
|
||||
return AZ::Success(AZStd::move(engineInfo));
|
||||
}
|
||||
|
||||
return AZ::Failure();
|
||||
}
|
||||
|
||||
bool PythonBindings::SetEngineInfo([[maybe_unused]] const EngineInfo& engineInfo)
|
||||
bool PythonBindings::SetEngineInfo(const EngineInfo& engineInfo)
|
||||
{
|
||||
return false;
|
||||
bool result = ExecuteWithLock([&] {
|
||||
pybind11::str enginePath = engineInfo.m_path.toStdString();
|
||||
pybind11::str defaultProjectsFolder = engineInfo.m_defaultProjectsFolder.toStdString();
|
||||
pybind11::str defaultGemsFolder = engineInfo.m_defaultGemsFolder.toStdString();
|
||||
pybind11::str defaultTemplatesFolder = engineInfo.m_defaultTemplatesFolder.toStdString();
|
||||
|
||||
auto registrationResult = m_registration.attr("register")(
|
||||
enginePath, // engine_path
|
||||
pybind11::none(), // project_path
|
||||
pybind11::none(), // gem_path
|
||||
pybind11::none(), // template_path
|
||||
pybind11::none(), // restricted_path
|
||||
pybind11::none(), // repo_uri
|
||||
pybind11::none(), // default_engines_folder
|
||||
defaultProjectsFolder,
|
||||
defaultGemsFolder,
|
||||
defaultTemplatesFolder
|
||||
);
|
||||
|
||||
if (registrationResult.cast<int>() != 0)
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
|
||||
auto manifest = m_registration.attr("load_o3de_manifest")();
|
||||
if (pybind11::isinstance<pybind11::dict>(manifest))
|
||||
{
|
||||
try
|
||||
{
|
||||
manifest["third_party_path"] = engineInfo.m_thirdPartyPath.toStdString();
|
||||
m_registration.attr("save_o3de_manifest")(manifest);
|
||||
}
|
||||
catch ([[maybe_unused]] const std::exception& e)
|
||||
{
|
||||
AZ_Warning("PythonBindings", false, "Failed to set third party path.");
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
AZ::Outcome<GemInfo> PythonBindings::GetGem(const QString& path)
|
||||
@@ -204,9 +457,28 @@ namespace O3DE::ProjectManager
|
||||
}
|
||||
}
|
||||
|
||||
AZ::Outcome<ProjectInfo> PythonBindings::CreateProject([[maybe_unused]] const ProjectTemplateInfo& projectTemplate,[[maybe_unused]] const ProjectInfo& projectInfo)
|
||||
AZ::Outcome<ProjectInfo> PythonBindings::CreateProject(const QString& projectTemplatePath, const ProjectInfo& projectInfo)
|
||||
{
|
||||
return AZ::Failure();
|
||||
ProjectInfo createdProjectInfo;
|
||||
bool result = ExecuteWithLock([&] {
|
||||
|
||||
pybind11::str projectPath = projectInfo.m_path.toStdString();
|
||||
pybind11::str templatePath = projectTemplatePath.toStdString();
|
||||
auto createProjectResult = m_engineTemplate.attr("create_project")(projectPath, templatePath);
|
||||
if (createProjectResult.cast<int>() == 0)
|
||||
{
|
||||
createdProjectInfo = ProjectInfoFromPath(projectPath);
|
||||
}
|
||||
});
|
||||
|
||||
if (!result || !createdProjectInfo.IsValid())
|
||||
{
|
||||
return AZ::Failure();
|
||||
}
|
||||
else
|
||||
{
|
||||
return AZ::Success(AZStd::move(createdProjectInfo));
|
||||
}
|
||||
}
|
||||
|
||||
AZ::Outcome<ProjectInfo> PythonBindings::GetProject(const QString& path)
|
||||
@@ -244,7 +516,8 @@ namespace O3DE::ProjectManager
|
||||
{
|
||||
for (auto dependency : data["Dependencies"])
|
||||
{
|
||||
gemInfo.m_dependingGemUuids.push_back(AZ::Uuid(Py_To_String(dependency["Uuid"])));
|
||||
const AZ::Uuid uuid = Py_To_String(dependency["Uuid"]);
|
||||
gemInfo.m_dependingGemUuids.push_back(uuid.ToString<AZStd::string>().c_str());
|
||||
}
|
||||
}
|
||||
if (data.contains("Tags"))
|
||||
@@ -268,16 +541,15 @@ namespace O3DE::ProjectManager
|
||||
{
|
||||
ProjectInfo projectInfo;
|
||||
projectInfo.m_path = Py_To_String(path);
|
||||
projectInfo.m_isNew = false;
|
||||
|
||||
auto projectData = m_registration.attr("get_project_json_data")(pybind11::none(), path);
|
||||
if (pybind11::isinstance<pybind11::dict>(projectData))
|
||||
{
|
||||
try
|
||||
{
|
||||
// required fields
|
||||
projectInfo.m_productName = Py_To_String(projectData["product_name"]);
|
||||
projectInfo.m_projectName = Py_To_String(projectData["project_name"]);
|
||||
projectInfo.m_projectId = AZ::Uuid(Py_To_String(projectData["project_id"]));
|
||||
projectInfo.m_displayName = Py_To_String_Optional(projectData,"display_name", projectInfo.m_projectName);
|
||||
}
|
||||
catch ([[maybe_unused]] const std::exception& e)
|
||||
{
|
||||
@@ -316,6 +588,42 @@ namespace O3DE::ProjectManager
|
||||
}
|
||||
}
|
||||
|
||||
bool PythonBindings::AddGemToProject(const QString& gemPath, const QString& projectPath)
|
||||
{
|
||||
bool result = ExecuteWithLock([&] {
|
||||
pybind11::str pyGemPath = gemPath.toStdString();
|
||||
pybind11::str pyProjectPath = projectPath.toStdString();
|
||||
|
||||
m_registration.attr("add_gem_to_project")(
|
||||
pybind11::none(), // gem_name
|
||||
pyGemPath,
|
||||
pybind11::none(), // gem_target
|
||||
pybind11::none(), // project_name
|
||||
pyProjectPath
|
||||
);
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool PythonBindings::RemoveGemFromProject(const QString& gemPath, const QString& projectPath)
|
||||
{
|
||||
bool result = ExecuteWithLock([&] {
|
||||
pybind11::str pyGemPath = gemPath.toStdString();
|
||||
pybind11::str pyProjectPath = projectPath.toStdString();
|
||||
|
||||
m_registration.attr("remove_gem_to_project")(
|
||||
pybind11::none(), // gem_name
|
||||
pyGemPath,
|
||||
pybind11::none(), // gem_target
|
||||
pybind11::none(), // project_name
|
||||
pyProjectPath
|
||||
);
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool PythonBindings::UpdateProject([[maybe_unused]] const ProjectInfo& projectInfo)
|
||||
{
|
||||
return false;
|
||||
|
||||
@@ -43,10 +43,12 @@ namespace O3DE::ProjectManager
|
||||
AZ::Outcome<QVector<GemInfo>> GetGems() override;
|
||||
|
||||
// Project
|
||||
AZ::Outcome<ProjectInfo> CreateProject(const ProjectTemplateInfo& projectTemplate, const ProjectInfo& projectInfo) override;
|
||||
AZ::Outcome<ProjectInfo> CreateProject(const QString& projectTemplatePath, const ProjectInfo& projectInfo) override;
|
||||
AZ::Outcome<ProjectInfo> GetProject(const QString& path) override;
|
||||
AZ::Outcome<QVector<ProjectInfo>> GetProjects() override;
|
||||
bool UpdateProject(const ProjectInfo& projectInfo) override;
|
||||
bool AddGemToProject(const QString& gemPath, const QString& projectPath) override;
|
||||
bool RemoveGemFromProject(const QString& gemPath, const QString& projectPath) override;
|
||||
|
||||
// ProjectTemplate
|
||||
AZ::Outcome<QVector<ProjectTemplateInfo>> GetProjectTemplates() override;
|
||||
@@ -62,6 +64,7 @@ namespace O3DE::ProjectManager
|
||||
bool StopPython();
|
||||
|
||||
AZ::IO::FixedMaxPath m_enginePath;
|
||||
pybind11::handle m_engineTemplate;
|
||||
AZStd::recursive_mutex m_lock;
|
||||
pybind11::handle m_registration;
|
||||
};
|
||||
|
||||
@@ -70,11 +70,11 @@ namespace O3DE::ProjectManager
|
||||
|
||||
/**
|
||||
* Create a project
|
||||
* @param projectTemplate the project template to use
|
||||
* @param projectTemplatePath the path to the project template to use
|
||||
* @param projectInfo the project info to use
|
||||
* @return an outcome with ProjectInfo on success
|
||||
*/
|
||||
virtual AZ::Outcome<ProjectInfo> CreateProject(const ProjectTemplateInfo& projectTemplate, const ProjectInfo& projectInfo) = 0;
|
||||
virtual AZ::Outcome<ProjectInfo> CreateProject(const QString& projectTemplatePath, const ProjectInfo& projectInfo) = 0;
|
||||
|
||||
/**
|
||||
* Get info about a project
|
||||
@@ -96,6 +96,22 @@ namespace O3DE::ProjectManager
|
||||
*/
|
||||
virtual bool UpdateProject(const ProjectInfo& projectInfo) = 0;
|
||||
|
||||
/**
|
||||
* Add a gem to a project
|
||||
* @param gemPath the absolute path to the gem
|
||||
* @param projectPath the absolute path to the project
|
||||
* @return true on success, false on failure
|
||||
*/
|
||||
virtual bool AddGemToProject(const QString& gemPath, const QString& projectPath) = 0;
|
||||
|
||||
/**
|
||||
* Remove gem to a project
|
||||
* @param gemPath the absolute path to the gem
|
||||
* @param projectPath the absolute path to the project
|
||||
* @return true on success, false on failure
|
||||
*/
|
||||
virtual bool RemoveGemFromProject(const QString& gemPath, const QString& projectPath) = 0;
|
||||
|
||||
|
||||
// Project Templates
|
||||
|
||||
|
||||
@@ -18,10 +18,11 @@ namespace O3DE::ProjectManager
|
||||
Invalid = -1,
|
||||
Empty,
|
||||
FirstTimeUse,
|
||||
NewProjectSettingsCore,
|
||||
CreateProject,
|
||||
NewProjectSettings,
|
||||
GemCatalog,
|
||||
ProjectsHome,
|
||||
UpdateProject,
|
||||
ProjectSettings,
|
||||
EngineSettings
|
||||
};
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
#include <ScreenFactory.h>
|
||||
|
||||
#include <FirstTimeUseScreen.h>
|
||||
#include <ProjectSettingsCtrl.h>
|
||||
#include <CreateProjectCtrl.h>
|
||||
#include <UpdateProjectCtrl.h>
|
||||
#include <NewProjectSettingsScreen.h>
|
||||
#include <GemCatalog/GemCatalogScreen.h>
|
||||
#include <ProjectsHomeScreen.h>
|
||||
@@ -30,8 +31,8 @@ namespace O3DE::ProjectManager
|
||||
case (ProjectManagerScreen::FirstTimeUse):
|
||||
newScreen = new FirstTimeUseScreen(parent);
|
||||
break;
|
||||
case (ProjectManagerScreen::NewProjectSettingsCore):
|
||||
newScreen = new ProjectSettingsCtrl(parent);
|
||||
case (ProjectManagerScreen::CreateProject):
|
||||
newScreen = new CreateProjectCtrl(parent);
|
||||
break;
|
||||
case (ProjectManagerScreen::NewProjectSettings):
|
||||
newScreen = new NewProjectSettingsScreen(parent);
|
||||
@@ -42,6 +43,9 @@ namespace O3DE::ProjectManager
|
||||
case (ProjectManagerScreen::ProjectsHome):
|
||||
newScreen = new ProjectsHomeScreen(parent);
|
||||
break;
|
||||
case (ProjectManagerScreen::UpdateProject):
|
||||
newScreen = new UpdateProjectCtrl(parent);
|
||||
break;
|
||||
case (ProjectManagerScreen::ProjectSettings):
|
||||
newScreen = new ProjectSettingsScreen(parent);
|
||||
break;
|
||||
|
||||
@@ -15,18 +15,20 @@
|
||||
#include <ScreenDefs.h>
|
||||
|
||||
#include <QWidget>
|
||||
#include <QStyleOption>
|
||||
#include <QPainter>
|
||||
#endif
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
class ScreenWidget
|
||||
: public QWidget
|
||||
: public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ScreenWidget(QWidget* parent = nullptr)
|
||||
: QWidget(parent)
|
||||
: QFrame(parent)
|
||||
{
|
||||
}
|
||||
~ScreenWidget() = default;
|
||||
@@ -39,15 +41,12 @@ namespace O3DE::ProjectManager
|
||||
{
|
||||
return true;
|
||||
}
|
||||
virtual QString GetNextButtonText()
|
||||
{
|
||||
return "Next";
|
||||
}
|
||||
|
||||
signals:
|
||||
void ChangeScreenRequest(ProjectManagerScreen screen);
|
||||
void GotoPreviousScreenRequest();
|
||||
void ResetScreenRequest(ProjectManagerScreen screen);
|
||||
void NotifyCurrentProject(const QString& projectPath);
|
||||
};
|
||||
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -22,6 +22,9 @@ namespace O3DE::ProjectManager
|
||||
: QWidget(parent)
|
||||
{
|
||||
QVBoxLayout* vLayout = new QVBoxLayout();
|
||||
vLayout->setMargin(0);
|
||||
vLayout->setSpacing(0);
|
||||
vLayout->setContentsMargins(0, 0, 0, 0);
|
||||
setLayout(vLayout);
|
||||
|
||||
m_screenStack = new QStackedWidget();
|
||||
@@ -114,6 +117,7 @@ namespace O3DE::ProjectManager
|
||||
connect(newScreen, &ScreenWidget::ChangeScreenRequest, this, &ScreensCtrl::ChangeToScreen);
|
||||
connect(newScreen, &ScreenWidget::GotoPreviousScreenRequest, this, &ScreensCtrl::GotoPreviousScreen);
|
||||
connect(newScreen, &ScreenWidget::ResetScreenRequest, this, &ScreensCtrl::ResetScreen);
|
||||
connect(newScreen, &ScreenWidget::NotifyCurrentProject, this, &ScreensCtrl::NotifyCurrentProject);
|
||||
}
|
||||
|
||||
void ScreensCtrl::ResetAllScreens()
|
||||
|
||||
@@ -35,6 +35,9 @@ namespace O3DE::ProjectManager
|
||||
ScreenWidget* FindScreen(ProjectManagerScreen screen);
|
||||
ScreenWidget* GetCurrentScreen();
|
||||
|
||||
signals:
|
||||
void NotifyCurrentProject(const QString& projectPath);
|
||||
|
||||
public slots:
|
||||
bool ChangeToScreen(ProjectManagerScreen screen);
|
||||
bool ForceChangeToScreen(ProjectManagerScreen screen, bool addVisit = true);
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* 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 <UpdateProjectCtrl.h>
|
||||
#include <ScreensCtrl.h>
|
||||
#include <PythonBindingsInterface.h>
|
||||
#include <ProjectSettingsScreen.h>
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QVBoxLayout>
|
||||
#include <QPushButton>
|
||||
#include <QMessageBox>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
UpdateProjectCtrl::UpdateProjectCtrl(QWidget* parent)
|
||||
: ScreenWidget(parent)
|
||||
{
|
||||
QVBoxLayout* vLayout = new QVBoxLayout();
|
||||
setLayout(vLayout);
|
||||
|
||||
m_screensCtrl = new ScreensCtrl();
|
||||
vLayout->addWidget(m_screensCtrl);
|
||||
|
||||
QDialogButtonBox* backNextButtons = new QDialogButtonBox();
|
||||
vLayout->addWidget(backNextButtons);
|
||||
|
||||
m_backButton = backNextButtons->addButton(tr("Back"), QDialogButtonBox::RejectRole);
|
||||
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(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();
|
||||
|
||||
}
|
||||
|
||||
ProjectManagerScreen UpdateProjectCtrl::GetScreenEnum()
|
||||
{
|
||||
return ProjectManagerScreen::UpdateProject;
|
||||
}
|
||||
|
||||
void UpdateProjectCtrl::HandleBackButton()
|
||||
{
|
||||
if (!m_screensCtrl->GotoPreviousScreen())
|
||||
{
|
||||
emit GotoPreviousScreenRequest();
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateNextButtonText();
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
auto projectScreen = reinterpret_cast<ProjectSettingsScreen*>(currentScreen);
|
||||
if (projectScreen)
|
||||
{
|
||||
if (!projectScreen->Validate())
|
||||
{
|
||||
QMessageBox::critical(this, tr("Invalid project settings"), tr("Invalid project settings"));
|
||||
return;
|
||||
}
|
||||
|
||||
m_projectInfo = projectScreen->GetProjectInfo();
|
||||
}
|
||||
}
|
||||
|
||||
if (screenOrderIter != m_screensOrder.end())
|
||||
{
|
||||
m_screensCtrl->ChangeToScreen(*screenOrderIter);
|
||||
UpdateNextButtonText();
|
||||
}
|
||||
else
|
||||
{
|
||||
auto result = PythonBindingsInterface::Get()->UpdateProject(m_projectInfo);
|
||||
if (result)
|
||||
{
|
||||
emit ChangeScreenRequest(ProjectManagerScreen::ProjectsHome);
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(this, tr("Project update failed"), tr("Failed to update project."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateProjectCtrl::UpdateCurrentProject(const QString& projectPath)
|
||||
{
|
||||
auto projectResult = PythonBindingsInterface::Get()->GetProject(projectPath);
|
||||
if (projectResult.IsSuccess())
|
||||
{
|
||||
m_projectInfo = projectResult.GetValue();
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateProjectCtrl::UpdateNextButtonText()
|
||||
{
|
||||
QString nextButtonText = tr("Continue");
|
||||
if (m_screensCtrl->GetCurrentScreen()->GetScreenEnum() == ProjectManagerScreen::GemCatalog)
|
||||
{
|
||||
nextButtonText = tr("Update Project");
|
||||
}
|
||||
m_nextButton->setText(nextButtonText);
|
||||
}
|
||||
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include "ProjectInfo.h"
|
||||
#include <ScreenWidget.h>
|
||||
#include <ScreensCtrl.h>
|
||||
#include <QPushButton>
|
||||
#endif
|
||||
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
class UpdateProjectCtrl
|
||||
: public ScreenWidget
|
||||
{
|
||||
public:
|
||||
explicit UpdateProjectCtrl(QWidget* parent = nullptr);
|
||||
~UpdateProjectCtrl() = default;
|
||||
ProjectManagerScreen GetScreenEnum() override;
|
||||
|
||||
|
||||
protected slots:
|
||||
void HandleBackButton();
|
||||
void HandleNextButton();
|
||||
void UpdateCurrentProject(const QString& projectPath);
|
||||
|
||||
private:
|
||||
void UpdateNextButtonText();
|
||||
|
||||
ScreensCtrl* m_screensCtrl;
|
||||
QPushButton* m_backButton;
|
||||
QPushButton* m_nextButton;
|
||||
QVector<ProjectManagerScreen> m_screensOrder;
|
||||
|
||||
ProjectInfo m_projectInfo;
|
||||
|
||||
ProjectManagerScreen m_screenEnum;
|
||||
};
|
||||
|
||||
} // namespace O3DE::ProjectManager
|
||||
Reference in New Issue
Block a user