LYN-7448 + LYN-7542 + LYN-7543 | Focus Mode - UX Improvements (#4837)

* Introduce Outliner button to simplify Prefab editing

Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com>

* Fix Focus Mode and disabled entities colors

Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com>

* Fix - propagate the event if the OnOutlinerItemClick function returns false.
This does not change current behavior but makes more sense in the context of future handlers.

Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com>

* Adjust disabled colors to match UX recommendations.

Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com>

* Display the edit button even if the prefab is disabled. Remove prefabWip check (it will be removed for focus mode by the time this goes in). Default to disabled capsule color for borders to save on checks.

Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com>

* Disable edit button on disabled prefabs as it caused conflicts in nested prefabs. May explore that possibility later.

Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com>

* Change disabled text color to be darker, as asked by UX.

Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com>
monroegm-disable-blank-issue-2
Danilo Aimini 4 years ago committed by GitHub
parent 50f66bde69
commit 52112be1ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.38947 2H2.97474C1.61046 2 0.5 3.09717 0.5 4.44876V13.0353C0.5 14.4028 1.61046 15.5 2.97474 15.5H11.5253C12.8895 15.5 14 14.4028 14 13.0353V9.61053C13.5767 9.88652 13.1131 10.1058 12.6199 10.2576V13.0353H12.5881C12.5881 13.6396 12.0964 14.1007 11.5094 14.1007H2.97474C2.37192 14.1007 1.896 13.6237 1.896 13.0353V4.44876C1.896 3.86042 2.38778 3.38339 2.97474 3.38339H5.74142C5.89324 2.88897 6.11287 2.42422 6.38947 2Z" fill="white"/>
<path d="M11 0.5C8.51446 0.5 6.5 2.51471 6.5 5C6.5 7.48529 8.51446 9.5 11 9.5C13.485 9.5 15.5 7.48529 15.5 5C15.5 2.51471 13.485 0.5 11 0.5ZM13.8633 6.39526C13.9155 6.43923 13.8975 6.54774 13.8221 6.63723L13.1024 7.49454C13.0276 7.58429 12.9237 7.62106 12.8715 7.57708L11.0003 6.00697L9.12903 7.57683C9.07683 7.62106 8.97346 7.58403 8.89811 7.49454L8.17837 6.63723C8.10354 6.54749 8.08503 6.43897 8.13723 6.39526L9.80017 4.99974L8.13723 3.60449C8.08503 3.56026 8.10303 3.452 8.17837 3.36251L8.8976 2.5052C8.97294 2.4152 9.07631 2.37869 9.12903 2.42266L11.0003 3.99277L12.8715 2.42266C12.9242 2.37869 13.0276 2.41546 13.1029 2.5052L13.8221 3.36251C13.8975 3.452 13.9155 3.56051 13.8633 3.60449L12.2003 5L13.8633 6.39526Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

@ -0,0 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12.5881 13.0353C12.5881 13.6396 12.0964 14.1007 11.5094 14.1007H2.97474C2.37192 14.1007 1.896 13.6237 1.896 13.0353V4.44876C1.896 3.86042 2.38778 3.38339 2.97474 3.38339H7.33725L8.71739 2H2.97474C1.61046 2 0.5 3.09717 0.5 4.44876V13.0353C0.5 14.4028 1.61046 15.5 2.97474 15.5H11.5253C12.8895 15.5 14 14.4028 14 13.0353V7.26325L12.6199 8.64664V13.0353H12.5881Z" fill="white"/>
<path d="M15.1805 2.87326L13.1392 0.850975C12.9217 0.633705 12.6205 0.5 12.3193 0.5C12.0014 0.5 11.717 0.616992 11.4995 0.834262L3.83621 8.41708C3.63543 8.61764 3.5183 8.88505 3.50157 9.16917L3.50157 11.2632C3.48484 11.5975 3.60196 11.9318 3.83621 12.1657C4.05373 12.383 4.3549 12.5 4.65608 12.5C4.67281 12.5 4.70628 12.5 4.72301 12.5H6.69739C6.98183 12.4833 7.24954 12.3663 7.45033 12.1657L15.1638 4.52786C15.3813 4.31059 15.4984 4.00975 15.4984 3.70891C15.5152 3.39137 15.398 3.09053 15.1805 2.87326ZM10.3784 4.02646L12.0014 5.64763L8.23673 9.39136L6.61373 7.77019L10.3784 4.02646ZM6.69739 10.929L4.97399 11.0292L5.07438 9.3078L5.55961 8.82312L7.18261 10.4443L6.69739 10.929ZM13.0221 4.59471L11.4158 2.99025L12.3193 2.08774L13.9423 3.70891L13.0221 4.59471Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

@ -6,6 +6,8 @@
<file alias="layer.svg">Entity/layer.svg</file> <file alias="layer.svg">Entity/layer.svg</file>
<file alias="prefab.svg">Entity/prefab.svg</file> <file alias="prefab.svg">Entity/prefab.svg</file>
<file alias="prefab_edit.svg">Entity/prefab_edit.svg</file> <file alias="prefab_edit.svg">Entity/prefab_edit.svg</file>
<file alias="prefab_edit_open.svg">Entity/prefab_edit_open.svg</file>
<file alias="prefab_edit_close.svg">Entity/prefab_edit_close.svg</file>
</qresource> </qresource>
<qresource prefix="/Level"> <qresource prefix="/Level">
<file alias="level.svg">Level/level.svg</file> <file alias="level.svg">Level/level.svg</file>

@ -206,6 +206,34 @@ namespace AzToolsFramework::Prefab
return instance.has_value() && (&instance->get() == &m_focusedInstance->get()); return instance.has_value() && (&instance->get() == &m_focusedInstance->get());
} }
bool PrefabFocusHandler::IsOwningPrefabInFocusHierarchy(AZ::EntityId entityId) const
{
if (!m_focusedInstance.has_value())
{
// PrefabFocusHandler has not been initialized yet.
return false;
}
if (!entityId.IsValid())
{
return false;
}
InstanceOptionalReference instance = m_instanceEntityMapperInterface->FindOwningInstance(entityId);
while (instance.has_value())
{
if (&instance->get() == &m_focusedInstance->get())
{
return true;
}
instance = instance->get().GetParentInstance();
}
return false;
}
const AZ::IO::Path& PrefabFocusHandler::GetPrefabFocusPath([[maybe_unused]] AzFramework::EntityContextId entityContextId) const const AZ::IO::Path& PrefabFocusHandler::GetPrefabFocusPath([[maybe_unused]] AzFramework::EntityContextId entityContextId) const
{ {
return m_instanceFocusPath; return m_instanceFocusPath;

@ -53,6 +53,7 @@ namespace AzToolsFramework::Prefab
PrefabFocusOperationResult FocusOnPathIndex(AzFramework::EntityContextId entityContextId, int index) override; PrefabFocusOperationResult FocusOnPathIndex(AzFramework::EntityContextId entityContextId, int index) override;
AZ::EntityId GetFocusedPrefabContainerEntityId(AzFramework::EntityContextId entityContextId) const override; AZ::EntityId GetFocusedPrefabContainerEntityId(AzFramework::EntityContextId entityContextId) const override;
bool IsOwningPrefabBeingFocused(AZ::EntityId entityId) const override; bool IsOwningPrefabBeingFocused(AZ::EntityId entityId) const override;
bool IsOwningPrefabInFocusHierarchy(AZ::EntityId entityId) const override;
const AZ::IO::Path& GetPrefabFocusPath(AzFramework::EntityContextId entityContextId) const override; const AZ::IO::Path& GetPrefabFocusPath(AzFramework::EntityContextId entityContextId) const override;
const int GetPrefabFocusPathLength(AzFramework::EntityContextId entityContextId) const override; const int GetPrefabFocusPathLength(AzFramework::EntityContextId entityContextId) const override;

@ -37,10 +37,15 @@ namespace AzToolsFramework::Prefab
//! Returns the entity id of the container entity for the instance the prefab system is focusing on. //! Returns the entity id of the container entity for the instance the prefab system is focusing on.
virtual AZ::EntityId GetFocusedPrefabContainerEntityId(AzFramework::EntityContextId entityContextId) const = 0; virtual AZ::EntityId GetFocusedPrefabContainerEntityId(AzFramework::EntityContextId entityContextId) const = 0;
//! Returns whether the entity belongs to the instance that is being focused on.
//! @param entityId The entityId of the queried entity.
//! @return true if the entity belongs to the focused instance, false otherwise.
virtual bool IsOwningPrefabBeingFocused(AZ::EntityId entityId) const = 0;
//! Returns whether the entity belongs to the instance that is being focused on, or one of its descendants. //! Returns whether the entity belongs to the instance that is being focused on, or one of its descendants.
//! @param entityId The entityId of the queried entity. //! @param entityId The entityId of the queried entity.
//! @return true if the entity belongs to the focused instance or one of its descendants, false otherwise. //! @return true if the entity belongs to the focused instance or one of its descendants, false otherwise.
virtual bool IsOwningPrefabBeingFocused(AZ::EntityId entityId) const = 0; virtual bool IsOwningPrefabInFocusHierarchy(AZ::EntityId entityId) const = 0;
//! Returns the path from the root instance to the currently focused instance. //! Returns the path from the root instance to the currently focused instance.
//! @return A path composed from the names of the container entities for the instance path. //! @return A path composed from the names of the container entities for the instance path.

@ -101,8 +101,25 @@ namespace AzToolsFramework
{ {
} }
void EditorEntityUiHandlerBase::OnDoubleClick([[maybe_unused]] AZ::EntityId entityId) const bool EditorEntityUiHandlerBase::OnOutlinerItemClick(
[[maybe_unused]] const QPoint& position,
[[maybe_unused]] const QStyleOptionViewItem& option,
[[maybe_unused]] const QModelIndex& index) const
{
return false;
}
void EditorEntityUiHandlerBase::OnOutlinerItemExpand([[maybe_unused]] const QModelIndex& index) const
{
}
void EditorEntityUiHandlerBase::OnOutlinerItemCollapse([[maybe_unused]] const QModelIndex& index) const
{
}
bool EditorEntityUiHandlerBase::OnEntityDoubleClick([[maybe_unused]] AZ::EntityId entityId) const
{ {
return false;
} }
} // namespace AzToolsFramework } // namespace AzToolsFramework

@ -61,8 +61,17 @@ namespace AzToolsFramework
virtual void PaintDescendantForeground(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index, virtual void PaintDescendantForeground(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index,
const QModelIndex& descendantIndex) const; const QModelIndex& descendantIndex) const;
//! Triggered when the entity is double clicked in the Outliner. //! Triggered when the entity is clicked in the Outliner.
virtual void OnDoubleClick(AZ::EntityId entityId) const; //! @return True if the click has been handled and should not be propagated, false otherwise.
virtual bool OnOutlinerItemClick(const QPoint& position, const QStyleOptionViewItem& option, const QModelIndex& index) const;
//! Triggered when an entity's children are expanded in the Outliner.
virtual void OnOutlinerItemExpand(const QModelIndex& index) const;
//! Triggered when an entity's children are collapsed in the Outliner.
virtual void OnOutlinerItemCollapse(const QModelIndex& index) const;
//! Triggered when the entity is double clicked in the Outliner or in the Viewport.
//! @return True if the double click has been handled and should not be propagated, false otherwise.
virtual bool OnEntityDoubleClick(AZ::EntityId entityId) const;
private: private:
EditorEntityUiHandlerId m_handlerId = 0; EditorEntityUiHandlerId m_handlerId = 0;

@ -11,10 +11,12 @@
#include <QApplication> #include <QApplication>
#include <QBitmap> #include <QBitmap>
#include <QCheckBox> #include <QCheckBox>
#include <QEvent>
#include <QFontMetrics> #include <QFontMetrics>
#include <QGuiApplication> #include <QGuiApplication>
#include <QMessageBox> #include <QMessageBox>
#include <QMimeData> #include <QMimeData>
#include <QMouseEvent>
#include <QPainter> #include <QPainter>
#include <QPainterPath> #include <QPainterPath>
#include <QStyle> #include <QStyle>
@ -2287,7 +2289,14 @@ namespace AzToolsFramework
// Now we setup a Text Document so it can draw the rich text // Now we setup a Text Document so it can draw the rich text
QTextDocument textDoc; QTextDocument textDoc;
textDoc.setDefaultFont(optionV4.font); textDoc.setDefaultFont(optionV4.font);
textDoc.setDefaultStyleSheet("body {color: white}"); if (option.state & QStyle::State_Enabled)
{
textDoc.setDefaultStyleSheet("body {color: white}");
}
else
{
textDoc.setDefaultStyleSheet("body {color: #7C7C7C}");
}
textDoc.setHtml("<body>" + entityNameRichText + "</body>"); textDoc.setHtml("<body>" + entityNameRichText + "</body>");
painter->translate(textRect.topLeft()); painter->translate(textRect.topLeft());
textDoc.setTextWidth(textRect.width()); textDoc.setTextWidth(textRect.width());
@ -2326,6 +2335,23 @@ namespace AzToolsFramework
return true; return true;
} }
if (event->type() == QEvent::MouseButtonPress)
{
AZ::EntityId entityId(index.data(EntityOutlinerListModel::EntityIdRole).value<AZ::u64>());
if (auto editorEntityUiInterface = AZ::Interface<EditorEntityUiInterface>::Get(); editorEntityUiInterface != nullptr)
{
auto mouseEvent = static_cast<QMouseEvent*>(event);
auto entityUiHandler = editorEntityUiInterface->GetHandler(entityId);
if (entityUiHandler && entityUiHandler->OnOutlinerItemClick(mouseEvent->pos(), option, index))
{
return true;
}
}
}
return QStyledItemDelegate::editorEvent(event, model, option, index); return QStyledItemDelegate::editorEvent(event, model, option, index);
} }

