1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
use bevy_ecs::prelude::*;
use super::color::Color;
use super::widget::Widget;
use crate::scene::SceneEntity;
/// A single line of screen-centered text, drawn without a background.
///
/// Position is recomputed from [`super::ScreenSize`] every frame, so a
/// heading stays centered across window resizes without layout bookkeeping.
#[derive(Component, Clone, Debug)]
pub struct HeadingText {
pub text: String,
pub pixel_size: f32,
pub color: Color,
/// Horizontal center as a fraction of screen width (0.5 = middle).
pub x_ratio: f32,
/// Vertical center as a fraction of screen height (0.5 = middle).
pub y_ratio: f32,
/// Pixels to shift down from `y_ratio`, for text that should sit a fixed
/// distance under a title rather than one that stretches with the window.
pub y_offset: f32,
}
/// Builder for a [`HeadingText`].
///
/// ```no_run
/// # use codecraft::{AppState, ui::Heading};
/// # fn demo(app: &mut AppState) {
/// app.spawn(Heading::text("CHESS RS"));
/// # }
/// ```
pub struct Heading {
heading: HeadingText,
}
impl Heading {
pub const DEFAULT_PIXEL_SIZE: f32 = 8.0;
pub fn text(text: impl Into<String>) -> Self {
Self {
heading: HeadingText {
text: text.into(),
pixel_size: Self::DEFAULT_PIXEL_SIZE,
color: Color::WHITE,
x_ratio: 0.5,
y_ratio: 0.5,
y_offset: 0.0,
},
}
}
/// Size of one bitmap-font pixel; the whole heading scales with it.
pub fn pixel_size(mut self, pixel_size: f32) -> Self {
self.heading.pixel_size = pixel_size;
self
}
pub fn color(mut self, color: Color) -> Self {
self.heading.color = color;
self
}
/// Horizontal placement as a fraction of screen width (0.5 = middle).
pub fn x_ratio(mut self, x_ratio: f32) -> Self {
self.heading.x_ratio = x_ratio;
self
}
/// Vertical placement as a fraction of screen height (0.5 = middle).
pub fn y_ratio(mut self, y_ratio: f32) -> Self {
self.heading.y_ratio = y_ratio;
self
}
/// Pixels to shift down from [`Heading::y_ratio`].
pub fn y_offset(mut self, y_offset: f32) -> Self {
self.heading.y_offset = y_offset;
self
}
}
impl Widget for Heading {
type Output = Entity;
fn spawn(self, world: &mut World, _screen_width: f32, _screen_height: f32) -> Entity {
world.spawn((self.heading, SceneEntity)).id()
}
}