Dependency confirmation screen and URL display fix
Signed-off-by: AMZN-alexpete <26804013+AMZN-alexpete@users.noreply.github.com>
This commit is contained in:
@@ -238,9 +238,13 @@ namespace O3DE::ProjectManager
|
||||
PythonBindingsInterface::Get()->AddProject(projectInfo.m_path);
|
||||
|
||||
#ifdef TEMPLATE_GEM_CONFIGURATION_ENABLED
|
||||
if (!m_gemCatalogScreen->EnableDisableGemsForProject(projectInfo.m_path))
|
||||
const GemCatalogScreen::EnableDisableGemsResult gemResult = m_gemCatalogScreen->EnableDisableGemsForProject(m_projectInfo.m_path);
|
||||
if (gemResult == GemCatalogScreen::EnableDisableGemsResult::Failed)
|
||||
{
|
||||
QMessageBox::critical(this, tr("Failed to configure gems"), tr("Failed to configure gems for template."));
|
||||
}
|
||||
if (gemResult != GemCatalogScreen::EnableDisableGemsResult::Success)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif // TEMPLATE_GEM_CONFIGURATION_ENABLED
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <GemCatalog/GemListHeaderWidget.h>
|
||||
#include <GemCatalog/GemSortFilterProxyModel.h>
|
||||
#include <GemCatalog/GemRequirementDialog.h>
|
||||
#include <GemCatalog/GemDependenciesDialog.h>
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QPushButton>
|
||||
@@ -134,7 +135,7 @@ namespace O3DE::ProjectManager
|
||||
}
|
||||
}
|
||||
|
||||
bool GemCatalogScreen::EnableDisableGemsForProject(const QString& projectPath)
|
||||
GemCatalogScreen::EnableDisableGemsResult GemCatalogScreen::EnableDisableGemsForProject(const QString& projectPath)
|
||||
{
|
||||
IPythonBindings* pythonBindings = PythonBindingsInterface::Get();
|
||||
QVector<QModelIndex> toBeAdded = m_gemModel->GatherGemsToBeAdded();
|
||||
@@ -142,15 +143,25 @@ namespace O3DE::ProjectManager
|
||||
|
||||
if (m_gemModel->DoGemsToBeAddedHaveRequirements())
|
||||
{
|
||||
GemRequirementDialog* confirmRequirementsDialog = new GemRequirementDialog(m_gemModel, toBeAdded, this);
|
||||
confirmRequirementsDialog->exec();
|
||||
|
||||
if (confirmRequirementsDialog->GetButtonResult() != QDialogButtonBox::ApplyRole)
|
||||
GemRequirementDialog* confirmRequirementsDialog = new GemRequirementDialog(m_gemModel, this);
|
||||
if(confirmRequirementsDialog->exec() == QDialog::Rejected)
|
||||
{
|
||||
return false;
|
||||
return EnableDisableGemsResult::Cancel;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_gemModel->HasDependentGemsToRemove())
|
||||
{
|
||||
GemDependenciesDialog* dependenciesDialog = new GemDependenciesDialog(m_gemModel, this);
|
||||
if(dependenciesDialog->exec() == QDialog::Rejected)
|
||||
{
|
||||
return EnableDisableGemsResult::Cancel;
|
||||
}
|
||||
|
||||
toBeAdded = m_gemModel->GatherGemsToBeAdded();
|
||||
toBeRemoved = m_gemModel->GatherGemsToBeRemoved();
|
||||
}
|
||||
|
||||
for (const QModelIndex& modelIndex : toBeAdded)
|
||||
{
|
||||
const QString gemPath = GemModel::GetPath(modelIndex);
|
||||
@@ -160,7 +171,7 @@ namespace O3DE::ProjectManager
|
||||
QMessageBox::critical(nullptr, "Operation failed",
|
||||
QString("Cannot add gem %1 to project.\n\nError:\n%2").arg(GemModel::GetDisplayName(modelIndex), result.GetError().c_str()));
|
||||
|
||||
return false;
|
||||
return EnableDisableGemsResult::Failed;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,11 +184,11 @@ namespace O3DE::ProjectManager
|
||||
QMessageBox::critical(nullptr, "Operation failed",
|
||||
QString("Cannot remove gem %1 from project.\n\nError:\n%2").arg(GemModel::GetDisplayName(modelIndex), result.GetError().c_str()));
|
||||
|
||||
return false;
|
||||
return EnableDisableGemsResult::Failed;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return EnableDisableGemsResult::Success;
|
||||
}
|
||||
|
||||
ProjectManagerScreen GemCatalogScreen::GetScreenEnum()
|
||||
|
||||
@@ -29,7 +29,14 @@ namespace O3DE::ProjectManager
|
||||
ProjectManagerScreen GetScreenEnum() override;
|
||||
|
||||
void ReinitForProject(const QString& projectPath);
|
||||
bool EnableDisableGemsForProject(const QString& projectPath);
|
||||
|
||||
enum class EnableDisableGemsResult
|
||||
{
|
||||
Failed = 0,
|
||||
Success,
|
||||
Cancel
|
||||
};
|
||||
EnableDisableGemsResult EnableDisableGemsForProject(const QString& projectPath);
|
||||
|
||||
GemModel* GetGemModel() const { return m_gemModel; }
|
||||
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <GemCatalog/GemDependenciesDialog.h>
|
||||
#include <GemCatalog/GemModel.h>
|
||||
#include <AzQtComponents/Components/FlowLayout.h>
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QCheckBox>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
GemDependenciesDialog::GemDependenciesDialog(GemModel* gemModel, QWidget *parent)
|
||||
: QDialog(parent)
|
||||
{
|
||||
setWindowTitle(tr("Dependent Gems"));
|
||||
setObjectName("GemDependenciesDialog");
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
setModal(true);
|
||||
|
||||
QVBoxLayout* layout = new QVBoxLayout();
|
||||
// layout margin/alignment cannot be set with qss
|
||||
layout->setMargin(15);
|
||||
layout->setAlignment(Qt::AlignTop);
|
||||
setLayout(layout);
|
||||
|
||||
// message
|
||||
QLabel* instructionLabel = new QLabel(
|
||||
tr("The following gem dependencies are no longer needed and will be deactivated.<br><br>"
|
||||
"To keep these Gems enabled, select the checkbox next to it."));
|
||||
layout->addWidget(instructionLabel);
|
||||
|
||||
// checkboxes
|
||||
FlowLayout* flowLayout = new FlowLayout();
|
||||
QVector<QModelIndex> gemsToRemove = gemModel->GatherGemsToBeRemoved(/*includeDependencies=*/true);
|
||||
for (const QModelIndex& gem : gemsToRemove)
|
||||
{
|
||||
if (GemModel::WasPreviouslyAddedDependency(gem))
|
||||
{
|
||||
QCheckBox* checkBox = new QCheckBox(GemModel::GetName(gem));
|
||||
connect(checkBox, &QCheckBox::stateChanged, this,
|
||||
[=](int state)
|
||||
{
|
||||
GemModel::SetIsAdded(*gemModel, gem, /*isAdded=*/state == Qt::Checked);
|
||||
});
|
||||
flowLayout->addWidget(checkBox);
|
||||
}
|
||||
}
|
||||
layout->addLayout(flowLayout);
|
||||
|
||||
layout->addSpacing(10);
|
||||
layout->addStretch(1);
|
||||
|
||||
// buttons
|
||||
QDialogButtonBox* dialogButtons = new QDialogButtonBox(QDialogButtonBox::Cancel | QDialogButtonBox::Ok);
|
||||
connect(dialogButtons, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||
connect(dialogButtons, &QDialogButtonBox::rejected, this,
|
||||
[=]()
|
||||
{
|
||||
// de-select any Gems the user selected because they're canceling
|
||||
for (const QModelIndex& gem : gemsToRemove)
|
||||
{
|
||||
if (GemModel::WasPreviouslyAddedDependency(gem) && GemModel::IsAdded(gem))
|
||||
{
|
||||
GemModel::SetIsAdded(*gemModel, gem, /*isAdded=*/false);
|
||||
}
|
||||
}
|
||||
|
||||
reject();
|
||||
});
|
||||
layout->addWidget(dialogButtons);
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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 <QDialog>
|
||||
#endif
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
QT_FORWARD_DECLARE_CLASS(GemModel)
|
||||
|
||||
class GemDependenciesDialog
|
||||
: public QDialog
|
||||
{
|
||||
Q_OBJECT // AUTOMOC
|
||||
public:
|
||||
explicit GemDependenciesDialog(GemModel* gemModel, QWidget *parent = nullptr);
|
||||
~GemDependenciesDialog() = default;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <GemCatalog/GemItemDelegate.h>
|
||||
#include <GemCatalog/GemModel.h>
|
||||
#include <GemCatalog/GemSortFilterProxyModel.h>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
#include <QEvent>
|
||||
#include <QAbstractItemView>
|
||||
#include <QPainter>
|
||||
@@ -16,6 +17,9 @@
|
||||
#include <QHelpEvent>
|
||||
#include <QToolTip>
|
||||
#include <QHoverEvent>
|
||||
#include <QTextDocument>
|
||||
#include <QAbstractTextDocumentLayout>
|
||||
#include <QDesktopServices>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
@@ -104,22 +108,11 @@ namespace O3DE::ProjectManager
|
||||
painter->drawText(gemCreatorRect, Qt::TextSingleLine, gemCreator);
|
||||
|
||||
// Gem summary
|
||||
|
||||
// In case there are feature tags displayed at the bottom, decrease the size of the summary text field.
|
||||
const QStringList featureTags = GemModel::GetFeatures(modelIndex);
|
||||
const int featureTagAreaHeight = 30;
|
||||
const int summaryHeight = contentRect.height() - (!featureTags.empty() * featureTagAreaHeight);
|
||||
|
||||
const int additionalSummarySpacing = s_itemMargins.right() * 3;
|
||||
const QSize summarySize = QSize(contentRect.width() - s_summaryStartX - s_buttonWidth - additionalSummarySpacing,
|
||||
summaryHeight);
|
||||
const QRect summaryRect = QRect(/*topLeft=*/QPoint(contentRect.left() + s_summaryStartX, contentRect.top()), summarySize);
|
||||
|
||||
painter->setFont(standardFont);
|
||||
painter->setPen(m_textColor);
|
||||
|
||||
const bool hasTags = !featureTags.isEmpty();
|
||||
const QString summary = GemModel::GetSummary(modelIndex);
|
||||
painter->drawText(summaryRect, Qt::AlignLeft | Qt::TextWordWrap, summary);
|
||||
const QRect summaryRect = CalcSummaryRect(contentRect, hasTags);
|
||||
DrawText(summary, painter, summaryRect, standardFont);
|
||||
|
||||
DrawButton(painter, contentRect, modelIndex);
|
||||
DrawPlatformIcons(painter, contentRect, modelIndex);
|
||||
@@ -128,6 +121,17 @@ namespace O3DE::ProjectManager
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
QRect GemItemDelegate::CalcSummaryRect(const QRect& contentRect, bool hasTags) const
|
||||
{
|
||||
const int featureTagAreaHeight = 30;
|
||||
const int summaryHeight = contentRect.height() - (hasTags * featureTagAreaHeight);
|
||||
|
||||
const int additionalSummarySpacing = s_itemMargins.right() * 3;
|
||||
const QSize summarySize = QSize(contentRect.width() - s_summaryStartX - s_buttonWidth - additionalSummarySpacing,
|
||||
summaryHeight);
|
||||
return QRect(QPoint(contentRect.left() + s_summaryStartX, contentRect.top()), summarySize);
|
||||
}
|
||||
|
||||
QSize GemItemDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& modelIndex) const
|
||||
{
|
||||
QStyleOptionViewItem options(option);
|
||||
@@ -154,7 +158,7 @@ namespace O3DE::ProjectManager
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (event->type() == QEvent::MouseButtonPress )
|
||||
else if (event->type() == QEvent::MouseButtonPress)
|
||||
{
|
||||
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
|
||||
|
||||
@@ -168,6 +172,21 @@ namespace O3DE::ProjectManager
|
||||
GemModel::SetIsAdded(*model, modelIndex, !isAdded);
|
||||
return true;
|
||||
}
|
||||
|
||||
// we must manually handle html links because we aren't using QLabels
|
||||
const QStringList featureTags = GemModel::GetFeatures(modelIndex);
|
||||
const bool hasTags = !featureTags.isEmpty();
|
||||
const QRect summaryRect = CalcSummaryRect(contentRect, hasTags);
|
||||
if (summaryRect.contains(mouseEvent->pos()))
|
||||
{
|
||||
const QString html = GemModel::GetSummary(modelIndex);
|
||||
QString anchor = anchorAt(html, mouseEvent->pos(), summaryRect);
|
||||
if (!anchor.isEmpty())
|
||||
{
|
||||
QDesktopServices::openUrl(QUrl(anchor));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return QStyledItemDelegate::editorEvent(event, model, option, modelIndex);
|
||||
@@ -321,6 +340,44 @@ namespace O3DE::ProjectManager
|
||||
}
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<QTextDocument> GetTextDocument(const QString& text, int width)
|
||||
{
|
||||
// using unique_ptr as a workaround for QTextDocument having a private copy constructor
|
||||
auto doc = AZStd::make_unique<QTextDocument>();
|
||||
QTextOption textOption(doc->defaultTextOption());
|
||||
textOption.setWrapMode(QTextOption::WordWrap);
|
||||
doc->setDefaultTextOption(textOption);
|
||||
doc->setHtml(text);
|
||||
doc->setTextWidth(width);
|
||||
return doc;
|
||||
}
|
||||
|
||||
void GemItemDelegate::DrawText(const QString& text, QPainter* painter, const QRect& rect, const QFont& standardFont) const
|
||||
{
|
||||
painter->save();
|
||||
|
||||
if (text.contains('<'))
|
||||
{
|
||||
painter->translate(rect.topLeft());
|
||||
|
||||
// use QTextDocument because drawText does not support rich text or html
|
||||
QAbstractTextDocumentLayout::PaintContext paintContext;
|
||||
paintContext.clip = QRect(0, 0, rect.width(), rect.height());
|
||||
paintContext.palette.setColor(QPalette::Text, painter->pen().color());
|
||||
|
||||
AZStd::unique_ptr<QTextDocument> textDocument = GetTextDocument(text, rect.width());
|
||||
textDocument->documentLayout()->draw(painter, paintContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
painter->setFont(standardFont);
|
||||
painter->setPen(m_textColor);
|
||||
painter->drawText(rect, Qt::AlignLeft | Qt::TextWordWrap, text);
|
||||
}
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
void GemItemDelegate::DrawButton(QPainter* painter, const QRect& contentRect, const QModelIndex& modelIndex) const
|
||||
{
|
||||
painter->save();
|
||||
@@ -355,4 +412,19 @@ namespace O3DE::ProjectManager
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
QString GemItemDelegate::anchorAt(const QString& html, const QPoint& position, const QRect& rect)
|
||||
{
|
||||
if (!html.isEmpty())
|
||||
{
|
||||
AZStd::unique_ptr<QTextDocument> doc = GetTextDocument(html, rect.width());
|
||||
QAbstractTextDocumentLayout* layout = doc->documentLayout();
|
||||
if (layout)
|
||||
{
|
||||
return layout->anchorAt(position - rect.topLeft());
|
||||
}
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -30,6 +30,7 @@ namespace O3DE::ProjectManager
|
||||
|
||||
void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& modelIndex) const override;
|
||||
QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& modelIndex) const override;
|
||||
virtual QString anchorAt(const QString& html, const QPoint& position, const QRect& rect);
|
||||
|
||||
// Colors
|
||||
const QColor m_textColor = QColor("#FFFFFF");
|
||||
@@ -71,9 +72,11 @@ namespace O3DE::ProjectManager
|
||||
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;
|
||||
QRect CalcSummaryRect(const QRect& contentRect, bool hasTags) const;
|
||||
void DrawPlatformIcons(QPainter* painter, const QRect& contentRect, const QModelIndex& modelIndex) const;
|
||||
void DrawButton(QPainter* painter, const QRect& contentRect, const QModelIndex& modelIndex) const;
|
||||
void DrawFeatureTags(QPainter* painter, const QRect& contentRect, const QStringList& featureTags, const QFont& standardFont, const QRect& summaryRect) const;
|
||||
void DrawText(const QString& text, QPainter* painter, const QRect& rect, const QFont& standardFont) const;
|
||||
|
||||
QAbstractItemModel* m_model = nullptr;
|
||||
|
||||
|
||||
@@ -8,27 +8,9 @@
|
||||
|
||||
#include <GemCatalog/GemListView.h>
|
||||
#include <GemCatalog/GemItemDelegate.h>
|
||||
#include <QStandardItemModel>
|
||||
#include <QProxyStyle>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
class GemListViewProxyStyle : public QProxyStyle
|
||||
{
|
||||
public:
|
||||
using QProxyStyle::QProxyStyle;
|
||||
int styleHint(StyleHint hint, const QStyleOption* option = nullptr, const QWidget* widget = nullptr, QStyleHintReturn* returnData = nullptr) const override
|
||||
{
|
||||
if (hint == QStyle::SH_ToolTip_WakeUpDelay || hint == QStyle::SH_ToolTip_FallAsleepDelay)
|
||||
{
|
||||
// no delay
|
||||
return 0;
|
||||
}
|
||||
|
||||
return QProxyStyle::styleHint(hint, option, widget, returnData);
|
||||
}
|
||||
};
|
||||
|
||||
GemListView::GemListView(QAbstractItemModel* model, QItemSelectionModel* selectionModel, QWidget* parent)
|
||||
: QListView(parent)
|
||||
{
|
||||
@@ -38,8 +20,5 @@ namespace O3DE::ProjectManager
|
||||
setModel(model);
|
||||
setSelectionModel(selectionModel);
|
||||
setItemDelegate(new GemItemDelegate(model, this));
|
||||
|
||||
// use a custom proxy style so we get immediate tooltips for gem radio buttons
|
||||
setStyle(new GemListViewProxyStyle(this->style()));
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -391,6 +391,20 @@ namespace O3DE::ProjectManager
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GemModel::HasDependentGemsToRemove() const
|
||||
{
|
||||
for (int row = 0; row < rowCount(); ++row)
|
||||
{
|
||||
const QModelIndex modelIndex = index(row, 0);
|
||||
if (GemModel::NeedsToBeRemoved(modelIndex, /*includeDependencies=*/true) &&
|
||||
GemModel::WasPreviouslyAddedDependency(modelIndex))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QVector<QModelIndex> GemModel::GatherGemDependencies(const QModelIndex& modelIndex) const
|
||||
{
|
||||
QVector<QModelIndex> result;
|
||||
|
||||
@@ -66,6 +66,7 @@ namespace O3DE::ProjectManager
|
||||
static void UpdateDependencies(QAbstractItemModel& model, const QModelIndex& modelIndex);
|
||||
|
||||
bool DoGemsToBeAddedHaveRequirements() const;
|
||||
bool HasDependentGemsToRemove() const;
|
||||
|
||||
QVector<QModelIndex> GatherGemDependencies(const QModelIndex& modelIndex) const;
|
||||
QVector<QModelIndex> GatherDependentGems(const QModelIndex& modelIndex, bool addedOnly = false) const;
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include <GemCatalog/GemModel.h>
|
||||
|
||||
#include <QPainter>
|
||||
#include <QMouseEvent>
|
||||
#include <QDesktopServices>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
@@ -38,7 +40,6 @@ namespace O3DE::ProjectManager
|
||||
standardFont.setPixelSize(static_cast<int>(s_fontSize));
|
||||
QFontMetrics standardFontMetrics(standardFont);
|
||||
|
||||
painter->save();
|
||||
painter->setClipping(true);
|
||||
painter->setClipRect(fullRect);
|
||||
painter->setFont(options.font);
|
||||
@@ -65,25 +66,51 @@ namespace O3DE::ProjectManager
|
||||
painter->drawText(gemNameRect, Qt::TextSingleLine, gemName);
|
||||
|
||||
// Gem requirement
|
||||
const QSize requirementSize = QSize(contentRect.width() - s_summaryStartX - s_itemMargins.right(), contentRect.height());
|
||||
const QRect requirementRect = QRect(QPoint(contentRect.left() + s_summaryStartX, contentRect.top()), requirementSize);
|
||||
|
||||
painter->setFont(standardFont);
|
||||
painter->setPen(m_textColor);
|
||||
|
||||
const QRect requirementRect = CalcRequirementRect(contentRect);
|
||||
const QString requirement = GemModel::GetRequirement(modelIndex);
|
||||
painter->drawText(requirementRect, Qt::AlignLeft | Qt::TextWordWrap, requirement);
|
||||
DrawText(requirement, painter, requirementRect, standardFont);
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
QRect GemRequirementDelegate::CalcRequirementRect(const QRect& contentRect) const
|
||||
{
|
||||
const QSize requirementSize = QSize(contentRect.width() - s_summaryStartX - s_itemMargins.right(), contentRect.height());
|
||||
return QRect(QPoint(contentRect.left() + s_summaryStartX, contentRect.top()), requirementSize);
|
||||
}
|
||||
|
||||
bool GemRequirementDelegate::editorEvent(
|
||||
[[maybe_unused]] QEvent* event,
|
||||
[[maybe_unused]] QAbstractItemModel* model,
|
||||
[[maybe_unused]] const QStyleOptionViewItem& option,
|
||||
[[maybe_unused]] const QModelIndex& modelIndex)
|
||||
{
|
||||
// Do nothing here
|
||||
return false;
|
||||
if (!modelIndex.isValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (event->type() == QEvent::MouseButtonPress)
|
||||
{
|
||||
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
|
||||
|
||||
QRect fullRect, itemRect, contentRect;
|
||||
CalcRects(option, fullRect, itemRect, contentRect);
|
||||
|
||||
const QRect requirementsRect = CalcRequirementRect(contentRect);
|
||||
if (requirementsRect.contains(mouseEvent->pos()))
|
||||
{
|
||||
const QString html = GemModel::GetRequirement(modelIndex);
|
||||
QString anchor = anchorAt(html, mouseEvent->pos(), requirementsRect);
|
||||
if (!anchor.isEmpty())
|
||||
{
|
||||
QDesktopServices::openUrl(QUrl(anchor));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return QStyledItemDelegate::editorEvent(event, model, option, modelIndex);
|
||||
}
|
||||
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -29,5 +29,8 @@ namespace O3DE::ProjectManager
|
||||
|
||||
const QColor m_backgroundColor = QColor("#444444"); // Outside of the actual gem item
|
||||
const QColor m_itemBackgroundColor = QColor("#393939"); // Background color of the gem item
|
||||
|
||||
private:
|
||||
QRect CalcRequirementRect(const QRect& contentRect) const;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -19,11 +19,12 @@
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
GemRequirementDialog::GemRequirementDialog(GemModel* model, const QVector<QModelIndex>& gemsToAdd, QWidget* parent)
|
||||
GemRequirementDialog::GemRequirementDialog(GemModel* model, QWidget* parent)
|
||||
: QDialog(parent)
|
||||
{
|
||||
setWindowTitle(tr("Manual setup is required"));
|
||||
setModal(true);
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
QVBoxLayout* vLayout = new QVBoxLayout();
|
||||
vLayout->setMargin(0);
|
||||
@@ -51,7 +52,7 @@ namespace O3DE::ProjectManager
|
||||
|
||||
vLayout->addSpacing(20);
|
||||
|
||||
GemRequirementFilterProxyModel* proxModel = new GemRequirementFilterProxyModel(model, gemsToAdd, this);
|
||||
GemRequirementFilterProxyModel* proxModel = new GemRequirementFilterProxyModel(model, this);
|
||||
|
||||
GemRequirementListView* m_gemListView = new GemRequirementListView(proxModel, proxModel->GetSelectionModel(), this);
|
||||
vLayout->addWidget(m_gemListView);
|
||||
@@ -62,27 +63,9 @@ namespace O3DE::ProjectManager
|
||||
|
||||
QPushButton* cancelButton = dialogButtons->addButton(tr("Cancel"), QDialogButtonBox::RejectRole);
|
||||
cancelButton->setProperty("secondary", true);
|
||||
QPushButton* continueButton = dialogButtons->addButton(tr("Continue"), QDialogButtonBox::ApplyRole);
|
||||
QPushButton* continueButton = dialogButtons->addButton(tr("Continue"), QDialogButtonBox::AcceptRole);
|
||||
|
||||
connect(cancelButton, &QPushButton::clicked, this, &GemRequirementDialog::CancelButtonPressed);
|
||||
connect(continueButton, &QPushButton::clicked, this, &GemRequirementDialog::ContinueButtonPressed);
|
||||
connect(cancelButton, &QPushButton::clicked, this, &QDialog::reject);
|
||||
connect(continueButton, &QPushButton::clicked, this, &QDialog::accept);
|
||||
}
|
||||
|
||||
QDialogButtonBox::ButtonRole GemRequirementDialog::GetButtonResult()
|
||||
{
|
||||
return m_buttonResult;
|
||||
}
|
||||
|
||||
void GemRequirementDialog::CancelButtonPressed()
|
||||
{
|
||||
m_buttonResult = QDialogButtonBox::RejectRole;
|
||||
close();
|
||||
}
|
||||
|
||||
void GemRequirementDialog::ContinueButtonPressed()
|
||||
{
|
||||
m_buttonResult = QDialogButtonBox::ApplyRole;
|
||||
close();
|
||||
}
|
||||
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <QDialog>
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#endif
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
@@ -23,15 +21,7 @@ namespace O3DE::ProjectManager
|
||||
{
|
||||
Q_OBJECT // AUTOMOC
|
||||
public:
|
||||
explicit GemRequirementDialog(GemModel* model, const QVector<QModelIndex>& gemsToAdd, QWidget *parent = nullptr);
|
||||
explicit GemRequirementDialog(GemModel* model, QWidget *parent = nullptr);
|
||||
~GemRequirementDialog() = default;
|
||||
|
||||
QDialogButtonBox::ButtonRole GetButtonResult();
|
||||
|
||||
private:
|
||||
void CancelButtonPressed();
|
||||
void ContinueButtonPressed();
|
||||
|
||||
QDialogButtonBox::ButtonRole m_buttonResult = QDialogButtonBox::RejectRole;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -13,10 +13,8 @@
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
GemRequirementFilterProxyModel::GemRequirementFilterProxyModel(GemModel* sourceModel, const QVector<QModelIndex>& addedGems, QObject* parent)
|
||||
GemRequirementFilterProxyModel::GemRequirementFilterProxyModel(GemModel* sourceModel, QObject* parent)
|
||||
: QSortFilterProxyModel(parent)
|
||||
, m_sourceModel(sourceModel)
|
||||
, m_addedGems(addedGems)
|
||||
{
|
||||
setSourceModel(sourceModel);
|
||||
m_selectionProxyModel = new AzQtComponents::SelectionProxyModel(sourceModel->GetSelectionModel(), this, parent);
|
||||
@@ -26,22 +24,7 @@ namespace O3DE::ProjectManager
|
||||
{
|
||||
// Do not use sourceParent->child because an invalid parent does not produce valid children (which our index function does)
|
||||
QModelIndex sourceIndex = sourceModel()->index(sourceRow, 0, sourceParent);
|
||||
if (!sourceIndex.isValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_addedGems.contains(sourceIndex))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_sourceModel->HasRequirement(sourceIndex))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return GemModel::IsAdded(sourceIndex) && GemModel::HasRequirement(sourceIndex);
|
||||
}
|
||||
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -25,16 +25,13 @@ namespace O3DE::ProjectManager
|
||||
Q_OBJECT // AUTOMOC
|
||||
|
||||
public:
|
||||
GemRequirementFilterProxyModel(GemModel* sourceModel, const QVector<QModelIndex>& addedGems, QObject* parent = nullptr);
|
||||
GemRequirementFilterProxyModel(GemModel* sourceModel, QObject* parent = nullptr);
|
||||
|
||||
AzQtComponents::SelectionProxyModel* GetSelectionModel() const { return m_selectionProxyModel; }
|
||||
|
||||
bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const override;
|
||||
|
||||
private:
|
||||
GemModel* m_sourceModel = nullptr;
|
||||
AzQtComponents::SelectionProxyModel* m_selectionProxyModel = nullptr;
|
||||
|
||||
QVector<QModelIndex> m_addedGems;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#include <GemCatalog/GemRequirementListView.h>
|
||||
#include <GemCatalog/GemRequirementDelegate.h>
|
||||
#include <QStandardItemModel>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
|
||||
@@ -8,87 +8,44 @@
|
||||
|
||||
#include <TagWidget.h>
|
||||
#include <QVBoxLayout>
|
||||
#include <AzQtComponents/Components/FlowLayout.h>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
TagWidget::TagWidget(const QString& text, QWidget* parent)
|
||||
: QLabel(text, parent)
|
||||
{
|
||||
setFixedHeight(24);
|
||||
setMargin(5);
|
||||
setStyleSheet("font-size: 12px; background-color: #333333; border-radius: 3px;");
|
||||
setObjectName("TagWidget");
|
||||
}
|
||||
|
||||
TagContainerWidget::TagContainerWidget(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
m_layout = new QVBoxLayout();
|
||||
m_layout->setAlignment(Qt::AlignTop);
|
||||
m_layout->setMargin(0);
|
||||
setLayout(m_layout);
|
||||
setObjectName("TagWidgetContainer");
|
||||
setLayout(new FlowLayout(this));
|
||||
|
||||
// layout margins cannot be set via qss
|
||||
constexpr int verticalMargin = 10;
|
||||
constexpr int horizontalMargin = 0;
|
||||
layout()->setContentsMargins(horizontalMargin, verticalMargin, horizontalMargin, verticalMargin);
|
||||
|
||||
setAttribute(Qt::WA_StyledBackground, true);
|
||||
}
|
||||
|
||||
void TagContainerWidget::Update(const QStringList& tags)
|
||||
{
|
||||
QWidget* parentWidget = qobject_cast<QWidget*>(parent());
|
||||
int width = 200;
|
||||
if (parentWidget)
|
||||
FlowLayout* flowLayout = static_cast<FlowLayout*>(layout());
|
||||
|
||||
// remove old tags
|
||||
QLayoutItem* layoutItem = nullptr;
|
||||
while ((layoutItem = layout()->takeAt(0)) != nullptr)
|
||||
{
|
||||
width = parentWidget->width();
|
||||
layoutItem->widget()->deleteLater();
|
||||
}
|
||||
|
||||
if (m_widget)
|
||||
foreach (const QString& tag, tags)
|
||||
{
|
||||
// Hide the old widget and request deletion.
|
||||
m_widget->hide();
|
||||
m_widget->deleteLater();
|
||||
}
|
||||
|
||||
QVBoxLayout* vLayout = new QVBoxLayout();
|
||||
m_widget = new QWidget(this);
|
||||
m_widget->setLayout(vLayout);
|
||||
m_layout->addWidget(m_widget);
|
||||
|
||||
vLayout->setAlignment(Qt::AlignTop);
|
||||
vLayout->setMargin(0);
|
||||
|
||||
QHBoxLayout* hLayout = nullptr;
|
||||
int usedSpaceInRow = 0;
|
||||
const int numTags = tags.count();
|
||||
|
||||
for (int i = 0; i < numTags; ++i)
|
||||
{
|
||||
// Create the new tag widget.
|
||||
TagWidget* tagWidget = new TagWidget(tags[i]);
|
||||
const int tagWidgetWidth = tagWidget->minimumSizeHint().width();
|
||||
|
||||
// Calculate the width we're currently using in the current row. Does the new tag still fit in the current row?
|
||||
const bool isRowFull = width - usedSpaceInRow - tagWidgetWidth < 0;
|
||||
if (isRowFull || i == 0)
|
||||
{
|
||||
// Add a spacer widget after the last tag widget in a row to push the tag widgets to the left.
|
||||
if (i > 0)
|
||||
{
|
||||
QWidget* spacerWidget = new QWidget();
|
||||
spacerWidget->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);
|
||||
hLayout->addWidget(spacerWidget);
|
||||
}
|
||||
|
||||
// Add a new row for the current tag widget.
|
||||
hLayout = new QHBoxLayout();
|
||||
hLayout->setAlignment(Qt::AlignLeft);
|
||||
hLayout->setMargin(0);
|
||||
vLayout->addLayout(hLayout);
|
||||
|
||||
// Reset the used space in the row.
|
||||
usedSpaceInRow = 0;
|
||||
}
|
||||
|
||||
// Calculate the width of the tag widgets including the spacing between them of the current row.
|
||||
usedSpaceInRow += tagWidgetWidth + hLayout->spacing();
|
||||
|
||||
// Add the tag widget to the current row.
|
||||
hLayout->addWidget(tagWidget);
|
||||
flowLayout->addWidget(new TagWidget(tag));
|
||||
}
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
#include <QWidget>
|
||||
#endif
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QVBoxLayout)
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
// Single tag
|
||||
@@ -40,9 +38,5 @@ namespace O3DE::ProjectManager
|
||||
~TagContainerWidget() = default;
|
||||
|
||||
void Update(const QStringList& tags);
|
||||
|
||||
private:
|
||||
QVBoxLayout* m_layout = nullptr;
|
||||
QWidget* m_widget = nullptr;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -137,9 +137,13 @@ namespace O3DE::ProjectManager
|
||||
else if (m_stack->currentIndex() == ScreenOrder::Gems && m_gemCatalogScreen)
|
||||
{
|
||||
// Enable or disable the gems that got adjusted in the gem catalog and apply them to the given project.
|
||||
if (!m_gemCatalogScreen->EnableDisableGemsForProject(m_projectInfo.m_path))
|
||||
const GemCatalogScreen::EnableDisableGemsResult result = m_gemCatalogScreen->EnableDisableGemsForProject(m_projectInfo.m_path);
|
||||
if (result == GemCatalogScreen::EnableDisableGemsResult::Failed)
|
||||
{
|
||||
QMessageBox::critical(this, tr("Failed to configure gems"), tr("Failed to configure gems for project."));
|
||||
}
|
||||
if (result != GemCatalogScreen::EnableDisableGemsResult::Success)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user