@ -73,6 +73,8 @@ namespace AzToolsFramework
void EntityOutlinerTreeView::leaveEvent([[maybe_unused]] QEvent* event) void EntityOutlinerTreeView::leaveEvent([[maybe_unused]] QEvent* event)
{ {
m_mousePosition = QPoint(); m_mousePosition = QPoint();
m_currentHoveredIndex = QModelIndex();
update();
} }
void EntityOutlinerTreeView::mousePressEvent(QMouseEvent* event) void EntityOutlinerTreeView::mousePressEvent(QMouseEvent* event)
@ -129,6 +131,11 @@ namespace AzToolsFramework
} }
m_mousePosition = event->pos(); m_mousePosition = event->pos();
if (QModelIndex hoveredIndex = indexAt(m_mousePosition); m_currentHoveredIndex != indexAt(m_mousePosition))
{
m_currentHoveredIndex = hoveredIndex;
update();
}
//process mouse movement as normal, potentially triggering drag and drop //process mouse movement as normal, potentially triggering drag and drop
QTreeView::mouseMoveEvent(event); QTreeView::mouseMoveEvent(event);

@ -90,6 +90,8 @@ namespace AzToolsFramework
const QColor m_selectedColor = QColor(255, 255, 255, 45); const QColor m_selectedColor = QColor(255, 255, 255, 45);
const QColor m_hoverColor = QColor(255, 255, 255, 30); const QColor m_hoverColor = QColor(255, 255, 255, 30);
QModelIndex m_currentHoveredIndex;
EditorEntityUiInterface* m_editorEntityFrameworkInterface; EditorEntityUiInterface* m_editorEntityFrameworkInterface;
}; };

