Files
XCEngine/engine/include/XCEngine/UI/Input/UIInputRouter.h

105 lines
2.5 KiB
C++

#pragma once
#include "UIInputPath.h"
#include <XCEngine/UI/Types.h>
#include <cstdint>
#include <utility>
#include <vector>
namespace XCEngine {
namespace UI {
enum class UIInputRoutingPhase : std::uint8_t {
Capture = 0,
Target,
Bubble
};
enum class UIInputTargetKind : std::uint8_t {
None = 0,
Hovered,
Focused,
Captured
};
struct UIInputRouteContext {
UIInputPath hoveredPath = {};
UIInputPath focusedPath = {};
UIInputPath capturePath = {};
};
struct UIInputRoutingStep {
UIElementId elementId = 0;
UIInputRoutingPhase phase = UIInputRoutingPhase::Target;
bool isTargetElement = false;
};
struct UIInputRoutingPlan {
UIInputTargetKind targetKind = UIInputTargetKind::None;
UIInputPath targetPath = {};
std::vector<UIInputRoutingStep> steps = {};
bool HasTargetPath() const {
return !targetPath.Empty();
}
};
struct UIInputDispatchRequest {
const UIInputEvent* event = nullptr;
UIElementId elementId = 0;
UIInputRoutingPhase phase = UIInputRoutingPhase::Target;
UIInputTargetKind targetKind = UIInputTargetKind::None;
bool isTargetElement = false;
};
struct UIInputDispatchDecision {
bool handled = false;
bool stopPropagation = false;
};
struct UIInputDispatchResult {
UIInputRoutingPlan plan = {};
bool handled = false;
};
class UIInputRouter {
public:
static bool IsPointerEvent(UIInputEventType type);
static bool IsKeyboardEvent(UIInputEventType type);
static UIInputRoutingPlan BuildRoutingPlan(
const UIInputEvent& event,
const UIInputRouteContext& context);
template <typename HandlerFn>
static UIInputDispatchResult Dispatch(
const UIInputEvent& event,
const UIInputRouteContext& context,
HandlerFn&& handler) {
UIInputDispatchResult result = {};
result.plan = BuildRoutingPlan(event, context);
for (const UIInputRoutingStep& step : result.plan.steps) {
UIInputDispatchRequest request = {};
request.event = &event;
request.elementId = step.elementId;
request.phase = step.phase;
request.targetKind = result.plan.targetKind;
request.isTargetElement = step.isTargetElement;
const UIInputDispatchDecision decision = handler(request);
result.handled = result.handled || decision.handled;
if (decision.stopPropagation) {
break;
}
}
return result;
}
};
} // namespace UI
} // namespace XCEngine