Add core popup overlay primitive
This commit is contained in:
113
engine/include/XCEngine/UI/Widgets/UIPopupOverlayModel.h
Normal file
113
engine/include/XCEngine/UI/Widgets/UIPopupOverlayModel.h
Normal file
@@ -0,0 +1,113 @@
|
||||
#pragma once
|
||||
|
||||
#include <XCEngine/UI/Input/UIInputPath.h>
|
||||
#include <XCEngine/UI/Types.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace UI {
|
||||
namespace Widgets {
|
||||
|
||||
enum class UIPopupPlacement : std::uint8_t {
|
||||
BottomStart = 0,
|
||||
BottomEnd,
|
||||
TopStart,
|
||||
TopEnd,
|
||||
RightStart,
|
||||
RightEnd,
|
||||
LeftStart,
|
||||
LeftEnd
|
||||
};
|
||||
|
||||
enum class UIPopupDismissReason : std::uint8_t {
|
||||
None = 0,
|
||||
Programmatic,
|
||||
EscapeKey,
|
||||
PointerOutside,
|
||||
FocusLoss
|
||||
};
|
||||
|
||||
struct UIPopupPlacementResult {
|
||||
UIRect rect = {};
|
||||
UIPopupPlacement effectivePlacement = UIPopupPlacement::BottomStart;
|
||||
bool clampedX = false;
|
||||
bool clampedY = false;
|
||||
};
|
||||
|
||||
struct UIPopupOverlayEntry {
|
||||
std::string popupId = {};
|
||||
std::string parentPopupId = {};
|
||||
UIRect anchorRect = {};
|
||||
UIInputPath anchorPath = {};
|
||||
UIInputPath surfacePath = {};
|
||||
UIPopupPlacement placement = UIPopupPlacement::BottomStart;
|
||||
bool dismissOnPointerOutside = true;
|
||||
bool dismissOnEscape = true;
|
||||
bool dismissOnFocusLoss = true;
|
||||
};
|
||||
|
||||
struct UIPopupOverlayMutationResult {
|
||||
bool changed = false;
|
||||
std::string openedPopupId = {};
|
||||
std::vector<std::string> closedPopupIds = {};
|
||||
UIPopupDismissReason dismissReason = UIPopupDismissReason::None;
|
||||
};
|
||||
|
||||
UIPopupPlacementResult ResolvePopupPlacementRect(
|
||||
const UIRect& anchorRect,
|
||||
const UISize& popupSize,
|
||||
const UIRect& viewportRect,
|
||||
UIPopupPlacement placement);
|
||||
|
||||
class UIPopupOverlayModel {
|
||||
public:
|
||||
static constexpr std::size_t InvalidIndex = static_cast<std::size_t>(-1);
|
||||
|
||||
const std::vector<UIPopupOverlayEntry>& GetPopupChain() const {
|
||||
return m_popupChain;
|
||||
}
|
||||
|
||||
bool HasOpenPopups() const {
|
||||
return !m_popupChain.empty();
|
||||
}
|
||||
|
||||
std::size_t GetPopupCount() const {
|
||||
return m_popupChain.size();
|
||||
}
|
||||
|
||||
const UIPopupOverlayEntry* GetRootPopup() const;
|
||||
const UIPopupOverlayEntry* GetTopmostPopup() const;
|
||||
const UIPopupOverlayEntry* FindPopup(std::string_view popupId) const;
|
||||
|
||||
UIPopupOverlayMutationResult OpenPopup(UIPopupOverlayEntry entry);
|
||||
UIPopupOverlayMutationResult ClosePopup(
|
||||
std::string_view popupId,
|
||||
UIPopupDismissReason dismissReason = UIPopupDismissReason::Programmatic);
|
||||
UIPopupOverlayMutationResult CloseAll(
|
||||
UIPopupDismissReason dismissReason = UIPopupDismissReason::Programmatic);
|
||||
UIPopupOverlayMutationResult DismissFromEscape();
|
||||
UIPopupOverlayMutationResult DismissFromPointerDown(const UIInputPath& hitPath);
|
||||
UIPopupOverlayMutationResult DismissFromFocusLoss(const UIInputPath& focusedPath);
|
||||
|
||||
private:
|
||||
std::size_t FindPopupIndex(std::string_view popupId) const;
|
||||
std::size_t FindDeepestContainingPopupIndex(const UIInputPath& path) const;
|
||||
UIPopupOverlayMutationResult CloseFromIndex(
|
||||
std::size_t index,
|
||||
UIPopupDismissReason dismissReason);
|
||||
|
||||
static bool PopupContainsPath(
|
||||
const UIPopupOverlayEntry& entry,
|
||||
const UIInputPath& path);
|
||||
|
||||
std::vector<UIPopupOverlayEntry> m_popupChain = {};
|
||||
};
|
||||
|
||||
} // namespace Widgets
|
||||
} // namespace UI
|
||||
} // namespace XCEngine
|
||||
Reference in New Issue
Block a user