diff options
Diffstat (limited to 'pixel-client/src/ui.rs')
-rw-r--r-- | pixel-client/src/ui.rs | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/pixel-client/src/ui.rs b/pixel-client/src/ui.rs new file mode 100644 index 00000000..802c8e2f --- /dev/null +++ b/pixel-client/src/ui.rs @@ -0,0 +1,169 @@ +use crate::render::{sprite::SpriteDraw, Renderer}; +use hurrycurry_protocol::glam::{IVec2, Vec2}; +use sdl2::{ + keyboard::{KeyboardState, Keycode, Scancode}, + mouse::MouseState, +}; + +#[derive(Default)] +pub struct FocusDevice { + focus: usize, + pressing: Option<usize>, + interact_just_pressed: bool, + interact_just_released: bool, + interact_down: bool, +} + +#[derive(Default)] +pub struct UiState { + mouse_position: Vec2, + ui_scale: Vec2, + + keyboard_focus: FocusDevice, + mouse_focus: FocusDevice, +} + +pub struct Ui<'a, 'b> { + cursor: Vec2, + size: Vec2, + cross_height: f32, + index: usize, + direction_horizontal: bool, + renderer: &'a mut Renderer<'b>, + state: &'a mut UiState, +} + +impl UiState { + pub fn update(&mut self, keyboard: &KeyboardState, mouse: &MouseState, _dt: f32) { + self.mouse_position = IVec2::new(mouse.x(), mouse.y()).as_vec2() / self.ui_scale; + + self.mouse_focus.update(mouse.left()); + self.keyboard_focus + .update(keyboard.is_scancode_pressed(Scancode::Space)); + } + pub fn keyboard_event(&mut self, keycode: Keycode, down: bool) { + if down { + match keycode { + Keycode::DOWN => self.keyboard_focus.focus += 1, + Keycode::UP if self.keyboard_focus.focus > 0 => self.keyboard_focus.focus -= 1, + _ => (), + } + } + } + + pub fn draw(&mut self, renderer: &mut Renderer, ui: impl FnOnce(&mut Ui)) { + self.ui_scale = renderer.ui_scale; + self.mouse_focus.focus = usize::MAX; + let mut u = Ui { + cursor: Vec2::ZERO, + direction_horizontal: false, + size: renderer.ui_size, + renderer, + state: self, + cross_height: 0., + index: 0, + }; + ui(&mut u); + + if self.mouse_focus.interact_just_released { + self.mouse_focus.pressing = None; + } + if self.keyboard_focus.interact_just_released { + self.keyboard_focus.pressing = None; + } + } +} + +impl FocusDevice { + pub fn update(&mut self, interact: bool) { + self.interact_just_pressed = interact && !self.interact_down; + self.interact_just_released = !interact && self.interact_down; + self.interact_down = interact; + } + pub fn element(&mut self, index: usize) -> (bool, bool, bool) { + let focus = self.focus == index; + if focus && self.interact_just_pressed { + self.pressing = Some(index) + }; + let pressing = self.pressing == Some(index); + let released = self.interact_just_released && pressing && focus; + (focus, pressing, released) + } +} + +impl<'a, 'b> Ui<'a, 'b> { + pub fn text(&mut self, text: &str) { + let margin = Vec2::splat(2.); + let size = margin + self.renderer.draw_text(self.cursor + margin, text) + margin; + self.advance(size); + } + pub fn button(&mut self, w: f32, label: &str) -> bool { + let c = self.cursor; + let margin = Vec2::splat(4.); + let text_size = self.renderer.draw_text(self.cursor + margin, label); + let size = margin + Vec2::new(w, text_size.y) + margin; + + self.index += 1; + + let mouse_rel = self.state.mouse_position - c; + if mouse_rel.x >= 0. && mouse_rel.y >= 0. && mouse_rel.x < size.x && mouse_rel.y < size.y { + self.state.mouse_focus.focus = self.index; + } + + let (focus, pressing, released) = { + let (mfocus, mpressing, mreleased) = self.state.mouse_focus.element(self.index); + let (kfocus, kpressing, kreleased) = self.state.keyboard_focus.element(self.index); + ( + mfocus || kfocus, + mpressing || kpressing, + mreleased || kreleased, + ) + }; + + let l = if pressing { + 100 + } else if focus { + 50 + } else { + 30 + }; + self.renderer.draw_ui(SpriteDraw::screen( + self.renderer.misc_textures.solid, + i32::MAX - 1, + c, + size, + Some([l, l, l, 200]), + )); + + self.advance(size); + released + } + + pub fn fill(&mut self) { + self.renderer.draw_ui(SpriteDraw::screen( + self.renderer.misc_textures.solid, + i32::MAX - 1, + self.cursor, + self.get_remaining(), + Some([30, 30, 30, 200]), + )); + } + + pub fn get_remaining(&self) -> Vec2 { + if self.direction_horizontal { + Vec2::new(self.size.x - self.cursor.x, self.cross_height) + } else { + Vec2::new(self.cross_height, self.size.y - self.cursor.y) + } + } + + pub fn advance(&mut self, size: Vec2) { + if self.direction_horizontal { + self.cursor.x += size.x; + self.cross_height = self.cross_height.max(size.y); + } else { + self.cursor.y += size.y; + self.cross_height = self.cross_height.max(size.x); + } + } +} |