Files
XCEngine/engine/include/XCEngine/UI/Widgets/UIFlatHierarchyHelpers.h

168 lines
4.8 KiB
C++

#pragma once
#include <cstddef>
#include <span>
#include <utility>
namespace XCEngine {
namespace UI {
namespace Widgets {
inline constexpr std::size_t kInvalidUIFlatHierarchyItemOffset = static_cast<std::size_t>(-1);
namespace Detail {
template <typename ResolveDepthFn>
float ResolveUIFlatHierarchyDepth(
std::span<const std::size_t> itemIndices,
std::size_t itemOffset,
ResolveDepthFn&& resolveDepth) {
if (itemOffset >= itemIndices.size()) {
return 0.0f;
}
const float depth = static_cast<float>(resolveDepth(itemIndices[itemOffset]));
return depth > 0.0f ? depth : 0.0f;
}
} // namespace Detail
template <typename ResolveDepthFn>
bool UIFlatHierarchyHasChildren(
std::span<const std::size_t> itemIndices,
std::size_t itemOffset,
ResolveDepthFn&& resolveDepth) {
if (itemOffset >= itemIndices.size()) {
return false;
}
const float itemDepth = Detail::ResolveUIFlatHierarchyDepth(
itemIndices,
itemOffset,
std::forward<ResolveDepthFn>(resolveDepth));
for (std::size_t candidateOffset = itemOffset + 1u;
candidateOffset < itemIndices.size();
++candidateOffset) {
const float candidateDepth = Detail::ResolveUIFlatHierarchyDepth(
itemIndices,
candidateOffset,
std::forward<ResolveDepthFn>(resolveDepth));
if (candidateDepth <= itemDepth) {
break;
}
return true;
}
return false;
}
template <typename ResolveDepthFn>
std::size_t UIFlatHierarchyFindParentOffset(
std::span<const std::size_t> itemIndices,
std::size_t itemOffset,
ResolveDepthFn&& resolveDepth) {
if (itemOffset >= itemIndices.size()) {
return kInvalidUIFlatHierarchyItemOffset;
}
const float itemDepth = Detail::ResolveUIFlatHierarchyDepth(
itemIndices,
itemOffset,
std::forward<ResolveDepthFn>(resolveDepth));
if (itemDepth <= 0.0f) {
return kInvalidUIFlatHierarchyItemOffset;
}
for (std::size_t candidateOffset = itemOffset; candidateOffset > 0u; --candidateOffset) {
const std::size_t previousOffset = candidateOffset - 1u;
const float previousDepth = Detail::ResolveUIFlatHierarchyDepth(
itemIndices,
previousOffset,
std::forward<ResolveDepthFn>(resolveDepth));
if (previousDepth < itemDepth) {
return previousOffset;
}
}
return kInvalidUIFlatHierarchyItemOffset;
}
template <typename ResolveDepthFn, typename IsExpandedFn>
bool UIFlatHierarchyIsVisible(
std::span<const std::size_t> itemIndices,
std::size_t itemOffset,
ResolveDepthFn&& resolveDepth,
IsExpandedFn&& isExpanded) {
if (itemOffset >= itemIndices.size()) {
return false;
}
float requiredAncestorDepth = Detail::ResolveUIFlatHierarchyDepth(
itemIndices,
itemOffset,
std::forward<ResolveDepthFn>(resolveDepth));
if (requiredAncestorDepth <= 0.0f) {
return true;
}
for (std::size_t candidateOffset = itemOffset;
candidateOffset > 0u && requiredAncestorDepth > 0.0f;
--candidateOffset) {
const std::size_t previousOffset = candidateOffset - 1u;
const float previousDepth = Detail::ResolveUIFlatHierarchyDepth(
itemIndices,
previousOffset,
std::forward<ResolveDepthFn>(resolveDepth));
if (previousDepth < requiredAncestorDepth) {
if (!isExpanded(itemIndices[previousOffset])) {
return false;
}
requiredAncestorDepth = previousDepth;
}
}
return true;
}
template <typename ResolveDepthFn, typename IsVisibleFn>
std::size_t UIFlatHierarchyFindFirstVisibleChildOffset(
std::span<const std::size_t> itemIndices,
std::size_t itemOffset,
ResolveDepthFn&& resolveDepth,
IsVisibleFn&& isVisible) {
if (!UIFlatHierarchyHasChildren(
itemIndices,
itemOffset,
std::forward<ResolveDepthFn>(resolveDepth))) {
return kInvalidUIFlatHierarchyItemOffset;
}
const float itemDepth = Detail::ResolveUIFlatHierarchyDepth(
itemIndices,
itemOffset,
std::forward<ResolveDepthFn>(resolveDepth));
for (std::size_t candidateOffset = itemOffset + 1u;
candidateOffset < itemIndices.size();
++candidateOffset) {
const float candidateDepth = Detail::ResolveUIFlatHierarchyDepth(
itemIndices,
candidateOffset,
std::forward<ResolveDepthFn>(resolveDepth));
if (candidateDepth <= itemDepth) {
break;
}
if (isVisible(itemIndices[candidateOffset])) {
return candidateOffset;
}
}
return kInvalidUIFlatHierarchyItemOffset;
}
} // namespace Widgets
} // namespace UI
} // namespace XCEngine