old school music tracker
1use std::ops::{Add, RangeInclusive};
2
3/// font size in pixel. font is a square
4pub const FONT_SIZE: u8 = 8;
5pub const FONT_SIZE16: u16 = FONT_SIZE as u16;
6/// window size in characters
7pub const WINDOW_SIZE_CHARS: (u8, u8) = (80, 50);
8/// window size in pixel
9pub const WINDOW_SIZE: (u16, u16) = (
10 // TODO: use from once const traits are available
11 FONT_SIZE16 * WINDOW_SIZE_CHARS.0 as u16,
12 FONT_SIZE16 * WINDOW_SIZE_CHARS.1 as u16,
13);
14
15/// CharRect as well as PixelRect uses all values inclusive, meaning the borders are included
16#[derive(Debug, Clone, Copy)]
17pub struct CharRect {
18 top: u8,
19 bot: u8,
20 left: u8,
21 right: u8,
22}
23
24impl CharRect {
25 /// row 11 is reserved for the page title. The page shouldn't draw on it
26 pub const PAGE_AREA: Self = Self::new(12, WINDOW_SIZE_CHARS.1 - 1, 0, WINDOW_SIZE_CHARS.0 - 1);
27 pub const HEADER_AREA: Self = Self::new(0, 10, 0, WINDOW_SIZE_CHARS.0 - 1);
28
29 pub const fn new(top: u8, bot: u8, left: u8, right: u8) -> Self {
30 assert!(top <= bot, "top needs to be smaller than bot");
31 assert!(left <= right, "left needs to be smaller than right");
32 assert!(bot < WINDOW_SIZE_CHARS.1, "lower than window bounds");
33 assert!(right < WINDOW_SIZE_CHARS.0, "right out of window bounds");
34
35 Self {
36 top,
37 bot,
38 left,
39 right,
40 }
41 }
42
43 pub const fn top(self) -> u8 {
44 self.top
45 }
46 pub const fn bot(self) -> u8 {
47 self.bot
48 }
49 pub const fn right(self) -> u8 {
50 self.right
51 }
52 pub const fn left(self) -> u8 {
53 self.left
54 }
55
56 pub const fn top_left(self) -> CharPosition {
57 CharPosition {
58 x: self.left,
59 y: self.top,
60 }
61 }
62
63 pub const fn width(self) -> u8 {
64 self.right - self.left
65 }
66
67 pub const fn height(self) -> u8 {
68 self.bot - self.top
69 }
70}
71
72impl From<CharPosition> for CharRect {
73 fn from(value: CharPosition) -> Self {
74 Self::new(value.y, value.y, value.x, value.x)
75 }
76}
77
78#[cfg(feature = "accesskit")]
79impl From<CharRect> for accesskit::Rect {
80 fn from(value: CharRect) -> Self {
81 accesskit::Rect {
82 x0: value.left as f64,
83 y0: value.top as f64,
84 x1: value.right as f64,
85 y1: value.bot as f64,
86 }
87 }
88}
89
90/// PixelRect as well as CharRect uses all values inclusive, meaning the borders are included
91#[derive(Debug, Clone, Copy)]
92pub struct PixelRect {
93 top: u16,
94 bot: u16,
95 right: u16,
96 left: u16,
97}
98
99impl PixelRect {
100 pub const fn new(top: u16, bot: u16, right: u16, left: u16) -> Self {
101 assert!(top <= bot, "top needs to be smaller than bot");
102 assert!(left <= right, "left needs to be smaller than right");
103 assert!(bot < WINDOW_SIZE.1, "lower than window bounds");
104 assert!(right < WINDOW_SIZE.0, "right out of window bounds");
105
106 Self {
107 top,
108 bot,
109 right,
110 left,
111 }
112 }
113
114 pub const fn vertical_range(&self) -> RangeInclusive<u16> {
115 RangeInclusive::new(self.top, self.bot)
116 }
117
118 pub const fn horizontal_range(&self) -> RangeInclusive<u16> {
119 RangeInclusive::new(self.left, self.right)
120 }
121
122 pub const fn top(&self) -> u16 {
123 self.top
124 }
125
126 pub const fn bot(&self) -> u16 {
127 self.bot
128 }
129
130 pub const fn right(&self) -> u16 {
131 self.right
132 }
133
134 pub const fn left(&self) -> u16 {
135 self.left
136 }
137}
138
139impl From<CharRect> for PixelRect {
140 fn from(value: CharRect) -> Self {
141 Self::new(
142 u16::from(value.top) * FONT_SIZE16,
143 u16::from(value.bot) * FONT_SIZE16 + FONT_SIZE16 - 1,
144 u16::from(value.right) * FONT_SIZE16 + FONT_SIZE16 - 1,
145 u16::from(value.left) * FONT_SIZE16,
146 )
147 }
148}
149
150impl From<CharPosition> for PixelRect {
151 fn from(value: CharPosition) -> Self {
152 Self::from(CharRect::from(value))
153 }
154}
155
156#[derive(Debug, Clone, Copy)]
157pub struct CharPosition {
158 x: u8,
159 y: u8,
160}
161
162impl CharPosition {
163 #[track_caller]
164 pub const fn new(x: u8, y: u8) -> Self {
165 assert!(y < WINDOW_SIZE_CHARS.1);
166 assert!(x < WINDOW_SIZE_CHARS.0);
167
168 Self { x, y }
169 }
170
171 pub const fn x(&self) -> u8 {
172 self.x
173 }
174
175 pub const fn y(&self) -> u8 {
176 self.y
177 }
178}
179
180impl Add for CharPosition {
181 type Output = Self;
182
183 #[track_caller]
184 fn add(self, rhs: Self) -> Self::Output {
185 Self::new(self.x + rhs.x, self.y + rhs.y)
186 }
187}
188
189impl Add<(u8, u8)> for CharPosition {
190 type Output = Self;
191
192 #[track_caller]
193 fn add(self, rhs: (u8, u8)) -> Self::Output {
194 Self::new(self.x + rhs.0, self.y + rhs.1)
195 }
196}
197
198// impl Mul<usize> for CharPosition {
199// type Output = Self;
200
201// fn mul(self, rhs: usize) -> Self::Output {
202// Self::new(self.x * rhs, self.y * rhs)
203// }
204// }