use std;
use std::fmt::Debug;
use std::sync::atomic::AtomicUsize;
use crate::color::Color;
use crate::cursor;
use crate::event::event::Event;
use crate::event_handler::{EventHandler, WidgetEvent, WindowEvent};
use crate::position::Dimensions;
use crate::render::cprimitives::CPrimitives;
use crate::state::environment::Environment;
use crate::text;
use crate::widget::Rectangle;
use crate::widget::primitive::Widget;
use crate::state::global_state::GlobalState;
use crate::event::input::Input;
use instant::Instant;
pub struct UiBuilder {
pub window_dimensions: Dimensions,
pub maybe_widgets_capacity: Option<usize>
}
#[derive(Debug)]
pub struct Ui<S> where S: GlobalState {
pub fonts: text::font::Map,
num_redraw_frames: u8,
redraw_count: AtomicUsize,
maybe_background_color: Option<Color>,
mouse_cursor: cursor::MouseCursor,
pub win_w: f64,
pub win_h: f64,
pub widgets: Box<dyn Widget<S>>,
event_handler: EventHandler,
pub environment: Environment<S>
}
#[derive(Debug)]
pub struct UiCell<'a, S: GlobalState> {
ui: &'a mut Ui<S>,
}
pub const SAFE_REDRAW_COUNT: u8 = 3;
impl UiBuilder {
pub fn new(window_dimensions: Dimensions) -> Self {
UiBuilder {
window_dimensions: window_dimensions,
maybe_widgets_capacity: None
}
}
pub fn widgets_capacity(mut self, value: usize) -> Self {
self.maybe_widgets_capacity = Some(value);
self
}
pub fn build<S: GlobalState>(self) -> Ui<S> {
Ui::new(self)
}
}
impl<S: GlobalState> Ui<S> {
fn new(builder: UiBuilder) -> Self {
let UiBuilder {
window_dimensions,
..
} = builder;
Ui {
fonts: text::font::Map::new(),
widgets: Rectangle::initialize(vec![]),
win_w: window_dimensions[0],
win_h: window_dimensions[1],
num_redraw_frames: SAFE_REDRAW_COUNT,
redraw_count: AtomicUsize::new(SAFE_REDRAW_COUNT as usize),
maybe_background_color: None,
mouse_cursor: cursor::MouseCursor::Arrow,
event_handler: EventHandler::new(),
environment: Environment::new()
}
}
pub fn handle_event(&mut self, event: Input, global_state: &mut S) {
let window_event = self.event_handler.handle_event(event, [self.win_w, self.win_h]);
let mut _needs_redraw = self.delegate_events(global_state);
match window_event {
None => (),
Some(event) => {
match event {
WindowEvent::Resize(dimensions) => {
self.win_w = dimensions[0];
self.win_h = dimensions[1];
}
WindowEvent::Focus => (), WindowEvent::UnFocus => (),
WindowEvent::Redraw => (), }
}
}
}
fn delegate_events(&mut self, global_state: &mut S) -> bool {
let now = Instant::now();
let events = self.event_handler.get_events();
for event in events {
match event {
WidgetEvent::Mouse(mouse_event) => {
let consumed = false;
self.widgets.process_mouse_event(mouse_event, &consumed, &mut self.environment, global_state);
}
WidgetEvent::Keyboard(keyboard_event) => {
self.widgets.process_keyboard_event(keyboard_event, &mut self.environment, global_state);
}
WidgetEvent::Window(_) => {
self.widgets.process_other_event(event, &mut self.environment, global_state);
}
WidgetEvent::Touch(_) => {
self.widgets.process_other_event(event, &mut self.environment, global_state);
}
}
}
self.widgets.sync_state(&mut self.environment, global_state);
self.environment.clear();
self.event_handler.clear_events();
if now.elapsed().as_millis() > 16 {
println!("Frame took: {}", now.elapsed().as_secs_f32());
}
return true
}
pub fn draw(&mut self) -> CPrimitives {
let Ui {
ref mut widgets,
win_w, win_h,
ref mut environment,
..
} = *self;
CPrimitives::new([win_w, win_h], widgets, environment)
}
pub fn mouse_cursor(&self) -> cursor::MouseCursor {
self.mouse_cursor
}
}
impl<'a, S: GlobalState> UiCell<'a, S> {
pub fn font(&self, id: text::font::Id) -> Option<&text::Font> {
self.ui.fonts.get(id)
}
pub fn window_dim(&self) -> Dimensions {
[self.ui.win_w, self.ui.win_h]
}
pub fn set_mouse_cursor(&mut self, cursor: cursor::MouseCursor) {
self.ui.mouse_cursor = cursor;
}
}
impl<'a, S: GlobalState> ::std::ops::Deref for UiCell<'a, S> {
type Target = Ui<S>;
fn deref(&self) -> &Ui<S> {
self.ui
}
}
impl<'a, S: GlobalState> AsRef<Ui<S>> for UiCell<'a, S> {
fn as_ref(&self) -> &Ui<S> {
&self.ui
}
}