Files
XCEngine/new_editor/src/Collections/UIEditorListView.cpp

197 lines
7.1 KiB
C++

#include <XCEditor/Collections/UIEditorListView.h>
#include <algorithm>
namespace XCEngine::UI::Editor::Widgets {
namespace {
float ClampNonNegative(float value) {
return (std::max)(value, 0.0f);
}
float ResolveListViewRowHeight(
const UIEditorListViewItem& item,
const UIEditorListViewMetrics& metrics) {
return item.desiredHeight > 0.0f ? item.desiredHeight : metrics.rowHeight;
}
} // namespace
bool IsUIEditorListViewPointInside(
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 FindUIEditorListViewItemIndex(
const std::vector<UIEditorListViewItem>& items,
std::string_view itemId) {
for (std::size_t itemIndex = 0u; itemIndex < items.size(); ++itemIndex) {
if (items[itemIndex].itemId == itemId) {
return itemIndex;
}
}
return UIEditorListViewInvalidIndex;
}
UIEditorListViewLayout BuildUIEditorListViewLayout(
const ::XCEngine::UI::UIRect& bounds,
const std::vector<UIEditorListViewItem>& items,
const UIEditorListViewMetrics& metrics) {
UIEditorListViewLayout layout = {};
layout.bounds = ::XCEngine::UI::UIRect(
bounds.x,
bounds.y,
ClampNonNegative(bounds.width),
ClampNonNegative(bounds.height));
layout.itemIndices.reserve(items.size());
layout.rowRects.reserve(items.size());
layout.primaryTextRects.reserve(items.size());
layout.secondaryTextRects.reserve(items.size());
layout.hasSecondaryText.reserve(items.size());
float rowY = layout.bounds.y;
for (std::size_t itemIndex = 0u; itemIndex < items.size(); ++itemIndex) {
const UIEditorListViewItem& item = items[itemIndex];
const bool hasSecondaryText = !item.secondaryText.empty();
const float rowHeight = ResolveListViewRowHeight(item, metrics);
const ::XCEngine::UI::UIRect rowRect(
layout.bounds.x,
rowY,
layout.bounds.width,
rowHeight);
const float textX = rowRect.x + ClampNonNegative(metrics.horizontalPadding);
const float textWidth =
(std::max)(0.0f, rowRect.width - ClampNonNegative(metrics.horizontalPadding) * 2.0f);
const ::XCEngine::UI::UIRect primaryTextRect(
textX,
rowRect.y + (hasSecondaryText
? ClampNonNegative(metrics.primaryTextInsetY)
: ClampNonNegative(metrics.singleLineTextInsetY)),
textWidth,
hasSecondaryText ? 14.0f : 18.0f);
const ::XCEngine::UI::UIRect secondaryTextRect(
textX,
rowRect.y + ClampNonNegative(metrics.secondaryTextInsetY),
textWidth,
hasSecondaryText ? 12.0f : 0.0f);
layout.itemIndices.push_back(itemIndex);
layout.rowRects.push_back(rowRect);
layout.primaryTextRects.push_back(primaryTextRect);
layout.secondaryTextRects.push_back(secondaryTextRect);
layout.hasSecondaryText.push_back(hasSecondaryText);
rowY += rowHeight + ClampNonNegative(metrics.rowGap);
}
return layout;
}
UIEditorListViewHitTarget HitTestUIEditorListView(
const UIEditorListViewLayout& layout,
const ::XCEngine::UI::UIPoint& point) {
for (std::size_t visibleIndex = 0u; visibleIndex < layout.rowRects.size(); ++visibleIndex) {
if (!IsUIEditorListViewPointInside(layout.rowRects[visibleIndex], point)) {
continue;
}
UIEditorListViewHitTarget target = {};
target.kind = UIEditorListViewHitTargetKind::Row;
target.visibleIndex = visibleIndex;
target.itemIndex = layout.itemIndices[visibleIndex];
return target;
}
return {};
}
void AppendUIEditorListViewBackground(
::XCEngine::UI::UIDrawList& drawList,
const UIEditorListViewLayout& layout,
const std::vector<UIEditorListViewItem>& items,
const ::XCEngine::UI::Widgets::UISelectionModel& selectionModel,
const UIEditorListViewState& state,
const UIEditorListViewPalette& palette,
const UIEditorListViewMetrics& metrics) {
drawList.AddFilledRect(layout.bounds, palette.surfaceColor, metrics.cornerRounding);
drawList.AddRectOutline(
layout.bounds,
state.focused ? palette.focusedBorderColor : palette.borderColor,
state.focused ? metrics.focusedBorderThickness : metrics.borderThickness,
metrics.cornerRounding);
for (std::size_t visibleIndex = 0u; visibleIndex < layout.rowRects.size(); ++visibleIndex) {
const UIEditorListViewItem& item = items[layout.itemIndices[visibleIndex]];
const bool selected = selectionModel.IsSelected(item.itemId);
const bool hovered = state.hoveredItemId == item.itemId;
if (!selected && !hovered) {
continue;
}
const ::XCEngine::UI::UIColor rowColor =
selected
? (state.focused ? palette.rowSelectedFocusedColor : palette.rowSelectedColor)
: palette.rowHoverColor;
drawList.AddFilledRect(layout.rowRects[visibleIndex], rowColor, metrics.cornerRounding);
}
}
void AppendUIEditorListViewForeground(
::XCEngine::UI::UIDrawList& drawList,
const UIEditorListViewLayout& layout,
const std::vector<UIEditorListViewItem>& items,
const UIEditorListViewPalette& palette,
const UIEditorListViewMetrics&) {
drawList.PushClipRect(layout.bounds);
for (std::size_t visibleIndex = 0u; visibleIndex < layout.rowRects.size(); ++visibleIndex) {
const UIEditorListViewItem& item = items[layout.itemIndices[visibleIndex]];
drawList.PushClipRect(layout.rowRects[visibleIndex]);
drawList.AddText(
::XCEngine::UI::UIPoint(
layout.primaryTextRects[visibleIndex].x,
layout.primaryTextRects[visibleIndex].y),
item.primaryText,
palette.primaryTextColor,
12.0f);
if (layout.hasSecondaryText[visibleIndex]) {
drawList.AddText(
::XCEngine::UI::UIPoint(
layout.secondaryTextRects[visibleIndex].x,
layout.secondaryTextRects[visibleIndex].y),
item.secondaryText,
palette.secondaryTextColor,
11.0f);
}
drawList.PopClipRect();
}
drawList.PopClipRect();
}
void AppendUIEditorListView(
::XCEngine::UI::UIDrawList& drawList,
const ::XCEngine::UI::UIRect& bounds,
const std::vector<UIEditorListViewItem>& items,
const ::XCEngine::UI::Widgets::UISelectionModel& selectionModel,
const UIEditorListViewState& state,
const UIEditorListViewPalette& palette,
const UIEditorListViewMetrics& metrics) {
const UIEditorListViewLayout layout =
BuildUIEditorListViewLayout(bounds, items, metrics);
AppendUIEditorListViewBackground(
drawList,
layout,
items,
selectionModel,
state,
palette,
metrics);
AppendUIEditorListViewForeground(drawList, layout, items, palette, metrics);
}
} // namespace XCEngine::UI::Editor::Widgets