freya_components/
tooltip.rs1use std::borrow::Cow;
2
3use freya_core::prelude::*;
4use torin::{
5 prelude::{
6 Alignment,
7 Area,
8 Direction,
9 },
10 size::Size,
11};
12
13use crate::{
14 get_theme,
15 theming::component_themes::{
16 TooltipTheme,
17 TooltipThemePartial,
18 },
19};
20
21#[cfg_attr(feature = "docs",
40 doc = embed_doc_image::embed_image!("tooltip", "images/gallery_tooltip.png")
41)]
42#[derive(PartialEq, Clone)]
43pub struct Tooltip {
44 pub(crate) theme: Option<TooltipThemePartial>,
46 text: Cow<'static, str>,
48 key: DiffKey,
49}
50
51impl KeyExt for Tooltip {
52 fn write_key(&mut self) -> &mut DiffKey {
53 &mut self.key
54 }
55}
56
57impl Tooltip {
58 pub fn new(text: impl Into<Cow<'static, str>>) -> Self {
59 Self {
60 theme: None,
61 text: text.into(),
62 key: DiffKey::None,
63 }
64 }
65}
66
67impl Render for Tooltip {
68 fn render(&self) -> impl IntoElement {
69 let theme = get_theme!(&self.theme, tooltip);
70 let TooltipTheme {
71 background,
72 color,
73 border_fill,
74 } = theme;
75
76 rect()
77 .padding((4., 10.))
78 .border(
79 Border::new()
80 .width(1.)
81 .alignment(BorderAlignment::Inner)
82 .fill(border_fill),
83 )
84 .background(background)
85 .corner_radius(8.)
86 .child(
87 label()
88 .max_lines(1)
89 .font_size(14.)
90 .color(color)
91 .text(self.text.clone()),
92 )
93 }
94
95 fn render_key(&self) -> DiffKey {
96 self.key.clone().or(self.default_key())
97 }
98}
99
100#[derive(PartialEq, Clone, Copy, Debug, Default)]
101pub enum TooltipPosition {
102 Besides,
103 #[default]
104 Below,
105}
106
107#[derive(PartialEq)]
108pub struct TooltipContainer {
109 tooltip: Tooltip,
110 children: Vec<Element>,
111 position: TooltipPosition,
112 key: DiffKey,
113}
114
115impl KeyExt for TooltipContainer {
116 fn write_key(&mut self) -> &mut DiffKey {
117 &mut self.key
118 }
119}
120
121impl ChildrenExt for TooltipContainer {
122 fn get_children(&mut self) -> &mut Vec<Element> {
123 &mut self.children
124 }
125}
126
127impl TooltipContainer {
128 pub fn new(tooltip: Tooltip) -> Self {
129 Self {
130 tooltip,
131 children: vec![],
132 position: TooltipPosition::Below,
133 key: DiffKey::None,
134 }
135 }
136
137 pub fn position(mut self, position: TooltipPosition) -> Self {
138 self.position = position;
139 self
140 }
141}
142
143impl Render for TooltipContainer {
144 fn render(&self) -> impl IntoElement {
145 let mut is_hovering = use_state(|| false);
146 let mut size = use_state(Area::default);
147
148 let on_pointer_enter = move |_| {
149 is_hovering.set(true);
150 };
151
152 let on_pointer_leave = move |_| {
153 is_hovering.set(false);
154 };
155
156 let on_sized = move |e: Event<SizedEventData>| {
157 size.set(e.area);
158 };
159
160 let direction = match self.position {
161 TooltipPosition::Below => Direction::vertical(),
162 TooltipPosition::Besides => Direction::horizontal(),
163 };
164
165 rect()
166 .direction(direction)
167 .on_sized(on_sized)
168 .on_pointer_enter(on_pointer_enter)
169 .on_pointer_leave(on_pointer_leave)
170 .children(self.children.clone())
171 .child(
172 rect()
173 .width(Size::px(0.))
174 .height(Size::px(0.))
175 .layer(1500)
176 .maybe_child(if *is_hovering.read() {
177 Some(match self.position {
178 TooltipPosition::Below => rect()
179 .width(Size::px(size.read().width()))
180 .cross_align(Alignment::Center)
181 .main_align(Alignment::Center)
182 .padding((5., 0., 0., 0.))
183 .child(self.tooltip.clone()),
184 TooltipPosition::Besides => rect()
185 .height(Size::px(size.read().height()))
186 .cross_align(Alignment::Center)
187 .main_align(Alignment::Center)
188 .padding((0., 0., 0., 5.))
189 .child(self.tooltip.clone()),
190 })
191 } else {
192 None
193 }),
194 )
195 }
196
197 fn render_key(&self) -> DiffKey {
198 self.key.clone().or(self.default_key())
199 }
200}