diff --git a/Code/Tools/ProjectManager/Resources/Delete.svg b/Code/Tools/ProjectManager/Resources/Delete.svg
new file mode 100644
index 0000000000..f932c71544
--- /dev/null
+++ b/Code/Tools/ProjectManager/Resources/Delete.svg
@@ -0,0 +1,4 @@
+
diff --git a/Code/Tools/ProjectManager/Resources/Edit.svg b/Code/Tools/ProjectManager/Resources/Edit.svg
new file mode 100644
index 0000000000..3ee9bbbfae
--- /dev/null
+++ b/Code/Tools/ProjectManager/Resources/Edit.svg
@@ -0,0 +1,7 @@
+
diff --git a/Code/Tools/ProjectManager/Resources/ProjectManager.qrc b/Code/Tools/ProjectManager/Resources/ProjectManager.qrc
index 2e93e9eca9..30bcc1ace5 100644
--- a/Code/Tools/ProjectManager/Resources/ProjectManager.qrc
+++ b/Code/Tools/ProjectManager/Resources/ProjectManager.qrc
@@ -35,5 +35,8 @@
Backgrounds/DefaultBackground.jpg
Backgrounds/FtueBackground.jpg
FeatureTagClose.svg
+ Refresh.svg
+ Edit.svg
+ Delete.svg
diff --git a/Code/Tools/ProjectManager/Resources/ProjectManager.qss b/Code/Tools/ProjectManager/Resources/ProjectManager.qss
index 17c5077d83..30117d6636 100644
--- a/Code/Tools/ProjectManager/Resources/ProjectManager.qss
+++ b/Code/Tools/ProjectManager/Resources/ProjectManager.qss
@@ -518,3 +518,82 @@ QProgressBar::chunk {
font-size: 12px;
font-weight: 600;
}
+
+/************** Engine **************/
+
+#engineTab::tab-bar {
+ left: 60px;
+}
+
+#engineTabBar::tab {
+ height: 50px;
+ background-color: transparent;
+ font-weight: 400;
+ font-size: 18px;
+ min-width: 160px;
+}
+
+#engineTabBar::tab:selected {
+ border-bottom: 3px solid #94D2FF;
+ color: #94D2FF;
+ font-weight: 600;
+}
+#engineTabBar::tab:hover {
+ color: #94D2FF;
+ font-weight: 600;
+}
+#engineTabBar::tab:pressed {
+ color: #66bcfa;
+}
+
+#engineTopFrame {
+ background-color:#1E252F;
+}
+
+/************** Gem Repo **************/
+
+#gemRepoHeaderLabel {
+ font-size: 12px;
+}
+
+#gemRepoHeaderRefreshButton {
+ background-color: transparent;
+ qproperty-flat: true;
+ qproperty-iconSize: 14px;
+}
+
+#gemRepoHeaderAddButton {
+ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
+ stop: 0 #888888, stop: 1.0 #555555);
+ qproperty-flat: true;
+ margin-right:30px;
+ min-width:120px;
+ max-width:120px;
+ min-height:24px;
+ max-height:24px;
+ border-radius: 3px;
+ text-align:center;
+ font-size:12px;
+ font-weight:600;
+}
+#gemRepoHeaderAddButton:hover {
+ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
+ stop: 0 #999999, stop: 1.0 #666666);
+}
+#gemRepoHeaderAddButton:pressed {
+ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
+ stop: 0 #555555, stop: 1.0 #777777);
+}
+
+#gemRepoHeaderTable {
+ background-color: transparent;
+ max-height: 30px;
+}
+
+#gemRepoListHeader {
+ background-color: transparent;
+}
+
+#gemRepoInspector {
+ background: #444444;
+}
diff --git a/Code/Tools/ProjectManager/Resources/Refresh.svg b/Code/Tools/ProjectManager/Resources/Refresh.svg
new file mode 100644
index 0000000000..80cc892c68
--- /dev/null
+++ b/Code/Tools/ProjectManager/Resources/Refresh.svg
@@ -0,0 +1,4 @@
+
diff --git a/Code/Tools/ProjectManager/Source/EngineScreenCtrl.cpp b/Code/Tools/ProjectManager/Source/EngineScreenCtrl.cpp
new file mode 100644
index 0000000000..c78a9426db
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/EngineScreenCtrl.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+namespace O3DE::ProjectManager
+{
+ EngineScreenCtrl::EngineScreenCtrl(QWidget* parent)
+ : ScreenWidget(parent)
+ {
+ QVBoxLayout* vLayout = new QVBoxLayout();
+ vLayout->setContentsMargins(0, 0, 0, 0);
+
+ QFrame* topBarFrameWidget = new QFrame(this);
+ topBarFrameWidget->setObjectName("engineTopFrame");
+ QHBoxLayout* topBarHLayout = new QHBoxLayout();
+ topBarHLayout->setContentsMargins(0, 0, 0, 0);
+
+ topBarFrameWidget->setLayout(topBarHLayout);
+
+ QTabWidget* tabWidget = new QTabWidget();
+ tabWidget->setObjectName("engineTab");
+ tabWidget->tabBar()->setObjectName("engineTabBar");
+ tabWidget->tabBar()->setFocusPolicy(Qt::TabFocus);
+
+ m_engineSettingsScreen = new EngineSettingsScreen();
+ m_gemRepoScreen = new GemRepoScreen();
+
+ tabWidget->addTab(m_engineSettingsScreen, tr("General"));
+ tabWidget->addTab(m_gemRepoScreen, tr("Gem Repositories"));
+ topBarHLayout->addWidget(tabWidget);
+
+ vLayout->addWidget(topBarFrameWidget);
+
+ setLayout(vLayout);
+ }
+
+ ProjectManagerScreen EngineScreenCtrl::GetScreenEnum()
+ {
+ return ProjectManagerScreen::UpdateProject;
+ }
+
+ QString EngineScreenCtrl::GetTabText()
+ {
+ return tr("Engine");
+ }
+
+ bool EngineScreenCtrl::IsTab()
+ {
+ return true;
+ }
+
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/EngineScreenCtrl.h b/Code/Tools/ProjectManager/Source/EngineScreenCtrl.h
new file mode 100644
index 0000000000..9e799f13e7
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/EngineScreenCtrl.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+#pragma once
+
+#if !defined(Q_MOC_RUN)
+#include
+#endif
+
+namespace O3DE::ProjectManager
+{
+ QT_FORWARD_DECLARE_CLASS(EngineSettingsScreen)
+ QT_FORWARD_DECLARE_CLASS(GemRepoScreen)
+
+ class EngineScreenCtrl
+ : public ScreenWidget
+ {
+ public:
+ explicit EngineScreenCtrl(QWidget* parent = nullptr);
+ ~EngineScreenCtrl() = default;
+ ProjectManagerScreen GetScreenEnum() override;
+
+ QString GetTabText() override;
+ bool IsTab() override;
+
+ EngineSettingsScreen* m_engineSettingsScreen = nullptr;
+ GemRepoScreen* m_gemRepoScreen = nullptr;
+ };
+
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/EngineSettingsScreen.cpp b/Code/Tools/ProjectManager/Source/EngineSettingsScreen.cpp
index 0c24aac9f1..dec1c9a257 100644
--- a/Code/Tools/ProjectManager/Source/EngineSettingsScreen.cpp
+++ b/Code/Tools/ProjectManager/Source/EngineSettingsScreen.cpp
@@ -7,15 +7,16 @@
*/
#include
-#include
-#include
-#include
-#include
#include
#include
#include
#include
+#include
+#include
+#include
+#include
+
namespace O3DE::ProjectManager
{
EngineSettingsScreen::EngineSettingsScreen(QWidget* parent)
@@ -78,16 +79,6 @@ namespace O3DE::ProjectManager
return ProjectManagerScreen::EngineSettings;
}
- QString EngineSettingsScreen::GetTabText()
- {
- return tr("Engine");
- }
-
- bool EngineSettingsScreen::IsTab()
- {
- return true;
- }
-
void EngineSettingsScreen::OnTextChanged()
{
// save engine settings
diff --git a/Code/Tools/ProjectManager/Source/EngineSettingsScreen.h b/Code/Tools/ProjectManager/Source/EngineSettingsScreen.h
index 9d212c44b1..2f16400405 100644
--- a/Code/Tools/ProjectManager/Source/EngineSettingsScreen.h
+++ b/Code/Tools/ProjectManager/Source/EngineSettingsScreen.h
@@ -24,8 +24,6 @@ namespace O3DE::ProjectManager
~EngineSettingsScreen() = default;
ProjectManagerScreen GetScreenEnum() override;
- QString GetTabText() override;
- bool IsTab() override;
protected slots:
void OnTextChanged();
diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInfo.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInfo.cpp
new file mode 100644
index 0000000000..3e524d8ec8
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInfo.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include
+
+namespace O3DE::ProjectManager
+{
+ GemRepoInfo::GemRepoInfo(
+ const QString& name, const QString& creator, const QString& summary, const QDateTime& lastUpdated, bool isEnabled = true)
+ : m_name(name)
+ , m_creator(creator)
+ , m_summary(summary)
+ , m_lastUpdated(lastUpdated)
+ , m_isEnabled(isEnabled)
+ {
+ }
+
+ bool GemRepoInfo::IsValid() const
+ {
+ return !m_name.isEmpty();
+ }
+
+ bool GemRepoInfo::operator<(const GemRepoInfo& gemRepoInfo) const
+ {
+ return (m_lastUpdated < gemRepoInfo.m_lastUpdated);
+ }
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInfo.h b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInfo.h
new file mode 100644
index 0000000000..6f4f828951
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInfo.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#pragma once
+
+#if !defined(Q_MOC_RUN)
+#include
+#include
+#endif
+
+namespace O3DE::ProjectManager
+{
+ class GemRepoInfo
+ {
+ public:
+ GemRepoInfo() = default;
+ GemRepoInfo(const QString& name, const QString& creator, const QString& summary, const QDateTime& lastUpdated, bool isEnabled);
+
+ bool IsValid() const;
+
+ bool operator<(const GemRepoInfo& gemRepoInfo) const;
+
+ QString m_path;
+ QString m_name = "Unknown Gem Repo Name";
+ QString m_creator = "Unknown Creator";
+ bool m_isEnabled = false; //! Is the repo currently enabled for this engine?
+ QString m_summary = "No summary provided.";
+ QString m_directoryLink;
+ QString m_repoLink;
+ QDateTime m_lastUpdated;
+ };
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoItemDelegate.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoItemDelegate.cpp
new file mode 100644
index 0000000000..88ccee2636
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoItemDelegate.cpp
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include
+#include
+
+#include
+#include
+#include
+
+namespace O3DE::ProjectManager
+{
+ GemRepoItemDelegate::GemRepoItemDelegate(QAbstractItemModel* model, QObject* parent)
+ : QStyledItemDelegate(parent)
+ , m_model(model)
+ {
+ m_refreshIcon = QIcon(":/Refresh.svg").pixmap(s_refreshIconSize, s_refreshIconSize);
+ m_editIcon = QIcon(":/Edit.svg").pixmap(s_iconSize, s_iconSize);
+ m_deleteIcon = QIcon(":/Delete.svg").pixmap(s_iconSize, s_iconSize);
+ }
+
+ void GemRepoItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& modelIndex) const
+ {
+ if (!modelIndex.isValid())
+ {
+ return;
+ }
+
+ QStyleOptionViewItem options(option);
+ initStyleOption(&options, modelIndex);
+
+ painter->setRenderHint(QPainter::Antialiasing);
+
+ QRect fullRect, itemRect, contentRect;
+ CalcRects(options, fullRect, itemRect, contentRect);
+ QRect buttonRect = CalcButtonRect(contentRect);
+
+ QFont standardFont(options.font);
+ standardFont.setPixelSize(static_cast(s_fontSize));
+ QFontMetrics standardFontMetrics(standardFont);
+
+ painter->save();
+ painter->setClipping(true);
+ painter->setClipRect(fullRect);
+ painter->setFont(standardFont);
+ painter->setPen(m_textColor);
+
+ // Draw background
+ painter->fillRect(fullRect, m_backgroundColor);
+
+ // Draw item background
+ const QColor itemBackgroundColor = options.state & QStyle::State_MouseOver ? m_itemBackgroundColor.lighter(120) : m_itemBackgroundColor;
+ painter->fillRect(itemRect, itemBackgroundColor);
+
+ // Draw border
+ if (options.state & QStyle::State_Selected)
+ {
+ painter->save();
+ QPen borderPen(m_borderColor);
+ borderPen.setWidth(s_borderWidth);
+ painter->setPen(borderPen);
+ painter->drawRect(itemRect);
+
+ painter->restore();
+ }
+
+ // Repo enabled
+ DrawButton(painter, buttonRect, modelIndex);
+
+ // Repo name
+ QString repoName = GemRepoModel::GetName(modelIndex);
+ repoName = QFontMetrics(standardFont).elidedText(repoName, Qt::TextElideMode::ElideRight, s_nameMaxWidth);
+
+ QRect repoNameRect = GetTextRect(standardFont, repoName, s_fontSize);
+ int currentHorizontalOffset = buttonRect.left() + s_buttonWidth + s_buttonSpacing;
+ repoNameRect.moveTo(currentHorizontalOffset, contentRect.center().y() - repoNameRect.height() / 2);
+ repoNameRect = painter->boundingRect(repoNameRect, Qt::TextSingleLine, repoName);
+
+ painter->drawText(repoNameRect, Qt::TextSingleLine, repoName);
+
+ // Rem repo creator
+ QString repoCreator = GemRepoModel::GetCreator(modelIndex);
+ repoCreator = standardFontMetrics.elidedText(repoCreator, Qt::TextElideMode::ElideRight, s_creatorMaxWidth);
+
+ QRect repoCreatorRect = GetTextRect(standardFont, repoCreator, s_fontSize);
+ currentHorizontalOffset += s_nameMaxWidth + s_contentSpacing;
+ repoCreatorRect.moveTo(currentHorizontalOffset, contentRect.center().y() - repoCreatorRect.height() / 2);
+ repoCreatorRect = painter->boundingRect(repoCreatorRect, Qt::TextSingleLine, repoCreator);
+
+ painter->drawText(repoCreatorRect, Qt::TextSingleLine, repoCreator);
+
+ // Repo update
+ QString repoUpdatedDate = GemRepoModel::GetLastUpdated(modelIndex).toString("dd/MM/yyyy hh:mmap");
+ repoUpdatedDate = standardFontMetrics.elidedText(repoUpdatedDate, Qt::TextElideMode::ElideRight, s_updatedMaxWidth);
+
+ QRect repoUpdatedDateRect = GetTextRect(standardFont, repoUpdatedDate, s_fontSize);
+ currentHorizontalOffset += s_creatorMaxWidth + s_contentSpacing;
+ repoUpdatedDateRect.moveTo(currentHorizontalOffset, contentRect.center().y() - repoUpdatedDateRect.height() / 2);
+ repoUpdatedDateRect = painter->boundingRect(repoUpdatedDateRect, Qt::TextSingleLine, repoUpdatedDate);
+
+ painter->drawText(repoUpdatedDateRect, Qt::TextSingleLine, repoUpdatedDate);
+
+ // Draw refresh button
+ painter->drawPixmap(
+ repoUpdatedDateRect.left() + repoUpdatedDateRect.width() + s_refreshIconSpacing,
+ contentRect.center().y() - s_refreshIconSize / 3, // Dividing size by 3 centers much better
+ m_refreshIcon);
+
+ if (options.state & QStyle::State_MouseOver)
+ {
+ DrawEditButtons(painter, contentRect);
+ }
+
+ painter->restore();
+ }
+
+ QSize GemRepoItemDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& modelIndex) const
+ {
+ QStyleOptionViewItem options(option);
+ initStyleOption(&options, modelIndex);
+
+ int marginsHorizontal = s_itemMargins.left() + s_itemMargins.right() + s_contentMargins.left() + s_contentMargins.right();
+ return QSize(marginsHorizontal + s_buttonWidth + s_buttonSpacing + s_nameMaxWidth + s_creatorMaxWidth + s_updatedMaxWidth + s_contentSpacing * 3, s_height);
+ }
+
+ bool GemRepoItemDelegate::editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& modelIndex)
+ {
+ if (!modelIndex.isValid())
+ {
+ return false;
+ }
+
+ if (event->type() == QEvent::KeyPress)
+ {
+ auto keyEvent = static_cast(event);
+ if (keyEvent->key() == Qt::Key_Space)
+ {
+ const bool isAdded = GemRepoModel::IsEnabled(modelIndex);
+ GemRepoModel::SetEnabled(*model, modelIndex, !isAdded);
+ return true;
+ }
+ }
+
+ if (event->type() == QEvent::MouseButtonPress)
+ {
+ QMouseEvent* mouseEvent = static_cast(event);
+
+ QRect fullRect, itemRect, contentRect;
+ CalcRects(option, fullRect, itemRect, contentRect);
+ const QRect buttonRect = CalcButtonRect(contentRect);
+
+ if (buttonRect.contains(mouseEvent->pos()))
+ {
+ const bool isAdded = GemRepoModel::IsEnabled(modelIndex);
+ GemRepoModel::SetEnabled(*model, modelIndex, !isAdded);
+ return true;
+ }
+ }
+
+ return QStyledItemDelegate::editorEvent(event, model, option, modelIndex);
+ }
+
+ void GemRepoItemDelegate::CalcRects(const QStyleOptionViewItem& option, QRect& outFullRect, QRect& outItemRect, QRect& outContentRect) const
+ {
+ outFullRect = QRect(option.rect);
+ 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()));
+ }
+
+ QRect GemRepoItemDelegate::GetTextRect(QFont& font, const QString& text, qreal fontSize) const
+ {
+ font.setPixelSize(static_cast(fontSize));
+ return QFontMetrics(font).boundingRect(text);
+ }
+
+ QRect GemRepoItemDelegate::CalcButtonRect(const QRect& contentRect) const
+ {
+ const QPoint topLeft = QPoint(contentRect.left(), contentRect.top() + contentRect.height() / 2 - s_buttonHeight / 2);
+ const QSize size = QSize(s_buttonWidth, s_buttonHeight);
+ return QRect(topLeft, size);
+ }
+
+ void GemRepoItemDelegate::DrawButton(QPainter* painter, const QRect& buttonRect, const QModelIndex& modelIndex) const
+ {
+ painter->save();
+ QPoint circleCenter;
+
+ const bool isEnabled = GemRepoModel::IsEnabled(modelIndex);
+ if (isEnabled)
+ {
+ painter->setBrush(m_buttonEnabledColor);
+ painter->setPen(m_buttonEnabledColor);
+
+ circleCenter = buttonRect.center() + QPoint(buttonRect.width() / 2 - s_buttonBorderRadius + 1, 1);
+ }
+ else
+ {
+ circleCenter = buttonRect.center() + QPoint(-buttonRect.width() / 2 + s_buttonBorderRadius + 1, 1);
+ }
+
+ // Rounded rect
+ painter->drawRoundedRect(buttonRect, s_buttonBorderRadius, s_buttonBorderRadius);
+
+ // Circle
+ painter->setBrush(m_textColor);
+ painter->drawEllipse(circleCenter, s_buttonCircleRadius, s_buttonCircleRadius);
+
+ painter->restore();
+ }
+
+ void GemRepoItemDelegate::DrawEditButtons(QPainter* painter, const QRect& contentRect) const
+ {
+ painter->drawPixmap(contentRect.right() - s_iconSize * 2 - s_iconSpacing, contentRect.center().y() - s_iconSize / 2, m_editIcon);
+ painter->drawPixmap(contentRect.right() - s_iconSize, contentRect.center().y() - s_iconSize / 2, m_deleteIcon);
+ }
+
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoItemDelegate.h b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoItemDelegate.h
new file mode 100644
index 0000000000..08d1fdffae
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoItemDelegate.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#pragma once
+
+#if !defined(Q_MOC_RUN)
+#include
+#include
+#endif
+
+QT_FORWARD_DECLARE_CLASS(QAbstractItemModel)
+QT_FORWARD_DECLARE_CLASS(QEvent)
+
+namespace O3DE::ProjectManager
+{
+ class GemRepoItemDelegate
+ : public QStyledItemDelegate
+ {
+ Q_OBJECT // AUTOMOC
+
+ public:
+ explicit GemRepoItemDelegate(QAbstractItemModel* model, QObject* parent = nullptr);
+ ~GemRepoItemDelegate() = 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;
+
+ // Colors
+ const QColor m_textColor = QColor("#FFFFFF");
+ const QColor m_backgroundColor = QColor("#333333"); // Outside of the actual repo item
+ const QColor m_itemBackgroundColor = QColor("#404040"); // Background color of the repo item
+ const QColor m_borderColor = QColor("#1E70EB");
+ const QColor m_buttonEnabledColor = QColor("#1E70EB");
+
+ // Item
+ inline constexpr static int s_height = 72; // Repo item total height
+ inline constexpr static qreal s_fontSize = 12.0;
+
+ // Margin and borders
+ inline constexpr static QMargins s_itemMargins = QMargins(/*left=*/0, /*top=*/8, /*right=*/60, /*bottom=*/8); // Item border distances
+ inline constexpr static QMargins s_contentMargins = QMargins(/*left=*/20, /*top=*/20, /*right=*/20, /*bottom=*/20); // Distances of the elements within an item to the item borders
+ inline constexpr static int s_borderWidth = 4;
+
+ // Content
+ inline constexpr static int s_contentSpacing = 5;
+ inline constexpr static int s_nameMaxWidth = 145;
+ inline constexpr static int s_creatorMaxWidth = 115;
+ inline constexpr static int s_updatedMaxWidth = 125;
+
+ // Button
+ inline constexpr static int s_buttonWidth = 32;
+ inline constexpr static int s_buttonHeight = 16;
+ inline constexpr static int s_buttonBorderRadius = 8;
+ inline constexpr static int s_buttonCircleRadius = s_buttonBorderRadius - 2;
+ inline constexpr static int s_buttonSpacing = 20;
+
+ // Icon
+ inline constexpr static int s_iconSize = 24;
+ inline constexpr static int s_iconSpacing = 16;
+ inline constexpr static int s_refreshIconSize = 14;
+ inline constexpr static int s_refreshIconSpacing = 10;
+
+ protected:
+ 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 DrawButton(QPainter* painter, const QRect& contentRect, const QModelIndex& modelIndex) const;
+ void DrawEditButtons(QPainter* painter, const QRect& contentRect) const;
+
+ QAbstractItemModel* m_model = nullptr;
+
+ QPixmap m_refreshIcon;
+ QPixmap m_editIcon;
+ QPixmap m_deleteIcon;
+ };
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoListView.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoListView.cpp
new file mode 100644
index 0000000000..519d52cb35
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoListView.cpp
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include
+#include
+
+namespace O3DE::ProjectManager
+{
+ GemRepoListView::GemRepoListView(QAbstractItemModel* model, QWidget* parent)
+ : QListView(parent)
+ {
+ setObjectName("gemRepoListView");
+ setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
+
+ setModel(model);
+ setItemDelegate(new GemRepoItemDelegate(model, this));
+ }
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoListView.h b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoListView.h
new file mode 100644
index 0000000000..0fd5d5c180
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoListView.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#pragma once
+
+#if !defined(Q_MOC_RUN)
+#include
+#endif
+
+QT_FORWARD_DECLARE_CLASS(QAbstractItemModel)
+
+namespace O3DE::ProjectManager
+{
+ class GemRepoListView
+ : public QListView
+ {
+ Q_OBJECT // AUTOMOC
+
+ public:
+ explicit GemRepoListView(QAbstractItemModel* model, QWidget* parent = nullptr);
+ ~GemRepoListView() = default;
+ };
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoModel.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoModel.cpp
new file mode 100644
index 0000000000..7a42c135e9
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoModel.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include
+
+#include
+
+namespace O3DE::ProjectManager
+{
+ GemRepoModel::GemRepoModel(QObject* parent)
+ : QStandardItemModel(parent)
+ {
+ m_selectionModel = new QItemSelectionModel(this, parent);
+ }
+
+ QItemSelectionModel* GemRepoModel::GetSelectionModel() const
+ {
+ return m_selectionModel;
+ }
+
+ void GemRepoModel::AddGemRepo(const GemRepoInfo& gemRepoInfo)
+ {
+ QStandardItem* item = new QStandardItem();
+
+ item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
+
+ item->setData(gemRepoInfo.m_name, RoleName);
+ item->setData(gemRepoInfo.m_creator, RoleCreator);
+ item->setData(gemRepoInfo.m_summary, RoleSummary);
+ item->setData(gemRepoInfo.m_isEnabled, RoleIsEnabled);
+ item->setData(gemRepoInfo.m_directoryLink, RoleDirectoryLink);
+ item->setData(gemRepoInfo.m_repoLink, RoleRepoLink);
+ item->setData(gemRepoInfo.m_lastUpdated, RoleLastUpdated);
+ item->setData(gemRepoInfo.m_path, RolePath);
+
+ appendRow(item);
+ }
+
+ void GemRepoModel::Clear()
+ {
+ clear();
+ }
+
+ QString GemRepoModel::GetName(const QModelIndex& modelIndex)
+ {
+ return modelIndex.data(RoleName).toString();
+ }
+
+ QString GemRepoModel::GetCreator(const QModelIndex& modelIndex)
+ {
+ return modelIndex.data(RoleCreator).toString();
+ }
+
+ QString GemRepoModel::GetSummary(const QModelIndex& modelIndex)
+ {
+ return modelIndex.data(RoleSummary).toString();
+ }
+
+ QString GemRepoModel::GetDirectoryLink(const QModelIndex& modelIndex)
+ {
+ return modelIndex.data(RoleDirectoryLink).toString();
+ }
+
+ QString GemRepoModel::GetRepoLink(const QModelIndex& modelIndex)
+ {
+ return modelIndex.data(RoleRepoLink).toString();
+ }
+
+ QDateTime GemRepoModel::GetLastUpdated(const QModelIndex& modelIndex)
+ {
+ return modelIndex.data(RoleLastUpdated).toDateTime();
+ }
+
+ QString GemRepoModel::GetPath(const QModelIndex& modelIndex)
+ {
+ return modelIndex.data(RolePath).toString();
+ }
+
+ bool GemRepoModel::IsEnabled(const QModelIndex& modelIndex)
+ {
+ return modelIndex.data(RoleIsEnabled).toBool();
+ }
+
+ void GemRepoModel::SetEnabled(QAbstractItemModel& model, const QModelIndex& modelIndex, bool isEnabled)
+ {
+ model.setData(modelIndex, isEnabled, RoleIsEnabled);
+ }
+
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoModel.h b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoModel.h
new file mode 100644
index 0000000000..2f1537d339
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoModel.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#pragma once
+
+#if !defined(Q_MOC_RUN)
+#include
+#include
+#endif
+
+QT_FORWARD_DECLARE_CLASS(QItemSelectionModel)
+
+namespace O3DE::ProjectManager
+{
+ class GemRepoModel
+ : public QStandardItemModel
+ {
+ Q_OBJECT // AUTOMOC
+
+ public:
+ explicit GemRepoModel(QObject* parent = nullptr);
+ QItemSelectionModel* GetSelectionModel() const;
+
+ void AddGemRepo(const GemRepoInfo& gemInfo);
+ void Clear();
+
+ static QString GetName(const QModelIndex& modelIndex);
+ static QString GetCreator(const QModelIndex& modelIndex);
+ static QString GetSummary(const QModelIndex& modelIndex);
+ static QString GetDirectoryLink(const QModelIndex& modelIndex);
+ static QString GetRepoLink(const QModelIndex& modelIndex);
+ static QDateTime GetLastUpdated(const QModelIndex& modelIndex);
+ static QString GetPath(const QModelIndex& modelIndex);
+
+ static bool IsEnabled(const QModelIndex& modelIndex);
+ static void SetEnabled(QAbstractItemModel& model, const QModelIndex& modelIndex, bool isEnabled);
+
+ private:
+ enum UserRole
+ {
+ RoleName = Qt::UserRole,
+ RoleCreator,
+ RoleSummary,
+ RoleIsEnabled,
+ RoleDirectoryLink,
+ RoleRepoLink,
+ RoleLastUpdated,
+ RolePath
+ };
+
+ QItemSelectionModel* m_selectionModel = nullptr;
+ };
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp
new file mode 100644
index 0000000000..82de53a0d0
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace O3DE::ProjectManager
+{
+ GemRepoScreen::GemRepoScreen(QWidget* parent)
+ : ScreenWidget(parent)
+ {
+ m_gemRepoModel = new GemRepoModel(this);
+
+ QVBoxLayout* vLayout = new QVBoxLayout();
+ vLayout->setMargin(0);
+ vLayout->setSpacing(0);
+ setLayout(vLayout);
+
+ QHBoxLayout* hLayout = new QHBoxLayout();
+ hLayout->setMargin(0);
+ hLayout->setSpacing(0);
+ vLayout->addLayout(hLayout);
+
+ hLayout->addSpacing(60);
+
+ m_gemRepoInspector = new QFrame(this);
+ m_gemRepoInspector->setObjectName(tr("gemRepoInspector"));
+ m_gemRepoInspector->setFixedWidth(240);
+
+ QVBoxLayout* middleVLayout = new QVBoxLayout();
+ middleVLayout->setMargin(0);
+ middleVLayout->setSpacing(0);
+
+ middleVLayout->addSpacing(30);
+
+ QHBoxLayout* topMiddleHLayout = new QHBoxLayout();
+ topMiddleHLayout->setMargin(0);
+ topMiddleHLayout->setSpacing(0);
+
+ m_lastAllUpdateLabel = new QLabel(tr("Last Updated: Never"), this);
+ m_lastAllUpdateLabel->setObjectName("gemRepoHeaderLabel");
+ topMiddleHLayout->addWidget(m_lastAllUpdateLabel);
+
+ topMiddleHLayout->addSpacing(20);
+
+ m_AllUpdateButton = new QPushButton(QIcon(":/Refresh.svg"), tr("Update All"), this);
+ m_AllUpdateButton->setObjectName("gemRepoHeaderRefreshButton");
+ topMiddleHLayout->addWidget(m_AllUpdateButton);
+
+ topMiddleHLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum));
+
+ m_AddRepoButton = new QPushButton(tr("Add Repository"), this);
+ m_AddRepoButton->setObjectName("gemRepoHeaderAddButton");
+ topMiddleHLayout->addWidget(m_AddRepoButton);
+
+ middleVLayout->addLayout(topMiddleHLayout);
+
+ middleVLayout->addSpacing(30);
+
+ // Create a QTableWidget just for its header
+ // Using a seperate model allows the setup of a header exactly as needed
+ m_gemRepoHeaderTable = new QTableWidget(this);
+ m_gemRepoHeaderTable->setObjectName("gemRepoHeaderTable");
+ m_gemRepoListHeader = m_gemRepoHeaderTable->horizontalHeader();
+ m_gemRepoListHeader->setObjectName("gemRepoListHeader");
+ m_gemRepoListHeader->setSectionResizeMode(QHeaderView::ResizeMode::Fixed);
+
+ // Insert columns so the header labels will show up
+ m_gemRepoHeaderTable->insertColumn(0);
+ m_gemRepoHeaderTable->insertColumn(1);
+ m_gemRepoHeaderTable->insertColumn(2);
+ m_gemRepoHeaderTable->insertColumn(3);
+ m_gemRepoHeaderTable->setHorizontalHeaderLabels({ tr("Enabled"), tr("Repository Name"), tr("Creator"), tr("Updated") });
+
+ const int headerExtraMargin = 10;
+ m_gemRepoListHeader->resizeSection(0, GemRepoItemDelegate::s_buttonWidth + GemRepoItemDelegate::s_buttonSpacing - 3);
+ m_gemRepoListHeader->resizeSection(1, GemRepoItemDelegate::s_nameMaxWidth + GemRepoItemDelegate::s_contentSpacing - headerExtraMargin);
+ m_gemRepoListHeader->resizeSection(2, GemRepoItemDelegate::s_creatorMaxWidth + GemRepoItemDelegate::s_contentSpacing - headerExtraMargin);
+ m_gemRepoListHeader->resizeSection(3, GemRepoItemDelegate::s_updatedMaxWidth + GemRepoItemDelegate::s_contentSpacing - headerExtraMargin);
+
+ // Required to set stylesheet in code as it will not be respected if set in qss
+ m_gemRepoHeaderTable->horizontalHeader()->setStyleSheet("QHeaderView::section { background-color:transparent; color:white; font-size:12px; text-align:left; border-style:none; }");
+ middleVLayout->addWidget(m_gemRepoHeaderTable);
+
+ m_gemRepoListView = new GemRepoListView(m_gemRepoModel, this);
+ middleVLayout->addWidget(m_gemRepoListView);
+
+ hLayout->addLayout(middleVLayout);
+ hLayout->addWidget(m_gemRepoInspector);
+
+ Reinit();
+ }
+
+ void GemRepoScreen::Reinit()
+ {
+ m_gemRepoModel->clear();
+ FillModel();
+
+ // Select the first entry after everything got correctly sized
+ QTimer::singleShot(200, [=]{
+ QModelIndex firstModelIndex = m_gemRepoListView->model()->index(0,0);
+ m_gemRepoListView->selectionModel()->select(firstModelIndex, QItemSelectionModel::ClearAndSelect);
+ });
+ }
+
+ void GemRepoScreen::FillModel()
+ {
+ AZ::Outcome, AZStd::string> allGemRepoInfosResult = PythonBindingsInterface::Get()->GetAllGemRepoInfos();
+ if (allGemRepoInfosResult.IsSuccess())
+ {
+ // Add all available repos to the model
+ const QVector allGemRepoInfos = allGemRepoInfosResult.GetValue();
+ for (const GemRepoInfo& gemRepoInfo : allGemRepoInfos)
+ {
+ m_gemRepoModel->AddGemRepo(gemRepoInfo);
+ }
+ }
+ else
+ {
+ QMessageBox::critical(this, tr("Operation failed"), QString("Cannot retrieve gem repos for engine.\n\nError:\n%2").arg(allGemRepoInfosResult.GetError().c_str()));
+ }
+ }
+
+ ProjectManagerScreen GemRepoScreen::GetScreenEnum()
+ {
+ return ProjectManagerScreen::GemRepos;
+ }
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h
new file mode 100644
index 0000000000..b5316db84f
--- /dev/null
+++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#pragma once
+
+#if !defined(Q_MOC_RUN)
+#include
+#endif
+
+QT_FORWARD_DECLARE_CLASS(QLabel)
+QT_FORWARD_DECLARE_CLASS(QPushButton)
+QT_FORWARD_DECLARE_CLASS(QHeaderView)
+QT_FORWARD_DECLARE_CLASS(QTableWidget)
+
+namespace O3DE::ProjectManager
+{
+ QT_FORWARD_DECLARE_CLASS(GemRepoListView)
+ QT_FORWARD_DECLARE_CLASS(GemRepoModel)
+
+ class GemRepoScreen
+ : public ScreenWidget
+ {
+ public:
+ explicit GemRepoScreen(QWidget* parent = nullptr);
+ ~GemRepoScreen() = default;
+ ProjectManagerScreen GetScreenEnum() override;
+
+ void Reinit();
+
+ GemRepoModel* GetGemRepoModel() const { return m_gemRepoModel; }
+
+ private:
+ void FillModel();
+
+ QTableWidget* m_gemRepoHeaderTable = nullptr;
+ QHeaderView* m_gemRepoListHeader = nullptr;
+ GemRepoListView* m_gemRepoListView = nullptr;
+ QFrame* m_gemRepoInspector = nullptr;
+ GemRepoModel* m_gemRepoModel = nullptr;
+
+ QLabel* m_lastAllUpdateLabel;
+ QPushButton* m_AllUpdateButton;
+ QPushButton* m_AddRepoButton;
+ };
+} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/ProjectManagerWindow.cpp b/Code/Tools/ProjectManager/Source/ProjectManagerWindow.cpp
index a723ccb917..d2f2d969f1 100644
--- a/Code/Tools/ProjectManager/Source/ProjectManagerWindow.cpp
+++ b/Code/Tools/ProjectManager/Source/ProjectManagerWindow.cpp
@@ -22,7 +22,7 @@ namespace O3DE::ProjectManager
QVector screenEnums =
{
ProjectManagerScreen::Projects,
- ProjectManagerScreen::EngineSettings,
+ ProjectManagerScreen::Engine,
ProjectManagerScreen::CreateProject,
ProjectManagerScreen::UpdateProject
};
diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp
index 18901946f3..6f8ff9abce 100644
--- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp
+++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp
@@ -912,4 +912,45 @@ namespace O3DE::ProjectManager
return AZ::Success(AZStd::move(templates));
}
}
+
+ GemRepoInfo PythonBindings::GemRepoInfoFromPath(pybind11::handle path, pybind11::handle pyEnginePath)
+ {
+ /* Placeholder Logic */
+ (void)path;
+ (void)pyEnginePath;
+
+ return GemRepoInfo();
+ }
+
+//#define MOCK_GEM_REPO_INFO true
+
+ AZ::Outcome, AZStd::string> PythonBindings::GetAllGemRepoInfos()
+ {
+ QVector gemRepos;
+
+#ifndef MOCK_GEM_REPO_INFO
+ auto result = ExecuteWithLockErrorHandling(
+ [&]
+ {
+ /* Placeholder Logic, o3de scripts need method added
+ *
+ for (auto path : m_manifest.attr("get_gem_repos")())
+ {
+ gemRepos.push_back(GemRepoInfoFromPath(path, pybind11::none()));
+ }
+ *
+ */
+ });
+ if (!result.IsSuccess())
+ {
+ return AZ::Failure(result.GetError().c_str());
+ }
+#else
+ gemRepos.push_back(GemRepoInfo("JohnCreates", "John Smith", "", QDateTime(QDate(2021, 8, 31), QTime(11, 57)), true));
+ gemRepos.push_back(GemRepoInfo("JanesGems", "Jane Doe", "", QDateTime(QDate(2021, 9, 10), QTime(18, 23)), false));
+#endif // MOCK_GEM_REPO_INFO
+
+ std::sort(gemRepos.begin(), gemRepos.end());
+ return AZ::Success(AZStd::move(gemRepos));
+ }
}
diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.h b/Code/Tools/ProjectManager/Source/PythonBindings.h
index 8482ac56e7..3b766c3797 100644
--- a/Code/Tools/ProjectManager/Source/PythonBindings.h
+++ b/Code/Tools/ProjectManager/Source/PythonBindings.h
@@ -56,12 +56,16 @@ namespace O3DE::ProjectManager
// ProjectTemplate
AZ::Outcome> GetProjectTemplates(const QString& projectPath = {}) override;
+ // Gem Repos
+ AZ::Outcome, AZStd::string> GetAllGemRepoInfos() override;
+
private:
AZ_DISABLE_COPY_MOVE(PythonBindings);
AZ::Outcome ExecuteWithLockErrorHandling(AZStd::function executionCallback);
bool ExecuteWithLock(AZStd::function executionCallback);
GemInfo GemInfoFromPath(pybind11::handle path, pybind11::handle pyProjectPath);
+ GemRepoInfo GemRepoInfoFromPath(pybind11::handle path, pybind11::handle pyEnginePath);
ProjectInfo ProjectInfoFromPath(pybind11::handle path);
ProjectTemplateInfo ProjectTemplateInfoFromPath(pybind11::handle path, pybind11::handle pyProjectPath);
bool RegisterThisEngine();
diff --git a/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h b/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h
index ca14a54630..9fd3002f93 100644
--- a/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h
+++ b/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h
@@ -17,6 +17,7 @@
#include
#include
#include
+#include
namespace O3DE::ProjectManager
{
@@ -56,14 +57,14 @@ namespace O3DE::ProjectManager
/**
* Get info about a Gem
- * @param path the absolute path to the Gem
+ * @param projectPath the absolute path to the Gem
* @return an outcome with GemInfo on success
*/
virtual AZ::Outcome GetGemInfo(const QString& path, const QString& projectPath = {}) = 0;
/**
* Get all available gem infos. This concatenates gems registered by the engine and the project.
- * @param path The absolute path to the project.
+ * @param projectPath The absolute path to the project.
* @return A list of gem infos.
*/
virtual AZ::Outcome, AZStd::string> GetAllGemInfos(const QString& projectPath) = 0;
@@ -155,6 +156,14 @@ namespace O3DE::ProjectManager
* @return an outcome with ProjectTemplateInfos on success
*/
virtual AZ::Outcome> GetProjectTemplates(const QString& projectPath = {}) = 0;
+
+ // Gem Repos
+
+ /**
+ * Get all available gem repo infos. Gathers all repos registered with the engine.
+ * @return A list of gem repo infos.
+ */
+ virtual AZ::Outcome, AZStd::string> GetAllGemRepoInfos() = 0;
};
using PythonBindingsInterface = AZ::Interface;
diff --git a/Code/Tools/ProjectManager/Source/ScreenDefs.h b/Code/Tools/ProjectManager/Source/ScreenDefs.h
index 97ebe19751..2ced8c08c9 100644
--- a/Code/Tools/ProjectManager/Source/ScreenDefs.h
+++ b/Code/Tools/ProjectManager/Source/ScreenDefs.h
@@ -23,7 +23,9 @@ namespace O3DE::ProjectManager
Projects,
UpdateProject,
UpdateProjectSettings,
- EngineSettings
+ Engine,
+ EngineSettings,
+ GemRepos
};
static QHash s_ProjectManagerStringNames = {
@@ -34,7 +36,9 @@ namespace O3DE::ProjectManager
{ "Projects", ProjectManagerScreen::Projects},
{ "UpdateProject", ProjectManagerScreen::UpdateProject},
{ "UpdateProjectSettings", ProjectManagerScreen::UpdateProjectSettings},
- { "EngineSettings", ProjectManagerScreen::EngineSettings}
+ { "Engine", ProjectManagerScreen::Engine},
+ { "EngineSettings", ProjectManagerScreen::EngineSettings},
+ { "GemRepos", ProjectManagerScreen::GemRepos}
};
// need to define qHash for ProjectManagerScreen when using scoped enums
diff --git a/Code/Tools/ProjectManager/Source/ScreenFactory.cpp b/Code/Tools/ProjectManager/Source/ScreenFactory.cpp
index f3bddfdd27..44aa713e6a 100644
--- a/Code/Tools/ProjectManager/Source/ScreenFactory.cpp
+++ b/Code/Tools/ProjectManager/Source/ScreenFactory.cpp
@@ -13,7 +13,9 @@
#include
#include
#include
+#include
#include
+#include
namespace O3DE::ProjectManager
{
@@ -41,9 +43,15 @@ namespace O3DE::ProjectManager
case (ProjectManagerScreen::UpdateProjectSettings):
newScreen = new UpdateProjectSettingsScreen(parent);
break;
+ case (ProjectManagerScreen::Engine):
+ newScreen = new EngineScreenCtrl(parent);
+ break;
case (ProjectManagerScreen::EngineSettings):
newScreen = new EngineSettingsScreen(parent);
break;
+ case (ProjectManagerScreen::GemRepos):
+ newScreen = new GemRepoScreen(parent);
+ break;
case (ProjectManagerScreen::Empty):
default:
newScreen = new ScreenWidget(parent);
diff --git a/Code/Tools/ProjectManager/project_manager_files.cmake b/Code/Tools/ProjectManager/project_manager_files.cmake
index 6d0f392e52..7a336972e0 100644
--- a/Code/Tools/ProjectManager/project_manager_files.cmake
+++ b/Code/Tools/ProjectManager/project_manager_files.cmake
@@ -56,6 +56,8 @@ set(FILES
Source/ProjectsScreen.cpp
Source/ProjectSettingsScreen.h
Source/ProjectSettingsScreen.cpp
+ Source/EngineScreenCtrl.h
+ Source/EngineScreenCtrl.cpp
Source/EngineSettingsScreen.h
Source/EngineSettingsScreen.cpp
Source/ProjectButtonWidget.h
@@ -98,4 +100,14 @@ set(FILES
Source/GemCatalog/GemRequirementListView.cpp
Source/GemCatalog/GemSortFilterProxyModel.h
Source/GemCatalog/GemSortFilterProxyModel.cpp
+ Source/GemRepo/GemRepoScreen.h
+ Source/GemRepo/GemRepoScreen.cpp
+ Source/GemRepo/GemRepoInfo.h
+ Source/GemRepo/GemRepoInfo.cpp
+ Source/GemRepo/GemRepoItemDelegate.h
+ Source/GemRepo/GemRepoItemDelegate.cpp
+ Source/GemRepo/GemRepoListView.h
+ Source/GemRepo/GemRepoListView.cpp
+ Source/GemRepo/GemRepoModel.h
+ Source/GemRepo/GemRepoModel.cpp
)