Skip to main content

ferroui_controls/
label.rs

1use crate::primitives::TemplatedControlImpl;
2use crate::{ContentControl, ContentControlImpl, ControlImpl};
3use ferroui_base::input::{
4    AccessKeyHandler, AccessKeyPressedEventArgs, InputElement, InputElementImpl, InputElementImplExt,
5    PointerPressedEventArgs, PointerUpdateKind,
6};
7use ferroui_base::interactivity::{IRoutedEventArgs, InteractiveImpl, RoutedEventArgs};
8use ferroui_base::layout::LayoutableImpl;
9use ferroui_base::{
10    ferro_class, ferro_impl_classes, ferro_property, instantiate, FerroObjectImpl, FerroProperty,
11    Nullable, Ref, StyledElementImpl, StyledProperty, Upcast, VisualImpl,
12};
13
14/// Label control. Focuses its `Target` when the label is activated: when it
15/// is clicked, or when its access key is pressed.
16#[repr(C)]
17pub struct Label {
18    base: ContentControl,
19}
20
21ferro_class!(Label: ContentControl);
22ferroui_base::ferro_class_info!(Label { new: Label::new });
23ferro_impl_classes!(
24    Label: StyledElementImpl,
25    VisualImpl,
26    LayoutableImpl,
27    InteractiveImpl,
28    TemplatedControlImpl,
29    ContentControlImpl
30);
31
32impl ControlImpl for Label {
33    fn on_create_automation_peer(this: &Self) -> Ref<crate::automation::peers::AutomationPeer> {
34        crate::automation::peers::LabelAutomationPeer::new(this).upcast()
35    }
36}
37
38ferroui_base::ferro_impl_classes!(Label: FerroObjectImpl);
39
40impl InputElementImpl for Label {
41    fn on_access_key(this: &Self, e: &dyn IRoutedEventArgs) {
42        this.label_activated(e);
43    }
44
45    /// Handles a pointer pressed event.
46    fn on_pointer_pressed(this: &Self, e: &PointerPressedEventArgs) {
47        if e.get_current_point(Some(this.upcast())).properties.pointer_update_kind
48            == PointerUpdateKind::LeftButtonPressed
49        {
50            this.label_activated(e);
51        }
52        Self::parent_on_pointer_pressed(this, e);
53    }
54}
55
56ferroui_base::ferro_properties! { impl Label {
57    ferro_property!(
58        /// Defines the `Target` property.
59        ///
60        /// The label does not own its target, so the value is an element
61        /// reference.
62        pub fn target_property() -> StyledProperty<Option<ferroui_base::ElementRef<InputElement>>> {
63            ferroui_base::data::core::ValueTypes::register_element_ref::<InputElement>();
64            FerroProperty::register::<Label, _>("Target", None)
65        }
66    );
67} }
68
69impl Label {
70    fn static_constructor() {
71        AccessKeyHandler::access_key_pressed_event().add_class_handler::<Label>(Self::on_access_key_pressed);
72        // The tab stop property defaults to false for labels.
73        InputElement::is_tab_stop_property().override_default_value::<Label>(false);
74    }
75
76    /// Creates the class data; see [`ferroui_base::FerroObject::construct`].
77    pub fn construct() -> Self {
78        Self { base: ContentControl::construct() }
79    }
80
81    /// Initializes a new label.
82    pub fn new() -> Ref<Self> {
83        instantiate(Self::construct())
84    }
85
86    /// Gets the label's target.
87    pub fn target(&self) -> Option<Ref<InputElement>> {
88        ferroui_base::ElementRef::resolve(&self.get_value(Self::target_property()))
89    }
90
91    /// Sets the label's target.
92    pub fn set_target(&self, value: impl Into<Nullable<InputElement>>) {
93        self.set_value(Self::target_property(), ferroui_base::ElementRef::from_nullable(value.into().0))
94    }
95
96    fn label_activated(&self, e: &RoutedEventArgs) {
97        let target = self.target();
98        if let Some(target) = &target {
99            target.focus();
100        }
101        e.set_handled(target.is_some());
102    }
103
104    fn on_access_key_pressed(label: &Label, e: &AccessKeyPressedEventArgs) {
105        if e.handled() || e.target().is_some() {
106            return;
107        }
108
109        e.set_target(label.target());
110        e.set_handled(true);
111    }
112}