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