163 lines
3.9 KiB
Rust
163 lines
3.9 KiB
Rust
use std::sync::Arc;
|
|
|
|
use super::super::api::Rect;
|
|
use crate::{
|
|
ui::{api::Color, event::Event},
|
|
vertexbuffer::types::UiInstance,
|
|
RenderInput, RenderState,
|
|
};
|
|
use galactica_content::{Sprite, SpriteAutomaton};
|
|
use galactica_util::to_radians;
|
|
use rhai::ImmutableString;
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct UiSprite {
|
|
pub anim: SpriteAutomaton,
|
|
pub name: ImmutableString,
|
|
|
|
/// Sprite angle, in degrees
|
|
angle: f32,
|
|
|
|
/// If true, this sprite will be scaled to fit in its box without affecting aspect ratio.
|
|
/// If false, this sprite will be stretched to fit in its box
|
|
preserve_aspect: bool,
|
|
|
|
rect: Rect,
|
|
mask: Option<Arc<Sprite>>,
|
|
color: Color,
|
|
|
|
/// If true, ignore mouse events until click is released
|
|
waiting_for_release: bool,
|
|
has_mouse: bool,
|
|
has_click: bool,
|
|
}
|
|
|
|
impl UiSprite {
|
|
pub fn new(name: ImmutableString, sprite: Arc<Sprite>, rect: Rect) -> Self {
|
|
Self {
|
|
name,
|
|
anim: SpriteAutomaton::new(sprite),
|
|
rect,
|
|
angle: 0.0,
|
|
color: Color::new(1.0, 1.0, 1.0, 1.0),
|
|
mask: None,
|
|
has_mouse: false,
|
|
has_click: false,
|
|
waiting_for_release: false,
|
|
preserve_aspect: false,
|
|
}
|
|
}
|
|
|
|
pub fn set_mask(&mut self, mask: Option<Arc<Sprite>>) {
|
|
self.mask = mask;
|
|
}
|
|
|
|
pub fn set_angle(&mut self, angle: f32) {
|
|
self.angle = angle;
|
|
}
|
|
|
|
pub fn set_rect(&mut self, rect: Rect) {
|
|
self.rect = rect;
|
|
}
|
|
|
|
pub fn set_color(&mut self, color: Color) {
|
|
self.color = color;
|
|
}
|
|
|
|
pub fn set_preserve_aspect(&mut self, preserve_aspect: bool) {
|
|
self.preserve_aspect = preserve_aspect;
|
|
}
|
|
|
|
pub fn push_to_buffer(&self, input: &RenderInput, state: &mut RenderState) {
|
|
let mut rect = self
|
|
.rect
|
|
.to_centered(&state.window, input.ct.config.ui_scale);
|
|
|
|
if self.preserve_aspect {
|
|
let rect_aspect = rect.dim.x / rect.dim.y;
|
|
let sprite_aspect = self.anim.get_sprite().aspect;
|
|
|
|
// "wide rect" case => match height, reduce width
|
|
if rect_aspect > sprite_aspect {
|
|
let shrink = rect.dim.x - rect.dim.y * sprite_aspect;
|
|
rect.dim.x -= shrink;
|
|
|
|
// "tall rect" case => match width, reduce height
|
|
} else if rect_aspect < sprite_aspect {
|
|
let shrink = rect.dim.y - rect.dim.x / sprite_aspect;
|
|
rect.dim.y -= shrink;
|
|
}
|
|
}
|
|
|
|
let anim_state = self.anim.get_texture_idx();
|
|
state.push_ui_buffer(UiInstance {
|
|
position: rect.pos.into(),
|
|
angle: to_radians(90.0 + self.angle),
|
|
dim: rect.dim.into(),
|
|
color: self.color.as_array(),
|
|
texture_index: anim_state.texture_index(),
|
|
texture_fade: anim_state.fade,
|
|
mask_index: self
|
|
.mask
|
|
.as_ref()
|
|
.map(|x| {
|
|
let texture_b = x.get_first_frame(); // TODO: animate?
|
|
[1, texture_b]
|
|
})
|
|
.unwrap_or([0, 0]),
|
|
});
|
|
}
|
|
|
|
pub fn check_events(&mut self, input: &RenderInput, state: &mut RenderState) -> Event {
|
|
let r = self
|
|
.rect
|
|
.to_centered(&state.window, input.ct.config.ui_scale);
|
|
|
|
if self.waiting_for_release && self.has_mouse && !input.player.input.pressed_leftclick() {
|
|
self.waiting_for_release = false;
|
|
}
|
|
|
|
if !self.waiting_for_release
|
|
&& self.has_mouse
|
|
&& !self.has_click
|
|
&& input.player.input.pressed_leftclick()
|
|
{
|
|
self.has_click = true;
|
|
return Event::MouseClick;
|
|
}
|
|
|
|
if self.has_mouse && self.has_click && !input.player.input.pressed_leftclick() {
|
|
self.has_click = false;
|
|
return Event::MouseRelease;
|
|
}
|
|
|
|
// Release mouse when cursor leaves box
|
|
if self.has_click && !self.has_mouse {
|
|
self.has_click = false;
|
|
return Event::MouseRelease;
|
|
}
|
|
|
|
if r.contains_mouse(input, state) && !self.has_mouse {
|
|
if input.player.input.pressed_leftclick() {
|
|
// If we're holding click when the cursor enters,
|
|
// don't trigger the `Click` event.
|
|
self.waiting_for_release = true;
|
|
}
|
|
self.has_mouse = true;
|
|
return Event::MouseHover;
|
|
}
|
|
|
|
if !r.contains_mouse(input, state) && self.has_mouse {
|
|
self.waiting_for_release = false;
|
|
self.has_mouse = false;
|
|
return Event::MouseUnhover;
|
|
}
|
|
|
|
return Event::None;
|
|
}
|
|
|
|
pub fn step(&mut self, input: &RenderInput, _state: &mut RenderState) {
|
|
self.anim.step(input.time_since_last_run);
|
|
}
|
|
}
|