oxframe_components/
title.rs1use oxframe_2d::{
4 Accent, BaseProps, Group, Lg, Md, Muted, NodeBuilder, NodeId, Rect, Surface, Txt, pct,
5};
6use oxframe_core::Tween;
7
8use crate::host::{self, Host};
9
10fn plate(root: &Group, title: String, subtitle: Option<String>) -> Host {
11 root.add(
12 Rect::new()
13 .width(pct(64))
14 .height(260.0)
15 .radius(Lg)
16 .fill(Surface)
17 .elevation(Md)
18 .name("plate"),
19 );
20 root.add(Txt::new().text(title).h1().y(-28.0).name("title"));
21 let mut reveals = Vec::new();
22 if let Some(text) = subtitle {
23 let line = root.add(
24 Txt::new()
25 .text(text)
26 .caption()
27 .fill(Muted)
28 .y(56.0)
29 .opacity(0.0)
30 .name("subtitle"),
31 );
32 reveals.push(line.node());
33 }
34 Host::new(root.node(), reveals)
35}
36
37pub struct TitleCard {
39 host: Host,
40}
41
42impl TitleCard {
43 #[allow(clippy::new_ret_no_self)]
45 pub fn new(title: impl Into<String>) -> TitleCardBuilder {
46 TitleCardBuilder {
47 base: BaseProps::default(),
48 title: title.into(),
49 subtitle: None,
50 }
51 }
52
53 pub fn enter(&self) -> Tween<f64> {
55 self.host.enter()
56 }
57 pub fn next(&self) -> Tween<f64> {
59 self.host.next()
60 }
61 pub fn exit(&self) -> Tween<f64> {
63 self.host.exit()
64 }
65}
66
67#[must_use = "a builder does nothing until it is passed to `add`"]
69pub struct TitleCardBuilder {
70 base: BaseProps,
71 title: String,
72 subtitle: Option<String>,
73}
74
75impl TitleCardBuilder {
76 pub fn subtitle(mut self, text: impl Into<String>) -> Self {
78 self.subtitle = Some(text.into());
79 self
80 }
81}
82
83impl NodeBuilder for TitleCardBuilder {
84 type Handle = TitleCard;
85 fn base(&mut self) -> &mut BaseProps {
86 &mut self.base
87 }
88 fn build(self, _: &oxframe_2d::SceneGraph, parent: NodeId) -> TitleCard {
89 let root = host::root(parent, self.base);
90 TitleCard {
91 host: plate(&root, self.title, self.subtitle),
92 }
93 }
94}
95
96pub struct EndCard {
98 host: Host,
99}
100
101impl EndCard {
102 #[allow(clippy::new_ret_no_self)]
104 pub fn new(title: impl Into<String>) -> EndCardBuilder {
105 EndCardBuilder {
106 base: BaseProps::default(),
107 title: title.into(),
108 note: None,
109 }
110 }
111
112 pub fn enter(&self) -> Tween<f64> {
114 self.host.enter()
115 }
116 pub fn next(&self) -> Tween<f64> {
118 self.host.next()
119 }
120 pub fn exit(&self) -> Tween<f64> {
122 self.host.exit()
123 }
124}
125
126#[must_use = "a builder does nothing until it is passed to `add`"]
128pub struct EndCardBuilder {
129 base: BaseProps,
130 title: String,
131 note: Option<String>,
132}
133
134impl EndCardBuilder {
135 pub fn note(mut self, text: impl Into<String>) -> Self {
137 self.note = Some(text.into());
138 self
139 }
140}
141
142impl NodeBuilder for EndCardBuilder {
143 type Handle = EndCard;
144 fn base(&mut self) -> &mut BaseProps {
145 &mut self.base
146 }
147 fn build(self, _: &oxframe_2d::SceneGraph, parent: NodeId) -> EndCard {
148 let root = host::root(parent, self.base);
149 EndCard {
150 host: plate(&root, self.title, self.note),
151 }
152 }
153}
154
155pub struct BulletList {
157 host: Host,
158}
159
160impl BulletList {
161 #[allow(clippy::new_ret_no_self)]
163 pub fn new(items: impl IntoIterator<Item = impl Into<String>>) -> BulletListBuilder {
164 BulletListBuilder {
165 base: BaseProps::default(),
166 items: items.into_iter().map(Into::into).collect(),
167 }
168 }
169
170 pub fn enter(&self) -> Tween<f64> {
172 self.host.enter()
173 }
174 pub fn next(&self) -> Tween<f64> {
176 self.host.next()
177 }
178 pub fn exit(&self) -> Tween<f64> {
180 self.host.exit()
181 }
182 pub fn len(&self) -> usize {
184 self.host.len()
185 }
186 pub fn is_empty(&self) -> bool {
188 self.host.is_empty()
189 }
190}
191
192#[must_use = "a builder does nothing until it is passed to `add`"]
194pub struct BulletListBuilder {
195 base: BaseProps,
196 items: Vec<String>,
197}
198
199impl NodeBuilder for BulletListBuilder {
200 type Handle = BulletList;
201 fn base(&mut self) -> &mut BaseProps {
202 &mut self.base
203 }
204 fn build(self, _: &oxframe_2d::SceneGraph, parent: NodeId) -> BulletList {
205 let root = host::root(parent, self.base);
206 let n = self.items.len().max(1) as f64;
207 let pitch = 72.0;
208 let y0 = -(n - 1.0) * pitch / 2.0;
209 let mut reveals = Vec::new();
210 for (i, text) in self.items.into_iter().enumerate() {
211 let row: Group = root.add(
212 Group::new()
213 .y(y0 + i as f64 * pitch)
214 .opacity(0.0)
215 .name(format!("item{}", i + 1)),
216 );
217 row.add(Rect::new().size(18.0).fill(Accent).x(-220.0).name("mark"));
218 row.add(Txt::new().text(text).body().x(16.0).name("line"));
219 reveals.push(row.node());
220 }
221 BulletList {
222 host: Host::new(root.node(), reveals),
223 }
224 }
225}