diff --git a/crates/render/src/ui/api/functions/ct.rs b/crates/render/src/ui/api/functions/ct.rs new file mode 100644 index 0000000..216261f --- /dev/null +++ b/crates/render/src/ui/api/functions/ct.rs @@ -0,0 +1,121 @@ +use galactica_content::{Content, Outfit}; +use log::error; +use rhai::{CustomType, FnNamespace, FuncRegistration, ImmutableString, Module, TypeBuilder}; +use std::sync::Arc; + +pub fn build_ct_module(ct_src: Arc) -> Module { + let mut module = Module::new(); + module.set_id("GalacticaContentModule"); + + let ct = ct_src.clone(); + let _ = FuncRegistration::new("get_outfit") + .with_namespace(FnNamespace::Internal) + .set_into_module(&mut module, move |outfit_name: ImmutableString| { + let outfit = ct.outfits.get(&outfit_name.clone().into()); + + match outfit { + Some(o) => OutfitState::new(o.clone()), + None => { + error!("called `ct::get_outfit` with an invalid outfit `{outfit_name:?}`"); + OutfitState::new_none() + } + } + }); + + return module; +} + +#[derive(Debug, Clone)] +pub struct OutfitState { + outfit: Option>, +} + +impl OutfitState { + pub fn new(outfit: Arc) -> Self { + Self { + outfit: Some(outfit), + } + } + + pub fn new_none() -> Self { + Self { outfit: None } + } +} + +impl CustomType for OutfitState { + fn build(mut builder: TypeBuilder) { + builder + .with_name("OutfitState") + .with_fn("is_some", |s: &mut Self| s.outfit.is_some()) + .with_fn("display_name", |s: &mut Self| { + s.outfit + .as_ref() + .map(|x| x.display_name.clone()) + .unwrap_or("".to_string()) + }) + .with_fn("desc", |s: &mut Self| { + s.outfit + .as_ref() + .map(|x| x.desc.clone()) + .unwrap_or("".to_string()) + }) + .with_fn("index", |s: &mut Self| { + s.outfit + .as_ref() + .map(|x| x.index.to_string()) + .unwrap_or("".to_string()) + }) + .with_fn("thumbnail", |s: &mut Self| { + s.outfit + .as_ref() + .map(|x| x.thumbnail.index.to_string()) + .unwrap_or("".to_string()) + }) + // + // Stat getters + // + .with_fn("stat_thrust", |s: &mut Self| { + s.outfit + .as_ref() + .map(|x| x.stats.steer_power) + .unwrap_or(0.0) + }) + .with_fn("stat_steer_power", |s: &mut Self| { + s.outfit + .as_ref() + .map(|x| x.stats.steer_power) + .unwrap_or(0.0) + }) + .with_fn("stat_shield_strength", |s: &mut Self| { + s.outfit + .as_ref() + .map(|x| x.stats.shield_strength) + .unwrap_or(0.0) + }) + .with_fn("stat_shield_generation", |s: &mut Self| { + s.outfit + .as_ref() + .map(|x| x.stats.shield_generation) + .unwrap_or(0.0) + }) + .with_fn("stat_shield_delay", |s: &mut Self| { + s.outfit + .as_ref() + .map(|x| x.stats.shield_delay) + .unwrap_or(0.0) + }) + .with_fn("stat_shield_dps", |s: &mut Self| { + s.outfit + .as_ref() + .map(|x| { + if x.gun.is_some() { + (1.0 / x.gun.as_ref().unwrap().rate) + * x.gun.as_ref().unwrap().projectile.damage + } else { + 0.0 + } + }) + .unwrap_or(0.0) + }); + } +} diff --git a/crates/render/src/ui/api/functions/mod.rs b/crates/render/src/ui/api/functions/mod.rs index 058568c..440e9d8 100644 --- a/crates/render/src/ui/api/functions/mod.rs +++ b/crates/render/src/ui/api/functions/mod.rs @@ -1,4 +1,5 @@ mod conf; +mod ct; mod radialbar; mod scrollbox; mod sprite; @@ -6,6 +7,7 @@ mod textbox; mod ui; pub use conf::build_conf_module; +pub use ct::{build_ct_module, OutfitState}; pub use radialbar::build_radialbar_module; pub use scrollbox::build_scrollbox_module; pub use sprite::build_sprite_module; diff --git a/crates/render/src/ui/api/functions/sprite.rs b/crates/render/src/ui/api/functions/sprite.rs index b83e899..85c95df 100644 --- a/crates/render/src/ui/api/functions/sprite.rs +++ b/crates/render/src/ui/api/functions/sprite.rs @@ -62,6 +62,32 @@ pub fn build_sprite_module(ct_src: Arc, state_src: Rc> } }); + let state = state_src.clone(); + let ct = ct_src.clone(); + let _ = FuncRegistration::new("set_sprite") + .with_namespace(FnNamespace::Internal) + .set_into_module( + &mut module, + move |name: ImmutableString, sprite: ImmutableString| { + let mut ui_state = state.borrow_mut(); + + match ui_state.get_mut_by_name(&name) { + Some(UiElement::Sprite(x)) => { + let m = ct.sprites.get(&sprite.clone().into()).clone(); + if m.is_none() { + error!("called `sprite::set_sprite` with an invalid sprite `{sprite}`"); + return; + } + x.set_sprite(m.unwrap().clone()) + } + + _ => { + error!("called `sprite::set_sprite` on an invalid name `{sprite}`") + } + } + }, + ); + let state = state_src.clone(); let ct = ct_src.clone(); let _ = FuncRegistration::new("set_mask") @@ -198,6 +224,7 @@ pub fn build_sprite_module(ct_src: Arc, state_src: Rc> e.set_color(x); }); + // TODO: fix click collider when preserving aspect let state = state_src.clone(); let _ = FuncRegistration::new("preserve_aspect") .with_namespace(FnNamespace::Internal) @@ -221,8 +248,9 @@ pub fn build_sprite_module(ct_src: Arc, state_src: Rc> e.set_preserve_aspect(x); }); + // TODO: maybe remove? let state = state_src.clone(); - let _ = FuncRegistration::new("set_disable_events") + let _ = FuncRegistration::new("disable_events") .with_namespace(FnNamespace::Internal) .set_into_module(&mut module, move |name: ImmutableString, x: bool| { let mut ui_state = state.borrow_mut(); @@ -230,13 +258,13 @@ pub fn build_sprite_module(ct_src: Arc, state_src: Rc> Some(UiElement::SubElement { element, .. }) => match &mut **element { UiElement::Sprite(x) => x, _ => { - error!("called `sprite::set_disable_events` on an invalid name `{name}`"); + error!("called `sprite::disable_events` on an invalid name `{name}`"); return; } }, Some(UiElement::Sprite(x)) => x, _ => { - error!("called `sprite::set_disable_events` on an invalid name `{name}`"); + error!("called `sprite::disable_events` on an invalid name `{name}`"); return; } }; diff --git a/crates/render/src/ui/api/functions/textbox.rs b/crates/render/src/ui/api/functions/textbox.rs index bbc59de..59131e1 100644 --- a/crates/render/src/ui/api/functions/textbox.rs +++ b/crates/render/src/ui/api/functions/textbox.rs @@ -23,8 +23,8 @@ pub fn build_textbox_module( move |name: ImmutableString, font_size: f32, line_height: f32, - rect: Rect, - color: Color| { + color: Color, + rect: Rect| { let mut ui_state = state.borrow_mut(); if ui_state.contains_name(&name) { @@ -72,6 +72,32 @@ pub fn build_textbox_module( }, ); + let state = state_src.clone(); + let font = font_src.clone(); + let _ = FuncRegistration::new("set_color") + .with_namespace(FnNamespace::Internal) + .set_into_module(&mut module, move |name: ImmutableString, color: Color| { + let mut ui_state = state.borrow_mut(); + + let e = match ui_state.get_mut_by_name(&name) { + Some(UiElement::SubElement { element, .. }) => match &mut **element { + UiElement::Text(x) => x, + _ => { + error!("called `textbox::set_color` on an invalid name `{name}`"); + return; + } + }, + + Some(UiElement::Text(x)) => x, + _ => { + error!("called `textbox::set_color` on an invalid name `{name}`"); + return; + } + }; + + e.set_color(&mut font.borrow_mut(), color); + }); + let state = state_src.clone(); let font = font_src.clone(); let _ = FuncRegistration::new("align_left") diff --git a/crates/render/src/ui/api/helpers/anchor.rs b/crates/render/src/ui/api/helpers/anchor.rs index 992e60a..5586782 100644 --- a/crates/render/src/ui/api/helpers/anchor.rs +++ b/crates/render/src/ui/api/helpers/anchor.rs @@ -10,19 +10,11 @@ pub enum Anchor { } #[export_module] +#[allow(non_upper_case_globals)] pub mod anchor_mod { - #[allow(non_upper_case_globals)] pub const Center: Anchor = Anchor::Center; - - #[allow(non_upper_case_globals)] pub const NorthWest: Anchor = Anchor::NorthWest; - - #[allow(non_upper_case_globals)] pub const NorthEast: Anchor = Anchor::NorthEast; - - #[allow(non_upper_case_globals)] pub const SouthWest: Anchor = Anchor::SouthWest; - - #[allow(non_upper_case_globals)] pub const SouthEast: Anchor = Anchor::SouthEast; } diff --git a/crates/render/src/ui/api/helpers/rect.rs b/crates/render/src/ui/api/helpers/rect.rs index bc5e145..4fca31b 100644 --- a/crates/render/src/ui/api/helpers/rect.rs +++ b/crates/render/src/ui/api/helpers/rect.rs @@ -17,7 +17,7 @@ pub struct Rect { } impl Rect { - pub fn new(x: f32, y: f32, w: f32, h: f32, anchor_self: Anchor, anchor_parent: Anchor) -> Self { + pub fn new(x: f32, y: f32, w: f32, h: f32, anchor_parent: Anchor, anchor_self: Anchor,) -> Self { Self { pos: Point2::new(x, y), dim: Vector2::new(w, h), diff --git a/crates/render/src/ui/api/mod.rs b/crates/render/src/ui/api/mod.rs index 6996ab4..c081463 100644 --- a/crates/render/src/ui/api/mod.rs +++ b/crates/render/src/ui/api/mod.rs @@ -6,6 +6,7 @@ mod state; pub use directive::*; pub use event::*; +pub use functions::OutfitState; pub use helpers::{anchor::*, color::*, rect::*, vector::*}; pub use state::*; @@ -52,6 +53,7 @@ pub fn register_into_engine( // Modules engine.register_static_module("ui", functions::build_ui_module(state_src.clone()).into()); + engine.register_static_module("ct", functions::build_ct_module(ct_src.clone()).into()); engine.register_static_module( "sprite", functions::build_sprite_module(ct_src.clone(), state_src.clone()).into(), diff --git a/crates/render/src/ui/api/state.rs b/crates/render/src/ui/api/state.rs index 93b2f67..c2f23a4 100644 --- a/crates/render/src/ui/api/state.rs +++ b/crates/render/src/ui/api/state.rs @@ -1,4 +1,4 @@ -use galactica_content::{Outfit, Ship, SystemObject}; +use galactica_content::{Ship, SystemObject}; use galactica_system::{ data::{self}, phys::{objects::PhysShip, PhysSimShipHandle}, @@ -10,7 +10,7 @@ use rapier2d::dynamics::RigidBody; use rhai::{Array, CustomType, Dynamic, ImmutableString, TypeBuilder}; use std::sync::Arc; -use super::{Color, UiVector}; +use super::{functions::OutfitState, Color, UiVector}; use crate::{RenderInput, RenderState}; #[derive(Debug, Clone)] @@ -147,101 +147,6 @@ impl CustomType for ShipState { } } -#[derive(Debug, Clone)] -pub struct OutfitState { - outfit: Option>, -} - -impl OutfitState { - pub fn new(outfit: Arc) -> Self { - Self { - outfit: Some(outfit), - } - } - - pub fn new_none() -> Self { - Self { outfit: None } - } -} - -impl CustomType for OutfitState { - fn build(mut builder: TypeBuilder) { - builder - .with_name("OutfitState") - .with_fn("is_some", |s: &mut Self| s.outfit.is_some()) - .with_fn("display_name", |s: &mut Self| { - s.outfit - .as_ref() - .map(|x| x.display_name.clone()) - .unwrap_or("".to_string()) - }) - .with_fn("desc", |s: &mut Self| { - s.outfit - .as_ref() - .map(|x| x.desc.clone()) - .unwrap_or("".to_string()) - }) - .with_fn("index", |s: &mut Self| { - s.outfit - .as_ref() - .map(|x| x.index.to_string()) - .unwrap_or("".to_string()) - }) - .with_fn("thumbnail", |s: &mut Self| { - s.outfit - .as_ref() - .map(|x| x.thumbnail.index.to_string()) - .unwrap_or("".to_string()) - }) - // - // Stat getters - // - .with_fn("stat_thrust", |s: &mut Self| { - s.outfit - .as_ref() - .map(|x| x.stats.steer_power) - .unwrap_or(0.0) - }) - .with_fn("stat_steer_power", |s: &mut Self| { - s.outfit - .as_ref() - .map(|x| x.stats.steer_power) - .unwrap_or(0.0) - }) - .with_fn("stat_shield_strength", |s: &mut Self| { - s.outfit - .as_ref() - .map(|x| x.stats.shield_strength) - .unwrap_or(0.0) - }) - .with_fn("stat_shield_generation", |s: &mut Self| { - s.outfit - .as_ref() - .map(|x| x.stats.shield_generation) - .unwrap_or(0.0) - }) - .with_fn("stat_shield_delay", |s: &mut Self| { - s.outfit - .as_ref() - .map(|x| x.stats.shield_delay) - .unwrap_or(0.0) - }) - .with_fn("stat_shield_dps", |s: &mut Self| { - s.outfit - .as_ref() - .map(|x| { - if x.gun.is_some() { - (1.0 / x.gun.as_ref().unwrap().rate) - * x.gun.as_ref().unwrap().projectile.damage - } else { - 0.0 - } - }) - .unwrap_or(0.0) - }); - } -} - #[derive(Debug, Clone)] pub struct SystemObjectState { object: Option>, diff --git a/crates/render/src/ui/elements/sprite.rs b/crates/render/src/ui/elements/sprite.rs index 35c39de..c35eadf 100644 --- a/crates/render/src/ui/elements/sprite.rs +++ b/crates/render/src/ui/elements/sprite.rs @@ -50,6 +50,10 @@ impl UiSprite { } } + pub fn set_sprite(&mut self, sprite: Arc) { + self.anim = SpriteAutomaton::new(sprite); + } + pub fn set_mask(&mut self, mask: Option>) { self.mask = mask; } diff --git a/crates/render/src/ui/elements/textbox.rs b/crates/render/src/ui/elements/textbox.rs index 6b272dc..e845c1b 100644 --- a/crates/render/src/ui/elements/textbox.rs +++ b/crates/render/src/ui/elements/textbox.rs @@ -64,6 +64,11 @@ impl UiTextBox { self.reflow(font); } + pub fn set_color(&mut self, font: &mut FontSystem, color: api::Color) { + self.color = color; + self.reflow(font); + } + pub fn set_align(&mut self, font: &mut FontSystem, align: Align) { self.justify = align; self.reflow(font);