use crate::runner::UI_ROOT_NAME;
use nightshade::ecs::ui::state::UiStateTrait;
use nightshade::ecs::ui::units::UiValue;
use nightshade::prelude::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ScreenAnchor {
TopLeft,
TopRight,
BottomLeft,
BottomRight,
Center,
}
pub fn spawn_text(world: &mut World, text: &str, anchor: ScreenAnchor) -> Entity {
let root = ui_root(world);
let (position, anchor_kind, alignment) = anchor_window(anchor);
let entity = {
let mut tree = UiTreeBuilder::from_parent(world, root);
tree.add_node()
.window(position, Ab(vec2(960.0, 96.0)), anchor_kind)
.with_text(text, 18.0)
.with_text_alignment(alignment, VerticalAlignment::Middle)
.with_text_outline(Vec4::new(0.0, 0.0, 0.0, 1.0), 0.15)
.color_raw::<UiBase>(Vec4::new(1.0, 1.0, 1.0, 1.0))
.without_pointer_events()
.entity()
};
ui_mark_render_dirty(world);
entity
}
pub fn spawn_label(world: &mut World, text: &str, position: Vec3) -> Entity {
spawn_3d_billboard_text_with_properties(
world,
text,
position,
TextProperties {
font_size: 24.0,
alignment: TextAlignment::Center,
vertical_alignment: VerticalAlignment::Middle,
..Default::default()
},
)
}
pub fn set_text_color(world: &mut World, entity: Entity, color: [f32; 4]) {
let rgba = Vec4::new(color[0], color[1], color[2], color[3]);
if is_screen_text(world, entity) {
if let Some(node_color) = world.ui.get_ui_node_color_mut(entity) {
node_color.colors[UiBase::INDEX] = Some(rgba);
}
ui_mark_render_dirty(world);
return;
}
if let Some(component) = world.core.get_text_mut(entity) {
component.set_color(rgba);
}
}
pub fn set_text_size(world: &mut World, entity: Entity, size: f32) {
if is_screen_text(world, entity) {
if let Some(UiNodeContent::Text {
font_size_override, ..
}) = world.ui.get_ui_node_content_mut(entity)
{
*font_size_override = Some(size);
}
ui_mark_render_dirty(world);
return;
}
if let Some(component) = world.core.get_text_mut(entity) {
component.set_font_size(size);
}
}
pub fn set_text(world: &mut World, entity: Entity, text: &str) {
if let Some(slot) = screen_text_slot(world, entity) {
if world.resources.text.cache.get_text(slot) == Some(text) {
return;
}
world.resources.text.cache.set_text(slot, text);
ui_mark_render_dirty(world);
return;
}
let Some(text_index) = world
.core
.get_text(entity)
.map(|component| component.text_index)
else {
return;
};
if world.resources.text.cache.get_text(text_index) == Some(text) {
return;
}
world.resources.text.cache.set_text(text_index, text);
if let Some(component) = world.core.get_text_mut(entity) {
component.dirty = true;
}
}
fn ui_root(world: &mut World) -> Entity {
if let Some(&root) = world.resources.entities.names.get(UI_ROOT_NAME)
&& world.ui.get_ui_layout_root(root).is_some()
{
return root;
}
let root = UiTreeBuilder::new(world).finish();
world
.resources
.entities
.names
.insert(UI_ROOT_NAME.to_string(), root);
root
}
fn is_screen_text(world: &World, entity: Entity) -> bool {
matches!(
world.ui.get_ui_node_content(entity),
Some(UiNodeContent::Text { .. })
)
}
fn screen_text_slot(world: &World, entity: Entity) -> Option<usize> {
match world.ui.get_ui_node_content(entity) {
Some(UiNodeContent::Text { text_slot, .. }) => Some(*text_slot),
_ => None,
}
}
fn anchor_window(anchor: ScreenAnchor) -> (UiValue<Vec2>, Anchor, TextAlignment) {
match anchor {
ScreenAnchor::TopLeft => (
Ab(vec2(20.0, 16.0)).into(),
Anchor::TopLeft,
TextAlignment::Left,
),
ScreenAnchor::TopRight => (
Rl(vec2(100.0, 0.0)) + Ab(vec2(-20.0, 16.0)),
Anchor::TopRight,
TextAlignment::Right,
),
ScreenAnchor::BottomLeft => (
Rl(vec2(0.0, 100.0)) + Ab(vec2(20.0, -16.0)),
Anchor::BottomLeft,
TextAlignment::Left,
),
ScreenAnchor::BottomRight => (
Rl(vec2(100.0, 100.0)) + Ab(vec2(-20.0, -16.0)),
Anchor::BottomRight,
TextAlignment::Right,
),
ScreenAnchor::Center => (
Rl(vec2(50.0, 50.0)).into(),
Anchor::Center,
TextAlignment::Center,
),
}
}