use std::cell::Cell;
use yog_gfx::{Rect, Vec2};
use yog_ui::{Align, FlexDir, widget};
use super::geometry::{
ARROW_BACK_V, ARROW_H, ARROW_NEXT_V, ARROW_U, ARROW_W, HOME_H, HOME_U, HOME_V, MIN_TITLE_FIT,
NAV_H, PAGE_W, SEP_H, SEP_U, SEP_V, SEP_W, TITLE_INSET,
};
use super::overlay::{BgSprite, OverlayCmd, SpriteSheet};
use crate::theme::BookTheme;
thread_local! {
static TEXT_SCALE: Cell<f32> = const { Cell::new(1.0) };
}
pub(crate) fn set_text_scale(scale: f32) {
TEXT_SCALE.with(|s| s.set(scale));
}
pub(crate) fn text_scale() -> f32 {
TEXT_SCALE.with(|s| s.get())
}
pub(crate) fn lbl(text: impl Into<String>) -> widget::Widget {
widget::label(text).shadow(false).font_scale(text_scale())
}
pub(crate) fn fit(text: &str, width: f32) -> f32 {
(width / yog_ui::text::str_width(text, 1.0)).clamp(MIN_TITLE_FIT, 1.0)
}
pub(crate) fn title_lbl(text: impl Into<String>) -> widget::Widget {
let text = text.into();
let w = PAGE_W - TITLE_INSET;
let fit = fit(&text, w);
widget::label(text)
.shadow(false)
.font_scale(text_scale() * fit)
.no_wrap()
.ellipsis()
.w(w * text_scale())
}
pub(crate) struct Nav<'a> {
pub prev: &'a str,
pub next: &'a str,
pub label: String,
pub home: Option<&'a str>,
}
impl Nav<'_> {
pub(crate) fn row(self, sheet: &str, theme: &BookTheme, sx: f32, sy: f32) -> widget::Widget {
let arrow = |region: Rect, action: &str| {
widget::image(sheet)
.region(region)
.stretch(yog_ui::Stretch::Fill)
.w(region.w * sx)
.h(region.h * sy)
.on_click(action)
.id(action)
};
let back = arrow(
Rect::new(ARROW_U, ARROW_BACK_V, ARROW_W, ARROW_H),
self.prev,
);
let mut row = widget::panel(FlexDir::Row)
.h(NAV_H * sy)
.gap(NAV_GAP)
.align(Align::Center)
.child(back);
row = row.child(
lbl(&self.label)
.color(theme.nav)
.flex(1.0)
.align(Align::Center),
);
if let Some(home) = self.home {
row = row.child(arrow(Rect::new(HOME_U, HOME_V, ARROW_W, HOME_H), home));
}
row.child(arrow(
Rect::new(ARROW_U, ARROW_NEXT_V, ARROW_W, ARROW_H),
self.next,
))
}
}
const NAV_GAP: f32 = 2.0;
pub(crate) struct Canvas<'a> {
pub theme: &'a BookTheme,
pub sheet: &'a str,
pub sx: f32,
pub sy: f32,
pub sprites: &'a mut Vec<BgSprite>,
pub overlays: &'a mut Vec<OverlayCmd>,
}
impl Canvas<'_> {
pub(crate) fn nav(&self, nav: Nav<'_>) -> widget::Widget {
nav.row(self.sheet, self.theme, self.sx, self.sy)
}
pub(crate) fn rect(&self, origin: Vec2, r: Rect) -> Rect {
Rect::new(
origin.x + r.x * self.sx,
origin.y + r.y * self.sy,
r.w * self.sx,
r.h * self.sy,
)
}
pub(crate) fn sep_h(&self) -> f32 {
(SEP_H * self.sy).max(1.0)
}
pub(crate) fn separator(&mut self, page: Vec2, y: f32) {
let x = page.x + (PAGE_W - SEP_W) / 2.0 * self.sx;
let dst = Rect::new(x, page.y + y * self.sy, SEP_W * self.sx, self.sep_h());
self.sprites.push(BgSprite {
sheet: SpriteSheet::Book,
src: Rect::new(SEP_U, SEP_V, SEP_W, SEP_H),
dst,
});
}
}