use std::cell::RefCell;
use std::collections::HashMap;
use std::collections::HashSet;
use crate::core::callbacks::*;
use crate::core::drawing_texture::*;
use crate::core::point::*;
use crate::core::widget_store::*;
use crate::widget::widget::*;
use glfw_window::GlfwWindow;
use graphics::math::scale;
use graphics::*;
use opengl_graphics::{GlGraphics, OpenGL};
use piston::event_loop::*;
use piston::input::*;
use piston::window::*;
pub struct Pushrod {
window: GlfwWindow,
events: Events,
pub widget_store: RefCell<WidgetStore>,
pub drawing_texture: DrawingTexture,
}
impl Pushrod {
pub fn new(window: GlfwWindow) -> Self {
let event_settings = EventSettings::new().max_fps(30);
Self {
window,
events: Events::new(event_settings),
widget_store: RefCell::new(WidgetStore::new()),
drawing_texture: DrawingTexture::new(),
}
}
pub fn add_widget(&mut self, name: &str, widget: Box<dyn Widget>) -> i32 {
self.widget_store.borrow_mut().add_widget(name, widget)
}
pub fn add_widget_to_parent(
&mut self,
name: &str,
widget: Box<dyn Widget>,
parent_id: i32,
) -> i32 {
self.widget_store
.borrow_mut()
.add_widget_to_parent(name, widget, parent_id)
}
pub fn add_widget_to_parent_by_name(
&mut self,
parent_name: &str,
name: &str,
widget: Box<dyn Widget>,
) -> i32 {
let parent_id = self
.widget_store
.borrow_mut()
.get_widget_id_for_name(parent_name);
self.widget_store
.borrow_mut()
.add_widget_to_parent(name, widget, parent_id)
}
fn broadcast_event(&mut self, event: CallbackEvent) {
self.widget_store
.borrow_mut()
.widgets
.iter_mut()
.for_each(|container| { container.widget.borrow_mut().handle_event(false, event.clone()); });
}
fn handle_event(
&mut self,
widget_id: i32,
event_handler: &mut PushrodCallbackEvents,
event: CallbackEvent,
) {
if widget_id == -1 {
return;
}
let injectable_event = self
.widget_store
.borrow_mut()
.handle_event(widget_id, event.clone());
event_handler.handle_event(event.clone(), &mut self.widget_store.borrow_mut());
match injectable_event {
Some(new_event) => {
event_handler.handle_event(new_event.clone(), &mut self.widget_store.borrow_mut())
}
None => (),
}
}
fn handle_resize(&mut self, width: u32, height: u32) {
eprintln!("[Resize] W={} H={}", width, height);
self.rebuild_gl_buffers();
}
fn rebuild_gl_buffers(&mut self) {
let draw_size = self.window.draw_size();
self.drawing_texture.resize(crate::core::point::Size {
w: draw_size.width as i32,
h: draw_size.height as i32,
});
eprintln!("Rebuild of OpenGL buffers for rendering complete.");
}
pub fn run(&mut self, event_handler: &mut PushrodCallbackEvents) {
let mut last_widget_id = -1;
let mut previous_mouse_position: Point = make_origin_point();
let mut button_map: HashMap<i32, HashSet<Button>> = HashMap::new();
let injectable_map: Vec<i32> = self
.widget_store
.borrow_mut()
.widgets
.iter()
.filter(|x| x.widget.borrow_mut().injects_events())
.map(|x| x.widget_id)
.collect();
let mut gl: GlGraphics = GlGraphics::new(OpenGL::V3_2);
eprintln!("Injectable Map: {:?}", injectable_map);
eprintln!("Window Size: {:?}", self.window.size());
eprintln!("Draw Size: {:?}", self.window.draw_size());
self.widget_store.borrow_mut().invalidate_all_widgets();
self.rebuild_gl_buffers();
while let Some(ref event) = self.events.next(&mut self.window) {
event.mouse_cursor(|x, y| {
let mouse_point = make_point_f64(x, y);
if mouse_point.x != previous_mouse_position.x
|| mouse_point.y != previous_mouse_position.y
{
previous_mouse_position = mouse_point.clone();
let current_widget_id = self
.widget_store
.borrow_mut()
.get_widget_id_for_point(mouse_point.clone());
if current_widget_id != -1 {
self.handle_event(
current_widget_id,
event_handler,
CallbackEvent::MouseMoved {
widget_id: current_widget_id,
point: mouse_point.clone(),
},
);
}
if current_widget_id != last_widget_id {
if last_widget_id != -1 {
self.handle_event(
last_widget_id,
event_handler,
CallbackEvent::MouseExited {
widget_id: last_widget_id,
},
);
}
last_widget_id = current_widget_id;
if last_widget_id != -1 {
self.handle_event(
last_widget_id,
event_handler,
CallbackEvent::MouseEntered {
widget_id: last_widget_id,
},
);
}
}
}
});
event.mouse_scroll(|x, y| {
let mouse_point = make_point_f64(x, y);
if last_widget_id != -1 {
self.handle_event(
last_widget_id,
event_handler,
CallbackEvent::MouseScrolled {
widget_id: last_widget_id,
point: mouse_point.clone(),
},
);
}
});
event.button(|args| match args.state {
ButtonState::Press => {
button_map
.entry(last_widget_id)
.or_insert(HashSet::new())
.insert(args.button);
self.handle_event(
last_widget_id,
event_handler,
CallbackEvent::MouseButtonDown {
widget_id: last_widget_id,
button: args.button,
},
);
}
ButtonState::Release => {
let button_set = button_map.entry(last_widget_id).or_insert(HashSet::new());
if button_set.contains(&args.button) {
button_set.remove(&args.button);
self.handle_event(
last_widget_id,
event_handler,
CallbackEvent::MouseButtonUpInside {
widget_id: last_widget_id,
button: args.button,
},
);
} else {
for (widget_id, button_set) in button_map.iter_mut() {
if button_set.contains(&args.button) {
self.handle_event(
*widget_id,
event_handler,
CallbackEvent::MouseButtonUpOutside {
widget_id: *widget_id,
button: args.button,
},
);
button_set.remove(&args.button);
}
}
}
}
});
event.resize(|w, h| {
self.handle_resize(w as u32, h as u32);
self.broadcast_event(CallbackEvent::WindowResized {
size: crate::core::point::Size {
w: w as i32,
h: h as i32,
},
},
);
self.widget_store.borrow_mut().invalidate_all_widgets();
});
event.focus(|focused| {
self.handle_event(
last_widget_id,
event_handler,
CallbackEvent::WindowFocused { flag: focused },
);
});
match event {
Event::Input(Input::Button(ButtonArgs {
state,
button: Button::Keyboard(key),
scancode: _,
})) => {
self.handle_event(
last_widget_id,
event_handler,
CallbackEvent::KeyPressed {
widget_id: last_widget_id,
key: *key,
state: *state,
},
);
}
_ => {}
};
event.render(|args| {
injectable_map.iter().for_each(|widget_id| {
let injectable_event = self
.widget_store
.borrow_mut()
.get_widget_for_id(*widget_id)
.borrow_mut()
.inject_event(*widget_id);
match injectable_event {
Some(x) => {
self.handle_event(*widget_id, event_handler, x.clone());
self.widget_store.borrow_mut().inject_event(x.clone());
}
None => (),
}
});
if self.widget_store.borrow_mut().needs_repaint() {
let widgets = &mut self.widget_store.borrow_mut();
self.drawing_texture.switch_to_texture();
gl.draw(args.viewport(), |c, g| {
widgets.draw(0, c, g, self.drawing_texture.fbo)
});
self.drawing_texture.switch_to_fb(0);
}
gl.draw(args.viewport(), |c, g| {
clear([1.0, 1.0, 1.0, 0.0], g);
let flipped = c.transform.prepend_transform(scale(1.0, -1.0));
let zoom_factor = (self.window.size().width + self.window.size().height)
/ (self.window.draw_size().width + self.window.draw_size().height);
Image::new().draw(
&self.drawing_texture.texture,
&c.draw_state,
flipped.zoom(zoom_factor),
g,
);
});
});
}
}
}