use oxframe_2d::{
Accent, BaseProps, Group, Lg, Md, Muted, NodeBuilder, NodeId, Rect, Surface, Txt, pct,
};
use oxframe_core::Tween;
use crate::host::{self, Host};
fn plate(root: &Group, title: String, subtitle: Option<String>) -> Host {
root.add(
Rect::new()
.width(pct(64))
.height(260.0)
.radius(Lg)
.fill(Surface)
.elevation(Md)
.name("plate"),
);
root.add(Txt::new().text(title).h1().y(-28.0).name("title"));
let mut reveals = Vec::new();
if let Some(text) = subtitle {
let line = root.add(
Txt::new()
.text(text)
.caption()
.fill(Muted)
.y(56.0)
.opacity(0.0)
.name("subtitle"),
);
reveals.push(line.node());
}
Host::new(root.node(), reveals)
}
pub struct TitleCard {
host: Host,
}
impl TitleCard {
#[allow(clippy::new_ret_no_self)]
pub fn new(title: impl Into<String>) -> TitleCardBuilder {
TitleCardBuilder {
base: BaseProps::default(),
title: title.into(),
subtitle: None,
}
}
pub fn enter(&self) -> Tween<f64> {
self.host.enter()
}
pub fn next(&self) -> Tween<f64> {
self.host.next()
}
pub fn exit(&self) -> Tween<f64> {
self.host.exit()
}
}
#[must_use = "a builder does nothing until it is passed to `add`"]
pub struct TitleCardBuilder {
base: BaseProps,
title: String,
subtitle: Option<String>,
}
impl TitleCardBuilder {
pub fn subtitle(mut self, text: impl Into<String>) -> Self {
self.subtitle = Some(text.into());
self
}
}
impl NodeBuilder for TitleCardBuilder {
type Handle = TitleCard;
fn base(&mut self) -> &mut BaseProps {
&mut self.base
}
fn build(self, _: &oxframe_2d::SceneGraph, parent: NodeId) -> TitleCard {
let root = host::root(parent, self.base);
TitleCard {
host: plate(&root, self.title, self.subtitle),
}
}
}
pub struct EndCard {
host: Host,
}
impl EndCard {
#[allow(clippy::new_ret_no_self)]
pub fn new(title: impl Into<String>) -> EndCardBuilder {
EndCardBuilder {
base: BaseProps::default(),
title: title.into(),
note: None,
}
}
pub fn enter(&self) -> Tween<f64> {
self.host.enter()
}
pub fn next(&self) -> Tween<f64> {
self.host.next()
}
pub fn exit(&self) -> Tween<f64> {
self.host.exit()
}
}
#[must_use = "a builder does nothing until it is passed to `add`"]
pub struct EndCardBuilder {
base: BaseProps,
title: String,
note: Option<String>,
}
impl EndCardBuilder {
pub fn note(mut self, text: impl Into<String>) -> Self {
self.note = Some(text.into());
self
}
}
impl NodeBuilder for EndCardBuilder {
type Handle = EndCard;
fn base(&mut self) -> &mut BaseProps {
&mut self.base
}
fn build(self, _: &oxframe_2d::SceneGraph, parent: NodeId) -> EndCard {
let root = host::root(parent, self.base);
EndCard {
host: plate(&root, self.title, self.note),
}
}
}
pub struct BulletList {
host: Host,
}
impl BulletList {
#[allow(clippy::new_ret_no_self)]
pub fn new(items: impl IntoIterator<Item = impl Into<String>>) -> BulletListBuilder {
BulletListBuilder {
base: BaseProps::default(),
items: items.into_iter().map(Into::into).collect(),
}
}
pub fn enter(&self) -> Tween<f64> {
self.host.enter()
}
pub fn next(&self) -> Tween<f64> {
self.host.next()
}
pub fn exit(&self) -> Tween<f64> {
self.host.exit()
}
pub fn len(&self) -> usize {
self.host.len()
}
pub fn is_empty(&self) -> bool {
self.host.is_empty()
}
}
#[must_use = "a builder does nothing until it is passed to `add`"]
pub struct BulletListBuilder {
base: BaseProps,
items: Vec<String>,
}
impl NodeBuilder for BulletListBuilder {
type Handle = BulletList;
fn base(&mut self) -> &mut BaseProps {
&mut self.base
}
fn build(self, _: &oxframe_2d::SceneGraph, parent: NodeId) -> BulletList {
let root = host::root(parent, self.base);
let n = self.items.len().max(1) as f64;
let pitch = 72.0;
let y0 = -(n - 1.0) * pitch / 2.0;
let mut reveals = Vec::new();
for (i, text) in self.items.into_iter().enumerate() {
let row: Group = root.add(
Group::new()
.y(y0 + i as f64 * pitch)
.opacity(0.0)
.name(format!("item{}", i + 1)),
);
row.add(Rect::new().size(18.0).fill(Accent).x(-220.0).name("mark"));
row.add(Txt::new().text(text).body().x(16.0).name("line"));
reveals.push(row.node());
}
BulletList {
host: Host::new(root.node(), reveals),
}
}
}