ui: add typed editor field foundations
This commit is contained in:
@@ -3,6 +3,7 @@ add_executable(editor_ui_property_grid_basic_validation WIN32
|
||||
)
|
||||
|
||||
target_include_directories(editor_ui_property_grid_basic_validation PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/tests/UI/Editor/integration/shared/src
|
||||
${CMAKE_SOURCE_DIR}/new_editor/include
|
||||
${CMAKE_SOURCE_DIR}/new_editor/app
|
||||
${CMAKE_SOURCE_DIR}/engine/include
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
#endif
|
||||
|
||||
#include <XCEditor/Core/UIEditorPropertyGridInteraction.h>
|
||||
#include <XCEditor/Core/UIEditorTheme.h>
|
||||
#include <XCEditor/Widgets/UIEditorPropertyGrid.h>
|
||||
#include "EditorValidationTheme.h"
|
||||
#include "Host/AutoScreenshot.h"
|
||||
#include "Host/NativeRenderer.h"
|
||||
|
||||
@@ -48,24 +50,17 @@ using XCEngine::UI::Editor::UpdateUIEditorPropertyGridInteraction;
|
||||
using XCEngine::UI::Editor::Widgets::AppendUIEditorPropertyGridBackground;
|
||||
using XCEngine::UI::Editor::Widgets::AppendUIEditorPropertyGridForeground;
|
||||
using XCEngine::UI::Editor::Widgets::HitTestUIEditorPropertyGrid;
|
||||
using XCEngine::UI::Editor::Widgets::ResolveUIEditorPropertyGridFieldValueText;
|
||||
using XCEngine::UI::Editor::Widgets::UIEditorPropertyGridField;
|
||||
using XCEngine::UI::Editor::Widgets::UIEditorPropertyGridFieldKind;
|
||||
using XCEngine::UI::Editor::Widgets::UIEditorPropertyGridHitTarget;
|
||||
using XCEngine::UI::Editor::Widgets::UIEditorPropertyGridHitTargetKind;
|
||||
using XCEngine::UI::Editor::Widgets::UIEditorPropertyGridSection;
|
||||
namespace Style = XCEngine::UI::Style;
|
||||
|
||||
constexpr const wchar_t* kWindowClassName = L"XCUIEditorPropertyGridBasicValidation";
|
||||
constexpr const wchar_t* kWindowTitle = L"XCUI Editor | PropertyGrid Basic";
|
||||
|
||||
constexpr UIColor kWindowBg(0.13f, 0.13f, 0.13f, 1.0f);
|
||||
constexpr UIColor kCardBg(0.18f, 0.18f, 0.18f, 1.0f);
|
||||
constexpr UIColor kCardBorder(0.29f, 0.29f, 0.29f, 1.0f);
|
||||
constexpr UIColor kTextPrimary(0.94f, 0.94f, 0.94f, 1.0f);
|
||||
constexpr UIColor kTextMuted(0.72f, 0.72f, 0.72f, 1.0f);
|
||||
constexpr UIColor kTextWeak(0.56f, 0.56f, 0.56f, 1.0f);
|
||||
constexpr UIColor kTextSuccess(0.63f, 0.76f, 0.63f, 1.0f);
|
||||
constexpr UIColor kButtonBg(0.25f, 0.25f, 0.25f, 1.0f);
|
||||
constexpr UIColor kButtonHoverBg(0.32f, 0.32f, 0.32f, 1.0f);
|
||||
|
||||
enum class ActionId : unsigned char {
|
||||
Reset = 0,
|
||||
Capture
|
||||
@@ -95,6 +90,11 @@ std::filesystem::path ResolveRepoRootPath() {
|
||||
return std::filesystem::path(root).lexically_normal();
|
||||
}
|
||||
|
||||
std::filesystem::path ResolveValidationThemePath() {
|
||||
return (ResolveRepoRootPath() / "tests/UI/Editor/integration/shared/themes/editor_validation.xctheme")
|
||||
.lexically_normal();
|
||||
}
|
||||
|
||||
bool ContainsPoint(const UIRect& rect, float x, float y) {
|
||||
return x >= rect.x &&
|
||||
x <= rect.x + rect.width &&
|
||||
@@ -129,10 +129,13 @@ std::int32_t MapEditorKey(UINT keyCode) {
|
||||
}
|
||||
}
|
||||
|
||||
ScenarioLayout BuildScenarioLayout(float width, float height) {
|
||||
constexpr float margin = 20.0f;
|
||||
ScenarioLayout BuildScenarioLayout(
|
||||
float width,
|
||||
float height,
|
||||
const XCEngine::Tests::EditorUI::EditorValidationShellMetrics& shellMetrics) {
|
||||
const float margin = shellMetrics.margin;
|
||||
constexpr float leftWidth = 430.0f;
|
||||
constexpr float gap = 16.0f;
|
||||
const float gap = shellMetrics.gap;
|
||||
|
||||
ScenarioLayout layout = {};
|
||||
layout.introRect = UIRect(margin, margin, leftWidth, 214.0f);
|
||||
@@ -166,48 +169,109 @@ ScenarioLayout BuildScenarioLayout(float width, float height) {
|
||||
void DrawCard(
|
||||
UIDrawList& drawList,
|
||||
const UIRect& rect,
|
||||
const XCEngine::Tests::EditorUI::EditorValidationShellPalette& shellPalette,
|
||||
const XCEngine::Tests::EditorUI::EditorValidationShellMetrics& shellMetrics,
|
||||
std::string_view title,
|
||||
std::string_view subtitle = {}) {
|
||||
drawList.AddFilledRect(rect, kCardBg, 10.0f);
|
||||
drawList.AddRectOutline(rect, kCardBorder, 1.0f, 10.0f);
|
||||
drawList.AddText(UIPoint(rect.x + 16.0f, rect.y + 14.0f), std::string(title), kTextPrimary, 17.0f);
|
||||
drawList.AddFilledRect(rect, shellPalette.cardBackground, shellMetrics.cardRadius);
|
||||
drawList.AddRectOutline(rect, shellPalette.cardBorder, 1.0f, shellMetrics.cardRadius);
|
||||
drawList.AddText(
|
||||
UIPoint(rect.x + 16.0f, rect.y + 14.0f),
|
||||
std::string(title),
|
||||
shellPalette.textPrimary,
|
||||
shellMetrics.titleFontSize);
|
||||
if (!subtitle.empty()) {
|
||||
drawList.AddText(UIPoint(rect.x + 16.0f, rect.y + 40.0f), std::string(subtitle), kTextMuted, 12.0f);
|
||||
drawList.AddText(
|
||||
UIPoint(rect.x + 16.0f, rect.y + 40.0f),
|
||||
std::string(subtitle),
|
||||
shellPalette.textMuted,
|
||||
shellMetrics.bodyFontSize);
|
||||
}
|
||||
}
|
||||
|
||||
void DrawButton(
|
||||
UIDrawList& drawList,
|
||||
const ButtonLayout& button,
|
||||
const XCEngine::Tests::EditorUI::EditorValidationShellPalette& shellPalette,
|
||||
const XCEngine::Tests::EditorUI::EditorValidationShellMetrics& shellMetrics,
|
||||
bool hovered) {
|
||||
drawList.AddFilledRect(button.rect, hovered ? kButtonHoverBg : kButtonBg, 8.0f);
|
||||
drawList.AddRectOutline(button.rect, kCardBorder, 1.0f, 8.0f);
|
||||
drawList.AddFilledRect(
|
||||
button.rect,
|
||||
hovered ? shellPalette.buttonHoverBackground : shellPalette.buttonBackground,
|
||||
shellMetrics.buttonRadius);
|
||||
drawList.AddRectOutline(button.rect, shellPalette.cardBorder, 1.0f, shellMetrics.buttonRadius);
|
||||
drawList.AddText(
|
||||
UIPoint(button.rect.x + 16.0f, button.rect.y + 10.0f),
|
||||
button.label,
|
||||
kTextPrimary,
|
||||
12.0f);
|
||||
shellPalette.textPrimary,
|
||||
shellMetrics.bodyFontSize);
|
||||
}
|
||||
|
||||
UIEditorPropertyGridField MakeTextField(
|
||||
std::string id,
|
||||
std::string label,
|
||||
std::string value,
|
||||
bool readOnly = false) {
|
||||
UIEditorPropertyGridField field = {};
|
||||
field.fieldId = std::move(id);
|
||||
field.label = std::move(label);
|
||||
field.valueText = std::move(value);
|
||||
field.readOnly = readOnly;
|
||||
return field;
|
||||
}
|
||||
|
||||
UIEditorPropertyGridField MakeBoolField(
|
||||
std::string id,
|
||||
std::string label,
|
||||
bool value) {
|
||||
UIEditorPropertyGridField field = {};
|
||||
field.fieldId = std::move(id);
|
||||
field.label = std::move(label);
|
||||
field.kind = UIEditorPropertyGridFieldKind::Bool;
|
||||
field.boolValue = value;
|
||||
return field;
|
||||
}
|
||||
|
||||
UIEditorPropertyGridField MakeNumberField(
|
||||
std::string id,
|
||||
std::string label,
|
||||
double value) {
|
||||
UIEditorPropertyGridField field = {};
|
||||
field.fieldId = std::move(id);
|
||||
field.label = std::move(label);
|
||||
field.kind = UIEditorPropertyGridFieldKind::Number;
|
||||
field.numberValue.value = value;
|
||||
field.numberValue.step = 1.0;
|
||||
field.numberValue.minValue = 0.0;
|
||||
field.numberValue.maxValue = 5000.0;
|
||||
field.numberValue.integerMode = true;
|
||||
return field;
|
||||
}
|
||||
|
||||
UIEditorPropertyGridField MakeEnumField(
|
||||
std::string id,
|
||||
std::string label,
|
||||
std::vector<std::string> options,
|
||||
std::size_t selectedIndex) {
|
||||
UIEditorPropertyGridField field = {};
|
||||
field.fieldId = std::move(id);
|
||||
field.label = std::move(label);
|
||||
field.kind = UIEditorPropertyGridFieldKind::Enum;
|
||||
field.enumValue.options = std::move(options);
|
||||
field.enumValue.selectedIndex = selectedIndex;
|
||||
return field;
|
||||
}
|
||||
|
||||
std::vector<UIEditorPropertyGridSection> BuildSections() {
|
||||
return {
|
||||
{
|
||||
"transform",
|
||||
"Transform",
|
||||
"inspector",
|
||||
"Inspector",
|
||||
{
|
||||
{ "position", "Position", "0, 0, 0", false, 0.0f },
|
||||
{ "rotation", "Rotation", "0, 45, 0", false, 0.0f },
|
||||
{ "scale", "Scale", "1, 1, 1", false, 0.0f }
|
||||
},
|
||||
0.0f
|
||||
},
|
||||
{
|
||||
"material",
|
||||
"Material",
|
||||
{
|
||||
{ "shader", "Shader", "Standard/Lit", false, 0.0f },
|
||||
{ "queue", "Render Queue", "2000", false, 0.0f },
|
||||
{ "guid", "GUID", "asset-guid-001", true, 0.0f }
|
||||
MakeBoolField("enabled", "Enabled", true),
|
||||
MakeNumberField("render_queue", "Render Queue", 2000.0),
|
||||
MakeEnumField("render_mode", "Render Mode", { "Opaque", "Cutout", "Fade" }, 0u),
|
||||
MakeTextField("tag", "Tag", "Player")
|
||||
},
|
||||
0.0f
|
||||
},
|
||||
@@ -215,8 +279,7 @@ std::vector<UIEditorPropertyGridSection> BuildSections() {
|
||||
"metadata",
|
||||
"Metadata",
|
||||
{
|
||||
{ "tag", "Tag", "", false, 0.0f },
|
||||
{ "layer", "Layer", "Default", false, 0.0f }
|
||||
MakeTextField("guid", "GUID", "asset-guid-001", true)
|
||||
},
|
||||
0.0f
|
||||
}
|
||||
@@ -246,8 +309,7 @@ std::string DescribeHitTarget(
|
||||
|
||||
std::string BuildExpandedSummary(const UIExpansionModel& expansionModel) {
|
||||
std::ostringstream stream = {};
|
||||
stream << (expansionModel.IsExpanded("transform") ? "Transform" : "-");
|
||||
stream << " / " << (expansionModel.IsExpanded("material") ? "Material" : "-");
|
||||
stream << (expansionModel.IsExpanded("inspector") ? "Inspector" : "-");
|
||||
stream << " / " << (expansionModel.IsExpanded("metadata") ? "Metadata" : "-");
|
||||
return stream.str();
|
||||
}
|
||||
@@ -467,6 +529,14 @@ private:
|
||||
m_captureRoot =
|
||||
ResolveRepoRootPath() / "tests/UI/Editor/integration/shell/property_grid_basic/captures";
|
||||
m_autoScreenshot.Initialize(m_captureRoot);
|
||||
const auto themeLoad =
|
||||
XCEngine::Tests::EditorUI::LoadEditorValidationTheme(ResolveValidationThemePath());
|
||||
if (themeLoad.succeeded) {
|
||||
m_theme = themeLoad.theme;
|
||||
m_themeStatus = "loaded";
|
||||
} else {
|
||||
m_themeStatus = themeLoad.error.empty() ? "fallback" : themeLoad.error;
|
||||
}
|
||||
|
||||
ResetScenario();
|
||||
return true;
|
||||
@@ -492,16 +562,18 @@ private:
|
||||
GetClientRect(m_hwnd, &clientRect);
|
||||
const float width = static_cast<float>((std::max)(1L, clientRect.right - clientRect.left));
|
||||
const float height = static_cast<float>((std::max)(1L, clientRect.bottom - clientRect.top));
|
||||
return BuildScenarioLayout(width, height);
|
||||
return BuildScenarioLayout(
|
||||
width,
|
||||
height,
|
||||
XCEngine::Tests::EditorUI::ResolveEditorValidationShellMetrics(m_theme));
|
||||
}
|
||||
|
||||
void ResetScenario() {
|
||||
m_sections = BuildSections();
|
||||
m_selectionModel = {};
|
||||
m_selectionModel.SetSelection("rotation");
|
||||
m_selectionModel.SetSelection("render_queue");
|
||||
m_expansionModel = {};
|
||||
m_expansionModel.Expand("transform");
|
||||
m_expansionModel.Expand("material");
|
||||
m_expansionModel.Expand("inspector");
|
||||
m_expansionModel.Expand("metadata");
|
||||
m_propertyEditModel = {};
|
||||
m_interactionState = {};
|
||||
@@ -520,6 +592,7 @@ private:
|
||||
}
|
||||
|
||||
const ScenarioLayout layout = GetLayout();
|
||||
const auto metrics = XCEngine::UI::Editor::ResolveUIEditorPropertyGridMetrics(m_theme);
|
||||
m_gridFrame =
|
||||
UpdateUIEditorPropertyGridInteraction(
|
||||
m_interactionState,
|
||||
@@ -528,23 +601,16 @@ private:
|
||||
m_propertyEditModel,
|
||||
layout.gridRect,
|
||||
m_sections,
|
||||
{});
|
||||
{},
|
||||
metrics);
|
||||
}
|
||||
|
||||
void ApplyCommittedValue(const UIEditorPropertyGridInteractionResult& result) {
|
||||
if (!result.editCommitted || result.committedFieldId.empty()) {
|
||||
void UpdateLastCommit(const UIEditorPropertyGridInteractionResult& result) {
|
||||
if (!result.fieldValueChanged || result.changedFieldId.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (UIEditorPropertyGridSection& section : m_sections) {
|
||||
for (UIEditorPropertyGridField& field : section.fields) {
|
||||
if (field.fieldId == result.committedFieldId) {
|
||||
field.valueText = result.committedValue;
|
||||
m_lastCommit = result.committedFieldId + " = " + result.committedValue;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_lastCommit = result.changedFieldId + " = " + result.changedValue;
|
||||
}
|
||||
|
||||
void OnResize(UINT width, UINT height) {
|
||||
@@ -661,6 +727,7 @@ private:
|
||||
|
||||
UIEditorPropertyGridInteractionResult PumpGridEvents(std::vector<UIInputEvent> events) {
|
||||
const ScenarioLayout layout = GetLayout();
|
||||
const auto metrics = XCEngine::UI::Editor::ResolveUIEditorPropertyGridMetrics(m_theme);
|
||||
m_gridFrame =
|
||||
UpdateUIEditorPropertyGridInteraction(
|
||||
m_interactionState,
|
||||
@@ -669,8 +736,9 @@ private:
|
||||
m_propertyEditModel,
|
||||
layout.gridRect,
|
||||
m_sections,
|
||||
std::move(events));
|
||||
ApplyCommittedValue(m_gridFrame.result);
|
||||
std::move(events),
|
||||
metrics);
|
||||
UpdateLastCommit(m_gridFrame.result);
|
||||
return m_gridFrame.result;
|
||||
}
|
||||
|
||||
@@ -678,6 +746,26 @@ private:
|
||||
const UIEditorPropertyGridInteractionResult& result,
|
||||
bool wasFocused,
|
||||
bool insideGrid) {
|
||||
if (result.popupOpened && !m_interactionState.propertyGridState.popupFieldId.empty()) {
|
||||
m_lastResult = "打开枚举下拉: " + m_interactionState.propertyGridState.popupFieldId;
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.popupClosed && !result.fieldValueChanged) {
|
||||
m_lastResult = "关闭枚举下拉";
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.fieldValueChanged) {
|
||||
m_lastResult = "字段已更新: " + result.changedFieldId + " = " + result.changedValue;
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.editCommitRejected && !result.activeFieldId.empty()) {
|
||||
m_lastResult = "提交被拒绝: " + result.activeFieldId;
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.editCommitted) {
|
||||
m_lastResult = "提交字段: " + result.committedFieldId + " = " + result.committedValue;
|
||||
return;
|
||||
@@ -753,99 +841,124 @@ private:
|
||||
GetClientRect(m_hwnd, &clientRect);
|
||||
const float width = static_cast<float>((std::max)(1L, clientRect.right - clientRect.left));
|
||||
const float height = static_cast<float>((std::max)(1L, clientRect.bottom - clientRect.top));
|
||||
const ScenarioLayout layout = BuildScenarioLayout(width, height);
|
||||
const auto shellMetrics = XCEngine::Tests::EditorUI::ResolveEditorValidationShellMetrics(m_theme);
|
||||
const auto shellPalette = XCEngine::Tests::EditorUI::ResolveEditorValidationShellPalette(m_theme);
|
||||
const ScenarioLayout layout = BuildScenarioLayout(width, height, shellMetrics);
|
||||
RefreshGridFrame();
|
||||
|
||||
const UIEditorPropertyGridHitTarget currentHit =
|
||||
HitTestUIEditorPropertyGrid(m_gridFrame.layout, m_mousePosition);
|
||||
const auto propertyMetrics = XCEngine::UI::Editor::ResolveUIEditorPropertyGridMetrics(m_theme);
|
||||
const auto propertyPalette = XCEngine::UI::Editor::ResolveUIEditorPropertyGridPalette(m_theme);
|
||||
const auto popupMetrics = XCEngine::UI::Editor::ResolveUIEditorMenuPopupMetrics(m_theme);
|
||||
const auto popupPalette = XCEngine::UI::Editor::ResolveUIEditorMenuPopupPalette(m_theme);
|
||||
|
||||
UIDrawData drawData = {};
|
||||
UIDrawList& drawList = drawData.EmplaceDrawList("EditorPropertyGridBasic");
|
||||
drawList.AddFilledRect(UIRect(0.0f, 0.0f, width, height), kWindowBg);
|
||||
drawList.AddFilledRect(UIRect(0.0f, 0.0f, width, height), shellPalette.windowBackground);
|
||||
|
||||
DrawCard(
|
||||
drawList,
|
||||
layout.introRect,
|
||||
shellPalette,
|
||||
shellMetrics,
|
||||
"这个测试在验证什么功能",
|
||||
"只验证 Editor PropertyGrid 基础控件,不涉及任何 Inspector 业务逻辑。");
|
||||
"只验证 Editor PropertyGrid 作为 typed 属性宿主的基础契约,不涉及任何 Inspector 业务逻辑。");
|
||||
drawList.AddText(
|
||||
UIPoint(layout.introRect.x + 16.0f, layout.introRect.y + 72.0f),
|
||||
"1. 点击 section header,检查展开/折叠是否稳定,字段布局不能歪。",
|
||||
kTextPrimary,
|
||||
12.0f);
|
||||
shellPalette.textPrimary,
|
||||
shellMetrics.bodyFontSize);
|
||||
drawList.AddText(
|
||||
UIPoint(layout.introRect.x + 16.0f, layout.introRect.y + 94.0f),
|
||||
"2. 点击 field row 只切换 selection;点击 value box 才进入编辑态。",
|
||||
kTextPrimary,
|
||||
12.0f);
|
||||
"2. 点击 value host:Bool toggle、Number/Text edit、Enum popup。",
|
||||
shellPalette.textPrimary,
|
||||
shellMetrics.bodyFontSize);
|
||||
drawList.AddText(
|
||||
UIPoint(layout.introRect.x + 16.0f, layout.introRect.y + 116.0f),
|
||||
"3. 编辑态输入字符,按 Enter commit,按 Esc cancel,read-only 字段不能进编辑。",
|
||||
kTextPrimary,
|
||||
12.0f);
|
||||
"3. Number / Text 编辑后按 Enter commit、Esc cancel;GUID 只读。",
|
||||
shellPalette.textPrimary,
|
||||
shellMetrics.bodyFontSize);
|
||||
drawList.AddText(
|
||||
UIPoint(layout.introRect.x + 16.0f, layout.introRect.y + 138.0f),
|
||||
"4. Grid 获得 focus 后按 Up / Down / Home / End,检查字段导航和 selection 同步。",
|
||||
kTextPrimary,
|
||||
12.0f);
|
||||
shellPalette.textPrimary,
|
||||
shellMetrics.bodyFontSize);
|
||||
drawList.AddText(
|
||||
UIPoint(layout.introRect.x + 16.0f, layout.introRect.y + 160.0f),
|
||||
"5. 按 F12 手动截图;设置 XCUI_AUTO_CAPTURE_ON_STARTUP=1 可自动截图。",
|
||||
kTextPrimary,
|
||||
12.0f);
|
||||
shellPalette.textPrimary,
|
||||
shellMetrics.bodyFontSize);
|
||||
|
||||
DrawCard(drawList, layout.controlRect, "操作");
|
||||
DrawCard(drawList, layout.controlRect, shellPalette, shellMetrics, "操作");
|
||||
for (const ButtonLayout& button : layout.buttons) {
|
||||
DrawButton(
|
||||
drawList,
|
||||
button,
|
||||
shellPalette,
|
||||
shellMetrics,
|
||||
m_hasHoveredAction && m_hoveredAction == button.action);
|
||||
}
|
||||
|
||||
DrawCard(drawList, layout.stateRect, "状态摘要", "重点检查 hit / focus / selection / edit / commit。");
|
||||
DrawCard(
|
||||
drawList,
|
||||
layout.stateRect,
|
||||
shellPalette,
|
||||
shellMetrics,
|
||||
"状态摘要",
|
||||
"重点检查 hit / focus / selection / edit / popup / commit。");
|
||||
drawList.AddText(
|
||||
UIPoint(layout.stateRect.x + 16.0f, layout.stateRect.y + 70.0f),
|
||||
"Hover: " + DescribeHitTarget(currentHit, m_sections),
|
||||
kTextPrimary,
|
||||
12.0f);
|
||||
shellPalette.textPrimary,
|
||||
shellMetrics.bodyFontSize);
|
||||
drawList.AddText(
|
||||
UIPoint(layout.stateRect.x + 16.0f, layout.stateRect.y + 94.0f),
|
||||
std::string("Focused: ") + (m_interactionState.propertyGridState.focused ? "开" : "关"),
|
||||
kTextPrimary,
|
||||
12.0f);
|
||||
shellPalette.textPrimary,
|
||||
shellMetrics.bodyFontSize);
|
||||
drawList.AddText(
|
||||
UIPoint(layout.stateRect.x + 16.0f, layout.stateRect.y + 118.0f),
|
||||
"Selected: " +
|
||||
(m_selectionModel.HasSelection() ? m_selectionModel.GetSelectedId() : std::string("(none)")),
|
||||
kTextSuccess,
|
||||
12.0f);
|
||||
shellPalette.textSuccess,
|
||||
shellMetrics.bodyFontSize);
|
||||
drawList.AddText(
|
||||
UIPoint(layout.stateRect.x + 16.0f, layout.stateRect.y + 142.0f),
|
||||
"Active Edit: " +
|
||||
(m_propertyEditModel.HasActiveEdit() ? m_propertyEditModel.GetActiveFieldId() : std::string("(none)")),
|
||||
kTextMuted,
|
||||
12.0f);
|
||||
shellPalette.textMuted,
|
||||
shellMetrics.bodyFontSize);
|
||||
drawList.AddText(
|
||||
UIPoint(layout.stateRect.x + 16.0f, layout.stateRect.y + 166.0f),
|
||||
"Staged: " +
|
||||
(m_propertyEditModel.HasActiveEdit() ? m_propertyEditModel.GetStagedValue() : std::string("(none)")),
|
||||
kTextMuted,
|
||||
12.0f);
|
||||
shellPalette.textMuted,
|
||||
shellMetrics.bodyFontSize);
|
||||
drawList.AddText(
|
||||
UIPoint(layout.stateRect.x + 16.0f, layout.stateRect.y + 190.0f),
|
||||
"Expanded: " + BuildExpandedSummary(m_expansionModel),
|
||||
kTextMuted,
|
||||
12.0f);
|
||||
"Popup: " +
|
||||
(m_interactionState.propertyGridState.popupFieldId.empty()
|
||||
? std::string("(none)")
|
||||
: (m_interactionState.propertyGridState.popupFieldId + " / index " +
|
||||
std::to_string(m_interactionState.propertyGridState.popupHighlightedIndex))),
|
||||
shellPalette.textMuted,
|
||||
shellMetrics.bodyFontSize);
|
||||
drawList.AddText(
|
||||
UIPoint(layout.stateRect.x + 16.0f, layout.stateRect.y + 214.0f),
|
||||
"Last Commit: " + m_lastCommit,
|
||||
kTextPrimary,
|
||||
12.0f);
|
||||
"Expanded: " + BuildExpandedSummary(m_expansionModel),
|
||||
shellPalette.textPrimary,
|
||||
shellMetrics.bodyFontSize);
|
||||
drawList.AddText(
|
||||
UIPoint(layout.stateRect.x + 16.0f, layout.stateRect.y + 238.0f),
|
||||
"Last Commit: " + m_lastCommit,
|
||||
shellPalette.textPrimary,
|
||||
shellMetrics.bodyFontSize);
|
||||
drawList.AddText(
|
||||
UIPoint(layout.stateRect.x + 16.0f, layout.stateRect.y + 262.0f),
|
||||
"Result: " + m_lastResult,
|
||||
kTextPrimary,
|
||||
12.0f);
|
||||
shellPalette.textPrimary,
|
||||
shellMetrics.bodyFontSize);
|
||||
|
||||
const std::string captureSummary =
|
||||
m_autoScreenshot.HasPendingCapture()
|
||||
@@ -854,24 +967,42 @@ private:
|
||||
? std::string("F12 -> tests/UI/Editor/integration/shell/property_grid_basic/captures/")
|
||||
: m_autoScreenshot.GetLastCaptureSummary());
|
||||
drawList.AddText(
|
||||
UIPoint(layout.stateRect.x + 16.0f, layout.stateRect.y + 262.0f),
|
||||
UIPoint(layout.stateRect.x + 16.0f, layout.stateRect.y + 286.0f),
|
||||
captureSummary,
|
||||
kTextWeak,
|
||||
12.0f);
|
||||
shellPalette.textWeak,
|
||||
shellMetrics.bodyFontSize);
|
||||
drawList.AddText(
|
||||
UIPoint(layout.stateRect.x + 16.0f, layout.stateRect.y + 310.0f),
|
||||
"Theme: " + m_themeStatus,
|
||||
shellPalette.textWeak,
|
||||
shellMetrics.bodyFontSize);
|
||||
|
||||
DrawCard(drawList, layout.previewRect, "PropertyGrid 预览", "这里只放一个 PropertyGrid,不混入任何业务面板。");
|
||||
DrawCard(
|
||||
drawList,
|
||||
layout.previewRect,
|
||||
shellPalette,
|
||||
shellMetrics,
|
||||
"PropertyGrid 预览",
|
||||
"这里只放一个 PropertyGrid,用来验证 typed 属性宿主。");
|
||||
AppendUIEditorPropertyGridBackground(
|
||||
drawList,
|
||||
m_gridFrame.layout,
|
||||
m_sections,
|
||||
m_selectionModel,
|
||||
m_propertyEditModel,
|
||||
m_interactionState.propertyGridState);
|
||||
m_interactionState.propertyGridState,
|
||||
propertyPalette,
|
||||
propertyMetrics);
|
||||
AppendUIEditorPropertyGridForeground(
|
||||
drawList,
|
||||
m_gridFrame.layout,
|
||||
m_sections,
|
||||
m_propertyEditModel);
|
||||
m_interactionState.propertyGridState,
|
||||
m_propertyEditModel,
|
||||
propertyPalette,
|
||||
propertyMetrics,
|
||||
popupPalette,
|
||||
popupMetrics);
|
||||
|
||||
const bool framePresented = m_renderer.Render(drawData);
|
||||
m_autoScreenshot.CaptureIfRequested(
|
||||
@@ -893,11 +1024,13 @@ private:
|
||||
UIPropertyEditModel m_propertyEditModel = {};
|
||||
UIEditorPropertyGridInteractionState m_interactionState = {};
|
||||
UIEditorPropertyGridInteractionFrame m_gridFrame = {};
|
||||
Style::UITheme m_theme = {};
|
||||
UIPoint m_mousePosition = UIPoint(-1000.0f, -1000.0f);
|
||||
ActionId m_hoveredAction = ActionId::Reset;
|
||||
bool m_hasHoveredAction = false;
|
||||
std::string m_lastResult = {};
|
||||
std::string m_lastCommit = {};
|
||||
std::string m_themeStatus = "fallback";
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
Reference in New Issue
Block a user