2026-04-10 00:41:28 +08:00
|
|
|
#include <XCEditor/Fields/UIEditorBoolField.h>
|
2026-04-08 02:52:28 +08:00
|
|
|
#include <XCEditor/Widgets/UIEditorFieldRowLayout.h>
|
|
|
|
|
#include <XCEditor/Widgets/UIEditorTextLayout.h>
|
2026-04-07 17:55:42 +08:00
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
|
|
namespace XCEngine::UI::Editor::Widgets {
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
2026-04-08 02:52:28 +08:00
|
|
|
float ClampNonNegative(float value) {
|
|
|
|
|
return (std::max)(0.0f, value);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-07 17:55:42 +08:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
UIEditorBoolFieldLayout BuildUIEditorBoolFieldLayout(
|
|
|
|
|
const ::XCEngine::UI::UIRect& bounds,
|
2026-04-08 02:52:28 +08:00
|
|
|
const UIEditorBoolFieldSpec&,
|
2026-04-07 17:55:42 +08:00
|
|
|
const UIEditorBoolFieldMetrics& metrics) {
|
2026-04-08 02:52:28 +08:00
|
|
|
const UIEditorFieldRowLayout hostLayout = BuildUIEditorFieldRowLayout(
|
|
|
|
|
bounds,
|
|
|
|
|
metrics.checkboxSize,
|
|
|
|
|
UIEditorFieldRowLayoutMetrics {
|
|
|
|
|
metrics.rowHeight,
|
|
|
|
|
metrics.horizontalPadding,
|
|
|
|
|
metrics.labelControlGap,
|
|
|
|
|
metrics.controlColumnStart,
|
|
|
|
|
metrics.controlTrailingInset,
|
|
|
|
|
0.0f,
|
|
|
|
|
});
|
|
|
|
|
|
2026-04-07 17:55:42 +08:00
|
|
|
UIEditorBoolFieldLayout layout = {};
|
2026-04-08 02:52:28 +08:00
|
|
|
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;
|
2026-04-07 17:55:42 +08:00
|
|
|
return layout;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UIEditorBoolFieldHitTarget HitTestUIEditorBoolField(
|
|
|
|
|
const UIEditorBoolFieldLayout& layout,
|
|
|
|
|
const ::XCEngine::UI::UIPoint& point) {
|
|
|
|
|
if (!ContainsPoint(layout.bounds, point)) {
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-08 02:52:28 +08:00
|
|
|
if (ContainsPoint(layout.controlRect, point)) {
|
|
|
|
|
return { UIEditorBoolFieldHitTargetKind::Checkbox };
|
2026-04-07 17:55:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return { UIEditorBoolFieldHitTargetKind::Row };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AppendUIEditorBoolFieldBackground(
|
|
|
|
|
::XCEngine::UI::UIDrawList& drawList,
|
|
|
|
|
const UIEditorBoolFieldLayout& layout,
|
|
|
|
|
const UIEditorBoolFieldSpec& spec,
|
|
|
|
|
const UIEditorBoolFieldState& state,
|
|
|
|
|
const UIEditorBoolFieldPalette& palette,
|
|
|
|
|
const UIEditorBoolFieldMetrics& metrics) {
|
2026-04-08 02:52:28 +08:00
|
|
|
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);
|
2026-04-07 17:55:42 +08:00
|
|
|
drawList.AddRectOutline(
|
2026-04-08 02:52:28 +08:00
|
|
|
layout.checkboxRect,
|
|
|
|
|
palette.checkboxBorderColor,
|
2026-04-07 17:55:42 +08:00
|
|
|
metrics.borderThickness,
|
2026-04-08 02:52:28 +08:00
|
|
|
metrics.checkboxRounding);
|
2026-04-07 17:55:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AppendUIEditorBoolFieldForeground(
|
|
|
|
|
::XCEngine::UI::UIDrawList& drawList,
|
|
|
|
|
const UIEditorBoolFieldLayout& layout,
|
|
|
|
|
const UIEditorBoolFieldSpec& spec,
|
|
|
|
|
const UIEditorBoolFieldPalette& palette,
|
|
|
|
|
const UIEditorBoolFieldMetrics& metrics) {
|
2026-04-08 02:52:28 +08:00
|
|
|
drawList.PushClipRect(ResolveUIEditorTextClipRect(layout.labelRect, metrics.labelFontSize));
|
2026-04-07 17:55:42 +08:00
|
|
|
drawList.AddText(
|
2026-04-08 02:52:28 +08:00
|
|
|
::XCEngine::UI::UIPoint(
|
|
|
|
|
layout.labelRect.x,
|
|
|
|
|
ResolveUIEditorTextTop(layout.labelRect, metrics.labelFontSize, metrics.labelTextInsetY)),
|
2026-04-07 17:55:42 +08:00
|
|
|
spec.label,
|
|
|
|
|
palette.labelColor,
|
2026-04-08 02:52:28 +08:00
|
|
|
metrics.labelFontSize);
|
2026-04-07 17:55:42 +08:00
|
|
|
drawList.PopClipRect();
|
|
|
|
|
|
2026-04-08 02:52:28 +08:00
|
|
|
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);
|
|
|
|
|
}
|
2026-04-07 17:55:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AppendUIEditorBoolField(
|
|
|
|
|
::XCEngine::UI::UIDrawList& drawList,
|
|
|
|
|
const ::XCEngine::UI::UIRect& bounds,
|
|
|
|
|
const UIEditorBoolFieldSpec& spec,
|
|
|
|
|
const UIEditorBoolFieldState& state,
|
|
|
|
|
const UIEditorBoolFieldPalette& palette,
|
|
|
|
|
const UIEditorBoolFieldMetrics& metrics) {
|
|
|
|
|
const UIEditorBoolFieldLayout layout = BuildUIEditorBoolFieldLayout(bounds, spec, metrics);
|
|
|
|
|
AppendUIEditorBoolFieldBackground(drawList, layout, spec, state, palette, metrics);
|
|
|
|
|
AppendUIEditorBoolFieldForeground(drawList, layout, spec, palette, metrics);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace XCEngine::UI::Editor::Widgets
|