@ -902,6 +902,7 @@ namespace AzToolsFramework
EditorPickModeRequestBus::Broadcast( EditorPickModeRequestBus::Broadcast(
&EditorPickModeRequests::StopEntityPickMode); &EditorPickModeRequests::StopEntityPickMode);
return;
} }
switch (index.column()) switch (index.column())
@ -918,18 +919,30 @@ namespace AzToolsFramework
{ {
if (AZ::EntityId entityId = GetEntityIdFromIndex(index); auto entityUiHandler = m_editorEntityUiInterface->GetHandler(entityId)) if (AZ::EntityId entityId = GetEntityIdFromIndex(index); auto entityUiHandler = m_editorEntityUiInterface->GetHandler(entityId))
{ {
entityUiHandler->OnDoubleClick(entityId); entityUiHandler->OnEntityDoubleClick(entityId);
} }
} }
void EntityOutlinerWidget::OnTreeItemExpanded(const QModelIndex& index) void EntityOutlinerWidget::OnTreeItemExpanded(const QModelIndex& index)
{ {
m_listModel->OnEntityExpanded(GetEntityIdFromIndex(index)); AZ::EntityId entityId = GetEntityIdFromIndex(index);
if (auto entityUiHandler = m_editorEntityUiInterface->GetHandler(entityId))
{
entityUiHandler->OnOutlinerItemExpand(index);
}
m_listModel->OnEntityExpanded(entityId);
} }
void EntityOutlinerWidget::OnTreeItemCollapsed(const QModelIndex& index) void EntityOutlinerWidget::OnTreeItemCollapsed(const QModelIndex& index)
{ {
m_listModel->OnEntityCollapsed(GetEntityIdFromIndex(index)); AZ::EntityId entityId = GetEntityIdFromIndex(index);
if (auto entityUiHandler = m_editorEntityUiInterface->GetHandler(entityId))
{
entityUiHandler->OnOutlinerItemCollapse(index);
}
m_listModel->OnEntityCollapsed(entityId);
} }
void EntityOutlinerWidget::OnExpandEntity(const AZ::EntityId& entityId, bool expand) void EntityOutlinerWidget::OnExpandEntity(const AZ::EntityId& entityId, bool expand)
@ -1163,7 +1176,7 @@ namespace AzToolsFramework
{ {
QTimer::singleShot(1, this, [this]() { QTimer::singleShot(1, this, [this]() {
m_gui->m_objectTree->setUpdatesEnabled(true); m_gui->m_objectTree->setUpdatesEnabled(true);
m_gui->m_objectTree->expandToDepth(0); m_gui->m_objectTree->expand(m_proxyModel->index(0,0));
}); });
} }

