ui: add typed editor field foundations

This commit is contained in:
2026-04-08 02:52:28 +08:00
parent 805e07bf90
commit 0a392e1311
69 changed files with 11676 additions and 1169 deletions

View File

@@ -1,4 +1,6 @@
#include <XCEditor/Widgets/UIEditorBoolField.h>
#include <XCEditor/Widgets/UIEditorFieldRowLayout.h>
#include <XCEditor/Widgets/UIEditorTextLayout.h>
#include <algorithm>
@@ -6,6 +8,10 @@ namespace XCEngine::UI::Editor::Widgets {
namespace {
float ClampNonNegative(float value) {
return (std::max)(0.0f, value);
}
bool ContainsPoint(const ::XCEngine::UI::UIRect& rect, const ::XCEngine::UI::UIPoint& point) {
return point.x >= rect.x &&
point.x <= rect.x + rect.width &&
@@ -17,37 +23,30 @@ bool ContainsPoint(const ::XCEngine::UI::UIRect& rect, const ::XCEngine::UI::UIP
UIEditorBoolFieldLayout BuildUIEditorBoolFieldLayout(
const ::XCEngine::UI::UIRect& bounds,
const UIEditorBoolFieldSpec& spec,
const UIEditorBoolFieldSpec&,
const UIEditorBoolFieldMetrics& metrics) {
const UIEditorFieldRowLayout hostLayout = BuildUIEditorFieldRowLayout(
bounds,
metrics.checkboxSize,
UIEditorFieldRowLayoutMetrics {
metrics.rowHeight,
metrics.horizontalPadding,
metrics.labelControlGap,
metrics.controlColumnStart,
metrics.controlTrailingInset,
0.0f,
});
UIEditorBoolFieldLayout layout = {};
layout.bounds = bounds;
const float controlX = (std::min)(
bounds.x + bounds.width - metrics.horizontalPadding - metrics.toggleWidth,
bounds.x + metrics.controlColumnStart);
const float labelWidth = (std::max)(
0.0f,
controlX - bounds.x - metrics.horizontalPadding - metrics.labelControlGap);
layout.labelRect = ::XCEngine::UI::UIRect(
bounds.x + metrics.horizontalPadding,
bounds.y,
labelWidth,
bounds.height);
layout.toggleRect = ::XCEngine::UI::UIRect(
controlX,
bounds.y + (std::max)(0.0f, (bounds.height - metrics.toggleHeight) * 0.5f),
metrics.toggleWidth,
metrics.toggleHeight);
const float knobSize = (std::max)(0.0f, layout.toggleRect.height - metrics.toggleKnobInset * 2.0f);
const float knobX = spec.value
? layout.toggleRect.x + layout.toggleRect.width - metrics.toggleKnobInset - knobSize
: layout.toggleRect.x + metrics.toggleKnobInset;
layout.knobRect = ::XCEngine::UI::UIRect(
knobX,
layout.toggleRect.y + metrics.toggleKnobInset,
knobSize,
knobSize);
layout.bounds = hostLayout.bounds;
layout.labelRect = hostLayout.labelRect;
layout.controlRect = hostLayout.controlRect;
layout.checkboxRect = ::XCEngine::UI::UIRect(
layout.controlRect.x,
layout.bounds.y + ClampNonNegative((layout.bounds.height - metrics.checkboxSize) * 0.5f),
metrics.checkboxSize,
metrics.checkboxSize);
layout.checkmarkRect = layout.checkboxRect;
return layout;
}
@@ -58,8 +57,8 @@ UIEditorBoolFieldHitTarget HitTestUIEditorBoolField(
return {};
}
if (ContainsPoint(layout.toggleRect, point)) {
return { UIEditorBoolFieldHitTargetKind::Toggle };
if (ContainsPoint(layout.controlRect, point)) {
return { UIEditorBoolFieldHitTargetKind::Checkbox };
}
return { UIEditorBoolFieldHitTargetKind::Row };
@@ -72,27 +71,17 @@ void AppendUIEditorBoolFieldBackground(
const UIEditorBoolFieldState& state,
const UIEditorBoolFieldPalette& palette,
const UIEditorBoolFieldMetrics& metrics) {
const bool hovered = state.hoveredTarget != UIEditorBoolFieldHitTargetKind::None;
const ::XCEngine::UI::UIColor rowColor =
state.active ? palette.rowActiveColor :
(hovered ? palette.rowHoverColor : palette.surfaceColor);
drawList.AddFilledRect(layout.bounds, rowColor, metrics.cornerRounding);
const bool checkboxHovered = state.hoveredTarget == UIEditorBoolFieldHitTargetKind::Checkbox;
const ::XCEngine::UI::UIColor checkboxColor =
spec.readOnly
? palette.checkboxReadOnlyColor
: (checkboxHovered ? palette.checkboxHoverColor : palette.checkboxColor);
drawList.AddFilledRect(layout.checkboxRect, checkboxColor, metrics.checkboxRounding);
drawList.AddRectOutline(
layout.bounds,
state.focused ? palette.focusedBorderColor : palette.borderColor,
state.focused ? metrics.focusedBorderThickness : metrics.borderThickness,
metrics.cornerRounding);
const ::XCEngine::UI::UIColor toggleColor =
spec.readOnly ? palette.toggleReadOnlyColor :
(spec.value ? palette.toggleOnColor : palette.toggleOffColor);
drawList.AddFilledRect(layout.toggleRect, toggleColor, layout.toggleRect.height * 0.5f);
drawList.AddRectOutline(
layout.toggleRect,
palette.toggleBorderColor,
layout.checkboxRect,
palette.checkboxBorderColor,
metrics.borderThickness,
layout.toggleRect.height * 0.5f);
drawList.AddFilledRect(layout.knobRect, palette.knobColor, layout.knobRect.height * 0.5f);
metrics.checkboxRounding);
}
void AppendUIEditorBoolFieldForeground(
@@ -101,21 +90,28 @@ void AppendUIEditorBoolFieldForeground(
const UIEditorBoolFieldSpec& spec,
const UIEditorBoolFieldPalette& palette,
const UIEditorBoolFieldMetrics& metrics) {
drawList.PushClipRect(layout.labelRect);
drawList.AddText(
::XCEngine::UI::UIPoint(layout.labelRect.x, layout.labelRect.y + metrics.textInsetY),
spec.label,
palette.labelColor,
12.0f);
drawList.PopClipRect();
drawList.PushClipRect(ResolveUIEditorTextClipRect(layout.labelRect, metrics.labelFontSize));
drawList.AddText(
::XCEngine::UI::UIPoint(
layout.toggleRect.x - 42.0f,
layout.bounds.y + metrics.textInsetY),
spec.value ? "On" : "Off",
palette.valueColor,
12.0f);
layout.labelRect.x,
ResolveUIEditorTextTop(layout.labelRect, metrics.labelFontSize, metrics.labelTextInsetY)),
spec.label,
palette.labelColor,
metrics.labelFontSize);
drawList.PopClipRect();
if (spec.value) {
drawList.AddText(
::XCEngine::UI::UIPoint(
layout.checkmarkRect.x + metrics.checkboxGlyphInsetX,
ResolveUIEditorTextTop(
layout.checkmarkRect,
metrics.checkboxGlyphFontSize,
metrics.checkboxGlyphInsetY)),
"V",
palette.checkboxMarkColor,
metrics.checkboxGlyphFontSize);
}
}
void AppendUIEditorBoolField(