use crate::geometry::*;
use crate::graphics::*;
use crate::input::*;
use crate::widget::*;
use std::io;
pub struct ElementaryWidget {
pub layout: Box<Layout>,
pub elements: Vec<Box<LayoutElement>>,
}
impl ElementaryWidget {
pub fn new() -> Self {
ElementaryWidget {
layout: Box::new(FreeLayout),
elements: vec![],
}
}
pub fn set_layout<L: Layout + 'static>(&mut self, layout: L) {
self.layout = Box::new(layout);
}
pub fn add_element<E: LayoutElement + 'static, I: IntoLayoutElement<E>>(
&mut self,
item: I,
) -> &Self {
self.elements.push(Box::new(item.into_layout_element()));
self
}
fn push<F>(&mut self, mut input: Vec<GrinInput>, filter: F, output: &mut Vec<GrinInput>)
where
F: for<'r> FnMut(&'r &mut Box<dyn LayoutElement + 'static>) -> bool,
{
for mut e in self.elements.iter_mut().rev().filter(filter) {
input = e.widget_mut().consume(input);
}
output.extend(input.into_iter());
}
}
impl Widget for ElementaryWidget {
fn arrange(&mut self, window: Window) {
let size = window.size;
let total = self.elements.len();
for (element, i) in self.elements.iter_mut().zip(0..total) {
let layout = self.layout.layout(size, i, total);
let relative = element.placement().place(layout);
trace!("Relative: {:?}", relative);
let absolute = window.crop(&relative);
trace!("Absolute: {:?}", absolute);
element.state_mut().set_area(absolute);
element.widget_mut().arrange(absolute);
}
}
fn render(&self, painter: &mut Painter) -> io::Result<()> {
for element in self.elements.iter() {
let scope = element.state().get_area();
trace!("Render scope: {:?}", scope);
element.widget().render(&mut PainterScope::new(
&mut *painter,
scope,
Style::default(),
))?;
}
Ok(())
}
fn consume(&mut self, input: Vec<GrinInput>) -> Vec<GrinInput> {
let mut output: Vec<GrinInput> = vec![];
let input = input.into_iter();
for inp in input {
match inp {
GrinInput::Mouse(MouseEvent { action, position }) => {
match action {
MouseAction::WheelDown | MouseAction::WheelUp => {
self.push(
vec![GrinInput::Mouse(MouseEvent { action, position })],
|el| el.widget().captures(el.state().get_area(), position),
&mut output,
);
}
MouseAction::Drag | MouseAction::Release => {
self.push(
vec![GrinInput::Mouse(MouseEvent { action, position })],
|el| {
el.widget().captures(el.state().get_area(), position)
|| el.state().is_capturing()
},
&mut output,
);
}
MouseAction::PressLeft
| MouseAction::PressRight
| MouseAction::PressMiddle => {
for mut el in self.elements.iter_mut().rev() {
let state = el.widget().captures(el.state().get_area(), position);
el.state_mut().set_capture(state);
}
self.push(
vec![GrinInput::Mouse(MouseEvent { action, position })],
|el| el.state().is_capturing(),
&mut output,
);
}
};
}
inp => {
self.push(vec![inp], |el| el.state().is_capturing(), &mut output);
}
}
}
output
}
}