225 lines
7.6 KiB
C++
225 lines
7.6 KiB
C++
#include "ProductInspectorPanel.h"
|
|
|
|
#include <XCEditor/Foundation/UIEditorTheme.h>
|
|
|
|
#include <algorithm>
|
|
|
|
namespace XCEngine::UI::Editor::App {
|
|
|
|
namespace {
|
|
|
|
using ::XCEngine::UI::UIColor;
|
|
using ::XCEngine::UI::UIDrawList;
|
|
using ::XCEngine::UI::UIPoint;
|
|
using ::XCEngine::UI::UIRect;
|
|
|
|
constexpr std::string_view kInspectorPanelId = "inspector";
|
|
constexpr float kPanelPadding = 10.0f;
|
|
constexpr float kHeaderHeight = 22.0f;
|
|
constexpr float kSectionGap = 10.0f;
|
|
constexpr float kRowHeight = 21.0f;
|
|
constexpr float kLabelWidth = 88.0f;
|
|
constexpr float kTitleFontSize = 13.0f;
|
|
constexpr float kSubtitleFontSize = 11.0f;
|
|
constexpr float kSectionTitleFontSize = 11.0f;
|
|
constexpr float kRowFontSize = 11.0f;
|
|
|
|
constexpr UIColor kSurfaceColor(0.205f, 0.205f, 0.205f, 1.0f);
|
|
constexpr UIColor kSectionHeaderColor(0.225f, 0.225f, 0.225f, 1.0f);
|
|
constexpr UIColor kSectionBodyColor(0.215f, 0.215f, 0.215f, 1.0f);
|
|
constexpr UIColor kTitleColor(0.910f, 0.910f, 0.910f, 1.0f);
|
|
constexpr UIColor kSubtitleColor(0.650f, 0.650f, 0.650f, 1.0f);
|
|
constexpr UIColor kLabelColor(0.700f, 0.700f, 0.700f, 1.0f);
|
|
constexpr UIColor kValueColor(0.860f, 0.860f, 0.860f, 1.0f);
|
|
|
|
float ResolveTextTop(float rectY, float rectHeight, float fontSize) {
|
|
const float lineHeight = fontSize * 1.6f;
|
|
return rectY + std::floor((rectHeight - lineHeight) * 0.5f);
|
|
}
|
|
|
|
std::string PathToUtf8String(const std::filesystem::path& path) {
|
|
const std::u8string value = path.u8string();
|
|
return std::string(value.begin(), value.end());
|
|
}
|
|
|
|
} // namespace
|
|
|
|
const UIEditorPanelContentHostPanelState* ProductInspectorPanel::FindMountedInspectorPanel(
|
|
const UIEditorPanelContentHostFrame& contentHostFrame) const {
|
|
for (const UIEditorPanelContentHostPanelState& panelState : contentHostFrame.panelStates) {
|
|
if (panelState.panelId == kInspectorPanelId && panelState.mounted) {
|
|
return &panelState;
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void ProductInspectorPanel::BuildPresentation(const ProductEditorSession& session) {
|
|
m_sections.clear();
|
|
m_title.clear();
|
|
m_subtitle.clear();
|
|
m_hasSelection = false;
|
|
|
|
switch (session.selection.kind) {
|
|
case ProductEditorSelectionKind::HierarchyNode: {
|
|
m_hasSelection = true;
|
|
m_title = session.selection.displayName.empty()
|
|
? std::string("GameObject")
|
|
: session.selection.displayName;
|
|
m_subtitle = "GameObject";
|
|
|
|
Section identity = {};
|
|
identity.title = "Identity";
|
|
identity.rows = {
|
|
{ "Type", "GameObject" },
|
|
{ "Name", m_title },
|
|
{ "Id", session.selection.itemId }
|
|
};
|
|
m_sections.push_back(std::move(identity));
|
|
break;
|
|
}
|
|
|
|
case ProductEditorSelectionKind::ProjectItem: {
|
|
m_hasSelection = true;
|
|
m_title = session.selection.displayName.empty()
|
|
? (session.selection.directory ? std::string("Folder") : std::string("Asset"))
|
|
: session.selection.displayName;
|
|
m_subtitle = session.selection.directory ? "Folder" : "Asset";
|
|
|
|
Section identity = {};
|
|
identity.title = "Identity";
|
|
identity.rows = {
|
|
{ "Type", session.selection.directory ? std::string("Folder") : std::string("Asset") },
|
|
{ "Name", m_title },
|
|
{ "Id", session.selection.itemId }
|
|
};
|
|
m_sections.push_back(std::move(identity));
|
|
|
|
Section location = {};
|
|
location.title = "Location";
|
|
location.rows = {
|
|
{ "Path", PathToUtf8String(session.selection.absolutePath) }
|
|
};
|
|
m_sections.push_back(std::move(location));
|
|
break;
|
|
}
|
|
|
|
case ProductEditorSelectionKind::None:
|
|
default:
|
|
m_title = "Nothing selected";
|
|
m_subtitle = "Select a hierarchy item or project asset.";
|
|
break;
|
|
}
|
|
}
|
|
|
|
void ProductInspectorPanel::Update(
|
|
const ProductEditorSession& session,
|
|
const UIEditorPanelContentHostFrame& contentHostFrame) {
|
|
const UIEditorPanelContentHostPanelState* panelState =
|
|
FindMountedInspectorPanel(contentHostFrame);
|
|
if (panelState == nullptr) {
|
|
m_visible = false;
|
|
m_bounds = {};
|
|
m_sections.clear();
|
|
m_title.clear();
|
|
m_subtitle.clear();
|
|
m_hasSelection = false;
|
|
return;
|
|
}
|
|
|
|
m_visible = true;
|
|
m_bounds = panelState->bounds;
|
|
BuildPresentation(session);
|
|
}
|
|
|
|
void ProductInspectorPanel::Append(UIDrawList& drawList) const {
|
|
if (!m_visible || m_bounds.width <= 0.0f || m_bounds.height <= 0.0f) {
|
|
return;
|
|
}
|
|
|
|
const UIColor borderColor = ResolveUIEditorDockHostPalette().splitterColor;
|
|
drawList.AddFilledRect(m_bounds, kSurfaceColor);
|
|
|
|
const float contentX = m_bounds.x + kPanelPadding;
|
|
const float contentWidth = (std::max)(m_bounds.width - kPanelPadding * 2.0f, 0.0f);
|
|
float nextY = m_bounds.y + kPanelPadding;
|
|
|
|
const UIRect titleRect(contentX, nextY, contentWidth, 18.0f);
|
|
drawList.AddText(
|
|
UIPoint(titleRect.x, ResolveTextTop(titleRect.y, titleRect.height, kTitleFontSize)),
|
|
m_title,
|
|
kTitleColor,
|
|
kTitleFontSize);
|
|
nextY += titleRect.height;
|
|
|
|
const UIRect subtitleRect(contentX, nextY, contentWidth, 16.0f);
|
|
drawList.AddText(
|
|
UIPoint(subtitleRect.x, ResolveTextTop(subtitleRect.y, subtitleRect.height, kSubtitleFontSize)),
|
|
m_subtitle,
|
|
kSubtitleColor,
|
|
kSubtitleFontSize);
|
|
nextY += subtitleRect.height + kSectionGap;
|
|
|
|
if (!m_hasSelection) {
|
|
return;
|
|
}
|
|
|
|
for (const Section& section : m_sections) {
|
|
const float bodyHeight = static_cast<float>(section.rows.size()) * kRowHeight;
|
|
const UIRect headerRect(contentX, nextY, contentWidth, kHeaderHeight);
|
|
const UIRect bodyRect(contentX, headerRect.y + headerRect.height, contentWidth, bodyHeight);
|
|
|
|
drawList.AddFilledRect(headerRect, kSectionHeaderColor);
|
|
drawList.AddFilledRect(bodyRect, kSectionBodyColor);
|
|
drawList.AddRectOutline(
|
|
UIRect(headerRect.x, headerRect.y, headerRect.width, headerRect.height + bodyRect.height),
|
|
borderColor,
|
|
1.0f,
|
|
0.0f);
|
|
drawList.AddText(
|
|
UIPoint(headerRect.x + 8.0f, ResolveTextTop(headerRect.y, headerRect.height, kSectionTitleFontSize)),
|
|
section.title,
|
|
kTitleColor,
|
|
kSectionTitleFontSize);
|
|
|
|
float rowY = bodyRect.y;
|
|
for (std::size_t rowIndex = 0u; rowIndex < section.rows.size(); ++rowIndex) {
|
|
const SectionRow& row = section.rows[rowIndex];
|
|
const UIRect rowRect(contentX, rowY, contentWidth, kRowHeight);
|
|
const UIRect labelRect(rowRect.x + 8.0f, rowRect.y, kLabelWidth, rowRect.height);
|
|
const UIRect valueRect(
|
|
labelRect.x + labelRect.width + 8.0f,
|
|
rowRect.y,
|
|
(std::max)(rowRect.width - (labelRect.width + 24.0f), 0.0f),
|
|
rowRect.height);
|
|
|
|
if (rowIndex > 0u) {
|
|
drawList.AddFilledRect(
|
|
UIRect(rowRect.x, rowRect.y, rowRect.width, 1.0f),
|
|
borderColor);
|
|
}
|
|
|
|
drawList.AddText(
|
|
UIPoint(labelRect.x, ResolveTextTop(labelRect.y, labelRect.height, kRowFontSize)),
|
|
row.label,
|
|
kLabelColor,
|
|
kRowFontSize);
|
|
|
|
drawList.PushClipRect(valueRect);
|
|
drawList.AddText(
|
|
UIPoint(valueRect.x, ResolveTextTop(valueRect.y, valueRect.height, kRowFontSize)),
|
|
row.value,
|
|
kValueColor,
|
|
kRowFontSize);
|
|
drawList.PopClipRect();
|
|
|
|
rowY += kRowHeight;
|
|
}
|
|
|
|
nextY = bodyRect.y + bodyRect.height + kSectionGap;
|
|
}
|
|
}
|
|
|
|
} // namespace XCEngine::UI::Editor::App
|