API cleanup

master
Mark 2024-02-05 10:12:15 -08:00
parent d4bd7e82bd
commit a817ad0d0f
Signed by: Mark
GPG Key ID: C6D63995FE72FD80
17 changed files with 650 additions and 542 deletions

View File

@ -1,10 +1,10 @@
# Specific projects
## Now:
- Clean up API (modules)
- Clean up state api
- Persistent variables
- Better planet icons
- Clean up scripting & errors
- Clean up scripting errors
- Mouse colliders
- UI captures input?
- No UI zoom scroll

View File

@ -1,9 +1,9 @@
fn init(state) {
conf_set_starfield(true);
conf_set_phys(true);
conf::show_starfield(true);
conf::show_phys(true);
add_sprite(
sprite::add(
"ring",
"ui::status",
Rect(
@ -13,7 +13,7 @@ fn init(state) {
)
);
add_radialbar(
radialbar::add(
"shield", 2.5,
Color(0.3, 0.6, 0.8, 1.0),
Rect(
@ -23,7 +23,7 @@ fn init(state) {
)
);
add_radialbar(
radialbar::add(
"hull", 2.5,
Color(0.8, 0.7, 0.5, 1.0),
Rect(
@ -40,7 +40,7 @@ fn init(state) {
let radar_size = 150.0;
let radar_range = 4000.0;
add_sprite(
sprite::add(
"radar",
"ui::radar",
Rect(
@ -59,25 +59,25 @@ fn init(state) {
Anchor::NorthWest
);
add_sprite("radar.frame.ne", "ui::radarframe", init_pos);
add_sprite("radar.frame.se", "ui::radarframe", init_pos);
add_sprite("radar.frame.sw", "ui::radarframe", init_pos);
add_sprite("radar.frame.nw", "ui::radarframe", init_pos);
sprite_set_angle("radar.frame.se", 90.0);
sprite_set_angle("radar.frame.sw", 180.0);
sprite_set_angle("radar.frame.nw", 270.0);
sprite_set_color("radar.frame.ne", Color(0.3, 0.3, 0.3, 1.0));
sprite_set_color("radar.frame.se", Color(0.3, 0.3, 0.3, 1.0));
sprite_set_color("radar.frame.sw", Color(0.3, 0.3, 0.3, 1.0));
sprite_set_color("radar.frame.nw", Color(0.3, 0.3, 0.3, 1.0));
sprite::add("radar.frame.ne", "ui::radarframe", init_pos);
sprite::add("radar.frame.se", "ui::radarframe", init_pos);
sprite::add("radar.frame.sw", "ui::radarframe", init_pos);
sprite::add("radar.frame.nw", "ui::radarframe", init_pos);
sprite::set_angle("radar.frame.se", 90.0);
sprite::set_angle("radar.frame.sw", 180.0);
sprite::set_angle("radar.frame.nw", 270.0);
sprite::set_color("radar.frame.ne", Color(0.3, 0.3, 0.3, 1.0));
sprite::set_color("radar.frame.se", Color(0.3, 0.3, 0.3, 1.0));
sprite::set_color("radar.frame.sw", Color(0.3, 0.3, 0.3, 1.0));
sprite::set_color("radar.frame.nw", Color(0.3, 0.3, 0.3, 1.0));
add_sprite("radar.arrow", "ui::centerarrow", init_pos);
sprite::add("radar.arrow", "ui::centerarrow", init_pos);
}
fn event(state, event) {
if type_of(event) == "PlayerShipStateEvent" {
if state.player_ship().is_landed() {
go_to_scene("landed");
ui::go_to_scene("landed");
return;
}
return;
@ -85,11 +85,11 @@ fn event(state, event) {
}
fn step(state) {
radialbar_set_val("shield",
radialbar::set_val("shield",
state.player_ship().get_shields()
/ state.player_ship().get_total_shields()
);
radialbar_set_val("hull",
radialbar::set_val("hull",
state.player_ship().get_hull()
/ state.player_ship().get_total_hull()
);
@ -110,7 +110,7 @@ fn step(state) {
let position = Vector(5.0 + (radar_size / 2.0), -5.0 - (radar_size / 2.0));
let rot = Vector(0.915 * (radar_size / 2.0), 0.0);
let pos = position + rot.rotate(angle);
sprite_set_rect("radar.arrow",
sprite::set_rect("radar.arrow",
Rect(
pos.x(), pos.y(),
5.0, 5.0,
@ -118,8 +118,8 @@ fn step(state) {
Anchor::NorthWest
)
);
sprite_set_angle("radar.arrow", angle - 90.0);
sprite_set_color(
sprite::set_angle("radar.arrow", angle - 90.0);
sprite::set_color(
"radar.arrow",
Color(
1.0, 1.0, 1.0,
@ -139,8 +139,8 @@ fn step(state) {
s.is_dead() ||
s.is_landed()
){
if sprite_exists(sprite_name) {
remove_sprite(sprite_name);
if sprite::exists(sprite_name) {
sprite::remove(sprite_name);
}
continue;
}
@ -161,8 +161,8 @@ fn step(state) {
size = size_init;
}
if size < 1.0 {
if sprite_exists(sprite_name) {
remove_sprite(sprite_name);
if sprite::exists(sprite_name) {
sprite::remove(sprite_name);
}
continue;
}
@ -170,8 +170,8 @@ fn step(state) {
let pos = Vector(radar_size / 2.0 + 5.0, radar_size / -2.0 - 5.0);
pos = pos + (d * radar_size / 2.0);
if !sprite_exists(sprite_name) {
add_sprite(
if !sprite::exists(sprite_name) {
sprite::add(
sprite_name,
"ui::shipblip",
Rect(
@ -182,7 +182,7 @@ fn step(state) {
)
);
} else {
sprite_set_rect(
sprite::set_rect(
sprite_name,
Rect(
pos.x(), pos.y(),
@ -192,7 +192,7 @@ fn step(state) {
)
);
}
sprite_set_color(sprite_name, color);
sprite::set_color(sprite_name, color);
}
}
}
@ -203,8 +203,8 @@ fn step(state) {
let sprite_name = `radar.object.${o.get_label()}`;
if !o.is_some() {
if sprite_exists(sprite_name) {
remove_sprite(sprite_name);
if sprite::exists(sprite_name) {
sprite::remove(sprite_name);
}
continue;
}
@ -220,8 +220,8 @@ fn step(state) {
}
if size < 1.0 {
// Don't draw tiny sprites, they flicker
if sprite_exists(sprite_name) {
remove_sprite(sprite_name);
if sprite::exists(sprite_name) {
sprite::remove(sprite_name);
}
continue;
}
@ -231,8 +231,8 @@ fn step(state) {
+ (d * radar_size / 2.0)
);
if !sprite_exists(sprite_name) {
add_sprite(
if !sprite::exists(sprite_name) {
sprite::add(
sprite_name,
"ui::planetblip",
Rect(
@ -243,7 +243,7 @@ fn step(state) {
)
);
} else {
sprite_set_rect(
sprite::set_rect(
sprite_name,
Rect(
pos.x(), pos.y(),
@ -261,7 +261,7 @@ fn step(state) {
{
let dx = (((state.camera_zoom() / 2.0) * state.window_aspect()) / radar_range) * (radar_size / 2.0);
let dy = ((state.camera_zoom() / 2.0) / radar_range) * (radar_size / 2.0);
sprite_set_rect("radar.frame.ne",
sprite::set_rect("radar.frame.ne",
Rect(
(radar_size / 2.0 + 5) - dx,
(radar_size / -2.0 - 5) + dy,
@ -270,7 +270,7 @@ fn step(state) {
Anchor::NorthWest
)
);
sprite_set_rect("radar.frame.se",
sprite::set_rect("radar.frame.se",
Rect(
(radar_size / 2.0 + 5) - dx,
(radar_size / -2.0 - 5) - dy,
@ -279,7 +279,7 @@ fn step(state) {
Anchor::NorthWest
)
);
sprite_set_rect("radar.frame.sw",
sprite::set_rect("radar.frame.sw",
Rect(
(radar_size / 2.0 + 5) + dx,
(radar_size / -2.0 - 5) - dy,
@ -288,7 +288,7 @@ fn step(state) {
Anchor::NorthWest
)
);
sprite_set_rect("radar.frame.nw",
sprite::set_rect("radar.frame.nw",
Rect(
(radar_size / 2.0 + 5) + dx,
(radar_size / -2.0 - 5) + dy,

View File

@ -1,10 +1,10 @@
fn init(state) {
let player = state.player_ship();
conf_set_starfield(true);
conf_set_phys(false);
conf::show_starfield(true);
conf::show_phys(false);
add_sprite(
sprite::add(
"button",
"ui::planet::button",
Rect(
@ -14,7 +14,7 @@ fn init(state) {
)
);
add_sprite(
sprite::add(
"landscape",
{
if player.is_landed() {
@ -29,9 +29,9 @@ fn init(state) {
Anchor::Center
)
);
sprite_set_mask("landscape", "ui::landscapemask");
sprite::set_mask("landscape", "ui::landscapemask");
add_sprite(
sprite::add(
"frame",
"ui::planet",
Rect(
@ -42,7 +42,7 @@ fn init(state) {
);
add_textbox(
textbox::add(
"title", 10.0, 10.0,
Rect(
-70.79, 138.0, 59.867, 10.0,
@ -51,14 +51,14 @@ fn init(state) {
),
Color(1.0, 1.0, 1.0, 1.0)
);
textbox_align_center("title");
textbox_font_serif("title");
textbox_weight_bold("title");
textbox::align_center("title");
textbox::font_serif("title");
textbox::weight_bold("title");
if player.is_landed() {
textbox_set_text("title", player.landed_on().name());
textbox::set_text("title", player.landed_on().name());
}
add_textbox(
textbox::add(
"desc", 7.5, 8.0,
Rect(
-178.92, -20.3, 343.0, 81.467,
@ -67,9 +67,9 @@ fn init(state) {
),
Color(1.0, 1.0, 1.0, 1.0)
);
textbox_font_sans("desc");
textbox::font_sans("desc");
if player.is_landed() {
textbox_set_text("desc", player.landed_on().desc());
textbox::set_text("desc", player.landed_on().desc());
}
}
@ -78,9 +78,9 @@ fn event(state, event) {
let element = event.element();
if element == "button" {
if event.is_enter() {
sprite_take_edge("button", "on:top", 0.1);
sprite::take_edge("button", "on:top", 0.1);
} else {
sprite_take_edge("button", "off:top", 0.1);
sprite::take_edge("button", "off:top", 0.1);
}
}
return;
@ -94,7 +94,7 @@ fn event(state, event) {
let element = event.element();
if element == "button" {
go_to_scene("outfitter");
ui::go_to_scene("outfitter");
return;
}
return;
@ -102,7 +102,7 @@ fn event(state, event) {
if type_of(event) == "PlayerShipStateEvent" {
if !state.player_ship().is_landed() {
go_to_scene("flying");
ui::go_to_scene("flying");
return;
}
return;

View File

@ -1,9 +1,9 @@
fn init(state) {
conf_set_starfield(true);
conf_set_phys(false);
conf::show_starfield(true);
conf::show_phys(false);
add_sprite(
sprite::add(
"se_box",
"ui::outfitterbox",
Rect(
@ -13,7 +13,7 @@ fn init(state) {
)
);
add_textbox(
textbox::add(
"exit_text", 10.0, 10.0,
Rect(
122.71, 48.0, 51.0, 12.0,
@ -22,11 +22,11 @@ fn init(state) {
),
Color(1.0, 1.0, 1.0, 1.0)
);
textbox_font_serif("exit_text");
textbox_align_center("exit_text");
textbox_set_text("exit_text", "Exit");
textbox::font_serif("exit_text");
textbox::align_center("exit_text");
textbox::set_text("exit_text", "Exit");
add_sprite(
sprite::add(
"exit_button",
"ui::button",
Rect(
@ -38,7 +38,7 @@ fn init(state) {
add_sprite(
sprite::add(
"ship_bg",
"ui::outfitter-ship-bg",
Rect(
@ -48,7 +48,7 @@ fn init(state) {
)
);
add_sprite(
sprite::add(
"ship_thumb",
"icon::gypsum",
Rect(
@ -58,7 +58,7 @@ fn init(state) {
)
);
add_textbox(
textbox::add(
"ship_name", 10.0, 10.0,
Rect(
111.0, -167.27, 145.0, 10.0,
@ -67,11 +67,11 @@ fn init(state) {
),
Color(1.0, 1.0, 1.0, 1.0)
);
textbox_font_serif("ship_name");
textbox_align_center("ship_name");
textbox_set_text("ship_name", "Hyperion");
textbox::font_serif("ship_name");
textbox::align_center("ship_name");
textbox::set_text("ship_name", "Hyperion");
add_textbox(
textbox::add(
"ship_type", 7.0, 8.5,
Rect(
111.0, -178.0, 145.0, 8.5,
@ -80,14 +80,14 @@ fn init(state) {
),
Color(0.7, 0.7, 0.7, 1.0)
);
textbox_font_sans("ship_type");
textbox_align_center("ship_type");
textbox::font_sans("ship_type");
textbox::align_center("ship_type");
if state.player_ship().is_some() {
textbox_set_text("ship_type", state.player_ship().name());
textbox::set_text("ship_type", state.player_ship().name());
}
add_textbox(
textbox::add(
"ship_stats", 7.0, 8.5,
Rect(
38.526, -192.332, 144.948, 154.5,
@ -96,11 +96,11 @@ fn init(state) {
),
Color(1.0, 1.0, 1.0, 1.0)
);
textbox_font_mono("ship_stats");
textbox_set_text("ship_stats", "Earth");
textbox::font_mono("ship_stats");
textbox::set_text("ship_stats", "Earth");
add_sprite(
sprite::add(
"outfit_bg",
"ui::outfitter-outfit-bg",
Rect(
@ -110,7 +110,7 @@ fn init(state) {
)
);
add_sprite(
sprite::add(
"outfit_thumb",
"icon::engine",
Rect(
@ -120,7 +120,7 @@ fn init(state) {
)
);
add_textbox(
textbox::add(
"outfit_name", 16.0, 16.0,
Rect(
-312.0, -20.0, 200.0, 16.0,
@ -129,11 +129,11 @@ fn init(state) {
),
Color(1.0, 1.0, 1.0, 1.0)
);
textbox_font_serif("outfit_name");
textbox_weight_bold("outfit_name");
textbox_set_text("outfit_name", "Earth");
textbox::font_serif("outfit_name");
textbox::weight_bold("outfit_name");
textbox::set_text("outfit_name", "Earth");
add_textbox(
textbox::add(
"outfit_desc", 7.0, 8.5,
Rect(
-166.0, -219.0, 260.0, 78.0,
@ -142,11 +142,11 @@ fn init(state) {
),
Color(1.0, 1.0, 1.0, 1.0)
);
textbox_font_serif("outfit_desc");
textbox_set_text("outfit_desc", "Earth");
textbox::font_serif("outfit_desc");
textbox::set_text("outfit_desc", "Earth");
add_textbox(
textbox::add(
"outfit_stats", 7.0, 8.5,
Rect(
-295.0, -271.0, 164.0, 216.0,
@ -155,8 +155,8 @@ fn init(state) {
),
Color(1.0, 1.0, 1.0, 1.0)
);
textbox_font_mono("outfit_stats");
textbox_set_text("outfit_stats", "Earth");
textbox::font_mono("outfit_stats");
textbox::set_text("outfit_stats", "Earth");
}
@ -166,9 +166,9 @@ fn event(state, event) {
let element = event.element();
if element == "exit_button" {
if event.is_enter() {
sprite_take_edge("exit_button", "on:top", 0.1);
sprite::take_edge("exit_button", "on:top", 0.1);
} else {
sprite_take_edge("exit_button", "off:top", 0.1);
sprite::take_edge("exit_button", "off:top", 0.1);
}
}
return;
@ -182,7 +182,7 @@ fn event(state, event) {
let element = event.element();
if element == "exit_button" {
go_to_scene("landed");
ui::go_to_scene("landed");
return;
}
return;
@ -190,7 +190,7 @@ fn event(state, event) {
if type_of(event) == "PlayerShipStateEvent" {
if !state.player_ship().is_landed() {
go_to_scene("flying");
ui::go_to_scene("flying");
return;
}
return;

View File

@ -0,0 +1,27 @@
use rhai::{FnNamespace, FuncRegistration, Module};
use std::{cell::RefCell, rc::Rc};
use crate::ui::UiState;
pub fn build_conf_module(state_src: Rc<RefCell<UiState>>) -> Module {
let mut module = Module::new();
module.set_id("GalacticaConfModule");
let state = state_src.clone();
let _ = FuncRegistration::new("show_phys")
.with_namespace(FnNamespace::Internal)
.set_into_module(&mut module, move |b: bool| {
let mut ui_state = state.borrow_mut();
ui_state.config.show_phys = b;
});
let state = state_src.clone();
let _ = FuncRegistration::new("show_starfield")
.with_namespace(FnNamespace::Internal)
.set_into_module(&mut module, move |b: bool| {
let mut ui_state = state.borrow_mut();
ui_state.config.show_starfield = b;
});
return module;
}

View File

@ -0,0 +1,11 @@
mod conf;
mod radialbar;
mod sprite;
mod textbox;
mod ui;
pub use conf::build_conf_module;
pub use radialbar::build_radialbar_module;
pub use sprite::build_sprite_module;
pub use textbox::build_textbox_module;
pub use ui::build_ui_module;

View File

@ -0,0 +1,48 @@
use log::error;
use rhai::{FnNamespace, FuncRegistration, ImmutableString, Module};
use std::{cell::RefCell, rc::Rc};
use super::super::{Color, Rect};
use crate::ui::{elements::RadialBar, UiElement, UiState};
pub fn build_radialbar_module(state_src: Rc<RefCell<UiState>>) -> Module {
let mut module = Module::new();
module.set_id("GalacticaRadialbarModule");
let state = state_src.clone();
let _ = FuncRegistration::new("add")
.with_namespace(FnNamespace::Internal)
.set_into_module(
&mut module,
// TODO: fix ugly spaces
move |name: ImmutableString, stroke: f32, color: Color, rect: Rect| {
let mut ui_state = state.borrow_mut();
if ui_state.elements.contains_key(&name) {
error!("tried to make a radialbar using an existing name `{name}`");
return;
}
ui_state.names.push(name.clone());
ui_state.elements.insert(
name.clone(),
UiElement::RadialBar(RadialBar::new(name.clone(), stroke, color, rect, 1.0)),
);
},
);
let state = state_src.clone();
let _ = FuncRegistration::new("set_val")
.with_namespace(FnNamespace::Internal)
.set_into_module(&mut module, move |name: ImmutableString, val: f32| {
let mut ui_state = state.borrow_mut();
match ui_state.get_mut_by_name(&name) {
Some(UiElement::RadialBar(x)) => x.set_val(val),
_ => {
error!("called `radialbar_set_val` on an invalid name `{name}`")
}
}
});
return module;
}

View File

@ -0,0 +1,169 @@
use galactica_content::{resolve_edge_as_edge, Content};
use log::error;
use rhai::{FnNamespace, FuncRegistration, ImmutableString, Module};
use std::{cell::RefCell, rc::Rc, sync::Arc};
use crate::ui::{elements::Sprite, UiElement, UiState};
use super::super::{Color, Rect};
pub fn build_sprite_module(ct_src: Arc<Content>, state_src: Rc<RefCell<UiState>>) -> Module {
let mut module = Module::new();
module.set_id("GalacticaSpriteModule");
let state = state_src.clone();
let ct = ct_src.clone();
let _ = FuncRegistration::new("add")
.with_namespace(FnNamespace::Internal)
.set_into_module(
&mut module,
move |name: ImmutableString, sprite: ImmutableString, rect: Rect| {
let mut ui_state = state.borrow_mut();
let sprite_handle = ct.get_sprite_handle(sprite.as_str());
if sprite_handle.is_none() {
error!("made a sprite using an invalid source `{sprite}`");
return;
}
if ui_state.elements.contains_key(&name) {
error!("tried to make a sprite using an existing name `{name}`");
return;
}
ui_state.names.push(name.clone());
ui_state.elements.insert(
name.clone(),
UiElement::Sprite(Sprite::new(&ct, name.clone(), sprite_handle.unwrap(), rect)),
);
},
);
let state = state_src.clone();
let _ = FuncRegistration::new("remove")
.with_namespace(FnNamespace::Internal)
.set_into_module(&mut module, move |name: ImmutableString| {
let mut ui_state = state.borrow_mut();
if ui_state.elements.contains_key(&name) {
ui_state.elements.remove(&name).unwrap();
ui_state.names.retain(|x| *x != name);
} else {
error!("called `sprite::remove` on an invalid name `{name}`")
}
});
let state = state_src.clone();
let ct = ct_src.clone();
let _ = FuncRegistration::new("set_mask")
.with_namespace(FnNamespace::Internal)
.set_into_module(
&mut module,
move |name: ImmutableString, mask: ImmutableString| {
let mut ui_state = state.borrow_mut();
match ui_state.get_mut_by_name(&name) {
Some(UiElement::Sprite(x)) => {
let m = ct.get_sprite_handle(mask.as_str());
if m.is_none() {
error!("called `set_sprite_mask` with an invalid mask `{mask}`");
return;
}
x.set_mask(m)
}
_ => {
error!("called `sprite::set_mask` on an invalid name `{name}`")
}
}
},
);
let state = state_src.clone();
let ct = ct_src.clone();
let _ = FuncRegistration::new("take_edge")
.with_namespace(FnNamespace::Internal)
.set_into_module(
&mut module,
move |name: ImmutableString, edge_name: ImmutableString, duration: f32| {
let mut ui_state = state.borrow_mut();
match ui_state.get_mut_by_name(&name) {
Some(UiElement::Sprite(x)) => {
let sprite_handle = x.anim.get_sprite();
let sprite = &ct.get_sprite(sprite_handle);
let edge = resolve_edge_as_edge(edge_name.as_str(), duration, |x| {
sprite.get_section_handle_by_name(x)
});
let edge = match edge {
Err(_) => {
error!(
"called `sprite::take_edge` on an invalid edge `{}` on sprite `{}`",
edge_name, sprite.name
);
return;
}
Ok(s) => s,
};
x.anim.jump_to(&ct, edge);
}
_ => {
error!("called `sprite::take_edge` on an invalid name `{name}`")
}
}
},
);
let state = state_src.clone();
let _ = FuncRegistration::new("set_angle")
.with_namespace(FnNamespace::Internal)
.set_into_module(&mut module, move |name: ImmutableString, x: f32| {
let mut ui_state = state.borrow_mut();
match ui_state.get_mut_by_name(&name) {
Some(UiElement::Sprite(s)) => s.set_angle(x),
_ => {
error!("called `sprite::set_angle` on an invalid name `{name}`")
}
}
});
let state = state_src.clone();
let _ = FuncRegistration::new("set_rect")
.with_namespace(FnNamespace::Internal)
.set_into_module(&mut module, move |name: ImmutableString, x: Rect| {
let mut ui_state = state.borrow_mut();
match ui_state.get_mut_by_name(&name) {
Some(UiElement::Sprite(s)) => s.set_rect(x),
_ => {
error!("called `sprite::set_rect` on an invalid name `{name}`")
}
}
});
let state = state_src.clone();
let _ = FuncRegistration::new("set_color")
.with_namespace(FnNamespace::Internal)
.set_into_module(&mut module, move |name: ImmutableString, x: Color| {
let mut ui_state = state.borrow_mut();
match ui_state.get_mut_by_name(&name) {
Some(UiElement::Sprite(s)) => s.set_color(x),
_ => {
error!("called `sprite::set_color` on an invalid name `{name}`")
}
}
});
let state = state_src.clone();
let _ = FuncRegistration::new("exists")
.with_namespace(FnNamespace::Internal)
.set_into_module(&mut module, move |name: ImmutableString| {
let mut ui_state = state.borrow_mut();
match ui_state.get_mut_by_name(&name) {
Some(UiElement::Sprite(_)) => true,
_ => false,
}
});
return module;
}

View File

@ -0,0 +1,226 @@
use glyphon::{cosmic_text::Align, FamilyOwned, FontSystem, Style, Weight};
use log::error;
use rhai::{FnNamespace, FuncRegistration, ImmutableString, Module};
use std::{cell::RefCell, rc::Rc};
use super::super::{Color, Rect};
use crate::ui::{elements::TextBox, UiElement, UiState};
pub fn build_textbox_module(
font_src: Rc<RefCell<FontSystem>>,
state_src: Rc<RefCell<UiState>>,
) -> Module {
let mut module = Module::new();
module.set_id("GalacticaTextboxModule");
let state = state_src.clone();
let font = font_src.clone();
let _ = FuncRegistration::new("add")
.with_namespace(FnNamespace::Internal)
.set_into_module(
&mut module,
// TODO: fix ugly spaces
move |name: ImmutableString,
font_size: f32,
line_height: f32,
rect: Rect,
color: Color| {
let mut ui_state = state.borrow_mut();
if ui_state.elements.contains_key(&name) {
error!("tried to make a textbox using an existing name `{name}`");
return;
}
ui_state.names.push(name.clone());
ui_state.elements.insert(
name.clone(),
UiElement::Text(TextBox::new(
&mut font.borrow_mut(),
name.clone(),
font_size,
line_height,
rect,
color,
)),
);
},
);
let state = state_src.clone();
let font = font_src.clone();
let _ = FuncRegistration::new("set_text")
.with_namespace(FnNamespace::Internal)
.set_into_module(
&mut module,
move |name: ImmutableString, text: ImmutableString| {
let mut ui_state = state.borrow_mut();
match ui_state.get_mut_by_name(&name) {
Some(UiElement::Text(x)) => x.set_text(&mut font.borrow_mut(), text.as_str()),
_ => {
error!("called `textbox::set_text` on an invalid name `{name}`")
}
}
},
);
let state = state_src.clone();
let font = font_src.clone();
let _ = FuncRegistration::new("align_left")
.with_namespace(FnNamespace::Internal)
.set_into_module(&mut module, move |name: ImmutableString| {
let mut ui_state = state.borrow_mut();
match ui_state.get_mut_by_name(&name) {
Some(UiElement::Text(x)) => x.set_align(&mut font.borrow_mut(), Align::Left),
_ => {
error!("called `textbox::align_left` on an invalid name `{name}`")
}
}
});
let state = state_src.clone();
let font = font_src.clone();
let _ = FuncRegistration::new("align_right")
.with_namespace(FnNamespace::Internal)
.set_into_module(&mut module, move |name: ImmutableString| {
let mut ui_state = state.borrow_mut();
match ui_state.get_mut_by_name(&name) {
Some(UiElement::Text(x)) => x.set_align(&mut font.borrow_mut(), Align::Right),
_ => {
error!("called `textbox::align_right` on an invalid name `{name}`")
}
}
});
let state = state_src.clone();
let font = font_src.clone();
let _ = FuncRegistration::new("align_justify")
.with_namespace(FnNamespace::Internal)
.set_into_module(&mut module, move |name: ImmutableString| {
let mut ui_state = state.borrow_mut();
match ui_state.get_mut_by_name(&name) {
Some(UiElement::Text(x)) => x.set_align(&mut font.borrow_mut(), Align::Justified),
_ => {
error!("called `textbox::align_justify` on an invalid name `{name}`")
}
}
});
let state = state_src.clone();
let font = font_src.clone();
let _ = FuncRegistration::new("align_center")
.with_namespace(FnNamespace::Internal)
.set_into_module(&mut module, move |name: ImmutableString| {
let mut ui_state = state.borrow_mut();
match ui_state.get_mut_by_name(&name) {
Some(UiElement::Text(x)) => x.set_align(&mut font.borrow_mut(), Align::Center),
_ => {
error!("called `textbox::align_center` on an invalid name `{name}`")
}
}
});
let state = state_src.clone();
let font = font_src.clone();
let _ = FuncRegistration::new("weight_bold")
.with_namespace(FnNamespace::Internal)
.set_into_module(&mut module, move |name: ImmutableString| {
let mut ui_state = state.borrow_mut();
match ui_state.get_mut_by_name(&name) {
Some(UiElement::Text(x)) => x.set_weight(&mut font.borrow_mut(), Weight::BOLD),
_ => {
error!("called `textbox::weight_bold` on an invalid name `{name}`")
}
}
});
let state = state_src.clone();
let font = font_src.clone();
let _ = FuncRegistration::new("weight_normal")
.with_namespace(FnNamespace::Internal)
.set_into_module(&mut module, move |name: ImmutableString| {
let mut ui_state = state.borrow_mut();
match ui_state.get_mut_by_name(&name) {
Some(UiElement::Text(x)) => x.set_weight(&mut font.borrow_mut(), Weight::NORMAL),
_ => {
error!("called `textbox::weight_normal` on an invalid name `{name}`")
}
}
});
let state = state_src.clone();
let font = font_src.clone();
let _ = FuncRegistration::new("font_serif")
.with_namespace(FnNamespace::Internal)
.set_into_module(&mut module, move |name: ImmutableString| {
let mut ui_state = state.borrow_mut();
match ui_state.get_mut_by_name(&name) {
Some(UiElement::Text(x)) => x.set_font(&mut font.borrow_mut(), FamilyOwned::Serif),
_ => {
error!("called `textbox::font_serif` on an invalid name `{name}`")
}
}
});
let state = state_src.clone();
let font = font_src.clone();
let _ = FuncRegistration::new("font_sans")
.with_namespace(FnNamespace::Internal)
.set_into_module(&mut module, move |name: ImmutableString| {
let mut ui_state = state.borrow_mut();
match ui_state.get_mut_by_name(&name) {
Some(UiElement::Text(x)) => {
x.set_font(&mut font.borrow_mut(), FamilyOwned::SansSerif)
}
_ => {
error!("called `textbox::font_sans` on an invalid name `{name}`")
}
}
});
let state = state_src.clone();
let font = font_src.clone();
let _ = FuncRegistration::new("font_mono")
.with_namespace(FnNamespace::Internal)
.set_into_module(&mut module, move |name: ImmutableString| {
let mut ui_state = state.borrow_mut();
match ui_state.get_mut_by_name(&name) {
Some(UiElement::Text(x)) => {
x.set_font(&mut font.borrow_mut(), FamilyOwned::Monospace)
}
_ => {
error!("called `textbox::font_mono` on an invalid name `{name}`")
}
}
});
let state = state_src.clone();
let font = font_src.clone();
let _ = FuncRegistration::new("style_normal")
.with_namespace(FnNamespace::Internal)
.set_into_module(&mut module, move |name: ImmutableString| {
let mut ui_state = state.borrow_mut();
match ui_state.get_mut_by_name(&name) {
Some(UiElement::Text(x)) => x.set_style(&mut font.borrow_mut(), Style::Normal),
_ => {
error!("called `textbox::style_normal` on an invalid name `{name}`")
}
}
});
let state = state_src.clone();
let font = font_src.clone();
let _ = FuncRegistration::new("style_italic")
.with_namespace(FnNamespace::Internal)
.set_into_module(&mut module, move |name: ImmutableString| {
let mut ui_state = state.borrow_mut();
match ui_state.get_mut_by_name(&name) {
Some(UiElement::Text(x)) => x.set_style(&mut font.borrow_mut(), Style::Italic),
_ => {
error!("called `textbox::style_italic` on an invalid name `{name}`")
}
}
});
return module;
}

View File

@ -0,0 +1,19 @@
use rhai::{FnNamespace, FuncRegistration, ImmutableString, Module};
use std::{cell::RefCell, rc::Rc};
use crate::ui::UiState;
pub fn build_ui_module(state_src: Rc<RefCell<UiState>>) -> Module {
let mut module = Module::new();
module.set_id("GalacticaUiModule");
let state = state_src.clone();
let _ = FuncRegistration::new("go_to_scene")
.with_namespace(FnNamespace::Internal)
.set_into_module(&mut module, move |scene: ImmutableString| {
let mut ui_state = state.borrow_mut();
ui_state.set_scene(scene);
});
return module;
}

View File

@ -0,0 +1,4 @@
pub mod anchor;
pub mod color;
pub mod rect;
pub mod vector;

View File

@ -2,7 +2,7 @@ use nalgebra::{Point2, Vector2};
use rhai::{CustomType, TypeBuilder};
use winit::{dpi::LogicalSize, window::Window};
use super::Anchor;
use super::anchor::Anchor;
use crate::{RenderInput, RenderState};
#[derive(Debug, Clone)]

View File

@ -1,20 +1,25 @@
mod anchor;
mod color;
mod event;
mod rect;
mod functions;
mod helpers;
mod state;
mod vector;
pub use anchor::*;
pub use color::*;
pub use event::*;
pub use rect::*;
use glyphon::FontSystem;
pub use helpers::{anchor::*, color::*, rect::*, vector::*};
use log::debug;
pub use state::*;
pub use vector::*;
use rhai::{exported_module, Engine};
use super::UiState;
use galactica_content::Content;
use rhai::{exported_module, Dynamic, Engine};
use std::{cell::RefCell, rc::Rc, sync::Arc};
pub fn register_into_engine(engine: &mut Engine) {
pub fn register_into_engine(
engine: &mut Engine,
ct_src: Arc<Content>,
font_src: Rc<RefCell<FontSystem>>,
state_src: Rc<RefCell<UiState>>,
) {
engine
// Helpers
.build_type::<Rect>()
@ -31,4 +36,29 @@ pub fn register_into_engine(engine: &mut Engine) {
// Bigger modules
.register_type_with_name::<Anchor>("Anchor")
.register_static_module("Anchor", exported_module!(anchor_mod).into());
// Extra functions
engine.register_fn("print", move |d: Dynamic| {
debug!("{:?}", d);
});
engine.register_fn("clamp", move |x: f32, l: f32, h: f32| x.clamp(l, h));
// Modules
engine.register_static_module(
"sprite",
functions::build_sprite_module(ct_src.clone(), state_src.clone()).into(),
);
engine.register_static_module(
"textbox",
functions::build_textbox_module(font_src.clone(), state_src.clone()).into(),
);
engine.register_static_module(
"radialbar",
functions::build_radialbar_module(state_src.clone()).into(),
);
engine.register_static_module("ui", functions::build_ui_module(state_src.clone()).into());
engine.register_static_module(
"conf",
functions::build_conf_module(state_src.clone()).into(),
);
}

View File

@ -1,9 +1,8 @@
use anyhow::{Context, Result};
use galactica_content::{resolve_edge_as_edge, Content};
use galactica_content::Content;
use galactica_system::phys::PhysSimShipHandle;
use galactica_util::rhai_error_to_anyhow;
use glyphon::{cosmic_text::Align, FamilyOwned, FontSystem, Style, Weight};
use log::{debug, error};
use log::debug;
use rhai::{
packages::{BasicArrayPackage, BasicStringPackage, LogicPackage, MoreStringPackage, Package},
Dynamic, Engine, ImmutableString, Scope,
@ -11,8 +10,7 @@ use rhai::{
use std::{cell::RefCell, num::NonZeroU32, rc::Rc, sync::Arc};
use super::{
api::{self, Color, MouseClickEvent, MouseHoverEvent, PlayerShipStateEvent, Rect},
elements::{RadialBar, Sprite, TextBox},
api::{self, MouseClickEvent, MouseHoverEvent, PlayerShipStateEvent},
event::Event,
UiConfig, UiElement, UiState,
};
@ -46,12 +44,11 @@ impl UiScriptExecutor {
// Enables custom operators
engine.set_fast_operators(false);
api::register_into_engine(&mut engine);
Self::register_api(
api::register_into_engine(
&mut engine,
ct.clone(),
state.text_font_system.clone(),
elements.clone(),
&mut engine,
);
Self {
@ -241,426 +238,3 @@ impl UiScriptExecutor {
return Ok(());
}
}
// API
impl UiScriptExecutor {
pub fn register_api(
ct_src: Arc<Content>,
font_src: Rc<RefCell<FontSystem>>,
s: Rc<RefCell<UiState>>,
engine: &mut Engine,
) {
// Utilities
{
let c = s.clone();
engine.register_fn("go_to_scene", move |scene: ImmutableString| {
let mut ui_state = c.borrow_mut();
ui_state.set_scene(scene);
});
let c = s.clone();
engine.register_fn("conf_set_phys", move |b: bool| {
let mut ui_state = c.borrow_mut();
ui_state.config.show_phys = b;
});
let c = s.clone();
engine.register_fn("conf_set_starfield", move |b: bool| {
let mut ui_state = c.borrow_mut();
ui_state.config.show_starfield = b;
});
engine.register_fn("print", move |d: Dynamic| {
debug!("{:?}", d);
});
engine.register_fn("clamp", move |x: f32, l: f32, h: f32| x.clamp(l, h));
}
// Sprites
{
let c = s.clone();
let ct = ct_src.clone();
engine.register_fn(
"add_sprite",
move |name: ImmutableString, sprite: ImmutableString, rect: Rect| {
let mut ui_state = c.borrow_mut();
let sprite_handle = ct.get_sprite_handle(sprite.as_str());
if sprite_handle.is_none() {
error!("made a sprite using an invalid source `{sprite}`");
return;
}
if ui_state.elements.contains_key(&name) {
error!("tried to make a sprite using an existing name `{name}`");
return;
}
ui_state.names.push(name.clone());
ui_state.elements.insert(
name.clone(),
UiElement::Sprite(Sprite::new(
&ct,
name.clone(),
sprite_handle.unwrap(),
rect,
)),
);
},
);
let c = s.clone();
engine.register_fn("remove_sprite", move |name: ImmutableString| {
let mut ui_state = c.borrow_mut();
if ui_state.elements.contains_key(&name) {
ui_state.elements.remove(&name).unwrap();
ui_state.names.retain(|x| *x != name);
} else {
error!("called `remove_sprite` on an invalid name `{name}`")
}
});
let c = s.clone();
let ct = ct_src.clone();
engine.register_fn(
"sprite_set_mask",
move |name: ImmutableString, mask: ImmutableString| {
let mut ui_state = c.borrow_mut();
match ui_state.get_mut_by_name(&name) {
Some(UiElement::Sprite(x)) => {
let m = ct.get_sprite_handle(mask.as_str());
if m.is_none() {
error!("called `set_sprite_mask` with an invalid mask `{mask}`");
return;
}
x.set_mask(m)
}
_ => {
error!("called `sprite_set_mask` on an invalid name `{name}`")
}
}
},
);
let c = s.clone();
let ct = ct_src.clone();
engine.register_fn(
"sprite_take_edge",
move |name: ImmutableString, edge_name: ImmutableString, duration: f32| {
let mut ui_state = c.borrow_mut();
match ui_state.get_mut_by_name(&name) {
Some(UiElement::Sprite(x)) => {
let sprite_handle = x.anim.get_sprite();
let sprite = &ct.get_sprite(sprite_handle);
let edge = resolve_edge_as_edge(edge_name.as_str(), duration, |x| {
sprite.get_section_handle_by_name(x)
});
let edge = match edge {
Err(_) => {
error!(
"called `sprite_take_edge` on an invalid edge `{}` on sprite `{}`",
edge_name, sprite.name
);
return;
}
Ok(s) => s,
};
x.anim.jump_to(&ct, edge);
}
_ => {
error!("called `sprite_take_edge` on an invalid name `{name}`")
}
}
},
);
let c = s.clone();
engine.register_fn("sprite_set_angle", move |name: ImmutableString, x: f32| {
let mut ui_state = c.borrow_mut();
match ui_state.get_mut_by_name(&name) {
Some(UiElement::Sprite(s)) => s.set_angle(x),
_ => {
error!("called `sprite_set_angle` on an invalid name `{name}`")
}
}
});
let c = s.clone();
engine.register_fn("sprite_set_rect", move |name: ImmutableString, x: Rect| {
let mut ui_state = c.borrow_mut();
match ui_state.get_mut_by_name(&name) {
Some(UiElement::Sprite(s)) => s.set_rect(x),
_ => {
error!("called `sprite_set_rect` on an invalid name `{name}`")
}
}
});
let c = s.clone();
engine.register_fn(
"sprite_set_color",
move |name: ImmutableString, x: Color| {
let mut ui_state = c.borrow_mut();
match ui_state.get_mut_by_name(&name) {
Some(UiElement::Sprite(s)) => s.set_color(x),
_ => {
error!("called `sprite_set_color` on an invalid name `{name}`")
}
}
},
);
let c = s.clone();
engine.register_fn("sprite_exists", move |name: ImmutableString| {
let mut ui_state = c.borrow_mut();
match ui_state.get_mut_by_name(&name) {
Some(UiElement::Sprite(_)) => true,
_ => false,
}
});
}
// Textboxes
{
let c = s.clone();
let font = font_src.clone();
engine.register_fn(
"add_textbox",
// TODO: fix ugly spaces
move |name: ImmutableString,
font_size: f32,
line_height: f32,
rect: Rect,
color: Color| {
let mut ui_state = c.borrow_mut();
if ui_state.elements.contains_key(&name) {
error!("tried to make a textbox using an existing name `{name}`");
return;
}
ui_state.names.push(name.clone());
ui_state.elements.insert(
name.clone(),
UiElement::Text(TextBox::new(
&mut font.borrow_mut(),
name.clone(),
font_size,
line_height,
rect,
color,
)),
);
},
);
let c = s.clone();
let font = font_src.clone();
engine.register_fn(
"textbox_set_text",
move |name: ImmutableString, text: ImmutableString| {
let mut ui_state = c.borrow_mut();
match ui_state.get_mut_by_name(&name) {
Some(UiElement::Text(x)) => {
x.set_text(&mut font.borrow_mut(), text.as_str())
}
_ => {
error!("called `textbox_set_text` on an invalid name `{name}`")
}
}
},
);
let c = s.clone();
let font = font_src.clone();
engine.register_fn("textbox_align_left", move |name: ImmutableString| {
let mut ui_state = c.borrow_mut();
match ui_state.get_mut_by_name(&name) {
Some(UiElement::Text(x)) => x.set_align(&mut font.borrow_mut(), Align::Left),
_ => {
error!("called `textbox_align_left` on an invalid name `{name}`")
}
}
});
let c = s.clone();
let font = font_src.clone();
engine.register_fn("textbox_align_right", move |name: ImmutableString| {
let mut ui_state = c.borrow_mut();
match ui_state.get_mut_by_name(&name) {
Some(UiElement::Text(x)) => x.set_align(&mut font.borrow_mut(), Align::Right),
_ => {
error!("called `textbox_align_right` on an invalid name `{name}`")
}
}
});
let c = s.clone();
let font = font_src.clone();
engine.register_fn("textbox_align_justify", move |name: ImmutableString| {
let mut ui_state = c.borrow_mut();
match ui_state.get_mut_by_name(&name) {
Some(UiElement::Text(x)) => {
x.set_align(&mut font.borrow_mut(), Align::Justified)
}
_ => {
error!("called `textbox_align_justify` on an invalid name `{name}`")
}
}
});
let c = s.clone();
let font = font_src.clone();
engine.register_fn("textbox_align_center", move |name: ImmutableString| {
let mut ui_state = c.borrow_mut();
match ui_state.get_mut_by_name(&name) {
Some(UiElement::Text(x)) => x.set_align(&mut font.borrow_mut(), Align::Center),
_ => {
error!("called `textbox_align_center` on an invalid name `{name}`")
}
}
});
let c = s.clone();
let font = font_src.clone();
engine.register_fn("textbox_weight_bold", move |name: ImmutableString| {
let mut ui_state = c.borrow_mut();
match ui_state.get_mut_by_name(&name) {
Some(UiElement::Text(x)) => x.set_weight(&mut font.borrow_mut(), Weight::BOLD),
_ => {
error!("called `textbox_weight_bold` on an invalid name `{name}`")
}
}
});
let c = s.clone();
let font = font_src.clone();
engine.register_fn("textbox_weight_normal", move |name: ImmutableString| {
let mut ui_state = c.borrow_mut();
match ui_state.get_mut_by_name(&name) {
Some(UiElement::Text(x)) => {
x.set_weight(&mut font.borrow_mut(), Weight::NORMAL)
}
_ => {
error!("called `textbox_weight_normal` on an invalid name `{name}`")
}
}
});
let c = s.clone();
let font = font_src.clone();
engine.register_fn("textbox_font_serif", move |name: ImmutableString| {
let mut ui_state = c.borrow_mut();
match ui_state.get_mut_by_name(&name) {
Some(UiElement::Text(x)) => {
x.set_font(&mut font.borrow_mut(), FamilyOwned::Serif)
}
_ => {
error!("called `textbox_font_serif` on an invalid name `{name}`")
}
}
});
let c = s.clone();
let font = font_src.clone();
engine.register_fn("textbox_font_sans", move |name: ImmutableString| {
let mut ui_state = c.borrow_mut();
match ui_state.get_mut_by_name(&name) {
Some(UiElement::Text(x)) => {
x.set_font(&mut font.borrow_mut(), FamilyOwned::SansSerif)
}
_ => {
error!("called `textbox_font_sans` on an invalid name `{name}`")
}
}
});
let c = s.clone();
let font = font_src.clone();
engine.register_fn("textbox_font_mono", move |name: ImmutableString| {
let mut ui_state = c.borrow_mut();
match ui_state.get_mut_by_name(&name) {
Some(UiElement::Text(x)) => {
x.set_font(&mut font.borrow_mut(), FamilyOwned::Monospace)
}
_ => {
error!("called `textbox_font_mono` on an invalid name `{name}`")
}
}
});
let c = s.clone();
let font = font_src.clone();
engine.register_fn("textbox_style_normal", move |name: ImmutableString| {
let mut ui_state = c.borrow_mut();
match ui_state.get_mut_by_name(&name) {
Some(UiElement::Text(x)) => x.set_style(&mut font.borrow_mut(), Style::Normal),
_ => {
error!("called `textbox_style_normal` on an invalid name `{name}`")
}
}
});
let c = s.clone();
let font = font_src.clone();
engine.register_fn("textbox_style_italic", move |name: ImmutableString| {
let mut ui_state = c.borrow_mut();
match ui_state.get_mut_by_name(&name) {
Some(UiElement::Text(x)) => x.set_style(&mut font.borrow_mut(), Style::Italic),
_ => {
error!("called `textbox_style_italic` on an invalid name `{name}`")
}
}
});
}
// Radialbars
{
let c = s.clone();
engine.register_fn(
"add_radialbar",
// TODO: fix ugly spaces
move |name: ImmutableString, stroke: f32, color: Color, rect: Rect| {
let mut ui_state = c.borrow_mut();
if ui_state.elements.contains_key(&name) {
error!("tried to make a radialbar using an existing name `{name}`");
return;
}
ui_state.names.push(name.clone());
ui_state.elements.insert(
name.clone(),
UiElement::RadialBar(RadialBar::new(
name.clone(),
stroke,
color,
rect,
1.0,
)),
);
},
);
let c = s.clone();
engine.register_fn(
"radialbar_set_val",
move |name: ImmutableString, val: f32| {
let mut ui_state = c.borrow_mut();
match ui_state.get_mut_by_name(&name) {
Some(UiElement::RadialBar(x)) => x.set_val(val),
_ => {
error!("called `radialbar_set_val` on an invalid name `{name}`")
}
}
},
);
}
}
}