use crate::UiHost;
use fret_core::{
AppWindowId, Axis, CursorIcon, InternalDragKind, KeyCode, Modifiers, MouseButton, Point,
PointerId, PointerType, Rect, UiServices,
};
use fret_runtime::{
ActionId, CommandId, DefaultAction, DragHost, DragKindId, DragSession, Effect, Model,
ModelStore, PlatformTextInputQuery, PlatformTextInputQueryResult, TickId, TimerToken,
Utf16Range, WeakModel,
};
use std::any::{Any, TypeId};
use std::sync::Arc;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ActionCx {
pub window: AppWindowId,
pub target: crate::GlobalElementId,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ActivateReason {
Pointer,
Keyboard,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PressablePointerDownResult {
Continue,
SkipDefault,
SkipDefaultAndStopPropagation,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PressablePointerUpResult {
Continue,
SkipActivate,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DismissReason {
Escape,
OutsidePress {
pointer: Option<OutsidePressCx>,
},
FocusOutside,
Scroll,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DismissRequestCx {
pub reason: DismissReason,
default_prevented: bool,
}
impl DismissRequestCx {
pub fn new(reason: DismissReason) -> Self {
Self {
reason,
default_prevented: false,
}
}
pub fn prevent_default(&mut self) {
self.default_prevented = true;
}
pub fn default_prevented(&self) -> bool {
self.default_prevented
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct DismissibleLastDismissRequest {
pub tick_id: TickId,
pub reason: Option<DismissReason>,
pub default_prevented: bool,
}
impl Default for DismissibleLastDismissRequest {
fn default() -> Self {
Self {
tick_id: TickId(0),
reason: None,
default_prevented: false,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct AutoFocusRequestCx {
default_prevented: bool,
}
impl AutoFocusRequestCx {
pub fn new() -> Self {
Self {
default_prevented: false,
}
}
pub fn prevent_default(&mut self) {
self.default_prevented = true;
}
pub fn default_prevented(&self) -> bool {
self.default_prevented
}
}
impl Default for AutoFocusRequestCx {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct OutsidePressCx {
pub pointer_id: PointerId,
pub pointer_type: PointerType,
pub button: MouseButton,
pub modifiers: Modifiers,
pub click_count: u8,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct PointerDownCx {
pub pointer_id: PointerId,
pub position: Point,
pub position_local: Point,
pub position_window: Option<Point>,
pub tick_id: TickId,
pub pixels_per_point: f32,
pub button: MouseButton,
pub modifiers: Modifiers,
pub click_count: u8,
pub pointer_type: PointerType,
pub hit_is_text_input: bool,
pub hit_is_pressable: bool,
pub hit_pressable_target: Option<crate::GlobalElementId>,
pub hit_pressable_target_in_descendant_subtree: bool,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct PointerMoveCx {
pub pointer_id: PointerId,
pub position: Point,
pub position_local: Point,
pub position_window: Option<Point>,
pub tick_id: TickId,
pub pixels_per_point: f32,
pub velocity_window: Option<Point>,
pub buttons: fret_core::MouseButtons,
pub modifiers: Modifiers,
pub pointer_type: PointerType,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct WheelCx {
pub pointer_id: PointerId,
pub position: Point,
pub position_local: Point,
pub position_window: Option<Point>,
pub tick_id: TickId,
pub pixels_per_point: f32,
pub delta: Point,
pub delta_window: Option<Point>,
pub modifiers: Modifiers,
pub pointer_type: PointerType,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct PinchGestureCx {
pub pointer_id: PointerId,
pub position: Point,
pub position_local: Point,
pub position_window: Option<Point>,
pub tick_id: TickId,
pub pixels_per_point: f32,
pub delta: f32,
pub modifiers: Modifiers,
pub pointer_type: PointerType,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct PointerCancelCx {
pub pointer_id: PointerId,
pub position: Option<Point>,
pub position_local: Option<Point>,
pub position_window: Option<Point>,
pub tick_id: TickId,
pub pixels_per_point: f32,
pub buttons: fret_core::MouseButtons,
pub modifiers: Modifiers,
pub pointer_type: PointerType,
pub reason: fret_core::PointerCancelReason,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct PointerUpCx {
pub pointer_id: PointerId,
pub position: Point,
pub position_local: Point,
pub position_window: Option<Point>,
pub tick_id: TickId,
pub pixels_per_point: f32,
pub velocity_window: Option<Point>,
pub button: MouseButton,
pub modifiers: Modifiers,
pub is_click: bool,
pub click_count: u8,
pub pointer_type: PointerType,
pub down_hit_pressable_target: Option<crate::GlobalElementId>,
pub down_hit_pressable_target_in_descendant_subtree: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct KeyDownCx {
pub key: KeyCode,
pub modifiers: Modifiers,
pub repeat: bool,
pub ime_composing: bool,
}
pub trait UiActionHost {
fn models_mut(&mut self) -> &mut ModelStore;
fn push_effect(&mut self, effect: Effect);
fn request_redraw(&mut self, window: AppWindowId);
fn next_timer_token(&mut self) -> TimerToken;
fn next_clipboard_token(&mut self) -> fret_runtime::ClipboardToken;
fn next_share_sheet_token(&mut self) -> fret_runtime::ShareSheetToken;
fn set_router_command_availability(
&mut self,
_window: AppWindowId,
_can_back: bool,
_can_forward: bool,
) {
}
fn record_transient_event(&mut self, _cx: ActionCx, _key: u64) {}
fn notify(&mut self, _cx: ActionCx) {}
fn record_pending_command_dispatch_source(
&mut self,
_cx: ActionCx,
_command: &CommandId,
_reason: ActivateReason,
) {
}
fn record_pending_action_payload(
&mut self,
_cx: ActionCx,
_action: &ActionId,
_payload: Box<dyn Any + Send + Sync>,
) {
}
fn consume_pending_action_payload(
&mut self,
_window: AppWindowId,
_action: &ActionId,
) -> Option<Box<dyn Any + Send + Sync>> {
None
}
fn dispatch_command(&mut self, window: Option<AppWindowId>, command: CommandId) {
self.push_effect(Effect::Command { window, command });
}
}
pub trait UiFocusActionHost: UiActionHost {
fn request_focus(&mut self, target: crate::GlobalElementId);
}
pub trait UiDragActionHost: UiActionHost {
fn begin_drag_with_kind(
&mut self,
pointer_id: PointerId,
kind: DragKindId,
source_window: AppWindowId,
start: Point,
);
fn begin_cross_window_drag_with_kind(
&mut self,
pointer_id: PointerId,
kind: DragKindId,
source_window: AppWindowId,
start: Point,
);
fn drag(&self, pointer_id: PointerId) -> Option<&DragSession>;
fn drag_mut(&mut self, pointer_id: PointerId) -> Option<&mut DragSession>;
fn cancel_drag(&mut self, pointer_id: PointerId);
}
pub trait UiActionHostExt: UiActionHost {
fn read_weak_model<T: Any, R>(
&mut self,
model: &WeakModel<T>,
f: impl FnOnce(&T) -> R,
) -> Option<R> {
let model = model.upgrade()?;
self.models_mut().read(&model, f).ok()
}
fn update_model<T: Any, R>(
&mut self,
model: &Model<T>,
f: impl FnOnce(&mut T) -> R,
) -> Option<R> {
self.models_mut().update(model, f).ok()
}
fn update_weak_model<T: Any, R>(
&mut self,
model: &WeakModel<T>,
f: impl FnOnce(&mut T) -> R,
) -> Option<R> {
let model = model.upgrade()?;
self.update_model(&model, f)
}
}
impl<T> UiActionHostExt for T where T: UiActionHost + ?Sized {}
pub trait UiPointerActionHost: UiFocusActionHost + UiDragActionHost {
fn bounds(&self) -> fret_core::Rect;
fn capture_pointer(&mut self);
fn release_pointer_capture(&mut self);
fn set_cursor_icon(&mut self, icon: CursorIcon);
fn prevent_default(&mut self, action: DefaultAction);
fn invalidate(&mut self, _invalidation: crate::widget::Invalidation) {}
}
pub struct UiActionHostAdapter<'a, H: UiHost> {
pub app: &'a mut H,
}
impl<'a, H: UiHost> UiActionHost for UiActionHostAdapter<'a, H> {
fn models_mut(&mut self) -> &mut ModelStore {
self.app.models_mut()
}
fn push_effect(&mut self, effect: Effect) {
self.app.push_effect(effect);
}
fn request_redraw(&mut self, window: AppWindowId) {
self.app.request_redraw(window);
}
fn next_timer_token(&mut self) -> TimerToken {
self.app.next_timer_token()
}
fn next_clipboard_token(&mut self) -> fret_runtime::ClipboardToken {
self.app.next_clipboard_token()
}
fn next_share_sheet_token(&mut self) -> fret_runtime::ShareSheetToken {
self.app.next_share_sheet_token()
}
fn set_router_command_availability(
&mut self,
window: AppWindowId,
can_back: bool,
can_forward: bool,
) {
self.app.with_global_mut(
fret_runtime::WindowCommandAvailabilityService::default,
|svc, _app| {
svc.set_router_availability(window, can_back, can_forward);
},
);
}
fn record_transient_event(&mut self, cx: ActionCx, key: u64) {
crate::elements::record_transient_event(&mut *self.app, cx.window, cx.target, key);
}
fn record_pending_command_dispatch_source(
&mut self,
cx: ActionCx,
command: &CommandId,
reason: ActivateReason,
) {
let kind = match reason {
ActivateReason::Pointer => fret_runtime::CommandDispatchSourceKindV1::Pointer,
ActivateReason::Keyboard => fret_runtime::CommandDispatchSourceKindV1::Keyboard,
};
let source = fret_runtime::CommandDispatchSourceV1 {
kind,
element: Some(cx.target.0),
test_id: None,
};
self.app.with_global_mut(
fret_runtime::WindowPendingCommandDispatchSourceService::default,
|svc, app| {
svc.record(cx.window, app.tick_id(), command.clone(), source);
},
);
}
}
impl<'a, H: UiHost> UiDragActionHost for UiActionHostAdapter<'a, H> {
fn begin_drag_with_kind(
&mut self,
pointer_id: PointerId,
kind: DragKindId,
source_window: AppWindowId,
start: Point,
) {
DragHost::begin_drag_with_kind(&mut *self.app, pointer_id, kind, source_window, start, ());
}
fn begin_cross_window_drag_with_kind(
&mut self,
pointer_id: PointerId,
kind: DragKindId,
source_window: AppWindowId,
start: Point,
) {
DragHost::begin_cross_window_drag_with_kind(
&mut *self.app,
pointer_id,
kind,
source_window,
start,
(),
);
}
fn drag(&self, pointer_id: PointerId) -> Option<&DragSession> {
DragHost::drag(&*self.app, pointer_id)
}
fn drag_mut(&mut self, pointer_id: PointerId) -> Option<&mut DragSession> {
DragHost::drag_mut(&mut *self.app, pointer_id)
}
fn cancel_drag(&mut self, pointer_id: PointerId) {
DragHost::cancel_drag(&mut *self.app, pointer_id);
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct InternalDragCx {
pub pointer_id: PointerId,
pub position: Point,
pub position_window: Option<Point>,
pub tick_id: TickId,
pub kind: InternalDragKind,
pub modifiers: Modifiers,
}
pub type OnInternalDrag =
Arc<dyn Fn(&mut dyn UiDragActionHost, ActionCx, InternalDragCx) -> bool + 'static>;
#[derive(Default)]
pub(crate) struct InternalDragActionHooks {
pub on_internal_drag: Option<OnInternalDrag>,
}
pub type OnExternalDrag =
Arc<dyn Fn(&mut dyn UiActionHost, ActionCx, &fret_core::ExternalDragEvent) -> bool + 'static>;
#[derive(Default)]
pub(crate) struct ExternalDragActionHooks {
pub on_external_drag: Option<OnExternalDrag>,
}
pub type OnActivate = Arc<dyn Fn(&mut dyn UiActionHost, ActionCx, ActivateReason) + 'static>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SelectableTextSpanActivation {
pub tag: Arc<str>,
pub range: std::ops::Range<usize>,
}
pub type OnSelectableTextActivateSpan = Arc<
dyn Fn(&mut dyn UiActionHost, ActionCx, ActivateReason, SelectableTextSpanActivation) + 'static,
>;
#[derive(Default)]
pub(crate) struct SelectableTextActionHooks {
pub on_activate_span: Option<OnSelectableTextActivateSpan>,
}
pub type OnPressablePointerDown = Arc<
dyn Fn(&mut dyn UiPointerActionHost, ActionCx, PointerDownCx) -> PressablePointerDownResult
+ 'static,
>;
pub type OnPressablePointerMove =
Arc<dyn Fn(&mut dyn UiPointerActionHost, ActionCx, PointerMoveCx) -> bool + 'static>;
pub type OnPressablePointerUp = Arc<
dyn Fn(&mut dyn UiPointerActionHost, ActionCx, PointerUpCx) -> PressablePointerUpResult
+ 'static,
>;
pub type OnPressableClipboardWriteCompleted = Arc<
dyn Fn(
&mut dyn UiActionHost,
ActionCx,
fret_core::ClipboardToken,
&fret_core::ClipboardWriteOutcome,
) -> bool
+ 'static,
>;
#[derive(Default)]
pub(crate) struct PressableActionHooks {
pub on_activate: Option<OnActivate>,
pub on_pointer_down: Option<OnPressablePointerDown>,
pub on_pointer_move: Option<OnPressablePointerMove>,
pub on_pointer_up: Option<OnPressablePointerUp>,
pub on_clipboard_write_completed: Option<OnPressableClipboardWriteCompleted>,
}
pub type OnHoverChange = Arc<dyn Fn(&mut dyn UiActionHost, ActionCx, bool) + 'static>;
#[derive(Default)]
pub(crate) struct PressableHoverActionHooks {
pub on_hover_change: Option<OnHoverChange>,
}
pub type OnDismissRequest =
Arc<dyn Fn(&mut dyn UiActionHost, ActionCx, &mut DismissRequestCx) + 'static>;
pub type OnOpenAutoFocus =
Arc<dyn Fn(&mut dyn UiFocusActionHost, ActionCx, &mut AutoFocusRequestCx) + 'static>;
pub type OnCloseAutoFocus =
Arc<dyn Fn(&mut dyn UiFocusActionHost, ActionCx, &mut AutoFocusRequestCx) + 'static>;
pub type OnDismissiblePointerMove =
Arc<dyn Fn(&mut dyn UiActionHost, ActionCx, PointerMoveCx) -> bool + 'static>;
#[derive(Default)]
pub(crate) struct DismissibleActionHooks {
pub on_dismiss_request: Option<OnDismissRequest>,
pub on_pointer_move: Option<OnDismissiblePointerMove>,
}
pub type OnTextInputRegionTextInput =
Arc<dyn Fn(&mut dyn UiActionHost, ActionCx, &str) -> bool + 'static>;
pub type OnTextInputRegionIme =
Arc<dyn Fn(&mut dyn UiActionHost, ActionCx, &fret_core::ImeEvent) -> bool + 'static>;
pub type OnTextInputRegionClipboardReadText =
Arc<dyn Fn(&mut dyn UiActionHost, ActionCx, fret_core::ClipboardToken, &str) -> bool + 'static>;
pub type OnTextInputRegionClipboardReadFailed = Arc<
dyn Fn(
&mut dyn UiActionHost,
ActionCx,
fret_core::ClipboardToken,
&fret_core::ClipboardAccessError,
) -> bool
+ 'static,
>;
pub type OnTextInputRegionSetSelection =
Arc<dyn Fn(&mut dyn UiActionHost, ActionCx, u32, u32) -> bool + 'static>;
pub type OnTextInputRegionPlatformTextInputQuery = Arc<
dyn Fn(
&mut dyn UiActionHost,
ActionCx,
&mut dyn UiServices,
Rect,
f32,
&crate::element::TextInputRegionProps,
&PlatformTextInputQuery,
) -> Option<PlatformTextInputQueryResult>
+ 'static,
>;
pub type OnTextInputRegionPlatformTextInputReplaceTextInRangeUtf16 = Arc<
dyn Fn(
&mut dyn UiActionHost,
ActionCx,
&mut dyn UiServices,
Rect,
f32,
&crate::element::TextInputRegionProps,
Utf16Range,
&str,
) -> bool
+ 'static,
>;
pub type OnTextInputRegionPlatformTextInputReplaceAndMarkTextInRangeUtf16 = Arc<
dyn Fn(
&mut dyn UiActionHost,
ActionCx,
&mut dyn UiServices,
Rect,
f32,
&crate::element::TextInputRegionProps,
Utf16Range,
&str,
Option<Utf16Range>,
Option<Utf16Range>,
) -> bool
+ 'static,
>;
#[derive(Default)]
pub(crate) struct TextInputRegionActionHooks {
pub on_text_input: Option<OnTextInputRegionTextInput>,
pub on_ime: Option<OnTextInputRegionIme>,
pub on_clipboard_read_text: Option<OnTextInputRegionClipboardReadText>,
pub on_clipboard_read_failed: Option<OnTextInputRegionClipboardReadFailed>,
pub on_set_selection: Option<OnTextInputRegionSetSelection>,
pub on_platform_text_input_query: Option<OnTextInputRegionPlatformTextInputQuery>,
pub on_platform_text_input_replace_text_in_range_utf16:
Option<OnTextInputRegionPlatformTextInputReplaceTextInRangeUtf16>,
pub on_platform_text_input_replace_and_mark_text_in_range_utf16:
Option<OnTextInputRegionPlatformTextInputReplaceAndMarkTextInRangeUtf16>,
}
pub type OnPointerDown =
Arc<dyn Fn(&mut dyn UiPointerActionHost, ActionCx, PointerDownCx) -> bool + 'static>;
pub type OnPointerMove =
Arc<dyn Fn(&mut dyn UiPointerActionHost, ActionCx, PointerMoveCx) -> bool + 'static>;
pub type OnWheel = Arc<dyn Fn(&mut dyn UiPointerActionHost, ActionCx, WheelCx) -> bool + 'static>;
pub type OnPinchGesture =
Arc<dyn Fn(&mut dyn UiPointerActionHost, ActionCx, PinchGestureCx) -> bool + 'static>;
pub type OnPointerUp =
Arc<dyn Fn(&mut dyn UiPointerActionHost, ActionCx, PointerUpCx) -> bool + 'static>;
pub type OnPointerCancel =
Arc<dyn Fn(&mut dyn UiPointerActionHost, ActionCx, PointerCancelCx) -> bool + 'static>;
#[derive(Default)]
pub(crate) struct PointerActionHooks {
pub on_pointer_down: Option<OnPointerDown>,
pub on_pointer_move: Option<OnPointerMove>,
pub on_wheel: Option<OnWheel>,
pub on_pinch_gesture: Option<OnPinchGesture>,
pub on_pointer_up: Option<OnPointerUp>,
pub on_pointer_cancel: Option<OnPointerCancel>,
}
pub type OnKeyDown = Arc<dyn Fn(&mut dyn UiFocusActionHost, ActionCx, KeyDownCx) -> bool + 'static>;
#[derive(Default)]
pub(crate) struct KeyActionHooks {
pub on_key_down_capture: Option<OnKeyDown>,
pub on_key_down: Option<OnKeyDown>,
pub on_key_down_focused: Option<OnKeyDown>,
}
pub type OnCommand = Arc<dyn Fn(&mut dyn UiFocusActionHost, ActionCx, CommandId) -> bool + 'static>;
#[derive(Default)]
pub(crate) struct CommandActionHooks {
pub on_command: Option<OnCommand>,
}
#[derive(Clone)]
pub(crate) struct ActionRouteOwnerHooks {
pub owner: TypeId,
pub on_command: Option<OnCommand>,
pub on_command_availability: Option<OnCommandAvailability>,
}
#[derive(Default, Clone)]
pub(crate) struct ActionRouteHooks {
owners: Vec<ActionRouteOwnerHooks>,
}
impl ActionRouteHooks {
fn owner_mut(&mut self, owner: TypeId) -> &mut ActionRouteOwnerHooks {
if let Some(index) = self.owners.iter().position(|hooks| hooks.owner == owner) {
return &mut self.owners[index];
}
self.owners.push(ActionRouteOwnerHooks {
owner,
on_command: None,
on_command_availability: None,
});
self.owners
.last_mut()
.expect("action route owner slot must exist after insertion")
}
pub(crate) fn set_on_command(&mut self, owner: TypeId, handler: OnCommand) {
self.owner_mut(owner).on_command = Some(handler);
}
pub(crate) fn add_on_command(&mut self, owner: TypeId, handler: OnCommand) {
let hooks = self.owner_mut(owner);
hooks.on_command = match hooks.on_command.clone() {
None => Some(handler),
Some(prev) => {
let next = handler.clone();
Some(Arc::new(move |host, cx, command| {
prev(host, cx, command.clone()) || next(host, cx, command)
}))
}
};
}
pub(crate) fn clear_on_command(&mut self, owner: TypeId) {
self.owner_mut(owner).on_command = None;
}
pub(crate) fn on_command_handlers(&self) -> Vec<OnCommand> {
self.owners
.iter()
.filter_map(|hooks| hooks.on_command.clone())
.collect()
}
pub(crate) fn set_on_command_availability(
&mut self,
owner: TypeId,
handler: OnCommandAvailability,
) {
self.owner_mut(owner).on_command_availability = Some(handler);
}
pub(crate) fn add_on_command_availability(
&mut self,
owner: TypeId,
handler: OnCommandAvailability,
) {
let hooks = self.owner_mut(owner);
hooks.on_command_availability = match hooks.on_command_availability.clone() {
None => Some(handler),
Some(prev) => {
let next = handler.clone();
Some(Arc::new(move |host, cx, command| {
let availability = prev(host, cx.clone(), command.clone());
if availability != crate::widget::CommandAvailability::NotHandled {
return availability;
}
next(host, cx, command)
}))
}
};
}
pub(crate) fn clear_on_command_availability(&mut self, owner: TypeId) {
self.owner_mut(owner).on_command_availability = None;
}
pub(crate) fn on_command_availability_handlers(&self) -> Vec<OnCommandAvailability> {
self.owners
.iter()
.filter_map(|hooks| hooks.on_command_availability.clone())
.collect()
}
}
pub trait UiCommandAvailabilityActionHost {
fn models_mut(&mut self) -> &mut fret_runtime::ModelStore;
}
#[derive(Debug, Clone)]
pub struct CommandAvailabilityActionCx {
pub window: fret_core::AppWindowId,
pub target: crate::GlobalElementId,
pub node: fret_core::NodeId,
pub focus: Option<fret_core::NodeId>,
pub focus_in_subtree: bool,
pub input_ctx: fret_runtime::InputContext,
}
pub type OnCommandAvailability = Arc<
dyn Fn(
&mut dyn UiCommandAvailabilityActionHost,
CommandAvailabilityActionCx,
CommandId,
) -> crate::widget::CommandAvailability
+ 'static,
>;
#[derive(Default)]
pub(crate) struct CommandAvailabilityActionHooks {
pub on_command_availability: Option<OnCommandAvailability>,
}
pub type OnTimer = Arc<dyn Fn(&mut dyn UiFocusActionHost, ActionCx, TimerToken) -> bool + 'static>;
#[derive(Default)]
pub(crate) struct TimerActionHooks {
pub on_timer: Option<OnTimer>,
}
#[derive(Debug, Clone)]
pub struct RovingTypeaheadCx {
pub input: char,
pub current: Option<usize>,
pub len: usize,
pub disabled: Arc<[bool]>,
pub wrap: bool,
pub tick: u64,
}
pub type OnRovingActiveChange = Arc<dyn Fn(&mut dyn UiActionHost, ActionCx, usize) + 'static>;
pub type OnRovingTypeahead =
Arc<dyn Fn(&mut dyn UiActionHost, ActionCx, RovingTypeaheadCx) -> Option<usize> + 'static>;
#[derive(Debug, Clone)]
pub struct RovingNavigateCx {
pub key: KeyCode,
pub modifiers: Modifiers,
pub repeat: bool,
pub axis: Axis,
pub current: Option<usize>,
pub len: usize,
pub disabled: Arc<[bool]>,
pub wrap: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RovingNavigateResult {
NotHandled,
Handled { target: Option<usize> },
}
pub type OnRovingNavigate = Arc<
dyn Fn(&mut dyn UiActionHost, ActionCx, RovingNavigateCx) -> RovingNavigateResult + 'static,
>;
#[derive(Default)]
pub(crate) struct RovingActionHooks {
pub on_active_change: Option<OnRovingActiveChange>,
pub on_typeahead: Option<OnRovingTypeahead>,
pub on_navigate: Option<OnRovingNavigate>,
pub on_key_down: Vec<OnKeyDown>,
}