From 0afd30f7013900b44e1356eab2a0dc7fd711bd30 Mon Sep 17 00:00:00 2001 From: Paris DOUADY Date: Wed, 24 Jan 2024 21:38:12 +0100 Subject: [PATCH] start working on bottom tool picker --- Cargo.lock | 36 ++---- assets/ui/icons/curved_road.png | 3 + assets/ui/icons/straight_road.png | 3 + engine/src/yakui.rs | 2 + goryak/src/imagebutton.rs | 166 ++++++++++++++++++++++++++ goryak/src/lib.rs | 2 + native_app/src/gui/mod.rs | 5 +- native_app/src/gui/tools/roadbuild.rs | 23 +++- native_app/src/newgui/topgui.rs | 68 ++++++++++- 9 files changed, 271 insertions(+), 37 deletions(-) create mode 100644 assets/ui/icons/curved_road.png create mode 100644 assets/ui/icons/straight_road.png create mode 100644 goryak/src/imagebutton.rs diff --git a/Cargo.lock b/Cargo.lock index f17b37b3..f14145f8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2081,7 +2081,7 @@ version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" dependencies = [ - "proc-macro-crate 1.3.1", + "proc-macro-crate", "proc-macro2", "quote", "syn 1.0.109", @@ -2093,7 +2093,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" dependencies = [ - "proc-macro-crate 3.1.0", + "proc-macro-crate", "proc-macro2", "quote", "syn 2.0.48", @@ -2418,16 +2418,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" dependencies = [ "once_cell", - "toml_edit 0.19.15", -] - -[[package]] -name = "proc-macro-crate" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" -dependencies = [ - "toml_edit 0.21.0", + "toml_edit", ] [[package]] @@ -3148,17 +3139,6 @@ dependencies = [ "winnow", ] -[[package]] -name = "toml_edit" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" -dependencies = [ - "indexmap", - "toml_datetime", - "winnow", -] - [[package]] name = "tracing" version = "0.1.40" @@ -4030,7 +4010,7 @@ checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a" [[package]] name = "yakui" version = "0.2.0" -source = "git+https://github.com/Uriopass/yakui?branch=dev#35cefe44dd833db1e90f7af8feccb11b7c4c3ecf" +source = "git+https://github.com/Uriopass/yakui?branch=dev#6cd0b1a5147d46c17353b2c67d04fadd43fd6cb6" dependencies = [ "yakui-core", "yakui-widgets", @@ -4039,7 +4019,7 @@ dependencies = [ [[package]] name = "yakui-core" version = "0.2.0" -source = "git+https://github.com/Uriopass/yakui?branch=dev#35cefe44dd833db1e90f7af8feccb11b7c4c3ecf" +source = "git+https://github.com/Uriopass/yakui?branch=dev#6cd0b1a5147d46c17353b2c67d04fadd43fd6cb6" dependencies = [ "anymap", "bitflags 1.3.2", @@ -4055,7 +4035,7 @@ dependencies = [ [[package]] name = "yakui-wgpu" version = "0.2.0" -source = "git+https://github.com/Uriopass/yakui?branch=dev#35cefe44dd833db1e90f7af8feccb11b7c4c3ecf" +source = "git+https://github.com/Uriopass/yakui?branch=dev#6cd0b1a5147d46c17353b2c67d04fadd43fd6cb6" dependencies = [ "bytemuck", "glam", @@ -4068,7 +4048,7 @@ dependencies = [ [[package]] name = "yakui-widgets" version = "0.2.0" -source = "git+https://github.com/Uriopass/yakui?branch=dev#35cefe44dd833db1e90f7af8feccb11b7c4c3ecf" +source = "git+https://github.com/Uriopass/yakui?branch=dev#6cd0b1a5147d46c17353b2c67d04fadd43fd6cb6" dependencies = [ "fontdue", "smol_str 0.1.24", @@ -4079,7 +4059,7 @@ dependencies = [ [[package]] name = "yakui-winit" version = "0.2.0" -source = "git+https://github.com/Uriopass/yakui?branch=dev#35cefe44dd833db1e90f7af8feccb11b7c4c3ecf" +source = "git+https://github.com/Uriopass/yakui?branch=dev#6cd0b1a5147d46c17353b2c67d04fadd43fd6cb6" dependencies = [ "winit", "yakui-core", diff --git a/assets/ui/icons/curved_road.png b/assets/ui/icons/curved_road.png new file mode 100644 index 00000000..bd90d25e --- /dev/null +++ b/assets/ui/icons/curved_road.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c512cfe682e1a25cc5d88568e34e5368e71717cb29b07f049d2c78201ea732c8 +size 5011 diff --git a/assets/ui/icons/straight_road.png b/assets/ui/icons/straight_road.png new file mode 100644 index 00000000..5b557122 --- /dev/null +++ b/assets/ui/icons/straight_road.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c7c218e835cf411537997b3d53c301cc83112c65748347d243c7af5f743f36a2 +size 3908 diff --git a/engine/src/yakui.rs b/engine/src/yakui.rs index 06669345..fa8d39bd 100644 --- a/engine/src/yakui.rs +++ b/engine/src/yakui.rs @@ -42,6 +42,7 @@ impl YakuiWrapper { gfx.null_texture.mip_view(0), wgpu::FilterMode::Linear, wgpu::FilterMode::Linear, + wgpu::FilterMode::Linear, ); goryak::set_blur_texture(texture_id); @@ -62,6 +63,7 @@ impl YakuiWrapper { Arc::new(tex.texture.create_view(&TextureViewDescriptor::default())), wgpu::FilterMode::Linear, wgpu::FilterMode::Linear, + wgpu::FilterMode::Linear, ) } diff --git a/goryak/src/imagebutton.rs b/goryak/src/imagebutton.rs new file mode 100644 index 00000000..d760d5e5 --- /dev/null +++ b/goryak/src/imagebutton.rs @@ -0,0 +1,166 @@ +use yakui_core::event::{EventInterest, EventResponse, WidgetEvent}; +use yakui_core::geometry::{Color, Constraints, Rect, Vec2}; +use yakui_core::input::MouseButton; +use yakui_core::paint::PaintRect; +use yakui_core::widget::{EventContext, LayoutContext, PaintContext, Widget}; +use yakui_core::{Response, TextureId}; +use yakui_widgets::shapes::RoundedRectangle; +use yakui_widgets::widgets::{Image, Pad, PadWidget}; + +/** +A button based on an image + +Responds with [ImageButtonResponse]. + */ +#[derive(Debug, Clone)] +pub struct ImageButton { + pub texture: Option, + pub size: Vec2, + pub color: Color, + pub hover_color: Color, + pub active_color: Color, +} + +impl ImageButton { + pub fn empty() -> Self { + Self { + texture: None, + size: Vec2::ZERO, + color: Color::WHITE, + hover_color: Color::WHITE, + active_color: Color::WHITE, + } + } + + pub fn new( + texture: TextureId, + size: Vec2, + color: Color, + hover_color: Color, + active_color: Color, + ) -> Self { + Self { + texture: Some(texture), + size, + color, + hover_color, + active_color, + } + } + + pub fn show(self) -> Response { + yakui_widgets::util::widget::(self) + } +} + +pub fn image_button( + texture: TextureId, + size: Vec2, + color: Color, + hover_color: Color, + active_color: Color, +) -> Response { + ImageButton { + texture: Some(texture), + size, + color, + hover_color, + active_color, + } + .show() +} + +#[derive(Debug)] +pub struct ImageButtonWidget { + props: ImageButton, + resp: ImageButtonResponse, +} + +#[derive(Copy, Clone, Debug, Default)] +pub struct ImageButtonResponse { + pub hovering: bool, + pub mouse_down: bool, + pub mouse_entered: bool, + pub clicked: bool, +} + +impl Widget for ImageButtonWidget { + type Props<'a> = ImageButton; + type Response = ImageButtonResponse; + + fn new() -> Self { + Self { + props: ImageButton::empty(), + resp: ImageButtonResponse::default(), + } + } + + fn update(&mut self, props: Self::Props<'_>) -> Self::Response { + self.props = props; + let resp = self.resp; + self.resp.mouse_entered = false; + self.resp.clicked = false; + resp + } + + fn paint(&self, mut ctx: PaintContext<'_>) { + let node = ctx.dom.get_current(); + let layout_node = ctx.layout.get(ctx.dom.current()).unwrap(); + + let curcolor = if self.resp.mouse_down { + self.props.active_color + } else if self.resp.hovering { + self.props.hover_color + } else { + self.props.color + }; + + let mut rect = PaintRect::new(layout_node.rect); + rect.color = curcolor; + if let Some(tex) = self.props.texture { + rect.texture = Some((tex, Rect::ONE)); + } + rect.add(ctx.paint); + + for &child in &node.children { + ctx.paint(child); + } + } + + fn event_interest(&self) -> EventInterest { + EventInterest::MOUSE_ALL + } + + fn layout(&self, _ctx: LayoutContext<'_>, input: Constraints) -> Vec2 { + input.constrain_min(self.props.size) + } + + fn event(&mut self, _: EventContext<'_>, event: &WidgetEvent) -> EventResponse { + match event { + WidgetEvent::MouseEnter => { + self.resp.mouse_entered = true; + self.resp.hovering = true; + EventResponse::Bubble + } + WidgetEvent::MouseLeave => { + self.resp.hovering = false; + EventResponse::Bubble + } + WidgetEvent::MouseButtonChanged { + button: MouseButton::One, + down, + inside, + .. + } => { + if *down && *inside { + self.resp.clicked = true; + self.resp.mouse_down = true; + } else { + self.resp.mouse_down = false; + } + EventResponse::Bubble + } + _ => EventResponse::Bubble, + } + } +} diff --git a/goryak/src/lib.rs b/goryak/src/lib.rs index c2338940..4b9ee861 100644 --- a/goryak/src/lib.rs +++ b/goryak/src/lib.rs @@ -6,6 +6,7 @@ mod divider; mod dragvalue; mod hovered; mod icon; +mod imagebutton; mod interact_box; mod layout; mod roundrect; @@ -22,6 +23,7 @@ pub use divider::*; pub use dragvalue::*; pub use hovered::*; pub use icon::*; +pub use imagebutton::*; pub use interact_box::*; pub use layout::*; pub use roundrect::*; diff --git a/native_app/src/gui/mod.rs b/native_app/src/gui/mod.rs index 009c4d47..07860adf 100644 --- a/native_app/src/gui/mod.rs +++ b/native_app/src/gui/mod.rs @@ -187,7 +187,10 @@ impl UiTextures { } pub fn get_yakui(&self, name: &str) -> yakui::TextureId { - self.yakui_textures.get(name).unwrap().clone() + match self.yakui_textures.get(name) { + None => panic!("Couldn't find texture {}", name), + Some(x) => *x, + } } pub fn try_get(&self, name: &str) -> Option { diff --git a/native_app/src/gui/tools/roadbuild.rs b/native_app/src/gui/tools/roadbuild.rs index 399715d5..afd21fc4 100644 --- a/native_app/src/gui/tools/roadbuild.rs +++ b/native_app/src/gui/tools/roadbuild.rs @@ -392,7 +392,7 @@ impl RoadBuildResource { points: Option, ) { let mut proj_pos = proj.pos; - proj_pos.z += 0.1; + proj_pos.z += 0.4; let col = if is_valid { simulation::config().gui_primary } else { @@ -413,7 +413,11 @@ impl RoadBuildResource { for i in 0..=32 { let ang = std::f32::consts::PI * i as f32 * (2.0 / 32.0); let mut v = Vec3::from_angle(ang, dir.z); - let center = if v.dot(dir) < 0.0 { x.pos } else { proj.pos }; + let center = if v.dot(dir) < 0.0 { + x.pos.up(0.4) + } else { + proj_pos + }; v = v * patwidth * 0.5; v.z = 0.0; @@ -439,8 +443,17 @@ impl RoadBuildResource { .color(col); } - immdraw.circle(p.first(), patwidth * 0.5).color(col); - immdraw.circle(p.last(), patwidth * 0.5).color(col); - immdraw.polyline(p.into_vec(), patwidth, false).color(col); + immdraw.circle(p.first().up(0.4), patwidth * 0.5).color(col); + immdraw.circle(p.last().up(0.4), patwidth * 0.5).color(col); + immdraw + .polyline( + p.into_vec() + .into_iter() + .map(|v| v.up(0.4)) + .collect::>(), + patwidth, + false, + ) + .color(col); } } diff --git a/native_app/src/newgui/topgui.rs b/native_app/src/newgui/topgui.rs index 82b169b4..9a340e66 100644 --- a/native_app/src/newgui/topgui.rs +++ b/native_app/src/newgui/topgui.rs @@ -6,15 +6,15 @@ use yakui::{ }; use goryak::{ - blur_bg, button_primary, button_secondary, constrained_viewport, icon_map, monospace, padx, - padxy, secondary_container, + blur_bg, button_primary, button_secondary, constrained_viewport, icon_map, image_button, + monospace, padx, padxy, primary, secondary_container, }; use prototypes::GameTime; use simulation::map_dynamic::ElectricityFlow; use simulation::Simulation; use crate::gui::windows::settings::Settings; -use crate::gui::{Gui, UiTextures}; +use crate::gui::{Gui, Tool, UiTextures}; use crate::inputmap::{InputAction, InputMap}; use crate::uiworld::UiWorld; @@ -31,6 +31,7 @@ impl Gui { yakui::column(|| { self.time_controls(uiworld, sim); self.power_errors(uiworld, sim); + self.new_toolbox(uiworld, sim); }); } @@ -134,6 +135,67 @@ impl Gui { }); } + fn new_toolbox(&self, uiworld: &mut UiWorld, _sim: &Simulation) { + if uiworld + .read::() + .just_act + .contains(&InputAction::Close) + { + *uiworld.write::() = Tool::Hand; + } + + let tools = [ + ("straight_road", Tool::RoadbuildStraight), + ("curved_road", Tool::RoadbuildCurved), + //("road_edit", Tool::RoadEditor), + //("housebrush", Tool::LotBrush), + //("buildings", Tool::SpecialBuilding), + //("bulldozer", Tool::Bulldozer), + //("traintool", Tool::Train), + //("terraform", Tool::Terraforming), + ]; + + yakui::reflow(Alignment::TOP_LEFT, Dim2::ZERO, || { + constrained_viewport(|| { + let mut l = List::column(); + l.cross_axis_alignment = CrossAxisAlignment::Stretch; + + l.show(|| { + spacer(1); + yakui::opaque(|| { + blur_bg(secondary_container().with_alpha(0.3), 0.0, || { + padxy(0.0, 10.0, || { + let mut l = List::row(); + l.main_axis_alignment = MainAxisAlignment::Center; + l.show(|| { + for (name, tool) in &tools { + let tint = if *tool == *uiworld.read::() { + primary() + } else { + Color::WHITE + }; + + if image_button( + uiworld.read::().get_yakui(name), + Vec2::new(64.0, 64.0), + tint, + Color::WHITE.with_alpha(0.7), + primary(), + ) + .clicked + { + *uiworld.write::() = *tool; + } + } + }); + }); + }); + }); + }); + }); + }); + } + fn power_errors(&mut self, uiworld: &UiWorld, sim: &Simulation) { profiling::scope!("topgui::power_errors"); let map = sim.map();