use crate::{
widgets::{Widget, WidgetConfig},
LayerChannelReceiver, LayerChannelSender, LayerId, LayerInstructions, LayerNummerId, Response,
WidgetChannelReceiver, WidgetChannelSender, WidgetId, WidgetNummerId,
};
use indexmap::IndexMap;
use quicksilver::{geom::Vector, graphics::Image, input::MouseCursor, lifecycle::Window};
use std::sync::mpsc;
struct Layer<'a> {
is_active: bool,
widgets: IndexMap<WidgetNummerId, Box<dyn Widget + 'a>>,
current_id: LayerNummerId,
}
impl<'a> Default for Layer<'a> {
fn default() -> Self {
Self::new()
}
}
impl<'a> Layer<'a> {
pub fn new() -> Self {
Self {
is_active: true,
widgets: Default::default(),
current_id: 0,
}
}
pub fn get_mut(&mut self, index: &u64) -> Option<&mut Box<dyn Widget + 'a>> {
self.widgets.get_mut(index)
}
pub fn remove(&mut self, index: &u64) {
self.widgets.remove(index);
}
pub fn insert(&mut self, widget: Box<dyn Widget + 'a>) -> u64 {
self.current_id += 1;
self.widgets.insert(self.current_id, widget);
self.current_id
}
}
pub trait Assets {
fn get_image(&self, name: &str) -> &Image;
}
pub struct Context<'a> {
start_z: u32,
to_display: IndexMap<LayerNummerId, Layer<'a>>,
widget_with_focus: Option<(u64, u64)>,
last_layer_id: u64,
mouse_cursor: Vector,
layer_channel: LayerChannelReceiver,
layer_channel_creator: LayerChannelSender,
widget_channel: WidgetChannelReceiver,
widget_channel_creator: WidgetChannelSender,
}
impl<'a> Context<'a> {
pub fn new(cursor: Vector, start_z: u32) -> Self {
let (layer_send, layer_rec) = mpsc::channel();
let (widget_send, widget_rec) = mpsc::channel();
Self {
to_display: IndexMap::new(),
widget_with_focus: None,
last_layer_id: 0,
mouse_cursor: cursor,
start_z,
layer_channel: layer_rec,
layer_channel_creator: layer_send,
widget_channel: widget_rec,
widget_channel_creator: widget_send,
}
}
pub fn add_layer(&mut self) -> LayerId {
self.last_layer_id += 1;
self.to_display
.insert(self.last_layer_id, Default::default());
LayerId::new(self.last_layer_id, self.layer_channel_creator.clone())
}
fn get_focused_widget(&mut self) -> Option<&mut Box<dyn Widget + 'a>> {
self.widget_with_focus
.and_then(move |v| self.to_display.get_mut(&v.0).and_then(|x| x.get_mut(&v.1)))
}
fn get_widgets<'b>(
widgets: &'b IndexMap<u64, Layer<'a>>,
) -> Vec<((u64, u64), &'b Box<dyn Widget + 'a>)> {
widgets
.iter()
.filter(|(_, layer)| layer.is_active)
.flat_map(|(layer_id, layer)| {
layer
.widgets
.iter()
.map(move |(widget_id, widget)| ((layer_id, widget_id), widget))
})
.map(|(id, widget)| ((*id.0, *id.1), widget))
.collect()
}
fn get_widgets_mut<'b>(
widgets: &'b mut IndexMap<u64, Layer<'a>>,
) -> Vec<((u64, u64), &'b mut Box<dyn Widget + 'a>)> {
widgets
.iter_mut()
.filter(|(_, layer)| layer.is_active)
.flat_map(|(layer_id, layer)| {
layer
.widgets
.iter_mut()
.map(move |(widget_id, widget)| ((layer_id, widget_id), widget))
})
.map(|(id, widget)| ((*id.0, *id.1), widget))
.collect()
}
fn handle_extern_events(&mut self) {
self.handle_layer_events();
self.handle_widget_events();
}
fn handle_widget_events(&mut self) {
use crate::WidgetInstruction;
let channel = &self.widget_channel;
for event in channel.try_iter() {
let id = event.0;
let layer = id.0;
let id = id.1;
match event.1 {
WidgetInstruction::Drop => {
self.to_display.get_mut(&layer).map(|v| v.remove(&id));
}
}
}
}
fn handle_layer_events(&mut self) {
let channel = &self.layer_channel;
for event in channel.try_iter() {
let id = event.0;
match event.1 {
LayerInstructions::Drop => {
self.to_display.remove(&id);
}
LayerInstructions::SetIsActive(state) => {
self.to_display.get_mut(&id).map(|v| v.is_active = state);
}
}
}
}
pub fn event(&mut self, event: &quicksilver::lifecycle::Event, window: &mut Window) {
self.handle_extern_events();
use quicksilver::input::ButtonState;
use quicksilver::input::MouseButton;
use quicksilver::lifecycle::Event::*;
match event {
MouseMoved(val) => {
let cursor_location = &self.mouse_cursor;
let mut widgets = Context::get_widgets_mut(&mut self.to_display);
let mut widgets = widgets
.iter_mut()
.filter_map(|(_, widget)| {
let does_hover = widget.contains(&val);
if does_hover {
Some(widget)
} else {
widget.set_hover(cursor_location, false);
None
}
})
.collect::<Vec<_>>();
let cursor = widgets
.pop()
.map(|widget| {
widget.set_hover(cursor_location, true);
widget.get_cursor_on_hover(cursor_location)
})
.unwrap_or(MouseCursor::Default);
widgets
.iter_mut()
.for_each(|v| v.set_hover(cursor_location, false));
window.set_cursor(cursor);
self.mouse_cursor = *val;
}
MouseButton(MouseButton::Left, ButtonState::Pressed) => {
let cursor = &self.mouse_cursor;
let mut widgets = Context::get_widgets_mut(&mut self.to_display);
let mut maybe_focused_widgets: Vec<_> = widgets
.iter_mut()
.filter_map(|(id, widget)| {
let contains = widget.contains(cursor);
let is_focusable = widget.is_focusable(cursor);
if contains {
Some((id, widget, is_focusable))
} else {
widget.set_focus(cursor, false);
None
}
})
.collect();
let cursor = &self.mouse_cursor;
self.widget_with_focus =
maybe_focused_widgets
.pop()
.map(|(id, widget, is_focusable)| {
if is_focusable {
widget.set_focus(cursor, true)
};
widget.on_click(cursor);
(id.0, id.1)
});
maybe_focused_widgets
.iter_mut()
.for_each(|(_, widget, is_focusable)| {
if *is_focusable {
widget.set_focus(cursor, false)
}
});
}
MouseButton(_, _) => {
}
Key(key, state) => {
self.get_focused_widget()
.map(|focused| focused.on_key_press(*key, *state));
}
Typed(typed) => {
self.get_focused_widget().map(|v| v.on_typed(*typed));
}
_ => {}
}
}
pub fn render<Store: Assets>(&mut self, assets: &Store, window: &mut Window) {
self.handle_extern_events();
let mut z = self.start_z;
let widgets = Context::get_widgets(&self.to_display);
widgets.iter().for_each(|(_, widget)| {
widget.render(assets, window, z);
z += 1;
});
}
pub fn add_widget<R, W, Res>(
&mut self,
widget: R,
layer_id: &LayerId,
) -> Result<Response<Res>, ()>
where
R: WidgetConfig<Res, W>,
W: Widget + 'a,
Res: Sized,
{
match self.to_display.get_mut(&layer_id.id) {
Some(layer) => {
let (widget, res) = widget.to_widget();
Ok(Response {
channel: res,
id: WidgetId::new(
layer_id.id,
layer.insert(Box::new(widget)),
self.widget_channel_creator.clone(),
),
})
}
_ => Err(()),
}
}
}