Merge branch 'main' into ftue_auto_register

This commit is contained in:
scottr
2021-06-02 07:59:05 -07:00
680 changed files with 17085 additions and 13539 deletions
@@ -67,6 +67,15 @@ namespace O3DE::ProjectManager
return ProjectManagerScreen::CreateProject;
}
void CreateProjectCtrl::NotifyCurrentScreen()
{
ScreenWidget* currentScreen = reinterpret_cast<ScreenWidget*>(m_stack->currentWidget());
if (currentScreen)
{
currentScreen->NotifyCurrentScreen();
}
}
void CreateProjectCtrl::HandleBackButton()
{
if (m_stack->currentIndex() > 0)
@@ -110,6 +119,9 @@ namespace O3DE::ProjectManager
auto result = PythonBindingsInterface::Get()->CreateProject(m_projectTemplatePath, m_projectInfo);
if (result.IsSuccess())
{
// automatically register the project
PythonBindingsInterface::Get()->AddProject(m_projectInfo.m_path);
// adding gems is not implemented yet because we don't know what targets to add or how to add them
emit ChangeScreenRequest(ProjectManagerScreen::Projects);
}
@@ -31,6 +31,7 @@ namespace O3DE::ProjectManager
explicit CreateProjectCtrl(QWidget* parent = nullptr);
~CreateProjectCtrl() = default;
ProjectManagerScreen GetScreenEnum() override;
void NotifyCurrentScreen() override;
protected slots:
void HandleBackButton();
@@ -78,6 +78,14 @@ namespace O3DE::ProjectManager
m_errorLabel->setText(labelText);
}
void FormLineEditWidget::setErrorLabelVisible(bool visible)
{
m_errorLabel->setVisible(visible);
m_frame->setProperty("Valid", !visible);
refreshStyle();
}
QLineEdit* FormLineEditWidget::lineEdit() const
{
return m_lineEdit;
@@ -39,6 +39,7 @@ namespace O3DE::ProjectManager
//! Set the error message for to display when invalid.
void setErrorLabelText(const QString& labelText);
void setErrorLabelVisible(bool visible);
//! Returns a pointer to the underlying LineEdit.
QLineEdit* lineEdit() const;
@@ -25,10 +25,12 @@ namespace O3DE::ProjectManager
hLayout->setMargin(0);
setLayout(hLayout);
setStyleSheet("background-color: #1E252F;");
setObjectName("GemCatalogHeaderWidget");
hLayout->addSpacing(7);
QLabel* titleLabel = new QLabel(tr("Gem Catalog"));
titleLabel->setStyleSheet("font-size: 21px;");
titleLabel->setObjectName("GemCatalogTitle");
hLayout->addWidget(titleLabel);
hLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding));
@@ -42,7 +44,7 @@ namespace O3DE::ProjectManager
hLayout->addWidget(filterLineEdit);
hLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding));
hLayout->addSpacerItem(new QSpacerItem(220, 0, QSizePolicy::Fixed));
hLayout->addSpacerItem(new QSpacerItem(140, 0, QSizePolicy::Fixed));
setFixedHeight(60);
}
@@ -43,7 +43,6 @@ namespace O3DE::ProjectManager
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();
@@ -52,7 +51,7 @@ namespace O3DE::ProjectManager
// Category title
QLabel* headerLabel = new QLabel(header);
headerLabel->setStyleSheet("font-size: 11pt;");
headerLabel->setObjectName("GemCatalogFilterCategoryTitle");
collapseLayout->addWidget(headerLabel);
vLayout->addLayout(collapseLayout);
@@ -79,14 +78,14 @@ namespace O3DE::ProjectManager
elementWidget->setLayout(elementLayout);
QCheckBox* checkbox = new QCheckBox(elementNames[i]);
checkbox->setStyleSheet("font-size: 11pt;");
checkbox->setStyleSheet("font-size: 12px;");
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;");
countLabel->setStyleSheet("font-size: 12px; background-color: #333333; border-radius: 3px; color: #94D2FF;");
elementLayout->addWidget(countLabel);
m_elementWidgets.push_back(elementWidget);
@@ -110,6 +109,8 @@ namespace O3DE::ProjectManager
}
}
vLayout->addSpacing(5);
// Separating line
QFrame* hLine = new QFrame();
hLine->setFrameShape(QFrame::HLine);
@@ -181,6 +182,8 @@ namespace O3DE::ProjectManager
: QScrollArea(parent)
, m_filterProxyModel(filterProxyModel)
{
setObjectName("GemCatalogFilterWidget");
m_gemModel = m_filterProxyModel->GetSourceModel();
setWidgetResizable(true);
@@ -195,7 +198,7 @@ namespace O3DE::ProjectManager
mainWidget->setLayout(m_mainLayout);
QLabel* filterByLabel = new QLabel("Filter by");
filterByLabel->setStyleSheet("font-size: 15pt;");
filterByLabel->setStyleSheet("font-size: 16px;");
m_mainLayout->addWidget(filterByLabel);
AddGemOriginFilter();
@@ -25,7 +25,7 @@ namespace O3DE::ProjectManager
bool GemInfo::IsValid() const
{
return !m_path.isEmpty() && !m_uuid.IsNull();
return !m_name.isEmpty() && !m_path.isEmpty();
}
QString GemInfo::GetPlatformString(Platform platform)
@@ -64,7 +64,6 @@ namespace O3DE::ProjectManager
QString m_path;
QString m_name = "Unknown Gem Name";
QString m_displayName = "Unknown Gem Name";
AZ::Uuid m_uuid;
QString m_creator = "Unknown Creator";
GemOrigin m_gemOrigin = Local;
bool m_isAdded = false; //! Is the gem currently added and enabled in the project?
@@ -23,6 +23,7 @@ namespace O3DE::ProjectManager
: QScrollArea(parent)
, m_model(model)
{
setObjectName("GemCatalogInspector");
setWidgetResizable(true);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
@@ -85,7 +86,7 @@ namespace O3DE::ProjectManager
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));
result->setStyleSheet(QString("font-size: %1px; color: %2;").arg(QString::number(fontSize), colorCodeString));
layout->addWidget(result);
return result;
}
@@ -93,13 +94,13 @@ namespace O3DE::ProjectManager
void GemInspector::InitMainWidget()
{
// Gem name, creator and summary
m_nameLabel = CreateStyledLabel(m_mainLayout, 17, s_headerColor);
m_nameLabel = CreateStyledLabel(m_mainLayout, 18, 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_summaryLabel = CreateStyledLabel(m_mainLayout, 12, s_textColor);
m_mainLayout->addWidget(m_summaryLabel);
m_summaryLabel->setWordWrap(true);
m_mainLayout->addSpacing(5);
@@ -146,9 +147,9 @@ namespace O3DE::ProjectManager
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);
m_versionLabel = CreateStyledLabel(m_mainLayout, 12, s_textColor);
m_lastUpdatedLabel = CreateStyledLabel(m_mainLayout, 12, s_textColor);
m_binarySizeLabel = CreateStyledLabel(m_mainLayout, 12, s_textColor);
}
GemInspector::GemsSubWidget::GemsSubWidget(QWidget* parent)
@@ -159,8 +160,8 @@ namespace O3DE::ProjectManager
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_titleLabel = GemInspector::CreateStyledLabel(m_layout, 16, s_headerColor);
m_textLabel = GemInspector::CreateStyledLabel(m_layout, 10, s_textColor);
m_textLabel->setWordWrap(true);
m_tagWidget = new TagContainerWidget();
@@ -49,7 +49,7 @@ namespace O3DE::ProjectManager
painter->setRenderHint(QPainter::Antialiasing);
QRect fullRect, itemRect, contentRect;
CalcRects(options, modelIndex, fullRect, itemRect, contentRect);
CalcRects(options, fullRect, itemRect, contentRect);
QFont standardFont(options.font);
standardFont.setPixelSize(s_fontSize);
@@ -99,7 +99,7 @@ namespace O3DE::ProjectManager
painter->drawText(gemCreatorRect, Qt::TextSingleLine, gemCreator);
// Gem summary
const QSize summarySize = QSize(contentRect.width() - s_summaryStartX - s_buttonWidth - s_itemMargins.right() * 4, contentRect.height());
const QSize summarySize = QSize(contentRect.width() - s_summaryStartX - s_buttonWidth - s_itemMargins.right() * 3, contentRect.height());
const QRect summaryRect = QRect(/*topLeft=*/QPoint(contentRect.left() + s_summaryStartX, contentRect.top()), summarySize);
painter->setFont(standardFont);
@@ -131,15 +131,29 @@ namespace O3DE::ProjectManager
return false;
}
if (event->type() == QEvent::MouseButtonPress)
{
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
QRect fullRect, itemRect, contentRect;
CalcRects(option, fullRect, itemRect, contentRect);
const QRect buttonRect = CalcButtonRect(contentRect);
if (buttonRect.contains(mouseEvent->pos()))
{
const bool isAdded = GemModel::IsAdded(modelIndex);
GemModel::SetIsAdded(*model, modelIndex, !isAdded);
return true;
}
}
return QStyledItemDelegate::editorEvent(event, model, option, modelIndex);
}
void GemItemDelegate::CalcRects(const QStyleOptionViewItem& option, const QModelIndex& modelIndex, QRect& outFullRect, QRect& outItemRect, QRect& outContentRect) const
void GemItemDelegate::CalcRects(const QStyleOptionViewItem& option, QRect& outFullRect, QRect& outItemRect, QRect& outContentRect) const
{
const bool isFirst = modelIndex.row() == 0;
outFullRect = QRect(option.rect);
outItemRect = QRect(outFullRect.adjusted(s_itemMargins.left(), isFirst ? s_itemMargins.top() * 2 : s_itemMargins.top(), -s_itemMargins.right(), -s_itemMargins.bottom()));
outItemRect = QRect(outFullRect.adjusted(s_itemMargins.left(), s_itemMargins.top(), -s_itemMargins.right(), -s_itemMargins.bottom()));
outContentRect = QRect(outItemRect.adjusted(s_contentMargins.left(), s_contentMargins.top(), -s_contentMargins.right(), -s_contentMargins.bottom()));
}
@@ -194,12 +208,12 @@ namespace O3DE::ProjectManager
painter->setBrush(m_buttonEnabledColor);
painter->setPen(m_buttonEnabledColor);
circleCenter = buttonRect.center() + QPoint(buttonRect.width() / 2 - s_buttonBorderRadius, 1);
circleCenter = buttonRect.center() + QPoint(buttonRect.width() / 2 - s_buttonBorderRadius + 1, 1);
buttonText = "Added";
}
else
{
circleCenter = buttonRect.center() + QPoint(-buttonRect.width() / 2 + s_buttonBorderRadius + 1, 1);
circleCenter = buttonRect.center() + QPoint(-buttonRect.width() / 2 + s_buttonBorderRadius, 1);
buttonText = "Get";
}
@@ -45,25 +45,25 @@ namespace O3DE::ProjectManager
const QColor m_buttonEnabledColor = QColor("#00B931");
// Item
inline constexpr static int s_height = 135; // Gem item total height
inline constexpr static qreal s_gemNameFontSize = 16.0;
inline constexpr static qreal s_fontSize = 15.0;
inline constexpr static int s_summaryStartX = 200;
inline constexpr static int s_height = 105; // Gem item total height
inline constexpr static qreal s_gemNameFontSize = 13.0;
inline constexpr static qreal s_fontSize = 12.0;
inline constexpr static int s_summaryStartX = 150;
// Margin and borders
inline constexpr static QMargins s_itemMargins = QMargins(/*left=*/20, /*top=*/10, /*right=*/20, /*bottom=*/10); // Item border distances
inline constexpr static QMargins s_contentMargins = QMargins(/*left=*/15, /*top=*/12, /*right=*/12, /*bottom=*/12); // Distances of the elements within an item to the item borders
inline constexpr static QMargins s_itemMargins = QMargins(/*left=*/16, /*top=*/8, /*right=*/16, /*bottom=*/8); // Item border distances
inline constexpr static QMargins s_contentMargins = QMargins(/*left=*/20, /*top=*/12, /*right=*/15, /*bottom=*/12); // Distances of the elements within an item to the item borders
inline constexpr static int s_borderWidth = 4;
// Button
inline constexpr static int s_buttonWidth = 70;
inline constexpr static int s_buttonHeight = 24;
inline constexpr static int s_buttonBorderRadius = 12;
inline constexpr static int s_buttonCircleRadius = s_buttonBorderRadius - 3;
inline constexpr static qreal s_buttonFontSize = 12.0;
inline constexpr static int s_buttonWidth = 55;
inline constexpr static int s_buttonHeight = 18;
inline constexpr static int s_buttonBorderRadius = 9;
inline constexpr static int s_buttonCircleRadius = s_buttonBorderRadius - 2;
inline constexpr static qreal s_buttonFontSize = 10.0;
private:
void CalcRects(const QStyleOptionViewItem& option, const QModelIndex& modelIndex, QRect& outFullRect, QRect& outItemRect, QRect& outContentRect) const;
void CalcRects(const QStyleOptionViewItem& option, 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;
@@ -73,7 +73,7 @@ namespace O3DE::ProjectManager
// Platform icons
void AddPlatformIcon(GemInfo::Platform platform, const QString& iconPath);
inline constexpr static int s_platformIconSize = 16;
inline constexpr static int s_platformIconSize = 12;
QHash<GemInfo::Platform, QPixmap> m_platformIcons;
};
} // namespace O3DE::ProjectManager
@@ -35,7 +35,7 @@ namespace O3DE::ProjectManager
topLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding));
QLabel* showCountLabel = new QLabel();
showCountLabel->setStyleSheet("font-size: 11pt; font: italic;");
showCountLabel->setStyleSheet("font-size: 12px; font: italic;");
topLayout->addWidget(showCountLabel);
connect(proxyModel, &GemSortFilterProxyModel::OnInvalidated, this, [=]
{
@@ -61,16 +61,17 @@ namespace O3DE::ProjectManager
QHBoxLayout* columnHeaderLayout = new QHBoxLayout();
columnHeaderLayout->setAlignment(Qt::AlignLeft);
columnHeaderLayout->addSpacing(31);
const int gemNameStartX = GemItemDelegate::s_itemMargins.left() + GemItemDelegate::s_contentMargins.left() - 3;
columnHeaderLayout->addSpacing(gemNameStartX);
QLabel* gemNameLabel = new QLabel(tr("Gem Name"));
gemNameLabel->setStyleSheet("font-size: 11pt;");
gemNameLabel->setStyleSheet("font-size: 12px;");
columnHeaderLayout->addWidget(gemNameLabel);
columnHeaderLayout->addSpacing(111);
columnHeaderLayout->addSpacing(77);
QLabel* gemSummaryLabel = new QLabel(tr("Gem Summary"));
gemSummaryLabel->setStyleSheet("font-size: 11pt;");
gemSummaryLabel->setStyleSheet("font-size: 12px;");
columnHeaderLayout->addWidget(gemSummaryLabel);
vLayout->addLayout(columnHeaderLayout);
@@ -33,13 +33,12 @@ 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(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(false, RoleWasPreviouslyAdded);
item->setData(gemInfo.m_isAdded, RoleIsAdded);
item->setData(gemInfo.m_directoryLink, RoleDirectoryLink);
item->setData(gemInfo.m_documentationLink, RoleDocLink);
@@ -49,11 +48,12 @@ namespace O3DE::ProjectManager
item->setData(gemInfo.m_lastUpdatedDate, RoleLastUpdated);
item->setData(gemInfo.m_binarySizeInKB, RoleBinarySize);
item->setData(gemInfo.m_features, RoleFeatures);
item->setData(gemInfo.m_path, RolePath);
appendRow(item);
const QModelIndex modelIndex = index(rowCount()-1, 0);
m_uuidToIndexMap[uuidString] = modelIndex;
m_nameToIndexMap[gemInfo.m_name] = modelIndex;
}
void GemModel::Clear()
@@ -76,11 +76,6 @@ namespace O3DE::ProjectManager
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());
@@ -96,11 +91,6 @@ namespace O3DE::ProjectManager
return modelIndex.data(RoleSummary).toString();
}
bool GemModel::IsAdded(const QModelIndex& modelIndex)
{
return modelIndex.data(RoleIsAdded).toBool();
}
QString GemModel::GetDirectoryLink(const QModelIndex& modelIndex)
{
return modelIndex.data(RoleDirectoryLink).toString();
@@ -111,10 +101,10 @@ namespace O3DE::ProjectManager
return modelIndex.data(RoleDocLink).toString();
}
QModelIndex GemModel::FindIndexByUuidString(const QString& uuidString) const
QModelIndex GemModel::FindIndexByNameString(const QString& nameString) const
{
const auto iterator = m_uuidToIndexMap.find(uuidString);
if (iterator != m_uuidToIndexMap.end())
const auto iterator = m_nameToIndexMap.find(nameString);
if (iterator != m_nameToIndexMap.end())
{
return iterator.value();
}
@@ -122,11 +112,11 @@ namespace O3DE::ProjectManager
return {};
}
void GemModel::FindGemNamesByUuidStrings(QStringList& inOutGemNames)
void GemModel::FindGemNamesByNameStrings(QStringList& inOutGemNames)
{
for (QString& dependingGemString : inOutGemNames)
{
QModelIndex modelIndex = FindIndexByUuidString(dependingGemString);
QModelIndex modelIndex = FindIndexByNameString(dependingGemString);
if (modelIndex.isValid())
{
dependingGemString = GetName(modelIndex);
@@ -147,7 +137,7 @@ namespace O3DE::ProjectManager
return {};
}
FindGemNamesByUuidStrings(result);
FindGemNamesByNameStrings(result);
return result;
}
@@ -164,7 +154,7 @@ namespace O3DE::ProjectManager
return {};
}
FindGemNamesByUuidStrings(result);
FindGemNamesByNameStrings(result);
return result;
}
@@ -187,4 +177,62 @@ namespace O3DE::ProjectManager
{
return modelIndex.data(RoleFeatures).toStringList();
}
QString GemModel::GetPath(const QModelIndex& modelIndex)
{
return modelIndex.data(RolePath).toString();
}
bool GemModel::IsAdded(const QModelIndex& modelIndex)
{
return modelIndex.data(RoleIsAdded).toBool();
}
void GemModel::SetIsAdded(QAbstractItemModel& model, const QModelIndex& modelIndex, bool isAdded)
{
model.setData(modelIndex, isAdded, RoleIsAdded);
}
void GemModel::SetWasPreviouslyAdded(QAbstractItemModel& model, const QModelIndex& modelIndex, bool wasAdded)
{
model.setData(modelIndex, wasAdded, RoleWasPreviouslyAdded);
}
bool GemModel::NeedsToBeAdded(const QModelIndex& modelIndex)
{
return (!modelIndex.data(RoleWasPreviouslyAdded).toBool() && modelIndex.data(RoleIsAdded).toBool());
}
bool GemModel::NeedsToBeRemoved(const QModelIndex& modelIndex)
{
return (modelIndex.data(RoleWasPreviouslyAdded).toBool() && !modelIndex.data(RoleIsAdded).toBool());
}
QVector<QModelIndex> GemModel::GatherGemsToBeAdded() const
{
QVector<QModelIndex> result;
for (int row = 0; row < rowCount(); ++row)
{
const QModelIndex modelIndex = index(row, 0);
if (NeedsToBeAdded(modelIndex))
{
result.push_back(modelIndex);
}
}
return result;
}
QVector<QModelIndex> GemModel::GatherGemsToBeRemoved() const
{
QVector<QModelIndex> result;
for (int row = 0; row < rowCount(); ++row)
{
const QModelIndex modelIndex = index(row, 0);
if (NeedsToBeRemoved(modelIndex))
{
result.push_back(modelIndex);
}
}
return result;
}
} // namespace O3DE::ProjectManager
@@ -33,8 +33,8 @@ namespace O3DE::ProjectManager
void AddGem(const GemInfo& gemInfo);
void Clear();
QModelIndex FindIndexByUuidString(const QString& uuidString) const;
void FindGemNamesByUuidStrings(QStringList& inOutGemNames);
QModelIndex FindIndexByNameString(const QString& nameString) const;
void FindGemNamesByNameStrings(QStringList& inOutGemNames);
QStringList GetDependingGemUuids(const QModelIndex& modelIndex);
QStringList GetDependingGemNames(const QModelIndex& modelIndex);
QStringList GetConflictingGemUuids(const QModelIndex& modelIndex);
@@ -43,27 +43,35 @@ namespace O3DE::ProjectManager
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);
static QString GetPath(const QModelIndex& modelIndex);
static bool IsAdded(const QModelIndex& modelIndex);
static void SetIsAdded(QAbstractItemModel& model, const QModelIndex& modelIndex, bool isAdded);
static void SetWasPreviouslyAdded(QAbstractItemModel& model, const QModelIndex& modelIndex, bool wasAdded);
static bool NeedsToBeAdded(const QModelIndex& modelIndex);
static bool NeedsToBeRemoved(const QModelIndex& modelIndex);
QVector<QModelIndex> GatherGemsToBeAdded() const;
QVector<QModelIndex> GatherGemsToBeRemoved() const;
private:
enum UserRole
{
RoleName = Qt::UserRole,
RoleUuid,
RoleCreator,
RoleGemOrigin,
RolePlatforms,
RoleSummary,
RoleWasPreviouslyAdded,
RoleIsAdded,
RoleDirectoryLink,
RoleDocLink,
@@ -73,10 +81,11 @@ namespace O3DE::ProjectManager
RoleLastUpdated,
RoleBinarySize,
RoleFeatures,
RoleTypes
RoleTypes,
RolePath
};
QHash<QString, QModelIndex> m_uuidToIndexMap;
QHash<QString, QModelIndex> m_nameToIndexMap;
QItemSelectionModel* m_selectionModel = nullptr;
};
} // namespace O3DE::ProjectManager
@@ -37,7 +37,7 @@ namespace O3DE::ProjectManager
void LinkLabel::enterEvent([[maybe_unused]] QEvent* event)
{
setStyleSheet("font-size: 9pt; color: #94D2FF; text-decoration: underline;");
setStyleSheet("font-size: 10px; color: #94D2FF; text-decoration: underline;");
}
void LinkLabel::leaveEvent([[maybe_unused]] QEvent* event)
@@ -52,6 +52,6 @@ namespace O3DE::ProjectManager
void LinkLabel::SetDefaultStyle()
{
setStyleSheet("font-size: 9pt; color: #94D2FF;");
setStyleSheet("font-size: 10px; color: #94D2FF;");
}
} // namespace O3DE::ProjectManager
@@ -15,6 +15,7 @@
#include <FormLineEditWidget.h>
#include <FormBrowseEditWidget.h>
#include <PathValidator.h>
#include <EngineInfo.h>
#include <QVBoxLayout>
#include <QHBoxLayout>
@@ -49,16 +50,16 @@ namespace O3DE::ProjectManager
vLayout->setContentsMargins(0,0,0,0);
vLayout->setAlignment(Qt::AlignTop);
{
m_projectName = new FormLineEditWidget(tr("Project name"), tr("New Project"), this);
m_projectName->setErrorLabelText(
tr("A project with this name already exists at this location. Please choose a new name or location."));
const QString defaultName{ "NewProject" };
const QString defaultPath = QDir::toNativeSeparators(GetDefaultProjectPath() + "/" + defaultName);
m_projectName = new FormLineEditWidget(tr("Project name"), defaultName, this);
connect(m_projectName->lineEdit(), &QLineEdit::textChanged, this, &NewProjectSettingsScreen::ValidateProjectPath);
vLayout->addWidget(m_projectName);
m_projectPath =
new FormBrowseEditWidget(tr("Project Location"), QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), this);
m_projectPath = new FormBrowseEditWidget(tr("Project Location"), defaultPath, this);
m_projectPath->lineEdit()->setReadOnly(true);
m_projectPath->setErrorLabelText(tr("Please provide a valid path to a folder that exists"));
m_projectPath->lineEdit()->setValidator(new PathValidator(PathValidator::PathMode::ExistingFolder, this));
connect(m_projectPath->lineEdit(), &QLineEdit::textChanged, this, &NewProjectSettingsScreen::ValidateProjectPath);
vLayout->addWidget(m_projectPath);
// if we don't use a QFrame we cannot "contain" the widgets inside and move them around
@@ -112,17 +113,41 @@ namespace O3DE::ProjectManager
this->setLayout(hLayout);
}
QString NewProjectSettingsScreen::GetDefaultProjectPath()
{
QString defaultPath = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
AZ::Outcome<EngineInfo> engineInfoResult = PythonBindingsInterface::Get()->GetEngineInfo();
if (engineInfoResult.IsSuccess())
{
QDir path(QDir::toNativeSeparators(engineInfoResult.GetValue().m_defaultProjectsFolder));
if (path.exists())
{
defaultPath = path.absolutePath();
}
}
return defaultPath;
}
ProjectManagerScreen NewProjectSettingsScreen::GetScreenEnum()
{
return ProjectManagerScreen::NewProjectSettings;
}
void NewProjectSettingsScreen::ValidateProjectPath()
{
Validate();
}
void NewProjectSettingsScreen::NotifyCurrentScreen()
{
Validate();
}
ProjectInfo NewProjectSettingsScreen::GetProjectInfo()
{
ProjectInfo projectInfo;
projectInfo.m_projectName = m_projectName->lineEdit()->text();
projectInfo.m_path = QDir::toNativeSeparators(m_projectPath->lineEdit()->text() + "/" + projectInfo.m_projectName);
projectInfo.m_path = m_projectPath->lineEdit()->text();
return projectInfo;
}
@@ -133,24 +158,44 @@ namespace O3DE::ProjectManager
bool NewProjectSettingsScreen::Validate()
{
bool projectNameIsValid = true;
if (m_projectName->lineEdit()->text().isEmpty())
{
projectNameIsValid = false;
}
bool projectPathIsValid = true;
if (m_projectPath->lineEdit()->text().isEmpty())
{
projectPathIsValid = false;
m_projectPath->setErrorLabelText(tr("Please provide a valid location."));
}
QDir path(QDir::toNativeSeparators(m_projectPath->lineEdit()->text() + "/" + m_projectName->lineEdit()->text()));
if (path.exists() && !path.isEmpty())
else
{
projectPathIsValid = false;
QDir path(m_projectPath->lineEdit()->text());
if (path.exists() && !path.isEmpty())
{
projectPathIsValid = false;
m_projectPath->setErrorLabelText(tr("This folder exists and isn't empty. Please choose a different location."));
}
}
bool projectNameIsValid = true;
if (m_projectName->lineEdit()->text().isEmpty())
{
projectNameIsValid = false;
m_projectName->setErrorLabelText(tr("Please provide a project name."));
}
else
{
// this validation should roughly match the utils.validate_identifier which the cli
// uses to validate project names
QRegExp validProjectNameRegex("[A-Za-z][A-Za-z0-9_-]{0,63}");
const bool result = validProjectNameRegex.exactMatch(m_projectName->lineEdit()->text());
if (!result)
{
projectNameIsValid = false;
m_projectName->setErrorLabelText(tr("Project names must start with a letter and consist of up to 64 letter, number, '_' or '-' characters"));
}
}
m_projectName->setErrorLabelVisible(!projectNameIsValid);
m_projectPath->setErrorLabelVisible(!projectPathIsValid);
return projectNameIsValid && projectPathIsValid;
}
} // namespace O3DE::ProjectManager
@@ -36,10 +36,15 @@ namespace O3DE::ProjectManager
bool Validate();
void NotifyCurrentScreen() override;
protected slots:
void HandleBrowseButton();
void ValidateProjectPath();
private:
QString GetDefaultProjectPath();
FormLineEditWidget* m_projectName;
FormBrowseEditWidget* m_projectPath;
QButtonGroup* m_projectTemplateButtonGroup;
@@ -12,6 +12,7 @@
#include <ProjectButtonWidget.h>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QResizeEvent>
@@ -58,19 +59,15 @@ namespace O3DE::ProjectManager
m_overlayLabel->setText(text);
}
ProjectButton::ProjectButton(const QString& projectName, QWidget* parent)
ProjectButton::ProjectButton(const ProjectInfo& projectInfo, QWidget* parent)
: QFrame(parent)
, m_projectName(projectName)
, m_projectImagePath(":/Resources/DefaultProjectImage.png")
, m_projectInfo(projectInfo)
{
Setup();
}
if (m_projectInfo.m_imagePath.isEmpty())
{
m_projectInfo.m_imagePath = ":/DefaultProjectImage.png";
}
ProjectButton::ProjectButton(const QString& projectName, const QString& projectImage, QWidget* parent)
: QFrame(parent)
, m_projectName(projectName)
, m_projectImagePath(projectImage)
{
Setup();
}
@@ -85,20 +82,22 @@ namespace O3DE::ProjectManager
m_projectImageLabel = new LabelButton(this);
m_projectImageLabel->setFixedSize(s_projectImageWidth, s_projectImageHeight);
m_projectImageLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
vLayout->addWidget(m_projectImageLabel);
m_projectImageLabel->setPixmap(QPixmap(m_projectImagePath).scaled(m_projectImageLabel->size(), Qt::KeepAspectRatioByExpanding));
m_projectImageLabel->setPixmap(
QPixmap(m_projectInfo.m_imagePath).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"));
m_deleteProjectAction = newProjectMenu->addAction(tr("Delete this Project"));
#ifdef SHOW_ALL_PROJECT_ACTIONS
m_editProjectGemsAction = newProjectMenu->addAction(tr("Cutomize Gems..."));
#endif
QFrame* footer = new QFrame(this);
@@ -106,7 +105,7 @@ namespace O3DE::ProjectManager
hLayout->setContentsMargins(0, 0, 0, 0);
footer->setLayout(hLayout);
{
QLabel* projectNameLabel = new QLabel(m_projectName, this);
QLabel* projectNameLabel = new QLabel(m_projectInfo.m_displayName, this);
hLayout->addWidget(projectNameLabel);
QPushButton* projectMenuButton = new QPushButton(this);
@@ -117,14 +116,14 @@ namespace O3DE::ProjectManager
vLayout->addWidget(footer);
connect(m_projectImageLabel, &LabelButton::triggered, [this]() { emit OpenProject(m_projectName); });
connect(m_editProjectAction, &QAction::triggered, [this]() { emit EditProject(m_projectName); });
connect(m_projectImageLabel, &LabelButton::triggered, [this]() { emit OpenProject(m_projectInfo.m_path); });
connect(m_editProjectAction, &QAction::triggered, [this]() { emit EditProject(m_projectInfo.m_path); });
connect(m_copyProjectAction, &QAction::triggered, [this]() { emit CopyProject(m_projectInfo.m_path); });
connect(m_removeProjectAction, &QAction::triggered, [this]() { emit RemoveProject(m_projectInfo.m_path); });
connect(m_deleteProjectAction, &QAction::triggered, [this]() { emit DeleteProject(m_projectInfo.m_path); });
#ifdef SHOW_ALL_PROJECT_ACTIONS
connect(m_editProjectGemsAction, &QAction::triggered, [this]() { emit EditProjectGems(m_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); });
connect(m_editProjectGemsAction, &QAction::triggered, [this]() { emit EditProjectGems(m_projectInfo.m_path); });
#endif
}
@@ -13,7 +13,8 @@
#pragma once
#if !defined(Q_MOC_RUN)
#include <QFrame>
#include <ProjectInfo.h>
#include <QLabel>
#endif
@@ -52,8 +53,7 @@ namespace O3DE::ProjectManager
Q_OBJECT // AUTOMOC
public:
explicit ProjectButton(const QString& projectName, QWidget* parent = nullptr);
explicit ProjectButton(const QString& projectName, const QString& projectImage, QWidget* parent = nullptr);
explicit ProjectButton(const ProjectInfo& m_projectInfo, QWidget* parent = nullptr);
~ProjectButton() = default;
void SetButtonEnabled(bool enabled);
@@ -70,8 +70,7 @@ namespace O3DE::ProjectManager
private:
void Setup();
QString m_projectName;
QString m_projectImagePath;
ProjectInfo m_projectInfo;
LabelButton* m_projectImageLabel;
QAction* m_editProjectAction;
QAction* m_editProjectGemsAction;
@@ -14,13 +14,16 @@
#include <ScreensCtrl.h>
#include <AzQtComponents/Components/StyleManager.h>
#include <AzCore/IO/FileIO.h>
#include <AzCore/IO/Path/Path.h>
#include <AzFramework/CommandLine/CommandLine.h>
#include <AzFramework/Application/Application.h>
#include <QDir>
namespace O3DE::ProjectManager
{
ProjectManagerWindow::ProjectManagerWindow(QWidget* parent, const AZ::IO::PathView& engineRootPath)
ProjectManagerWindow::ProjectManagerWindow(QWidget* parent, const AZ::IO::PathView& engineRootPath, const AZ::IO::PathView& projectPath, ProjectManagerScreen startScreen)
: QMainWindow(parent)
{
m_pythonBindings = AZStd::make_unique<PythonBindings>(engineRootPath);
@@ -50,7 +53,18 @@ namespace O3DE::ProjectManager
// set stylesheet after creating the screens or their styles won't get updated
AzQtComponents::StyleManager::setStyleSheet(this, QStringLiteral("style:ProjectManager.qss"));
screensCtrl->ForceChangeToScreen(ProjectManagerScreen::Projects, false);
// always push the projects screen first so we have something to come back to
if (startScreen != ProjectManagerScreen::Projects)
{
screensCtrl->ForceChangeToScreen(ProjectManagerScreen::Projects);
}
screensCtrl->ForceChangeToScreen(startScreen);
if (!projectPath.empty())
{
const QString path = QString::fromUtf8(projectPath.Native().data(), aznumeric_cast<int>(projectPath.Native().size()));
emit screensCtrl->NotifyCurrentProject(path);
}
}
ProjectManagerWindow::~ProjectManagerWindow()
@@ -14,6 +14,7 @@
#if !defined(Q_MOC_RUN)
#include <QMainWindow>
#include <PythonBindings.h>
#include <ScreenDefs.h>
#endif
namespace O3DE::ProjectManager
@@ -24,7 +25,8 @@ namespace O3DE::ProjectManager
Q_OBJECT
public:
explicit ProjectManagerWindow(QWidget* parent, const AZ::IO::PathView& engineRootPath);
explicit ProjectManagerWindow(QWidget* parent, const AZ::IO::PathView& engineRootPath, const AZ::IO::PathView& projectPath,
ProjectManagerScreen startScreen = ProjectManagerScreen::Projects);
~ProjectManagerWindow();
private:
@@ -0,0 +1,207 @@
/*
* 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 <ProjectUtils.h>
#include <PythonBindingsInterface.h>
#include <QFileDialog>
#include <QDir>
#include <QMessageBox>
#include <QProgressDialog>
namespace O3DE::ProjectManager
{
namespace ProjectUtils
{
static bool WarnDirectoryOverwrite(const QString& path, QWidget* parent)
{
if (!QDir(path).isEmpty())
{
QMessageBox::StandardButton warningResult = QMessageBox::warning(
parent,
QObject::tr("Overwrite Directory"),
QObject::tr("Directory is not empty! Are you sure you want to overwrite it?"),
QMessageBox::No | QMessageBox::Yes
);
if (warningResult != QMessageBox::Yes)
{
return false;
}
}
return true;
}
static bool IsDirectoryDescedent(const QString& possibleAncestorPath, const QString& possibleDecedentPath)
{
QDir ancestor(possibleAncestorPath);
QDir descendent(possibleDecedentPath);
do
{
if (ancestor == descendent)
{
return false;
}
descendent.cdUp();
}
while (!descendent.isRoot());
return true;
}
static bool CopyDirectory(const QString& origPath, const QString& newPath)
{
QDir original(origPath);
if (!original.exists())
{
return false;
}
for (QString directory : original.entryList(QDir::Dirs | QDir::NoDotAndDotDot))
{
QString newDirectoryPath = newPath + QDir::separator() + directory;
original.mkpath(newDirectoryPath);
if (!CopyDirectory(origPath + QDir::separator() + directory, newDirectoryPath))
{
return false;
}
}
for (QString file : original.entryList(QDir::Files))
{
if (!QFile::copy(origPath + QDir::separator() + file, newPath + QDir::separator() + file))
return false;
}
return true;
}
bool AddProjectDialog(QWidget* parent)
{
QString path = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(parent, QObject::tr("Select Project Directory")));
if (!path.isEmpty())
{
return RegisterProject(path);
}
return false;
}
bool RegisterProject(const QString& path)
{
return PythonBindingsInterface::Get()->AddProject(path);
}
bool UnregisterProject(const QString& path)
{
return PythonBindingsInterface::Get()->RemoveProject(path);
}
bool CopyProjectDialog(const QString& origPath, QWidget* parent)
{
bool copyResult = false;
QDir parentOrigDir(origPath);
parentOrigDir.cdUp();
QString newPath = QDir::toNativeSeparators(
QFileDialog::getExistingDirectory(parent, QObject::tr("Select New Project Directory"), parentOrigDir.path()));
if (!newPath.isEmpty())
{
if (!WarnDirectoryOverwrite(newPath, parent))
{
return false;
}
// TODO: Block UX and Notify User they need to wait
copyResult = CopyProject(origPath, newPath);
}
return copyResult;
}
bool CopyProject(const QString& origPath, const QString& newPath)
{
// Disallow copying from or into subdirectory
if (!IsDirectoryDescedent(origPath, newPath) || !IsDirectoryDescedent(newPath, origPath))
{
return false;
}
if (!CopyDirectory(origPath, newPath))
{
// Cleanup whatever mess was made
DeleteProjectFiles(newPath, true);
return false;
}
if (!RegisterProject(newPath))
{
DeleteProjectFiles(newPath, true);
}
return true;
}
bool DeleteProjectFiles(const QString& path, bool force)
{
QDir projectDirectory(path);
if (projectDirectory.exists())
{
// Check if there is an actual project hereor just force it
if (force || PythonBindingsInterface::Get()->GetProject(path).IsSuccess())
{
return projectDirectory.removeRecursively();
}
}
return false;
}
bool MoveProject(const QString& origPath, const QString& newPath, QWidget* parent)
{
if (!WarnDirectoryOverwrite(newPath, parent) || !UnregisterProject(origPath))
{
return false;
}
QDir directory;
if (directory.rename(origPath, newPath))
{
return directory.rename(origPath, newPath);
}
if (!RegisterProject(newPath))
{
return false;
}
return true;
}
ProjectManagerScreen GetProjectManagerScreen(const QString& screen)
{
auto iter = s_ProjectManagerStringNames.find(screen);
if (iter != s_ProjectManagerStringNames.end())
{
return iter.value();
}
return ProjectManagerScreen::Invalid;
}
} // namespace ProjectUtils
} // namespace O3DE::ProjectManager
@@ -0,0 +1,30 @@
/*
* 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
#include <ScreenDefs.h>
#include <QWidget>
namespace O3DE::ProjectManager
{
namespace ProjectUtils
{
bool AddProjectDialog(QWidget* parent = nullptr);
bool RegisterProject(const QString& path);
bool UnregisterProject(const QString& path);
bool CopyProjectDialog(const QString& origPath, QWidget* parent = nullptr);
bool CopyProject(const QString& origPath, const QString& newPath);
bool DeleteProjectFiles(const QString& path, bool force = false);
bool MoveProject(const QString& origPath, const QString& newPath, QWidget* parent = nullptr);
ProjectManagerScreen GetProjectManagerScreen(const QString& screen);
} // namespace ProjectUtils
} // namespace O3DE::ProjectManager
@@ -14,6 +14,7 @@
#include <ProjectButtonWidget.h>
#include <PythonBindingsInterface.h>
#include <ProjectUtils.h>
#include <AzQtComponents/Components/FlowLayout.h>
#include <AzCore/Platform.h>
@@ -65,9 +66,6 @@ namespace O3DE::ProjectManager
m_stack->addWidget(m_projectsContent);
vLayout->addWidget(m_stack);
connect(m_createNewProjectAction, &QAction::triggered, this, &ProjectsScreen::HandleNewProjectButton);
connect(m_addExistingProjectAction, &QAction::triggered, this, &ProjectsScreen::HandleAddProjectButton);
}
QFrame* ProjectsScreen::CreateFirstTimeContent()
@@ -167,28 +165,27 @@ namespace O3DE::ProjectManager
#endif
{
ProjectButton* projectButton;
QString projectPreviewPath = project.m_path + m_projectPreviewImagePath;
QFileInfo doesPreviewExist(projectPreviewPath);
if (doesPreviewExist.exists() && doesPreviewExist.isFile())
{
projectButton = new ProjectButton(project.m_projectName, projectPreviewPath, this);
}
else
{
projectButton = new ProjectButton(project.m_projectName, this);
project.m_imagePath = projectPreviewPath;
}
projectButton = new ProjectButton(project, this);
flowLayout->addWidget(projectButton);
connect(projectButton, &ProjectButton::OpenProject, this, &ProjectsScreen::HandleOpenProject);
connect(projectButton, &ProjectButton::EditProject, this, &ProjectsScreen::HandleEditProject);
#ifdef DISPLAY_PROJECT_DEV_DATA
connect(projectButton, &ProjectButton::EditProjectGems, this, &ProjectsScreen::HandleEditProjectGems);
connect(projectButton, &ProjectButton::CopyProject, this, &ProjectsScreen::HandleCopyProject);
connect(projectButton, &ProjectButton::RemoveProject, this, &ProjectsScreen::HandleRemoveProject);
connect(projectButton, &ProjectButton::DeleteProject, this, &ProjectsScreen::HandleDeleteProject);
#endif
#ifdef SHOW_ALL_PROJECT_ACTIONS
connect(projectButton, &ProjectButton::EditProjectGems, this, &ProjectsScreen::HandleEditProjectGems);
#endif
}
layout->addWidget(projectsScrollArea);
@@ -242,7 +239,11 @@ namespace O3DE::ProjectManager
}
void ProjectsScreen::HandleAddProjectButton()
{
// Do nothing for now
if (ProjectUtils::AddProjectDialog(this))
{
emit ResetScreenRequest(ProjectManagerScreen::Projects);
emit ChangeScreenRequest(ProjectManagerScreen::Projects);
}
}
void ProjectsScreen::HandleOpenProject(const QString& projectPath)
{
@@ -300,18 +301,36 @@ namespace O3DE::ProjectManager
emit NotifyCurrentProject(projectPath);
emit ChangeScreenRequest(ProjectManagerScreen::GemCatalog);
}
void ProjectsScreen::HandleCopyProject([[maybe_unused]] const QString& projectPath)
void ProjectsScreen::HandleCopyProject(const QString& projectPath)
{
// Open file dialog and choose location for copied project then register copy with O3DE
if (ProjectUtils::CopyProjectDialog(projectPath, this))
{
emit ResetScreenRequest(ProjectManagerScreen::Projects);
emit ChangeScreenRequest(ProjectManagerScreen::Projects);
}
}
void ProjectsScreen::HandleRemoveProject([[maybe_unused]] const QString& projectPath)
void ProjectsScreen::HandleRemoveProject(const QString& projectPath)
{
// Unregister Project from O3DE
// Unregister Project from O3DE and reload projects
if (ProjectUtils::UnregisterProject(projectPath))
{
emit ResetScreenRequest(ProjectManagerScreen::Projects);
emit ChangeScreenRequest(ProjectManagerScreen::Projects);
}
}
void ProjectsScreen::HandleDeleteProject([[maybe_unused]] const QString& projectPath)
void ProjectsScreen::HandleDeleteProject(const QString& projectPath)
{
// Remove project from 03DE and delete from disk
ProjectsScreen::HandleRemoveProject(projectPath);
QMessageBox::StandardButton warningResult = QMessageBox::warning(
this, tr("Delete Project"), tr("Are you sure?\nProject will be removed from O3DE and directory will be deleted!"),
QMessageBox::No | QMessageBox::Yes);
if (warningResult == QMessageBox::Yes)
{
// Remove project from O3DE and delete from disk
HandleRemoveProject(projectPath);
ProjectUtils::DeleteProjectFiles(projectPath);
}
}
void ProjectsScreen::NotifyCurrentScreen()
@@ -322,6 +341,16 @@ namespace O3DE::ProjectManager
}
else
{
// refresh the projects content by re-creating it for now
if (m_projectsContent)
{
m_stack->removeWidget(m_projectsContent);
m_projectsContent->deleteLater();
}
m_projectsContent = CreateProjectsContent();
m_stack->addWidget(m_projectsContent);
m_stack->setCurrentWidget(m_projectsContent);
}
}
@@ -220,7 +220,7 @@ namespace RedirectOutput
}
} // namespace RedirectOutput
namespace O3DE::ProjectManager
namespace O3DE::ProjectManager
{
PythonBindings::PythonBindings(const AZ::IO::PathView& enginePath)
: m_enginePath(enginePath)
@@ -283,8 +283,11 @@ namespace O3DE::ProjectManager
AZ_Warning("ProjectManagerWindow", result != -1, "Append to sys path failed");
// import required modules
m_registration = pybind11::module::import("cmake.Tools.registration");
m_engineTemplate = pybind11::module::import("cmake.Tools.engine_template");
m_register = pybind11::module::import("o3de.register");
m_manifest = pybind11::module::import("o3de.manifest");
m_engineTemplate = pybind11::module::import("o3de.engine_template");
m_enableGemProject = pybind11::module::import("o3de.enable_gem");
m_disableGemProject = pybind11::module::import("o3de.disable_gem");
// make sure the engine is registered
RegisterThisEngine();
@@ -365,30 +368,30 @@ namespace O3DE::ProjectManager
}
}
AZ::Outcome<EngineInfo> PythonBindings::GetEngineInfo()
AZ::Outcome<EngineInfo> PythonBindings::GetEngineInfo()
{
EngineInfo engineInfo;
bool result = ExecuteWithLock([&] {
pybind11::str enginePath = m_registration.attr("get_this_engine_path")();
pybind11::str enginePath = m_manifest.attr("get_this_engine_path")();
auto o3deData = m_registration.attr("load_o3de_manifest")();
auto o3deData = m_manifest.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","");
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_data")(pybind11::none(), enginePath);
auto engineData = m_manifest.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");
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)
{
@@ -403,13 +406,13 @@ namespace O3DE::ProjectManager
}
else
{
return AZ::Success(AZStd::move(engineInfo));
return AZ::Success(AZStd::move(engineInfo));
}
return AZ::Failure();
}
bool PythonBindings::SetEngineInfo(const EngineInfo& engineInfo)
bool PythonBindings::SetEngineInfo(const EngineInfo& engineInfo)
{
bool result = ExecuteWithLock([&] {
pybind11::str enginePath = engineInfo.m_path.toStdString();
@@ -417,17 +420,18 @@ namespace O3DE::ProjectManager
pybind11::str defaultGemsFolder = engineInfo.m_defaultGemsFolder.toStdString();
pybind11::str defaultTemplatesFolder = engineInfo.m_defaultTemplatesFolder.toStdString();
auto registrationResult = m_registration.attr("register")(
auto registrationResult = m_register.attr("register")(
enginePath, // engine_path
pybind11::none(), // project_path
pybind11::none(), // gem_path
pybind11::none(), // gem_path
pybind11::none(), // external_subdir_path
pybind11::none(), // template_path
pybind11::none(), // restricted_path
pybind11::none(), // repo_uri
pybind11::none(), // default_engines_folder
defaultProjectsFolder,
defaultGemsFolder,
defaultTemplatesFolder
defaultGemsFolder,
defaultTemplatesFolder
);
if (registrationResult.cast<int>() != 0)
@@ -435,13 +439,13 @@ namespace O3DE::ProjectManager
result = false;
}
auto manifest = m_registration.attr("load_o3de_manifest")();
auto manifest = m_manifest.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);
m_manifest.attr("save_o3de_manifest")(manifest);
}
catch ([[maybe_unused]] const std::exception& e)
{
@@ -454,12 +458,12 @@ namespace O3DE::ProjectManager
return result;
}
AZ::Outcome<GemInfo> PythonBindings::GetGem(const QString& path)
AZ::Outcome<GemInfo> PythonBindings::GetGem(const QString& path)
{
GemInfo gemInfo = GemInfoFromPath(pybind11::str(path.toStdString()));
if (gemInfo.IsValid())
{
return AZ::Success(AZStd::move(gemInfo));
return AZ::Success(AZStd::move(gemInfo));
}
else
{
@@ -467,19 +471,19 @@ namespace O3DE::ProjectManager
}
}
AZ::Outcome<QVector<GemInfo>> PythonBindings::GetGems()
AZ::Outcome<QVector<GemInfo>> PythonBindings::GetGems()
{
QVector<GemInfo> gems;
bool result = ExecuteWithLock([&] {
// external gems
for (auto path : m_registration.attr("get_gems")())
// external gems
for (auto path : m_manifest.attr("get_gems")())
{
gems.push_back(GemInfoFromPath(path));
}
// gems from the engine
for (auto path : m_registration.attr("get_engine_gems")())
// gems from the engine
for (auto path : m_manifest.attr("get_engine_gems")())
{
gems.push_back(GemInfoFromPath(path));
}
@@ -491,18 +495,72 @@ namespace O3DE::ProjectManager
}
else
{
return AZ::Success(AZStd::move(gems));
return AZ::Success(AZStd::move(gems));
}
}
AZ::Outcome<ProjectInfo> PythonBindings::CreateProject(const QString& projectTemplatePath, const ProjectInfo& projectInfo)
bool PythonBindings::AddProject(const QString& path)
{
bool registrationResult = false;
bool result = ExecuteWithLock(
[&]
{
pybind11::str projectPath = path.toStdString();
auto pythonRegistrationResult = m_register.attr("register")(pybind11::none(), projectPath);
// Returns an exit code so boolify it then invert result
registrationResult = !pythonRegistrationResult.cast<bool>();
});
return result && registrationResult;
}
bool PythonBindings::RemoveProject(const QString& path)
{
bool registrationResult = false;
bool result = ExecuteWithLock(
[&]
{
pybind11::str projectPath = path.toStdString();
auto pythonRegistrationResult = m_register.attr("register")(
pybind11::none(), // engine_path
projectPath, // project_path
pybind11::none(), // gem_path
pybind11::none(), // external_subdir_path
pybind11::none(), // template_path
pybind11::none(), // restricted_path
pybind11::none(), // repo_uri
pybind11::none(), // default_engines_folder
pybind11::none(), // default_projects_folder
pybind11::none(), // default_gems_folder
pybind11::none(), // default_templates_folder
pybind11::none(), // default_restricted_folder
pybind11::none(), // external_subdir_engine_path
pybind11::none(), // external_subdir_project_path
true, // remove
false // force
);
// Returns an exit code so boolify it then invert result
registrationResult = !pythonRegistrationResult.cast<bool>();
});
return result && registrationResult;
}
AZ::Outcome<ProjectInfo> PythonBindings::CreateProject(const QString& projectTemplatePath, const ProjectInfo& projectInfo)
{
ProjectInfo createdProjectInfo;
bool result = ExecuteWithLock([&] {
pybind11::str projectPath = projectInfo.m_path.toStdString();
pybind11::str projectName = projectInfo.m_projectName.toStdString();
pybind11::str templatePath = projectTemplatePath.toStdString();
auto createProjectResult = m_engineTemplate.attr("create_project")(projectPath, templatePath);
auto createProjectResult = m_engineTemplate.attr("create_project")(
projectPath,
projectName,
templatePath
);
if (createProjectResult.cast<int>() == 0)
{
createdProjectInfo = ProjectInfoFromPath(projectPath);
@@ -515,16 +573,16 @@ namespace O3DE::ProjectManager
}
else
{
return AZ::Success(AZStd::move(createdProjectInfo));
return AZ::Success(AZStd::move(createdProjectInfo));
}
}
AZ::Outcome<ProjectInfo> PythonBindings::GetProject(const QString& path)
AZ::Outcome<ProjectInfo> PythonBindings::GetProject(const QString& path)
{
ProjectInfo projectInfo = ProjectInfoFromPath(pybind11::str(path.toStdString()));
if (projectInfo.IsValid())
{
return AZ::Success(AZStd::move(projectInfo));
return AZ::Success(AZStd::move(projectInfo));
}
else
{
@@ -535,30 +593,21 @@ namespace O3DE::ProjectManager
GemInfo PythonBindings::GemInfoFromPath(pybind11::handle path)
{
GemInfo gemInfo;
gemInfo.m_path = Py_To_String(path);
gemInfo.m_path = Py_To_String(path);
auto data = m_registration.attr("get_gem_data")(pybind11::none(), path);
auto data = m_manifest.attr("get_gem_json_data")(pybind11::none(), path);
if (pybind11::isinstance<pybind11::dict>(data))
{
try
{
// required
gemInfo.m_name = Py_To_String(data["Name"]);
gemInfo.m_uuid = AZ::Uuid(Py_To_String(data["Uuid"]));
gemInfo.m_name = Py_To_String(data["gem_name"]);
// optional
gemInfo.m_displayName = Py_To_String_Optional(data, "DisplayName", gemInfo.m_name);
gemInfo.m_summary = Py_To_String_Optional(data, "Summary", "");
gemInfo.m_version = Py_To_String_Optional(data, "Version", "");
gemInfo.m_displayName = Py_To_String_Optional(data, "DisplayName", gemInfo.m_name);
gemInfo.m_summary = Py_To_String_Optional(data, "Summary", "");
gemInfo.m_version = Py_To_String_Optional(data, "Version", "");
if (data.contains("Dependencies"))
{
for (auto dependency : data["Dependencies"])
{
const AZ::Uuid uuid = Py_To_String(dependency["Uuid"]);
gemInfo.m_dependingGemUuids.push_back(uuid.ToString<AZStd::string>().c_str());
}
}
if (data.contains("Tags"))
{
for (auto tag : data["Tags"])
@@ -582,13 +631,13 @@ namespace O3DE::ProjectManager
projectInfo.m_path = Py_To_String(path);
projectInfo.m_isNew = false;
auto projectData = m_registration.attr("get_project_data")(pybind11::none(), path);
auto projectData = m_manifest.attr("get_project_json_data")(pybind11::none(), path);
if (pybind11::isinstance<pybind11::dict>(projectData))
{
try
{
projectInfo.m_projectName = Py_To_String(projectData["project_name"]);
projectInfo.m_displayName = Py_To_String_Optional(projectData,"display_name", projectInfo.m_projectName);
projectInfo.m_projectName = Py_To_String(projectData["project_name"]);
projectInfo.m_displayName = Py_To_String_Optional(projectData,"display_name", projectInfo.m_projectName);
}
catch ([[maybe_unused]] const std::exception& e)
{
@@ -599,19 +648,19 @@ namespace O3DE::ProjectManager
return projectInfo;
}
AZ::Outcome<QVector<ProjectInfo>> PythonBindings::GetProjects()
AZ::Outcome<QVector<ProjectInfo>> PythonBindings::GetProjects()
{
QVector<ProjectInfo> projects;
bool result = ExecuteWithLock([&] {
// external projects
for (auto path : m_registration.attr("get_projects")())
// external projects
for (auto path : m_manifest.attr("get_projects")())
{
projects.push_back(ProjectInfoFromPath(path));
}
// projects from the engine
for (auto path : m_registration.attr("get_engine_projects")())
// projects from the engine
for (auto path : m_manifest.attr("get_engine_projects")())
{
projects.push_back(ProjectInfoFromPath(path));
}
@@ -623,7 +672,7 @@ namespace O3DE::ProjectManager
}
else
{
return AZ::Success(AZStd::move(projects));
return AZ::Success(AZStd::move(projects));
}
}
@@ -633,13 +682,12 @@ namespace O3DE::ProjectManager
pybind11::str pyGemPath = gemPath.toStdString();
pybind11::str pyProjectPath = projectPath.toStdString();
m_registration.attr("add_gem_to_project")(
m_enableGemProject.attr("enable_gem_in_project")(
pybind11::none(), // gem_name
pyGemPath,
pybind11::none(), // gem_target
pybind11::none(), // project_name
pyProjectPath
);
);
});
return result;
@@ -651,19 +699,18 @@ namespace O3DE::ProjectManager
pybind11::str pyGemPath = gemPath.toStdString();
pybind11::str pyProjectPath = projectPath.toStdString();
m_registration.attr("remove_gem_to_project")(
m_disableGemProject.attr("disable_gem_in_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)
bool PythonBindings::UpdateProject([[maybe_unused]] const ProjectInfo& projectInfo)
{
return false;
}
@@ -671,18 +718,18 @@ namespace O3DE::ProjectManager
ProjectTemplateInfo PythonBindings::ProjectTemplateInfoFromPath(pybind11::handle path)
{
ProjectTemplateInfo templateInfo;
templateInfo.m_path = Py_To_String(path);
templateInfo.m_path = Py_To_String(path);
auto data = m_registration.attr("get_template_data")(pybind11::none(), path);
auto data = m_manifest.attr("get_template_json_data")(pybind11::none(), path);
if (pybind11::isinstance<pybind11::dict>(data))
{
try
{
// required
templateInfo.m_displayName = Py_To_String(data["display_name"]);
templateInfo.m_name = Py_To_String(data["template_name"]);
templateInfo.m_summary = Py_To_String(data["summary"]);
templateInfo.m_displayName = Py_To_String(data["display_name"]);
templateInfo.m_name = Py_To_String(data["template_name"]);
templateInfo.m_summary = Py_To_String(data["summary"]);
// optional
if (data.contains("canonical_tags"))
{
@@ -708,12 +755,12 @@ namespace O3DE::ProjectManager
return templateInfo;
}
AZ::Outcome<QVector<ProjectTemplateInfo>> PythonBindings::GetProjectTemplates()
AZ::Outcome<QVector<ProjectTemplateInfo>> PythonBindings::GetProjectTemplates()
{
QVector<ProjectTemplateInfo> templates;
bool result = ExecuteWithLock([&] {
for (auto path : m_registration.attr("get_project_templates")())
for (auto path : m_manifest.attr("get_project_templates")())
{
templates.push_back(ProjectTemplateInfoFromPath(path));
}
@@ -725,7 +772,7 @@ namespace O3DE::ProjectManager
}
else
{
return AZ::Success(AZStd::move(templates));
return AZ::Success(AZStd::move(templates));
}
}
}
@@ -12,7 +12,7 @@
#pragma once
#include <PythonBindingsInterface.h>
#include <AzCore/IO/Path/Path.h>
#include <AzCore/IO/Path/Path.h>
#include <AzCore/std/parallel/semaphore.h>
// Qt defines slots, which interferes with the use here.
@@ -25,7 +25,7 @@
namespace O3DE::ProjectManager
{
class PythonBindings
class PythonBindings
: public PythonBindingsInterface::Registrar
{
public:
@@ -46,6 +46,8 @@ namespace O3DE::ProjectManager
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 AddProject(const QString& path) override;
bool RemoveProject(const QString& path) override;
bool UpdateProject(const ProjectInfo& projectInfo) override;
bool AddGemToProject(const QString& gemPath, const QString& projectPath) override;
bool RemoveGemFromProject(const QString& gemPath, const QString& projectPath) override;
@@ -68,6 +70,9 @@ namespace O3DE::ProjectManager
AZ::IO::FixedMaxPath m_enginePath;
pybind11::handle m_engineTemplate;
AZStd::recursive_mutex m_lock;
pybind11::handle m_registration;
pybind11::handle m_register;
pybind11::handle m_manifest;
pybind11::handle m_enableGemProject;
pybind11::handle m_disableGemProject;
};
}
@@ -88,6 +88,20 @@ namespace O3DE::ProjectManager
* @return an outcome with ProjectInfos on success
*/
virtual AZ::Outcome<QVector<ProjectInfo>> GetProjects() = 0;
/**
* Adds existing project on disk
* @param path the absolute path to the project
* @return true on success, false on failure
*/
virtual bool AddProject(const QString& path) = 0;
/**
* Adds existing project on disk
* @param path the absolute path to the project
* @return true on success, false on failure
*/
virtual bool RemoveProject(const QString& path) = 0;
/**
* Update a project
+22 -1
View File
@@ -11,9 +11,13 @@
*/
#pragma once
#include <AzCore/std/containers/unordered_map.h>
#include <AzCore/std/string/string.h>
#include <QHash>
namespace O3DE::ProjectManager
{
enum ProjectManagerScreen
enum class ProjectManagerScreen
{
Invalid = -1,
Empty,
@@ -25,4 +29,21 @@ namespace O3DE::ProjectManager
ProjectSettings,
EngineSettings
};
static QHash<QString, ProjectManagerScreen> s_ProjectManagerStringNames = {
{ "Empty", ProjectManagerScreen::Empty},
{ "CreateProject", ProjectManagerScreen::CreateProject},
{ "NewProjectSettings", ProjectManagerScreen::NewProjectSettings},
{ "GemCatalog", ProjectManagerScreen::GemCatalog},
{ "Projects", ProjectManagerScreen::Projects},
{ "UpdateProject", ProjectManagerScreen::UpdateProject},
{ "ProjectSettings", ProjectManagerScreen::ProjectSettings},
{ "EngineSettings", ProjectManagerScreen::EngineSettings}
};
// need to define qHash for ProjectManagerScreen when using scoped enums
inline uint qHash(ProjectManagerScreen key, uint seed)
{
return ::qHash(static_cast<uint>(key), seed);
}
} // namespace O3DE::ProjectManager
@@ -136,6 +136,7 @@ namespace O3DE::ProjectManager
{
shouldRestoreCurrentScreen = true;
}
int tabIndex = GetScreenTabIndex(screen);
// Delete old screen if it exists to start fresh
DeleteScreen(screen);
@@ -144,11 +145,19 @@ namespace O3DE::ProjectManager
ScreenWidget* newScreen = BuildScreen(this, screen);
if (newScreen->IsTab())
{
m_tabWidget->addTab(newScreen, newScreen->GetTabText());
if (tabIndex > -1)
{
m_tabWidget->insertTab(tabIndex, newScreen, newScreen->GetTabText());
}
else
{
m_tabWidget->addTab(newScreen, newScreen->GetTabText());
}
if (shouldRestoreCurrentScreen)
{
m_tabWidget->setCurrentWidget(newScreen);
m_screenStack->setCurrentWidget(m_tabWidget);
newScreen->NotifyCurrentScreen();
}
}
else
@@ -157,6 +166,7 @@ namespace O3DE::ProjectManager
if (shouldRestoreCurrentScreen)
{
m_screenStack->setCurrentWidget(newScreen);
newScreen->NotifyCurrentScreen();
}
}
@@ -219,4 +229,19 @@ namespace O3DE::ProjectManager
screen->NotifyCurrentScreen();
}
}
int ScreensCtrl::GetScreenTabIndex(ProjectManagerScreen screen)
{
const auto iter = m_screenMap.find(screen);
if (iter != m_screenMap.end())
{
ScreenWidget* screenWidget = iter.value();
if (screenWidget->IsTab())
{
return m_tabWidget->indexOf(screenWidget);
}
}
return -1;
}
} // namespace O3DE::ProjectManager
@@ -51,6 +51,8 @@ namespace O3DE::ProjectManager
void TabChanged(int index);
private:
int GetScreenTabIndex(ProjectManagerScreen screen);
QStackedWidget* m_screenStack;
QHash<ProjectManagerScreen, ScreenWidget*> m_screenMap;
QStack<ProjectManagerScreen> m_screenVisitOrder;
@@ -18,9 +18,9 @@ namespace O3DE::ProjectManager
TagWidget::TagWidget(const QString& text, QWidget* parent)
: QLabel(text, parent)
{
setFixedHeight(35);
setFixedHeight(24);
setMargin(5);
setStyleSheet("font-size: 12pt; background-color: #333333; border-radius: 4px;");
setStyleSheet("font-size: 12px; background-color: #333333; border-radius: 3px;");
}
TagContainerWidget::TagContainerWidget(QWidget* parent)
@@ -35,7 +35,7 @@ namespace O3DE::ProjectManager
void TagContainerWidget::Update(const QStringList& tags)
{
QWidget* parentWidget = qobject_cast<QWidget*>(parent());
int width = 250;
int width = 200;
if (parentWidget)
{
width = parentWidget->width();
+27 -1
View File
@@ -15,13 +15,17 @@
#include <AzCore/Component/ComponentApplication.h>
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
#include <AzCore/IO/Path/Path.h>
#include <AzFramework/CommandLine/CommandLine.h>
#include <ProjectManagerWindow.h>
#include <ProjectUtils.h>
#include <QApplication>
#include <QCoreApplication>
#include <QGuiApplication>
using namespace O3DE::ProjectManager;
int main(int argc, char* argv[])
{
QApplication::setOrganizationName("O3DE");
@@ -51,7 +55,29 @@ int main(int argc, char* argv[])
AzQtComponents::StyleManager styleManager(&app);
styleManager.initialize(&app, engineRootPath);
O3DE::ProjectManager::ProjectManagerWindow window(nullptr, engineRootPath);
// Get the initial start screen if one is provided via command line
constexpr char optionPrefix[] = "--";
AZ::CommandLine commandLine(optionPrefix);
commandLine.Parse(argc, argv);
ProjectManagerScreen startScreen = ProjectManagerScreen::Projects;
if(commandLine.HasSwitch("screen"))
{
QString screenOption = commandLine.GetSwitchValue("screen", 0).c_str();
ProjectManagerScreen screen = ProjectUtils::GetProjectManagerScreen(screenOption);
if (screen != ProjectManagerScreen::Invalid)
{
startScreen = screen;
}
}
AZ::IO::FixedMaxPath projectPath;
if (commandLine.HasSwitch("project-path"))
{
projectPath = commandLine.GetSwitchValue("project-path", 0).c_str();
}
ProjectManagerWindow window(nullptr, engineRootPath, projectPath, startScreen);
window.show();
// somethings is preventing us from moving the window to the center of the