use super::gesture_recognizers::GestureRecognizerCollection;
use super::text_input::TextInputMethodClientRequestedEventArgs;
use super::{
AccessKeyHandler, KeyBinding,
ContextRequestedEventArgs, Cursor, ICustomKeyboardNavigation, IScrollable, FocusChangedEventArgs, FocusChangingEventArgs, FocusManager, Gestures,
HoldingRoutedEventArgs, IInputElement, KeyEventArgs, KeyModifiers, KeyboardNavigation, NavigationMethod,
PointerCaptureChangingEventArgs, PointerCaptureLostEventArgs, PointerEventArgs, PointerPressedEventArgs,
PointerReleasedEventArgs, PointerWheelEventArgs, TappedEventArgs, TextInputEventArgs,
};
use crate::interactivity::{
IRoutedEventArgs, Interactive, InteractiveImpl, RoutedEvent, RoutedEventArgs, RoutedEventHandlerToken,
RoutingStrategies,
};
use crate::layout::LayoutableImpl;
use crate::visual_tree::IHostedVisualTreeRoot;
use crate::{
ferro_class, ferro_impl_classes, ferro_property, ferro_routed_event, instantiate, DirectProperty,
FerroObjectImpl, FerroObjectImplExt, FerroProperty, FerroPropertyChangedEventArgs, Ref, StyledElementImpl,
StyledProperty, StyledPropertyOptions, Visual, VisualImpl, VisualImplExt, VisualTreeAttachmentEventArgs,
};
use crate::collections::FerroList;
use std::cell::{Cell, OnceCell};
use std::rc::Rc;
#[repr(C)]
pub struct InputElement {
base: Interactive,
is_effectively_enabled: Cell<bool>,
is_focused: Cell<bool>,
is_keyboard_focus_within: Cell<bool>,
is_focus_visible: Cell<bool>,
is_pointer_over: Cell<bool>,
pub(super) is_context_menu_on_holding: Cell<bool>,
key_bindings: OnceCell<FerroList<Ref<KeyBinding>>>,
gesture_recognizers: OnceCell<GestureRecognizerCollection>,
}
ferro_class! {
InputElement: Interactive, virtuals InputElementImpl: InteractiveImpl {
fn is_enabled_core(this) -> bool;
fn is_focus_scope(this) -> bool;
fn on_getting_focus(this, e: &FocusChangingEventArgs);
fn on_losing_focus(this, e: &FocusChangingEventArgs);
fn on_got_focus(this, e: &FocusChangedEventArgs);
fn on_lost_focus(this, e: &FocusChangedEventArgs);
fn on_key_down(this, e: &KeyEventArgs);
fn on_key_up(this, e: &KeyEventArgs);
fn on_text_input(this, e: &TextInputEventArgs);
fn on_pointer_entered(this, e: &PointerEventArgs);
fn on_pointer_exited(this, e: &PointerEventArgs);
fn on_pointer_moved(this, e: &PointerEventArgs);
fn on_pointer_pressed(this, e: &PointerPressedEventArgs);
fn on_pointer_released(this, e: &PointerReleasedEventArgs);
fn on_pointer_capture_changing(this, e: &PointerCaptureChangingEventArgs);
fn on_pointer_capture_lost(this, e: &PointerCaptureLostEventArgs);
fn on_pointer_wheel_changed(this, e: &PointerWheelEventArgs);
fn on_tapped(this, e: &TappedEventArgs);
fn on_right_tapped(this, e: &TappedEventArgs);
fn on_double_tapped(this, e: &TappedEventArgs);
fn on_holding(this, e: &HoldingRoutedEventArgs);
fn on_access_key(this, e: &dyn IRoutedEventArgs);
fn get_next_tab_stop_override(this) -> Option<Ref<InputElement>>;
fn get_previous_tab_stop_override(this) -> Option<Ref<InputElement>>;
fn get_first_focusable_element_override(this) -> Option<Ref<InputElement>>;
fn get_last_focusable_element_override(this) -> Option<Ref<InputElement>>;
fn process_tab_stop_override(
this,
focused_element: Option<&Ref<InputElement>>,
candidate_tab_stop_element: Option<&Ref<InputElement>>,
is_reverse: bool,
did_cycle_focus_at_root_visual: bool,
new_tab_stop: &mut Option<Ref<InputElement>>
) -> bool;
fn process_candidate_tab_stop_override(
this,
focused_element: Option<&Ref<InputElement>>,
candidate_tab_stop_element: Option<&Ref<InputElement>>,
overriden_candidate_tab_stop_element: Option<&Ref<InputElement>>,
is_reverse: bool,
new_tab_stop: &mut Option<Ref<InputElement>>
) -> bool;
fn as_custom_keyboard_navigation(this) -> Option<&dyn ICustomKeyboardNavigation>;
fn as_scrollable(this) -> Option<&dyn IScrollable>;
fn as_hosted_visual_tree_root(this) -> Option<&dyn IHostedVisualTreeRoot>;
}
}
crate::ferro_class_info!(InputElement { new: InputElement::new });
ferro_impl_classes!(InputElement: StyledElementImpl, LayoutableImpl, InteractiveImpl);
crate::ferro_overrides! { impl FerroObjectImpl for InputElement {
fn constructed(this: &Self) {
Self::parent_constructed(this);
this.update_pseudo_classes(Some(this.is_focused()), Some(this.is_pointer_over()));
}
fn on_property_changed(this: &Self, change: &FerroPropertyChangedEventArgs<'_>) {
Self::parent_on_property_changed(this, change);
let property = change.property();
if property == Self::is_focused_property().as_property() {
this.update_pseudo_classes(Some(change.get_new_value::<bool>()), None);
} else if property == Self::is_pointer_over_property().as_property() {
this.update_pseudo_classes(None, Some(change.get_new_value::<bool>()));
} else if property == Self::is_keyboard_focus_within_property().as_property() {
this.pseudo_classes().set(":focus-within", change.get_new_value::<bool>());
} else if property == Visual::is_visible_property().as_property()
&& !change.get_new_value::<bool>()
&& this.is_keyboard_focus_within()
{
if let Some(focus_manager) = FocusManager::get_focus_manager(this) {
match (focus_manager.get_focused_element(), this.visual_parent()) {
(Some(focused_element), Some(visual_parent)) => {
focus_manager.clear_focus_on_element_removed(&focused_element, &visual_parent);
}
_ => {
focus_manager.focus(None, NavigationMethod::Unspecified, KeyModifiers::NONE);
}
}
}
}
}
} }
impl VisualImpl for InputElement {
fn on_detached_from_visual_tree_core(this: &Self, e: &VisualTreeAttachmentEventArgs) {
Self::parent_on_detached_from_visual_tree_core(this, e);
if this.is_focused() {
let root = e.attachment_point().unwrap_or(e.root_visual());
let focus_manager = e
.presentation_source()
.input_root()
.focus_manager()
.or_else(|| FocusManager::get_focus_manager(this));
if let Some(focus_manager) = focus_manager {
focus_manager.clear_focus_on_element_removed(this, root);
}
}
this.set_is_keyboard_focus_within(false);
}
fn on_attached_to_visual_tree_core(this: &Self, e: &VisualTreeAttachmentEventArgs) {
Self::parent_on_attached_to_visual_tree_core(this, e);
this.update_is_effectively_enabled();
}
}
impl InputElementImpl for InputElement {
fn is_enabled_core(this: &Self) -> bool {
this.is_enabled()
}
fn is_focus_scope(_this: &Self) -> bool {
false
}
fn on_getting_focus(_this: &Self, _e: &FocusChangingEventArgs) {}
fn on_losing_focus(_this: &Self, _e: &FocusChangingEventArgs) {}
fn on_got_focus(_this: &Self, _e: &FocusChangedEventArgs) {}
fn on_lost_focus(_this: &Self, _e: &FocusChangedEventArgs) {}
fn on_key_down(_this: &Self, _e: &KeyEventArgs) {}
fn on_key_up(_this: &Self, _e: &KeyEventArgs) {}
fn on_text_input(_this: &Self, _e: &TextInputEventArgs) {}
fn on_pointer_entered(_this: &Self, _e: &PointerEventArgs) {}
fn on_pointer_exited(_this: &Self, _e: &PointerEventArgs) {}
fn on_pointer_moved(_this: &Self, _e: &PointerEventArgs) {}
fn on_pointer_pressed(_this: &Self, _e: &PointerPressedEventArgs) {}
fn on_pointer_released(_this: &Self, _e: &PointerReleasedEventArgs) {}
fn on_pointer_capture_changing(_this: &Self, _e: &PointerCaptureChangingEventArgs) {}
fn on_pointer_capture_lost(_this: &Self, _e: &PointerCaptureLostEventArgs) {}
fn on_pointer_wheel_changed(_this: &Self, _e: &PointerWheelEventArgs) {}
fn on_tapped(_this: &Self, _e: &TappedEventArgs) {}
fn on_right_tapped(_this: &Self, _e: &TappedEventArgs) {}
fn on_double_tapped(_this: &Self, _e: &TappedEventArgs) {}
fn on_holding(_this: &Self, _e: &HoldingRoutedEventArgs) {}
fn on_access_key(this: &Self, _e: &dyn IRoutedEventArgs) {
this.focus_with(NavigationMethod::Tab, KeyModifiers::NONE);
}
fn get_next_tab_stop_override(_this: &Self) -> Option<Ref<InputElement>> {
None
}
fn get_previous_tab_stop_override(_this: &Self) -> Option<Ref<InputElement>> {
None
}
fn get_first_focusable_element_override(_this: &Self) -> Option<Ref<InputElement>> {
None
}
fn get_last_focusable_element_override(_this: &Self) -> Option<Ref<InputElement>> {
None
}
fn process_tab_stop_override(
_this: &Self,
_focused_element: Option<&Ref<InputElement>>,
_candidate_tab_stop_element: Option<&Ref<InputElement>>,
_is_reverse: bool,
_did_cycle_focus_at_root_visual: bool,
_new_tab_stop: &mut Option<Ref<InputElement>>,
) -> bool {
false
}
fn process_candidate_tab_stop_override(
_this: &Self,
_focused_element: Option<&Ref<InputElement>>,
_candidate_tab_stop_element: Option<&Ref<InputElement>>,
_overriden_candidate_tab_stop_element: Option<&Ref<InputElement>>,
_is_reverse: bool,
_new_tab_stop: &mut Option<Ref<InputElement>>,
) -> bool {
false
}
fn as_custom_keyboard_navigation(_this: &Self) -> Option<&dyn ICustomKeyboardNavigation> {
None
}
fn as_scrollable(_this: &Self) -> Option<&dyn IScrollable> {
None
}
fn as_hosted_visual_tree_root(_this: &Self) -> Option<&dyn IHostedVisualTreeRoot> {
None
}
}
macro_rules! routed_event_accessor {
($(#[$meta:meta])* $name:ident, $event:ident, $args:ty) => {
$(#[$meta])*
pub fn $name(&self, handler: impl Fn(&Interactive, &$args) + 'static) -> RoutedEventHandlerToken {
self.add_handler(Self::$event(), handler)
}
};
}
pub(super) use routed_event_accessor;
crate::ferro_properties! { impl InputElement, also [InputElement::register_gesture_properties] {
ferro_property!(
pub fn focusable_property() -> StyledProperty<bool> {
FerroProperty::register::<InputElement, _>("Focusable", false)
}
);
ferro_property!(
pub fn is_enabled_property() -> StyledProperty<bool> {
FerroProperty::register::<InputElement, _>("IsEnabled", true)
}
);
ferro_property!(
pub fn is_effectively_enabled_property() -> DirectProperty<InputElement, bool> {
FerroProperty::register_direct::<InputElement, _>(
"IsEffectivelyEnabled",
|o| o.is_effectively_enabled(),
None,
false,
)
}
);
ferro_property!(
pub fn cursor_property() -> StyledProperty<Option<Rc<Cursor>>> {
FerroProperty::register_with::<InputElement, _>("Cursor", StyledPropertyOptions::new(None).inherits(true))
}
);
ferro_property!(
pub fn is_keyboard_focus_within_property() -> DirectProperty<InputElement, bool> {
FerroProperty::register_direct::<InputElement, _>(
"IsKeyboardFocusWithin",
|o| o.is_keyboard_focus_within(),
None,
false,
)
}
);
ferro_property!(
pub fn is_focused_property() -> DirectProperty<InputElement, bool> {
FerroProperty::register_direct::<InputElement, _>("IsFocused", |o| o.is_focused(), None, false)
}
);
ferro_property!(
pub fn is_hit_test_visible_property() -> StyledProperty<bool> {
FerroProperty::register::<InputElement, _>("IsHitTestVisible", true)
}
);
ferro_property!(
pub fn is_pointer_over_property() -> DirectProperty<InputElement, bool> {
FerroProperty::register_direct::<InputElement, _>("IsPointerOver", |o| o.is_pointer_over(), None, false)
}
);
ferro_property!(
pub fn is_tab_stop_property() -> StyledProperty<bool> {
KeyboardNavigation::is_tab_stop_property().add_owner::<InputElement>()
}
);
ferro_property!(
pub fn tab_index_property() -> StyledProperty<i32> {
KeyboardNavigation::tab_index_property().add_owner::<InputElement>()
}
);
} }
impl InputElement {
ferro_routed_event!(
pub fn got_focus_event() -> RoutedEvent<FocusChangedEventArgs> {
RoutedEvent::register::<InputElement, _>("GotFocus", RoutingStrategies::BUBBLE)
}
);
ferro_routed_event!(
pub fn getting_focus_event() -> RoutedEvent<FocusChangingEventArgs> {
RoutedEvent::register::<InputElement, _>("GettingFocus", RoutingStrategies::BUBBLE)
}
);
ferro_routed_event!(
pub fn lost_focus_event() -> RoutedEvent<FocusChangedEventArgs> {
RoutedEvent::register::<InputElement, _>("LostFocus", RoutingStrategies::BUBBLE)
}
);
ferro_routed_event!(
pub fn losing_focus_event() -> RoutedEvent<FocusChangingEventArgs> {
RoutedEvent::register::<InputElement, _>("LosingFocus", RoutingStrategies::BUBBLE)
}
);
ferro_routed_event!(
pub fn key_down_event() -> RoutedEvent<KeyEventArgs> {
RoutedEvent::register::<InputElement, _>("KeyDown", RoutingStrategies::TUNNEL | RoutingStrategies::BUBBLE)
}
);
ferro_routed_event!(
pub fn key_up_event() -> RoutedEvent<KeyEventArgs> {
RoutedEvent::register::<InputElement, _>("KeyUp", RoutingStrategies::TUNNEL | RoutingStrategies::BUBBLE)
}
);
ferro_routed_event!(
pub fn text_input_event() -> RoutedEvent<TextInputEventArgs> {
RoutedEvent::register::<InputElement, _>(
"TextInput",
RoutingStrategies::TUNNEL | RoutingStrategies::BUBBLE,
)
}
);
ferro_routed_event!(
pub fn text_input_method_client_requested_event() -> RoutedEvent<TextInputMethodClientRequestedEventArgs> {
RoutedEvent::register::<InputElement, _>(
"TextInputMethodClientRequested",
RoutingStrategies::TUNNEL | RoutingStrategies::BUBBLE,
)
}
);
ferro_routed_event!(
pub fn pointer_entered_event() -> RoutedEvent<PointerEventArgs> {
RoutedEvent::register::<InputElement, _>("PointerEntered", RoutingStrategies::DIRECT)
}
);
ferro_routed_event!(
pub fn pointer_exited_event() -> RoutedEvent<PointerEventArgs> {
RoutedEvent::register::<InputElement, _>("PointerExited", RoutingStrategies::DIRECT)
}
);
ferro_routed_event!(
pub fn pointer_moved_event() -> RoutedEvent<PointerEventArgs> {
RoutedEvent::register::<InputElement, _>(
"PointerMoved",
RoutingStrategies::TUNNEL | RoutingStrategies::BUBBLE,
)
}
);
ferro_routed_event!(
pub fn pointer_pressed_event() -> RoutedEvent<PointerPressedEventArgs> {
RoutedEvent::register::<InputElement, _>(
"PointerPressed",
RoutingStrategies::TUNNEL | RoutingStrategies::BUBBLE,
)
}
);
ferro_routed_event!(
pub fn pointer_released_event() -> RoutedEvent<PointerReleasedEventArgs> {
RoutedEvent::register::<InputElement, _>(
"PointerReleased",
RoutingStrategies::TUNNEL | RoutingStrategies::BUBBLE,
)
}
);
ferro_routed_event!(
pub fn pointer_capture_changing_event() -> RoutedEvent<PointerCaptureChangingEventArgs> {
RoutedEvent::register::<InputElement, _>("PointerCaptureChanging", RoutingStrategies::DIRECT)
}
);
ferro_routed_event!(
pub fn pointer_capture_lost_event() -> RoutedEvent<PointerCaptureLostEventArgs> {
RoutedEvent::register::<InputElement, _>("PointerCaptureLost", RoutingStrategies::DIRECT)
}
);
ferro_routed_event!(
pub fn pointer_wheel_changed_event() -> RoutedEvent<PointerWheelEventArgs> {
RoutedEvent::register::<InputElement, _>(
"PointerWheelChanged",
RoutingStrategies::TUNNEL | RoutingStrategies::BUBBLE,
)
}
);
ferro_routed_event!(
pub fn context_requested_event() -> RoutedEvent<ContextRequestedEventArgs> {
RoutedEvent::register::<InputElement, _>(
"ContextRequested",
RoutingStrategies::TUNNEL | RoutingStrategies::BUBBLE,
)
}
);
ferro_routed_event!(
pub fn context_canceled_event() -> RoutedEvent<RoutedEventArgs> {
RoutedEvent::register::<InputElement, _>(
"ContextCanceled",
RoutingStrategies::TUNNEL | RoutingStrategies::BUBBLE,
)
}
);
fn static_constructor() {
Self::context_requested_event();
Self::context_canceled_event();
Self::register_gesture_events();
Self::is_enabled_property().changed().subscribe(|e| {
if let Some(sender) = e.sender().downcast_ref::<InputElement>() {
sender.update_is_effectively_enabled();
}
});
Self::got_focus_event().add_class_handler::<InputElement>(|x, e| x.on_got_focus_core(e));
Self::lost_focus_event().add_class_handler::<InputElement>(|x, e| x.on_lost_focus_core(e));
Self::getting_focus_event().add_class_handler::<InputElement>(|x, e| x.on_getting_focus(e));
Self::losing_focus_event().add_class_handler::<InputElement>(|x, e| x.on_losing_focus(e));
Self::key_down_event().add_class_handler::<InputElement>(|x, e| x.on_key_down(e));
Self::key_up_event().add_class_handler::<InputElement>(|x, e| x.on_key_up(e));
Self::text_input_event().add_class_handler::<InputElement>(|x, e| x.on_text_input(e));
Self::pointer_entered_event().add_class_handler::<InputElement>(|x, e| x.on_pointer_entered_core(e));
Self::pointer_exited_event().add_class_handler::<InputElement>(|x, e| x.on_pointer_exited_core(e));
Self::pointer_moved_event().add_class_handler::<InputElement>(|x, e| x.on_pointer_moved(e));
Self::pointer_pressed_event().add_class_handler::<InputElement>(|x, e| x.on_pointer_pressed(e));
Self::pointer_released_event().add_class_handler::<InputElement>(|x, e| x.on_pointer_released(e));
Self::pointer_capture_changing_event()
.add_class_handler::<InputElement>(|x, e| x.on_pointer_capture_changing(e));
Self::pointer_capture_lost_event().add_class_handler::<InputElement>(|x, e| x.on_pointer_capture_lost(e));
Self::pointer_wheel_changed_event().add_class_handler::<InputElement>(|x, e| x.on_pointer_wheel_changed(e));
Self::tapped_event().add_class_handler::<InputElement>(|x, e| x.on_tapped(e));
Self::right_tapped_event().add_class_handler::<InputElement>(|x, e| x.on_right_tapped(e));
Self::double_tapped_event().add_class_handler::<InputElement>(|x, e| x.on_double_tapped(e));
Self::holding_event().add_class_handler::<InputElement>(|x, e| x.on_holding(e));
Gestures::TYPE.ensure_class_init();
Gestures::add_tapped(|s, e| {
if s.is::<InputElement>() {
s.raise_event(e);
}
});
Gestures::add_right_tapped(|s, e| {
if s.is::<InputElement>() {
s.raise_event(e);
}
});
Gestures::add_double_tapped(|s, e| {
if s.is::<InputElement>() {
s.raise_event(e);
}
});
Gestures::add_holding(Self::on_preview_holding);
AccessKeyHandler::access_key_event().add_class_handler::<InputElement>(|x, e| x.on_access_key(e));
Self::pointer_moved_event().add_class_handler_with::<InputElement>(
|x, e| x.on_gesture_pointer_moved(e),
Interactive::DEFAULT_ROUTES,
true,
);
Self::pointer_pressed_event().add_class_handler_with::<InputElement>(
|x, e| x.on_gesture_pointer_pressed(e),
Interactive::DEFAULT_ROUTES,
true,
);
Self::pointer_released_event().add_class_handler_with::<InputElement>(
|x, e| x.on_gesture_pointer_released(e),
Interactive::DEFAULT_ROUTES,
true,
);
Self::pointer_capture_lost_event().add_class_handler_with::<InputElement>(
|x, e| x.on_gesture_pointer_capture_lost(e),
Interactive::DEFAULT_ROUTES,
true,
);
}
pub fn construct() -> Self {
Self {
base: Interactive::construct(),
is_effectively_enabled: Cell::new(true),
is_focused: Cell::new(false),
is_keyboard_focus_within: Cell::new(false),
is_focus_visible: Cell::new(false),
is_pointer_over: Cell::new(false),
is_context_menu_on_holding: Cell::new(false),
key_bindings: OnceCell::new(),
gesture_recognizers: OnceCell::new(),
}
}
pub fn new() -> Ref<Self> {
instantiate(Self::construct())
}
routed_event_accessor!(
got_focus, got_focus_event, FocusChangedEventArgs
);
routed_event_accessor!(
getting_focus, getting_focus_event, FocusChangingEventArgs
);
routed_event_accessor!(
lost_focus, lost_focus_event, FocusChangedEventArgs
);
routed_event_accessor!(
losing_focus, losing_focus_event, FocusChangingEventArgs
);
routed_event_accessor!(
key_down, key_down_event, KeyEventArgs
);
routed_event_accessor!(
key_up, key_up_event, KeyEventArgs
);
routed_event_accessor!(
text_input, text_input_event, TextInputEventArgs
);
routed_event_accessor!(
text_input_method_client_requested,
text_input_method_client_requested_event,
TextInputMethodClientRequestedEventArgs
);
routed_event_accessor!(
pointer_entered, pointer_entered_event, PointerEventArgs
);
routed_event_accessor!(
pointer_exited, pointer_exited_event, PointerEventArgs
);
routed_event_accessor!(
pointer_moved, pointer_moved_event, PointerEventArgs
);
routed_event_accessor!(
pointer_pressed, pointer_pressed_event, PointerPressedEventArgs
);
routed_event_accessor!(
pointer_released, pointer_released_event, PointerReleasedEventArgs
);
routed_event_accessor!(
pointer_capture_changing, pointer_capture_changing_event, PointerCaptureChangingEventArgs
);
routed_event_accessor!(
pointer_capture_lost, pointer_capture_lost_event, PointerCaptureLostEventArgs
);
routed_event_accessor!(
pointer_wheel_changed, pointer_wheel_changed_event, PointerWheelEventArgs
);
routed_event_accessor!(
context_requested, context_requested_event, ContextRequestedEventArgs
);
routed_event_accessor!(
context_canceled, context_canceled_event, RoutedEventArgs
);
pub fn focusable(&self) -> bool {
self.get_value(Self::focusable_property())
}
pub fn set_focusable(&self, value: bool) {
self.set_value(Self::focusable_property(), value)
}
pub fn is_enabled(&self) -> bool {
self.get_value(Self::is_enabled_property())
}
pub fn set_is_enabled(&self, value: bool) {
self.set_value(Self::is_enabled_property(), value)
}
pub fn cursor(&self) -> Option<Rc<Cursor>> {
self.get_value(Self::cursor_property())
}
pub fn set_cursor(&self, value: Option<Rc<Cursor>>) {
self.set_value(Self::cursor_property(), value)
}
#[inline]
pub fn is_keyboard_focus_within(&self) -> bool {
self.is_keyboard_focus_within.get()
}
pub(crate) fn set_is_keyboard_focus_within(&self, value: bool) {
self.set_and_raise_cell(Self::is_keyboard_focus_within_property(), &self.is_keyboard_focus_within, value);
}
#[inline]
pub fn is_focused(&self) -> bool {
self.is_focused.get()
}
fn set_is_focused(&self, value: bool) {
self.set_and_raise_cell(Self::is_focused_property(), &self.is_focused, value);
}
pub fn is_hit_test_visible(&self) -> bool {
self.get_value(Self::is_hit_test_visible_property())
}
pub fn set_is_hit_test_visible(&self, value: bool) {
self.set_value(Self::is_hit_test_visible_property(), value)
}
#[inline]
pub fn is_pointer_over(&self) -> bool {
self.is_pointer_over.get()
}
pub(crate) fn set_is_pointer_over(&self, value: bool) {
self.set_and_raise_cell(Self::is_pointer_over_property(), &self.is_pointer_over, value);
}
pub fn is_tab_stop(&self) -> bool {
self.get_value(Self::is_tab_stop_property())
}
pub fn set_is_tab_stop(&self, value: bool) {
self.set_value(Self::is_tab_stop_property(), value)
}
#[inline]
pub fn is_effectively_enabled(&self) -> bool {
self.is_effectively_enabled.get()
}
fn set_is_effectively_enabled(&self, value: bool) {
self.set_and_raise_cell(Self::is_effectively_enabled_property(), &self.is_effectively_enabled, value);
self.pseudo_classes().set(":disabled", !value);
if !self.is_effectively_enabled() {
if let Some(focus_manager) = FocusManager::get_focus_manager(self) {
let is_focused_element = focus_manager
.get_focused_element()
.is_some_and(|focused| std::ptr::eq::<InputElement>(&*focused, self));
if is_focused_element {
focus_manager.focus(None, NavigationMethod::Unspecified, KeyModifiers::NONE);
}
}
}
}
pub fn tab_index(&self) -> i32 {
self.get_value(Self::tab_index_property())
}
pub fn set_tab_index(&self, value: i32) {
self.set_value(Self::tab_index_property(), value)
}
pub fn key_bindings(&self) -> FerroList<Ref<KeyBinding>> {
self.key_bindings.get_or_init(FerroList::new).clone()
}
pub fn gesture_recognizers(&self) -> GestureRecognizerCollection {
self.gesture_recognizers.get_or_init(|| GestureRecognizerCollection::new(&self.to_ref())).clone()
}
fn on_gesture_pointer_released(&self, e: &PointerReleasedEventArgs) {
if !e.is_gesture_recognition_skipped() {
if let Some(recognizers) = self.gesture_recognizers.get() {
if recognizers.handle_pointer_released(e) {
e.set_handled(true);
}
}
}
}
fn on_gesture_pointer_capture_lost(&self, e: &PointerCaptureLostEventArgs) {
if let Some(recognizers) = self.gesture_recognizers.get() {
recognizers.handle_capture_lost(e.pointer());
}
}
fn on_gesture_pointer_pressed(&self, e: &PointerPressedEventArgs) {
if !e.is_gesture_recognition_skipped() {
if let Some(recognizers) = self.gesture_recognizers.get() {
if recognizers.handle_pointer_pressed(e) {
e.set_handled(true);
}
}
}
}
fn on_gesture_pointer_moved(&self, e: &PointerEventArgs) {
if !e.is_gesture_recognition_skipped() {
if let Some(recognizers) = self.gesture_recognizers.get() {
if recognizers.handle_pointer_moved(e) {
e.set_handled(true);
}
}
}
}
pub fn focus(&self) -> bool {
self.focus_with(NavigationMethod::Unspecified, KeyModifiers::NONE)
}
pub fn focus_with(&self, method: NavigationMethod, key_modifiers: KeyModifiers) -> bool {
match FocusManager::get_focus_manager(self) {
Some(focus_manager) => focus_manager.focus(Some(&self.to_ref()), method, key_modifiers),
None => false,
}
}
pub(crate) fn process_tab_stop(
_content_root: Option<&Ref<InputElement>>,
focused_element: Option<&Ref<InputElement>>,
candidate_tab_stop_element: Option<&Ref<InputElement>>,
is_reverse: bool,
did_cycle_focus_at_root_visual: bool,
) -> (bool, Option<Ref<InputElement>>) {
let new_tab_stop: Option<Ref<InputElement>> = None;
let mut is_tab_stop_overridden = false;
let mut sp_new_tab_stop: Option<Ref<InputElement>> = None;
if let Some(focused) = focused_element {
let (overridden, tab_stop) = focused.process_tab_stop_internal(
candidate_tab_stop_element,
is_reverse,
did_cycle_focus_at_root_visual,
);
is_tab_stop_overridden = overridden;
sp_new_tab_stop = tab_stop;
}
if !is_tab_stop_overridden {
if let Some(candidate) = candidate_tab_stop_element {
let (overridden, tab_stop) =
candidate.process_candidate_tab_stop_internal(focused_element, None, is_reverse);
is_tab_stop_overridden = overridden;
sp_new_tab_stop = tab_stop;
}
}
let _ = sp_new_tab_stop;
(is_tab_stop_overridden, new_tab_stop)
}
fn process_tab_stop_internal(
&self,
candidate_tab_stop_element: Option<&Ref<InputElement>>,
is_reverse: bool,
did_cycle_focus_at_root_visual: bool,
) -> (bool, Option<Ref<InputElement>>) {
let this = self.to_ref();
let mut current = Some(this.clone());
let mut new_tab_stop = None;
let mut candidate_tab_stop_overridden = false;
while let Some(c) = current {
if candidate_tab_stop_overridden {
break;
}
candidate_tab_stop_overridden = c.process_tab_stop_override(
Some(&this),
candidate_tab_stop_element,
is_reverse,
did_cycle_focus_at_root_visual,
&mut new_tab_stop,
);
current = c.parent().and_then(|parent| parent.downcast::<InputElement>().ok());
}
(candidate_tab_stop_overridden, new_tab_stop)
}
fn process_candidate_tab_stop_internal(
&self,
current_tab_stop: Option<&Ref<InputElement>>,
overriden_candidate_tab_stop_element: Option<&Ref<InputElement>>,
is_reverse: bool,
) -> (bool, Option<Ref<InputElement>>) {
let this = self.to_ref();
let mut current = Some(this.clone());
let mut new_tab_stop = None;
let mut candidate_tab_stop_overridden = false;
while let Some(c) = current {
if candidate_tab_stop_overridden {
break;
}
candidate_tab_stop_overridden = c.process_candidate_tab_stop_override(
current_tab_stop,
Some(&this),
overriden_candidate_tab_stop_element,
is_reverse,
&mut new_tab_stop,
);
current = c.parent().and_then(|parent| parent.downcast::<InputElement>().ok());
}
(candidate_tab_stop_overridden, new_tab_stop)
}
fn on_got_focus_core(&self, e: &FocusChangedEventArgs) {
let is_focused = e.is_source(self);
self.is_focus_visible.set(
is_focused
&& (e.navigation_method == NavigationMethod::Directional
|| e.navigation_method == NavigationMethod::Tab),
);
self.set_is_focused(is_focused);
self.on_got_focus(e);
}
fn on_lost_focus_core(&self, e: &FocusChangedEventArgs) {
self.is_focus_visible.set(false);
self.set_is_focused(false);
self.on_lost_focus(e);
}
pub fn update_is_effectively_enabled(&self) {
let parent = self.get_visual_parent_of_type::<InputElement>();
self.update_is_effectively_enabled_from(parent.as_deref());
}
fn on_pointer_entered_core(&self, e: &PointerEventArgs) {
self.set_is_pointer_over(true);
self.on_pointer_entered(e);
}
fn on_pointer_exited_core(&self, e: &PointerEventArgs) {
self.set_is_pointer_over(false);
self.on_pointer_exited(e);
}
fn update_is_effectively_enabled_from(&self, parent: Option<&InputElement>) {
self.set_is_effectively_enabled(
self.is_enabled_core() && parent.is_none_or(InputElement::is_effectively_enabled),
);
if let Some(children) = self.visual_children_snapshot() {
for child in children.iter() {
if let Some(child) = child.downcast_ref::<InputElement>() {
child.update_is_effectively_enabled_from(Some(self));
}
}
}
}
fn update_pseudo_classes(&self, is_focused: Option<bool>, is_pointer_over: Option<bool>) {
if let Some(is_focused) = is_focused {
self.pseudo_classes().set(":focus", is_focused);
self.pseudo_classes().set(":focus-visible", self.is_focus_visible.get());
}
if let Some(is_pointer_over) = is_pointer_over {
self.pseudo_classes().set(":pointerover", is_pointer_over);
}
}
}
impl IInputElement for InputElement {
fn focusable(&self) -> bool {
InputElement::focusable(self)
}
fn is_enabled(&self) -> bool {
InputElement::is_enabled(self)
}
fn cursor(&self) -> Option<Rc<Cursor>> {
InputElement::cursor(self)
}
fn is_effectively_enabled(&self) -> bool {
InputElement::is_effectively_enabled(self)
}
fn is_effectively_visible(&self) -> bool {
Visual::is_effectively_visible(self)
}
fn is_keyboard_focus_within(&self) -> bool {
InputElement::is_keyboard_focus_within(self)
}
fn is_focused(&self) -> bool {
InputElement::is_focused(self)
}
fn is_hit_test_visible(&self) -> bool {
InputElement::is_hit_test_visible(self)
}
fn is_pointer_over(&self) -> bool {
InputElement::is_pointer_over(self)
}
fn focus(&self, method: NavigationMethod, key_modifiers: KeyModifiers) -> bool {
InputElement::focus_with(self, method, key_modifiers)
}
}