oxframe_components/
callout.rs1use oxframe_2d::{
4 Accent, BaseProps, Group, Len, Line, Md, Muted, Node, NodeBuilder, NodeId, Side, Txt,
5};
6use oxframe_core::Tween;
7
8use crate::host::{self, Host};
9
10pub struct Callout {
13 host: Host,
14}
15
16impl Callout {
17 #[allow(clippy::new_ret_no_self)]
19 pub fn new(target: impl Into<Node>) -> CalloutBuilder {
20 CalloutBuilder {
21 base: BaseProps::default(),
22 target: target.into(),
23 text: String::new(),
24 }
25 }
26
27 pub fn enter(&self) -> Tween<f64> {
29 self.host.enter()
30 }
31 pub fn next(&self) -> Tween<f64> {
33 self.host.next()
34 }
35 pub fn exit(&self) -> Tween<f64> {
37 self.host.exit()
38 }
39}
40
41#[must_use = "a builder does nothing until it is passed to `add`"]
43pub struct CalloutBuilder {
44 base: BaseProps,
45 target: Node,
46 text: String,
47}
48
49impl CalloutBuilder {
50 pub fn text(mut self, text: impl Into<String>) -> Self {
52 self.text = text.into();
53 self
54 }
55}
56
57impl NodeBuilder for CalloutBuilder {
58 type Handle = Callout;
59 fn base(&mut self) -> &mut BaseProps {
60 &mut self.base
61 }
62 fn build(self, _: &oxframe_2d::SceneGraph, parent: NodeId) -> Callout {
63 let root: Group = host::root(parent, self.base);
64 let root = root.next_to(self.target, Side::Top);
65 let gap = Md.px();
66 root.add(
67 Line::new()
68 .points([(0.0, 28.0), (0.0, 28.0 + gap)])
69 .end_arrow(true)
70 .stroke(Accent)
71 .line_width(4.0)
72 .name("arrow"),
73 );
74 let caption = root.add(
75 Txt::new()
76 .text(self.text)
77 .caption()
78 .fill(Muted)
79 .opacity(0.0)
80 .name("caption"),
81 );
82 Callout {
83 host: Host::new(root, vec![caption.node()]),
84 }
85 }
86}