use std::rc::Rc;
use crate::event::EventContext;
use crate::geometry::Color;
use crate::layout::style::FlexStyle;
use crate::layout::types::FlexAlign;
use crate::view::node::{Listener, ViewNode};
use crate::view::paint::{PaintStyle, TextStyle};
use crate::widget::{BuildContext, Widget};
pub struct Tooltip {
child: Box<dyn Widget>,
tip: String,
offset_y: f32,
}
impl Tooltip {
pub fn new(child: Box<dyn Widget>, tip: impl Into<String>) -> Self {
Self {
child,
tip: tip.into(),
offset_y: -30.0,
}
}
pub fn offset_y(mut self, v: f32) -> Self {
self.offset_y = v;
self
}
}
impl Widget for Tooltip {
fn build(&self, ctx: &mut BuildContext) -> ViewNode {
let hovered = ctx.use_state::<bool>(|| false);
let h = hovered.clone();
let h2 = hovered.clone();
let on_enter = Rc::new(move |_ctx: &mut EventContext| {
h.set(true);
});
let on_leave = Rc::new(move |_ctx: &mut EventContext| {
h2.set(false);
});
let child_node = ctx.child(0, &*self.child);
let mut children = vec![child_node];
if *hovered.get() {
let chars = self.tip.chars().count();
let per_char = if self.tip.is_ascii() { 7.5f32 } else { 14.0f32 };
let tip_w = ((chars as f32) * per_char + 16.0).clamp(80.0, 360.0);
let tip_node = ViewNode::Div {
layout: FlexStyle::default()
.absolute()
.position_top(self.offset_y)
.width(tip_w)
.padding_all(6.0)
.align_items(FlexAlign::Center)
.justify_content(FlexAlign::Center),
paint: PaintStyle::new()
.background(Color::from_hex("#222222"))
.radius(crate::theme::current().radius.small),
children: vec![ViewNode::Text {
content: self.tip.clone(),
style: TextStyle {
font_size: 12.0,
color: Color::WHITE,
..Default::default()
},
layout: FlexStyle::default(),
key: None,
listeners: vec![],
}],
listeners: vec![],
key: Some("tip".into()),
};
children.push(tip_node);
}
ViewNode::Div {
layout: FlexStyle::default(),
paint: PaintStyle::new(),
children,
listeners: vec![
Listener::on_mouse_enter(on_enter).builtin(),
Listener::on_mouse_leave(on_leave).builtin(),
],
key: None,
}
}
}