ferroui_controls/
hyperlink_button.rs1use crate::metadata::PseudoClassesAttribute;
2use crate::primitives::TemplatedControlImpl;
3use crate::{Button, ButtonImpl, ButtonImplExt, ContentControlImpl, ControlImpl, TopLevel};
4use ferroui_base::input::InputElementImpl;
5use ferroui_base::interactivity::InteractiveImpl;
6use ferroui_base::layout::LayoutableImpl;
7use ferroui_base::threading::Dispatcher;
8use ferroui_base::utilities::Uri;
9use ferroui_base::{
10 ferro_class, ferro_impl_classes, ferro_property, instantiate, FerroObjectImpl, FerroObjectImplExt,
11 FerroProperty, FerroPropertyChangedEventArgs, Ref, StyledElementImpl, StyledProperty, VisualImpl,
12};
13
14const PC_VISITED: &str = ":visited";
16
17#[repr(C)]
19pub struct HyperlinkButton {
20 base: Button,
21}
22
23ferro_class!(HyperlinkButton: Button);
24ferroui_base::ferro_class_info!(HyperlinkButton { new: HyperlinkButton::new });
25ferro_impl_classes!(
26 HyperlinkButton: StyledElementImpl,
27 VisualImpl,
28 LayoutableImpl,
29 InteractiveImpl,
30 InputElementImpl,
31 ControlImpl,
32 TemplatedControlImpl,
33 ContentControlImpl
34);
35
36impl ButtonImpl for HyperlinkButton {
37 fn on_click(this: &Self) {
38 Self::parent_on_click(this);
39
40 let uri = this.navigate_uri();
41 if let Some(uri) = uri {
42 let this = this.to_ref();
43 let _ = Dispatcher::ui_thread().invoke_async_task_local(move || async move {
46 let Some(top_level) = TopLevel::get_top_level(Some(&this)) else {
47 return;
48 };
49 let success = top_level.launcher().launch_uri_async(&uri).await;
50 if success {
51 this.set_current_value(Self::is_visited_property(), true);
52 }
53 });
54 }
55 }
56}
57
58impl FerroObjectImpl for HyperlinkButton {
59 fn on_property_changed(this: &Self, change: &FerroPropertyChangedEventArgs<'_>) {
60 Self::parent_on_property_changed(this, change);
61
62 if change.property() == Self::is_visited_property().as_property() {
63 this.pseudo_classes().set(PC_VISITED, change.get_new_value::<bool>());
64 }
65 }
66}
67
68impl HyperlinkButton {
69 pub const PSEUDO_CLASSES: PseudoClassesAttribute = PseudoClassesAttribute::new(&[PC_VISITED]);
71}
72
73ferroui_base::ferro_properties! { impl HyperlinkButton {
74 ferro_property!(
75 pub fn is_visited_property() -> StyledProperty<bool> {
77 FerroProperty::register::<HyperlinkButton, _>("IsVisited", false)
78 }
79 );
80
81 ferro_property!(
82 pub fn navigate_uri_property() -> StyledProperty<Option<Uri>> {
84 FerroProperty::register::<HyperlinkButton, _>("NavigateUri", None)
85 }
86 );
87} }
88
89impl HyperlinkButton {
90 pub fn construct() -> Self {
92 Self { base: Button::construct() }
93 }
94
95 pub fn new() -> Ref<Self> {
97 instantiate(Self::construct())
98 }
99
100 pub fn is_visited(&self) -> bool {
102 self.get_value(Self::is_visited_property())
103 }
104
105 pub fn set_is_visited(&self, value: bool) {
106 self.set_value(Self::is_visited_property(), value)
107 }
108
109 pub fn navigate_uri(&self) -> Option<Uri> {
118 self.get_value(Self::navigate_uri_property())
119 }
120
121 pub fn set_navigate_uri(&self, value: Option<Uri>) {
122 self.set_value(Self::navigate_uri_property(), value)
123 }
124}