1use crate::rect::{Edge, Rect};
6use hatmil::Value;
7
8#[derive(Copy, Clone, Debug, PartialEq)]
10pub enum VerticalOffset {
11 Below,
13 At,
15 Above,
17}
18
19#[derive(Copy, Clone, Debug, PartialEq)]
21pub enum Anchor {
22 Start,
24 Middle,
26 End,
28}
29
30#[derive(Clone, Debug, PartialEq)]
32pub struct Label {
33 offset: VerticalOffset,
34 anchor: Anchor,
35 rounding_precision: Option<usize>,
36}
37
38#[derive(Debug, PartialEq)]
40pub struct Tick {
41 value: f32,
42 text: String,
43}
44
45impl From<Anchor> for Value<'_> {
46 fn from(anchor: Anchor) -> Self {
47 Value::from(match anchor {
48 Anchor::Start => "start",
49 Anchor::Middle => "middle",
50 Anchor::End => "end",
51 })
52 }
53}
54
55impl Default for Label {
56 fn default() -> Self {
57 Label {
58 offset: VerticalOffset::At,
59 anchor: Anchor::Middle,
60 rounding_precision: None,
61 }
62 }
63}
64
65#[allow(dead_code)]
66impl Label {
67 pub fn new() -> Self {
69 Self::default()
70 }
71
72 pub fn vertical_offset(&self) -> f32 {
74 match self.offset {
75 VerticalOffset::Above => -1.0,
76 VerticalOffset::At => 0.0,
77 VerticalOffset::Below => 1.0,
78 }
79 }
80
81 pub fn above(mut self) -> Self {
83 self.offset = VerticalOffset::Above;
84 self
85 }
86
87 pub fn below(mut self) -> Self {
89 self.offset = VerticalOffset::Below;
90 self
91 }
92
93 pub fn start(mut self) -> Self {
95 self.anchor = Anchor::Start;
96 self
97 }
98
99 pub fn end(mut self) -> Self {
101 self.anchor = Anchor::End;
102 self
103 }
104
105 pub fn rounded(&self, value: f32) -> String {
107 match self.rounding_precision {
108 Some(digits) => format!("{value:.0$}", digits),
109 None => value.to_string(),
110 }
111 }
112}
113
114impl Tick {
115 pub const LEN: i32 = 20;
116 pub const HLEN: i32 = Tick::LEN + 8;
117 pub const VLEN: i32 = Tick::LEN * 2;
118
119 pub fn new<T>(value: f32, text: T) -> Self
121 where
122 T: Into<String>,
123 {
124 let text = text.into();
125 Tick { value, text }
126 }
127
128 pub fn text(&self) -> &str {
130 &self.text
131 }
132
133 pub fn x(&self, edge: Edge, rect: Rect, len: i32) -> i32 {
135 match edge {
136 Edge::Left => rect.right() - len,
137 Edge::Right => rect.x + len,
138 _ => rect.x + (self.value * rect.width as f32).round() as i32,
139 }
140 }
141
142 pub fn y(&self, edge: Edge, rect: Rect, len: i32) -> i32 {
144 match edge {
145 Edge::Top => rect.bottom() - len,
146 Edge::Bottom => rect.y + len,
147 _ => rect.y + (self.value * rect.height as f32).round() as i32,
148 }
149 }
150}