@ -21,10 +21,16 @@
namespace AzToolsFramework namespace AzToolsFramework
{ {
const QColor PrefabUiHandler::m_backgroundColor = QColor("#444444");
const QColor PrefabUiHandler::m_backgroundHoverColor = QColor("#5A5A5A");
const QColor PrefabUiHandler::m_backgroundSelectedColor = QColor("#656565");
const QColor PrefabUiHandler::m_prefabCapsuleColor = QColor("#1E252F"); const QColor PrefabUiHandler::m_prefabCapsuleColor = QColor("#1E252F");
const QColor PrefabUiHandler::m_prefabCapsuleDisabledColor = QColor("#35383C");
const QColor PrefabUiHandler::m_prefabCapsuleEditColor = QColor("#4A90E2"); const QColor PrefabUiHandler::m_prefabCapsuleEditColor = QColor("#4A90E2");
const QString PrefabUiHandler::m_prefabIconPath = QString(":/Entity/prefab.svg"); const QString PrefabUiHandler::m_prefabIconPath = QString(":/Entity/prefab.svg");
const QString PrefabUiHandler::m_prefabEditIconPath = QString(":/Entity/prefab_edit.svg"); const QString PrefabUiHandler::m_prefabEditIconPath = QString(":/Entity/prefab_edit.svg");
const QString PrefabUiHandler::m_prefabEditOpenIconPath = QString(":/Entity/prefab_edit_open.svg");
const QString PrefabUiHandler::m_prefabEditCloseIconPath = QString(":/Entity/prefab_edit_close.svg");
PrefabUiHandler::PrefabUiHandler() PrefabUiHandler::PrefabUiHandler()
{ {
@ -75,7 +81,7 @@ namespace AzToolsFramework
if (!path.empty()) if (!path.empty())
{ {
tooltip = QObject::tr("%1").arg(path.Native().data()); tooltip = QObject::tr("Double click to edit.\n%1").arg(path.Native().data());
} }
return tooltip; return tooltip;
@ -102,13 +108,20 @@ namespace AzToolsFramework
AZ::EntityId entityId(index.data(EntityOutlinerListModel::EntityIdRole).value<AZ::u64>()); AZ::EntityId entityId(index.data(EntityOutlinerListModel::EntityIdRole).value<AZ::u64>());
const bool isFirstColumn = index.column() == EntityOutlinerListModel::ColumnName; const bool isFirstColumn = index.column() == EntityOutlinerListModel::ColumnName;
const bool isLastColumn = index.column() == EntityOutlinerListModel::ColumnLockToggle; const bool isLastColumn = index.column() == EntityOutlinerListModel::ColumnLockToggle;
const bool hasVisibleChildren = index.data(EntityOutlinerListModel::ExpandedRole).value<bool>() && index.model()->hasChildren(index); QModelIndex firstColumnIndex = index.siblingAtColumn(EntityOutlinerListModel::ColumnName);
const bool hasVisibleChildren =
firstColumnIndex.data(EntityOutlinerListModel::ExpandedRole).value<bool>() &&
firstColumnIndex.model()->hasChildren(firstColumnIndex);
QColor backgroundColor = m_prefabCapsuleColor; QColor backgroundColor = m_prefabCapsuleColor;
if (m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(entityId)) if (m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(entityId))
{ {
backgroundColor = m_prefabCapsuleEditColor; backgroundColor = m_prefabCapsuleEditColor;
} }
else if (!(option.state & QStyle::State_Enabled))
{
backgroundColor = m_prefabCapsuleDisabledColor;
}
QPainterPath backgroundPath; QPainterPath backgroundPath;
backgroundPath.setFillRule(Qt::WindingFill); backgroundPath.setFillRule(Qt::WindingFill);
@ -184,7 +197,8 @@ namespace AzToolsFramework
const bool isFirstColumn = descendantIndex.column() == EntityOutlinerListModel::ColumnName; const bool isFirstColumn = descendantIndex.column() == EntityOutlinerListModel::ColumnName;
const bool isLastColumn = descendantIndex.column() == EntityOutlinerListModel::ColumnLockToggle; const bool isLastColumn = descendantIndex.column() == EntityOutlinerListModel::ColumnLockToggle;
QColor borderColor = m_prefabCapsuleColor; // There is no legal way of opening prefabs in their default state, so default to disabled.
QColor borderColor = m_prefabCapsuleDisabledColor;
if (m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(entityId)) if (m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(entityId))
{ {
borderColor = m_prefabCapsuleEditColor; borderColor = m_prefabCapsuleEditColor;
@ -273,6 +287,71 @@ namespace AzToolsFramework
painter->restore(); painter->restore();
} }
void PrefabUiHandler::PaintItemForeground(QPainter* painter, const QStyleOptionViewItem& option, [[maybe_unused]] const QModelIndex& index) const
{
AZ::EntityId entityId(index.data(EntityOutlinerListModel::EntityIdRole).value<AZ::u64>());
const QPoint offset = QPoint(-18, 3);
QModelIndex firstColumnIndex = index.siblingAtColumn(EntityOutlinerListModel::ColumnName);
const int iconSize = 16;
const bool isHovered = (option.state & QStyle::State_MouseOver);
const bool isSelected = index.data(EntityOutlinerListModel::SelectedRole).template value<bool>();
const bool isFirstColumn = index.column() == EntityOutlinerListModel::ColumnName;
const bool isExpanded =
firstColumnIndex.data(EntityOutlinerListModel::ExpandedRole).value<bool>() &&
firstColumnIndex.model()->hasChildren(firstColumnIndex);
if (!isFirstColumn || !(option.state & QStyle::State_Enabled))
{
return;
}
painter->save();
painter->setRenderHint(QPainter::Antialiasing, true);
if (m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(entityId))
{
// Only show the close icon if the prefab is expanded.
// This allows the prefab container to be opened if it was collapsed during propagation.
if (!isExpanded)
{
return;
}
// Use the same color as the background.
QColor backgroundColor = m_backgroundColor;
if (isSelected)
{
backgroundColor = m_backgroundSelectedColor;
}
else if (isHovered)
{
backgroundColor = m_backgroundHoverColor;
}
// Paint a rect to cover up the expander.
QRect rect = QRect(0, 0, 16, 16);
rect.translate(option.rect.topLeft() + offset);
painter->fillRect(rect, backgroundColor);
// Paint the icon.
QIcon closeIcon = QIcon(m_prefabEditCloseIconPath);
painter->drawPixmap(option.rect.topLeft() + offset, closeIcon.pixmap(iconSize));
}
else
{
// Only show the edit icon on hover.
if (!isHovered)
{
return;
}
QIcon openIcon = QIcon(m_prefabEditOpenIconPath);
painter->drawPixmap(option.rect.topLeft() + offset, openIcon.pixmap(iconSize));
}
painter->restore();
}
bool PrefabUiHandler::IsLastVisibleChild(const QModelIndex& parent, const QModelIndex& child) bool PrefabUiHandler::IsLastVisibleChild(const QModelIndex& parent, const QModelIndex& child)
{ {
QModelIndex lastVisibleItemIndex = GetLastVisibleChild(parent); QModelIndex lastVisibleItemIndex = GetLastVisibleChild(parent);
@ -314,9 +393,53 @@ namespace AzToolsFramework
return Internal_GetLastVisibleChild(model, lastChild); return Internal_GetLastVisibleChild(model, lastChild);
} }
void PrefabUiHandler::OnDoubleClick(AZ::EntityId entityId) const bool PrefabUiHandler::OnOutlinerItemClick(const QPoint& position, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
AZ::EntityId entityId(index.data(EntityOutlinerListModel::EntityIdRole).value<AZ::u64>());
const QPoint offset = QPoint(-18, 3);
if (m_prefabFocusPublicInterface->IsOwningPrefabInFocusHierarchy(entityId))
{
QRect iconRect = QRect(0, 0, 16, 16);
iconRect.translate(option.rect.topLeft() + offset);
if (iconRect.contains(position))
{
if (!m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(entityId))
{
// Focus on this prefab.
m_prefabFocusPublicInterface->FocusOnOwningPrefab(entityId);
}
// Don't propagate event.
return true;
}
}
return false;
}
void PrefabUiHandler::OnOutlinerItemCollapse(const QModelIndex& index) const
{
AZ::EntityId entityId(index.data(EntityOutlinerListModel::EntityIdRole).value<AZ::u64>());
if (m_prefabFocusPublicInterface->IsOwningPrefabBeingFocused(entityId))
{
auto editorEntityContextId = AzFramework::EntityContextId::CreateNull();
EditorEntityContextRequestBus::BroadcastResult(editorEntityContextId, &EditorEntityContextRequests::GetEditorEntityContextId);
// Go one level up.
int length = m_prefabFocusPublicInterface->GetPrefabFocusPathLength(editorEntityContextId);
m_prefabFocusPublicInterface->FocusOnPathIndex(editorEntityContextId, length - 2);
}
}
bool PrefabUiHandler::OnEntityDoubleClick(AZ::EntityId entityId) const
{ {
// Focus on this prefab // Focus on this prefab
m_prefabFocusPublicInterface->FocusOnOwningPrefab(entityId); m_prefabFocusPublicInterface->FocusOnOwningPrefab(entityId);
// Don't propagate event.
return true;
} }
} }

@ -36,7 +36,10 @@ namespace AzToolsFramework
void PaintItemBackground(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override; void PaintItemBackground(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
void PaintDescendantBackground(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index, void PaintDescendantBackground(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index,
const QModelIndex& descendantIndex) const override; const QModelIndex& descendantIndex) const override;
void OnDoubleClick(AZ::EntityId entityId) const override; void PaintItemForeground(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
bool OnOutlinerItemClick(const QPoint& position, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
void OnOutlinerItemCollapse(const QModelIndex& index) const override;
bool OnEntityDoubleClick(AZ::EntityId entityId) const override;
private: private:
Prefab::PrefabFocusPublicInterface* m_prefabFocusPublicInterface = nullptr; Prefab::PrefabFocusPublicInterface* m_prefabFocusPublicInterface = nullptr;
@ -48,9 +51,15 @@ namespace AzToolsFramework
static constexpr int m_prefabCapsuleRadius = 6; static constexpr int m_prefabCapsuleRadius = 6;
static constexpr int m_prefabBorderThickness = 2; static constexpr int m_prefabBorderThickness = 2;
static const QColor m_backgroundColor;
static const QColor m_backgroundHoverColor;
static const QColor m_backgroundSelectedColor;
static const QColor m_prefabCapsuleColor; static const QColor m_prefabCapsuleColor;
static const QColor m_prefabCapsuleDisabledColor;
static const QColor m_prefabCapsuleEditColor; static const QColor m_prefabCapsuleEditColor;
static const QString m_prefabIconPath; static const QString m_prefabIconPath;
static const QString m_prefabEditIconPath; static const QString m_prefabEditIconPath;
static const QString m_prefabEditOpenIconPath;
static const QString m_prefabEditCloseIconPath;
}; };
} // namespace AzToolsFramework } // namespace AzToolsFramework

@ -20,7 +20,7 @@ namespace AzToolsFramework::ViewportUi::Internal
{ {
const static int HighlightBorderSize = 5; const static int HighlightBorderSize = 5;
const static int TopHighlightBorderSize = 25; const static int TopHighlightBorderSize = 25;
const static char* HighlightBorderColor = "#44B2F8"; const static char* HighlightBorderColor = "#4A90E2";
static void UnparentWidgets(ViewportUiElementIdInfoLookup& viewportUiElementIdInfoLookup) static void UnparentWidgets(ViewportUiElementIdInfoLookup& viewportUiElementIdInfoLookup)
{ {

Loading…
Cancel
Save