Refactor XCUI editor module layout
This commit is contained in:
250
new_editor/src/Fields/UIEditorEnumField.cpp
Normal file
250
new_editor/src/Fields/UIEditorEnumField.cpp
Normal file
@@ -0,0 +1,250 @@
|
||||
#include <XCEditor/Fields/UIEditorEnumField.h>
|
||||
#include <XCEditor/Widgets/UIEditorFieldRowLayout.h>
|
||||
#include <XCEditor/Widgets/UIEditorTextLayout.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace XCEngine::UI::Editor::Widgets {
|
||||
|
||||
namespace {
|
||||
|
||||
float ClampNonNegative(float value) {
|
||||
return (std::max)(0.0f, value);
|
||||
}
|
||||
|
||||
UIEditorEnumFieldMetrics ResolveMetrics(const UIEditorEnumFieldMetrics& metrics) {
|
||||
const auto& tokens = GetUIEditorInspectorFieldStyleTokens();
|
||||
|
||||
UIEditorEnumFieldMetrics resolved = metrics;
|
||||
if (AreUIEditorFieldMetricsEqual(metrics.controlTrailingInset, 8.0f)) {
|
||||
resolved.controlTrailingInset = tokens.controlTrailingInset;
|
||||
}
|
||||
if (AreUIEditorFieldMetricsEqual(metrics.valueBoxMinWidth, 96.0f)) {
|
||||
resolved.valueBoxMinWidth = tokens.controlMinWidth;
|
||||
}
|
||||
if (AreUIEditorFieldMetricsEqual(metrics.dropdownArrowWidth, 20.0f)) {
|
||||
resolved.dropdownArrowWidth = tokens.dropdownArrowWidth;
|
||||
}
|
||||
|
||||
return resolved;
|
||||
}
|
||||
|
||||
UIEditorEnumFieldPalette ResolvePalette(const UIEditorEnumFieldPalette& palette) {
|
||||
const auto& tokens = GetUIEditorInspectorFieldStyleTokens();
|
||||
|
||||
UIEditorEnumFieldPalette resolved = palette;
|
||||
if (AreUIEditorFieldColorsEqual(palette.rowHoverColor, ::XCEngine::UI::UIColor(0.0f, 0.0f, 0.0f, 0.0f))) {
|
||||
resolved.rowHoverColor = tokens.rowHoverColor;
|
||||
}
|
||||
if (AreUIEditorFieldColorsEqual(palette.rowActiveColor, ::XCEngine::UI::UIColor(0.0f, 0.0f, 0.0f, 0.0f))) {
|
||||
resolved.rowActiveColor = tokens.rowActiveColor;
|
||||
}
|
||||
if (AreUIEditorFieldColorsEqual(palette.focusedBorderColor, ::XCEngine::UI::UIColor(0.14f, 0.14f, 0.14f, 1.0f))) {
|
||||
resolved.focusedBorderColor = tokens.controlFocusedBorderColor;
|
||||
}
|
||||
if (AreUIEditorFieldColorsEqual(palette.valueBoxColor, ::XCEngine::UI::UIColor(0.18f, 0.18f, 0.18f, 1.0f))) {
|
||||
resolved.valueBoxColor = tokens.controlColor;
|
||||
}
|
||||
if (AreUIEditorFieldColorsEqual(palette.valueBoxHoverColor, ::XCEngine::UI::UIColor(0.21f, 0.21f, 0.21f, 1.0f))) {
|
||||
resolved.valueBoxHoverColor = tokens.controlHoverColor;
|
||||
}
|
||||
if (AreUIEditorFieldColorsEqual(palette.readOnlyColor, ::XCEngine::UI::UIColor(0.17f, 0.17f, 0.17f, 1.0f))) {
|
||||
resolved.readOnlyColor = tokens.controlReadOnlyColor;
|
||||
}
|
||||
if (AreUIEditorFieldColorsEqual(palette.controlBorderColor, ::XCEngine::UI::UIColor(0.14f, 0.14f, 0.14f, 1.0f))) {
|
||||
resolved.controlBorderColor = tokens.controlBorderColor;
|
||||
}
|
||||
if (AreUIEditorFieldColorsEqual(palette.labelColor, ::XCEngine::UI::UIColor(0.88f, 0.88f, 0.88f, 1.0f))) {
|
||||
resolved.labelColor = tokens.labelColor;
|
||||
}
|
||||
if (AreUIEditorFieldColorsEqual(palette.valueColor, ::XCEngine::UI::UIColor(0.88f, 0.88f, 0.88f, 1.0f))) {
|
||||
resolved.valueColor = tokens.valueColor;
|
||||
}
|
||||
if (AreUIEditorFieldColorsEqual(palette.arrowColor, ::XCEngine::UI::UIColor(0.88f, 0.88f, 0.88f, 1.0f))) {
|
||||
resolved.arrowColor = tokens.arrowColor;
|
||||
}
|
||||
|
||||
return resolved;
|
||||
}
|
||||
|
||||
bool ContainsPoint(const ::XCEngine::UI::UIRect& rect, const ::XCEngine::UI::UIPoint& point) {
|
||||
return point.x >= rect.x &&
|
||||
point.x <= rect.x + rect.width &&
|
||||
point.y >= rect.y &&
|
||||
point.y <= rect.y + rect.height;
|
||||
}
|
||||
|
||||
std::size_t ClampSelectedIndex(const UIEditorEnumFieldSpec& spec) {
|
||||
if (spec.options.empty()) {
|
||||
return 0u;
|
||||
}
|
||||
|
||||
return (std::min)(spec.selectedIndex, spec.options.size() - 1u);
|
||||
}
|
||||
|
||||
void AppendDropdownChevron(
|
||||
::XCEngine::UI::UIDrawList& drawList,
|
||||
const ::XCEngine::UI::UIRect& rect,
|
||||
const ::XCEngine::UI::UIColor& color) {
|
||||
const float centerX = rect.x + rect.width * 0.5f;
|
||||
const float centerY = rect.y + rect.height * 0.5f;
|
||||
const float halfWidth = ClampNonNegative(rect.width * 0.18f);
|
||||
const float halfHeight = ClampNonNegative(rect.height * 0.10f);
|
||||
drawList.AddLine(
|
||||
::XCEngine::UI::UIPoint(centerX - halfWidth, centerY - halfHeight),
|
||||
::XCEngine::UI::UIPoint(centerX, centerY + halfHeight),
|
||||
color,
|
||||
1.0f);
|
||||
drawList.AddLine(
|
||||
::XCEngine::UI::UIPoint(centerX, centerY + halfHeight),
|
||||
::XCEngine::UI::UIPoint(centerX + halfWidth, centerY - halfHeight),
|
||||
color,
|
||||
1.0f);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::string ResolveUIEditorEnumFieldValueText(const UIEditorEnumFieldSpec& spec) {
|
||||
if (spec.options.empty()) {
|
||||
return "(none)";
|
||||
}
|
||||
|
||||
return spec.options[ClampSelectedIndex(spec)];
|
||||
}
|
||||
|
||||
UIEditorEnumFieldLayout BuildUIEditorEnumFieldLayout(
|
||||
const ::XCEngine::UI::UIRect& bounds,
|
||||
const UIEditorEnumFieldSpec&,
|
||||
const UIEditorEnumFieldMetrics& metrics) {
|
||||
const UIEditorEnumFieldMetrics resolvedMetrics = ResolveMetrics(metrics);
|
||||
const UIEditorFieldRowLayout hostLayout = BuildUIEditorFieldRowLayout(
|
||||
bounds,
|
||||
resolvedMetrics.valueBoxMinWidth,
|
||||
UIEditorFieldRowLayoutMetrics {
|
||||
resolvedMetrics.rowHeight,
|
||||
resolvedMetrics.horizontalPadding,
|
||||
resolvedMetrics.labelControlGap,
|
||||
resolvedMetrics.controlColumnStart,
|
||||
resolvedMetrics.controlTrailingInset,
|
||||
resolvedMetrics.controlInsetY,
|
||||
});
|
||||
|
||||
UIEditorEnumFieldLayout layout = {};
|
||||
layout.bounds = hostLayout.bounds;
|
||||
layout.labelRect = hostLayout.labelRect;
|
||||
layout.controlRect = hostLayout.controlRect;
|
||||
layout.valueRect = layout.controlRect;
|
||||
const float arrowWidth = (std::min)(
|
||||
(std::max)(resolvedMetrics.dropdownArrowWidth, 0.0f),
|
||||
layout.valueRect.width);
|
||||
layout.arrowRect = ::XCEngine::UI::UIRect(
|
||||
layout.valueRect.x + (std::max)(0.0f, layout.valueRect.width - arrowWidth),
|
||||
layout.valueRect.y,
|
||||
arrowWidth,
|
||||
layout.valueRect.height);
|
||||
return layout;
|
||||
}
|
||||
|
||||
UIEditorEnumFieldHitTarget HitTestUIEditorEnumField(
|
||||
const UIEditorEnumFieldLayout& layout,
|
||||
const ::XCEngine::UI::UIPoint& point) {
|
||||
if (!ContainsPoint(layout.bounds, point)) {
|
||||
return {};
|
||||
}
|
||||
if (ContainsPoint(layout.arrowRect, point)) {
|
||||
return { UIEditorEnumFieldHitTargetKind::DropdownArrow };
|
||||
}
|
||||
if (ContainsPoint(layout.valueRect, point)) {
|
||||
return { UIEditorEnumFieldHitTargetKind::ValueBox };
|
||||
}
|
||||
return { UIEditorEnumFieldHitTargetKind::Row };
|
||||
}
|
||||
|
||||
void AppendUIEditorEnumFieldBackground(
|
||||
::XCEngine::UI::UIDrawList& drawList,
|
||||
const UIEditorEnumFieldLayout& layout,
|
||||
const UIEditorEnumFieldSpec& spec,
|
||||
const UIEditorEnumFieldState& state,
|
||||
const UIEditorEnumFieldPalette& palette,
|
||||
const UIEditorEnumFieldMetrics& metrics) {
|
||||
const UIEditorEnumFieldPalette resolvedPalette = ResolvePalette(palette);
|
||||
const UIEditorEnumFieldMetrics resolvedMetrics = ResolveMetrics(metrics);
|
||||
const auto rowFillColor =
|
||||
state.active ? resolvedPalette.rowActiveColor
|
||||
: (state.hoveredTarget != UIEditorEnumFieldHitTargetKind::None
|
||||
? resolvedPalette.rowHoverColor
|
||||
: resolvedPalette.surfaceColor);
|
||||
if (rowFillColor.a > 0.0f) {
|
||||
drawList.AddFilledRect(layout.bounds, rowFillColor, resolvedMetrics.cornerRounding);
|
||||
}
|
||||
|
||||
const bool controlHovered =
|
||||
state.hoveredTarget == UIEditorEnumFieldHitTargetKind::ValueBox ||
|
||||
state.hoveredTarget == UIEditorEnumFieldHitTargetKind::DropdownArrow;
|
||||
const ::XCEngine::UI::UIColor controlColor =
|
||||
spec.readOnly
|
||||
? resolvedPalette.readOnlyColor
|
||||
: (controlHovered || state.popupOpen ? resolvedPalette.valueBoxHoverColor : resolvedPalette.valueBoxColor);
|
||||
drawList.AddFilledRect(layout.valueRect, controlColor, resolvedMetrics.valueBoxRounding);
|
||||
drawList.AddRectOutline(
|
||||
layout.valueRect,
|
||||
state.popupOpen ? resolvedPalette.focusedBorderColor : resolvedPalette.controlBorderColor,
|
||||
state.popupOpen ? resolvedMetrics.focusedBorderThickness : resolvedMetrics.borderThickness,
|
||||
resolvedMetrics.valueBoxRounding);
|
||||
drawList.AddLine(
|
||||
::XCEngine::UI::UIPoint(layout.arrowRect.x, layout.arrowRect.y + 1.0f),
|
||||
::XCEngine::UI::UIPoint(layout.arrowRect.x, layout.arrowRect.y + layout.arrowRect.height - 1.0f),
|
||||
resolvedPalette.controlBorderColor,
|
||||
1.0f);
|
||||
}
|
||||
|
||||
void AppendUIEditorEnumFieldForeground(
|
||||
::XCEngine::UI::UIDrawList& drawList,
|
||||
const UIEditorEnumFieldLayout& layout,
|
||||
const UIEditorEnumFieldSpec& spec,
|
||||
const UIEditorEnumFieldPalette& palette,
|
||||
const UIEditorEnumFieldMetrics& metrics) {
|
||||
const UIEditorEnumFieldPalette resolvedPalette = ResolvePalette(palette);
|
||||
const UIEditorEnumFieldMetrics resolvedMetrics = ResolveMetrics(metrics);
|
||||
drawList.PushClipRect(ResolveUIEditorTextClipRect(layout.labelRect, resolvedMetrics.labelFontSize));
|
||||
drawList.AddText(
|
||||
::XCEngine::UI::UIPoint(
|
||||
layout.labelRect.x,
|
||||
ResolveUIEditorTextTop(layout.labelRect, resolvedMetrics.labelFontSize, resolvedMetrics.labelTextInsetY)),
|
||||
spec.label,
|
||||
resolvedPalette.labelColor,
|
||||
resolvedMetrics.labelFontSize);
|
||||
drawList.PopClipRect();
|
||||
|
||||
const ::XCEngine::UI::UIRect valueTextClipRect(
|
||||
layout.valueRect.x + resolvedMetrics.valueTextInsetX,
|
||||
layout.valueRect.y,
|
||||
ClampNonNegative(layout.arrowRect.x - layout.valueRect.x - resolvedMetrics.valueTextInsetX),
|
||||
layout.valueRect.height);
|
||||
drawList.PushClipRect(ResolveUIEditorTextClipRect(valueTextClipRect, resolvedMetrics.valueFontSize));
|
||||
drawList.AddText(
|
||||
::XCEngine::UI::UIPoint(
|
||||
layout.valueRect.x + resolvedMetrics.valueTextInsetX,
|
||||
ResolveUIEditorTextTop(layout.valueRect, resolvedMetrics.valueFontSize, resolvedMetrics.valueTextInsetY)),
|
||||
ResolveUIEditorEnumFieldValueText(spec),
|
||||
resolvedPalette.valueColor,
|
||||
resolvedMetrics.valueFontSize);
|
||||
drawList.PopClipRect();
|
||||
AppendDropdownChevron(drawList, layout.arrowRect, resolvedPalette.arrowColor);
|
||||
}
|
||||
|
||||
void AppendUIEditorEnumField(
|
||||
::XCEngine::UI::UIDrawList& drawList,
|
||||
const ::XCEngine::UI::UIRect& bounds,
|
||||
const UIEditorEnumFieldSpec& spec,
|
||||
const UIEditorEnumFieldState& state,
|
||||
const UIEditorEnumFieldPalette& palette,
|
||||
const UIEditorEnumFieldMetrics& metrics) {
|
||||
const UIEditorEnumFieldPalette resolvedPalette = ResolvePalette(palette);
|
||||
const UIEditorEnumFieldMetrics resolvedMetrics = ResolveMetrics(metrics);
|
||||
const UIEditorEnumFieldLayout layout = BuildUIEditorEnumFieldLayout(bounds, spec, resolvedMetrics);
|
||||
AppendUIEditorEnumFieldBackground(drawList, layout, spec, state, resolvedPalette, resolvedMetrics);
|
||||
AppendUIEditorEnumFieldForeground(drawList, layout, spec, resolvedPalette, resolvedMetrics);
|
||||
}
|
||||
|
||||
} // namespace XCEngine::UI::Editor::Widgets
|
||||
Reference in New Issue
Block a user