#![allow(non_snake_case)]
use anyhow::Context;
use hecs::World;
use hecs_schedule::{Read, Schedule, SubWorld, Write};
use ivy_base::{Events, Layer, Position2D, Size2D};
use ivy_resources::Resources;
use ivy_window::Window;
use crate::{handle_events, input_field_system, systems, Canvas};
mod event_handling;
pub use event_handling::*;
pub struct UILayer {
state: InteractiveState,
schedule: Schedule,
}
impl UILayer {
pub fn new(
_world: &mut World,
_resources: &mut Resources,
events: &mut Events,
) -> anyhow::Result<Self> {
let (tx, window_rx) = flume::unbounded();
events
.intercept(tx)
.context("Failed to intercept InputEvent for UI")?;
let control_rx = events.subscribe();
let input_field_rx = events.subscribe();
let schedule = Schedule::builder()
.add_system(
move |w: Write<_>, state: Write<_>, events: Write<_>, cursor_pos: Read<_>| {
handle_events(
w,
events,
state,
cursor_pos,
window_rx.try_iter(),
control_rx.try_iter(),
)
},
)
.add_system(move |w: SubWorld<_>, state: Read<_>, events: Write<_>| {
input_field_system(w, state, input_field_rx.try_iter(), events)
})
.build();
eprintln!("UI Layer: {}", schedule.batch_info());
Ok(Self {
state: InteractiveState::default(),
schedule,
})
}
}
impl Layer for UILayer {
fn on_update(
&mut self,
world: &mut World,
resources: &mut Resources,
events: &mut Events,
_frame_time: std::time::Duration,
) -> anyhow::Result<()> {
systems::update(world)?;
let window = resources.get_default::<Window>()?;
let cursor_pos = window.normalized_cursor_pos();
let (_, (_, size)) = world
.query_mut::<(&Canvas, &Size2D)>()
.into_iter()
.next()
.context("Failed to get canvas")?;
let mut cursor_pos = Position2D(cursor_pos * **size);
self.schedule
.execute((world, events, &mut self.state, &mut cursor_pos))
.context("Failed to execute UI schedule")?;
Ok(())
}
}