vizia_core/views/
badge.rs1use crate::prelude::*;
2
3#[derive(Default, Debug, Clone, Copy, PartialEq)]
5pub enum BadgePlacement {
6 TopLeft,
8 Top,
10 #[default]
12 TopRight,
13 Left,
15 Right,
17 BottomLeft,
19 Bottom,
21 BottomRight,
23}
24
25impl_res_simple!(BadgePlacement);
26
27pub struct Badge {
29 placement: Signal<BadgePlacement>,
30}
31
32impl BadgePlacement {
33 fn flip_h(self) -> Self {
35 match self {
36 Self::TopLeft => Self::TopRight,
37 Self::TopRight => Self::TopLeft,
38 Self::BottomLeft => Self::BottomRight,
39 Self::BottomRight => Self::BottomLeft,
40 Self::Left => Self::Right,
41 Self::Right => Self::Left,
42 other => other,
43 }
44 }
45}
46
47impl Badge {
48 fn common<F>(cx: &mut Context, content: F) -> Handle<Self>
49 where
50 F: FnOnce(&mut Context),
51 {
52 let placement = Signal::new(BadgePlacement::TopRight);
53 let direction = cx.environment().direction;
54 let combined = Memo::new(move |_| (placement.get(), direction.get()));
55
56 Self { placement }.build(cx, content).bind(combined, move |mut handle| {
57 let (raw_placement, env_dir) = combined.get();
58 let entity = handle.entity();
62 let dir = handle.cx.style.direction.get(entity).copied().unwrap_or(env_dir);
63 let placement =
64 if dir == Direction::RightToLeft { raw_placement.flip_h() } else { raw_placement };
65
66 let (t, b) = match placement {
67 BadgePlacement::TopLeft | BadgePlacement::TopRight => {
68 (Stretch(1.0), Percentage(85.35))
69 }
70 BadgePlacement::Top => (Stretch(1.0), Percentage(100.0)),
71 BadgePlacement::Bottom => (Percentage(100.0), Stretch(1.0)),
72 BadgePlacement::BottomLeft | BadgePlacement::BottomRight => {
73 (Percentage(85.35), Stretch(1.0))
74 }
75 BadgePlacement::Left | BadgePlacement::Right => (Stretch(1.0), Stretch(1.0)),
76 };
77
78 let (l, r) = match placement {
79 BadgePlacement::TopLeft | BadgePlacement::BottomLeft => {
80 (Stretch(1.0), Percentage(85.35))
81 }
82 BadgePlacement::TopRight | BadgePlacement::BottomRight => {
83 (Percentage(85.35), Stretch(1.0))
84 }
85 BadgePlacement::Left => (Stretch(1.0), Percentage(100.0)),
86 BadgePlacement::Right => (Percentage(100.0), Stretch(1.0)),
87 BadgePlacement::Top | BadgePlacement::Bottom => (Stretch(1.0), Stretch(1.0)),
88 };
89
90 handle = handle.top(t).bottom(b).left(l).right(r);
91
92 let translate = match placement {
93 BadgePlacement::TopLeft => (Percentage(50.0), Percentage(50.0)),
94 BadgePlacement::Top => (Percentage(0.0), Percentage(50.0)),
95 BadgePlacement::TopRight => (Percentage(-50.0), Percentage(50.0)),
96 BadgePlacement::BottomLeft => (Percentage(50.0), Percentage(-50.0)),
97 BadgePlacement::Bottom => (Percentage(0.0), Percentage(-50.0)),
98 BadgePlacement::BottomRight => (Percentage(-50.0), Percentage(-50.0)),
99 BadgePlacement::Left => (Percentage(50.0), Percentage(0.0)),
100 BadgePlacement::Right => (Percentage(-50.0), Percentage(0.0)),
101 };
102 handle.translate(translate);
103 })
104 }
105
106 pub fn empty(cx: &mut Context) -> Handle<Self> {
118 Self::common(cx, |_| {})
119 }
120
121 pub fn new<F, V>(cx: &mut Context, content: F) -> Handle<Self>
133 where
134 F: FnOnce(&mut Context) -> Handle<V>,
135 V: View,
136 {
137 Self::common(cx, |cx| {
138 (content)(cx);
139 })
140 }
141}
142
143impl View for Badge {
144 fn element(&self) -> Option<&'static str> {
145 Some("badge")
146 }
147}
148
149impl Handle<'_, Badge> {
150 pub fn placement<U: Into<BadgePlacement> + Clone + 'static>(
152 self,
153 placement: impl Res<U> + 'static,
154 ) -> Self {
155 let placement = placement.to_signal(self.cx);
156 self.bind(placement, move |handle| {
157 let value = placement.get();
158 let converted: BadgePlacement = value.into();
159 handle.modify(|badge| {
160 badge.placement.set(converted);
161 });
162 })
163 }
164}