diff options
author | Katharina Fey <kookie@spacekookie.de> | 2021-02-20 19:29:08 +0100 |
---|---|---|
committer | Katharina Fey <kookie@spacekookie.de> | 2021-02-21 16:20:21 +0100 |
commit | 4aa0222a1fb78aa66e6efd1179a1901d728dbfb8 (patch) | |
tree | 69ce1ae191edd0354a6e68a2b872f6fe6c7c3d7c /games | |
parent | 0491ac6198b4fa2946d799c5661286b8bd3c88de (diff) |
rstnode: basic ui abstraction (text button)
Diffstat (limited to 'games')
-rw-r--r-- | games/rstnode/rst-client/src/color.rs | 27 | ||||
-rw-r--r-- | games/rstnode/rst-client/src/editor/mod.rs | 50 | ||||
-rw-r--r-- | games/rstnode/rst-client/src/ui/button.rs | 109 | ||||
-rw-r--r-- | games/rstnode/rst-client/src/ui/mod.rs | 4 |
4 files changed, 189 insertions, 1 deletions
diff --git a/games/rstnode/rst-client/src/color.rs b/games/rstnode/rst-client/src/color.rs index 4fbd7519dcd0..65c32974ac81 100644 --- a/games/rstnode/rst-client/src/color.rs +++ b/games/rstnode/rst-client/src/color.rs @@ -1,7 +1,32 @@ use ggez::graphics::Color as EzColor; use rst_core::data::Color; - pub fn to(Color(r, g, b): Color) -> EzColor { EzColor::from_rgb(r, g, b) } + +/// A utility for manipulating colours +pub trait ColorUtils { + fn darken(&self, factor: u8) -> Self; + fn brighten(&self, factor: u8) -> Self; +} + +impl ColorUtils for EzColor { + fn darken(&self, factor: u8) -> Self { + Self { + r: self.r / factor as f32, + g: self.g / factor as f32, + b: self.b / factor as f32, + a: self.a, + } + } + + fn brighten(&self, factor: u8) -> Self { + Self { + r: self.r * factor as f32, + g: self.g * factor as f32, + b: self.b * factor as f32, + a: self.a, + } + } +} diff --git a/games/rstnode/rst-client/src/editor/mod.rs b/games/rstnode/rst-client/src/editor/mod.rs new file mode 100644 index 000000000000..ba7867017535 --- /dev/null +++ b/games/rstnode/rst-client/src/editor/mod.rs @@ -0,0 +1,50 @@ +use crate::{assets::Assets, input::InputHandle, ui::Button, viewport::Viewport, GameSettings}; +use ggez::{ + event::{EventHandler, MouseButton}, + graphics::{self, Color}, + Context, GameResult, +}; + +pub struct EditorState { + assets: Assets, + settings: GameSettings, + input: InputHandle, + vp: Viewport, + btn: Button, +} + +impl EditorState { + pub fn new(settings: GameSettings, assets: Assets) -> Self { + info!("Initialising map editor state"); + Self { + assets, + settings, + vp: Viewport::new(), + input: InputHandle::new(), + btn: Button::new( + (25.0, 25.0).into(), + (250.0, 125.0).into(), + Some("Create Node".into()), + Color::from_rgb(50, 50, 50), + ), + } + } +} + +impl EventHandler for EditorState { + fn update(&mut self, ctx: &mut Context) -> GameResult<()> { + Ok(()) + } + + fn mouse_button_down_event(&mut self, ctx: &mut Context, btn: MouseButton, x: f32, y: f32) { + self.btn.mouse_button_down_event(ctx, btn, x, y) + } + + fn draw(&mut self, ctx: &mut Context) -> GameResult<()> { + graphics::clear(ctx, graphics::Color::from_rgb(15, 15, 15)); + + self.btn.draw(ctx)?; + + graphics::present(ctx) + } +} diff --git a/games/rstnode/rst-client/src/ui/button.rs b/games/rstnode/rst-client/src/ui/button.rs new file mode 100644 index 000000000000..9d51b0271cbc --- /dev/null +++ b/games/rstnode/rst-client/src/ui/button.rs @@ -0,0 +1,109 @@ +use crate::color::ColorUtils; +use ggez::graphics::{self, Align, Color, DrawMode, DrawParam, Drawable, MeshBuilder, Rect, Text}; +use ggez::{ + event::{EventHandler, MouseButton}, + Context, GameResult, +}; +use rst_core::data::Pos; +use std::collections::HashMap; + +/// A button with next that can be clicked to run some code +pub struct Button { + pos: Pos, + size: Pos, + text: Option<String>, + color_base: Color, + color_trim: Color, + cbs: HashMap<MouseButton, Box<dyn FnMut() -> ()>>, +} + +impl Button { + /// Create a new button + pub fn new( + pos: Pos, + size: Pos, + text: impl Into<Option<String>>, + color: impl Into<Color>, + ) -> Self { + let color = color.into(); + + Self { + pos, + size, + text: text.into(), + color_base: color.clone(), + color_trim: color.brighten(2), + cbs: HashMap::new(), + } + } + + /// Register an on-click listening closure + pub fn on_click<C: FnMut() -> () + 'static>(&mut self, btn: MouseButton, cb: C) { + self.cbs.insert(btn, Box::new(cb)); + } + + /// Create a button with text which auto-infers its required size + pub fn auto(pos: Pos, text: String, color: impl Into<Color>) -> Self { + todo!() + } + + fn boundry_check(&self, x: f32, y: f32) -> bool { + self.pos.x < x + && (self.pos.x + self.size.x) > x + && self.pos.y < y + && (self.pos.y + self.size.y) > y + } +} + +impl EventHandler for Button { + fn update(&mut self, ctx: &mut Context) -> GameResult<()> { + Ok(()) + } + + fn mouse_button_down_event(&mut self, _ctx: &mut Context, btn: MouseButton, x: f32, y: f32) { + if self.boundry_check(x, y) { + trace!("Triggering button state"); + std::mem::swap(&mut self.color_base, &mut self.color_trim); + if let Some(ref mut callback) = self.cbs.get_mut(&btn) { + callback(); + } + } + } + + fn draw(&mut self, ctx: &mut Context) -> GameResult<()> { + let mut mb = MeshBuilder::new(); + let bounds = Rect { + x: self.pos.x, + y: self.pos.y, + w: self.size.x, + h: self.size.y, + }; + + // Create the basic building blocks + let rect = mb + .rectangle(DrawMode::fill(), bounds, self.color_base.clone())? + .build(ctx)?; + let frame = mb + .rectangle(DrawMode::stroke(2.0), bounds, self.color_trim.clone())? + .build(ctx)?; + + rect.draw(ctx, DrawParam::new())?; + frame.draw(ctx, DrawParam::new())?; + + if let Some(ref text) = self.text { + let Pos { x, y } = self.pos; + let Pos { x: w, y: h } = self.size; + + let mut text = Text::new(text.clone()); + text.draw( + ctx, + DrawParam::new().dest([ + x + (w / 2.0 - text.width(ctx) / 2.0), + y + (h / 2.0 - text.height(ctx) / 2.0), + ]), + )?; + } + + Ok(()) + } +} diff --git a/games/rstnode/rst-client/src/ui/mod.rs b/games/rstnode/rst-client/src/ui/mod.rs new file mode 100644 index 000000000000..449f04efc1e7 --- /dev/null +++ b/games/rstnode/rst-client/src/ui/mod.rs @@ -0,0 +1,4 @@ +//! Use ggez to render various UI elements and component clusters + +mod button; +pub use button::*; |