use std::fmt::{self, Debug};
use crate::callback::Condition;
use crate::macros::Widget;
use crate::event::{Action, GuiResponse, Handler, NoResponse, err_num, err_unhandled};
use crate::{Class, Coord, Core, CoreData, TkWidget, Widget};
pub trait Window: Widget {
fn as_widget(&self) -> &Widget;
fn as_widget_mut(&mut self) -> &mut Widget;
#[cfg(feature = "layout")]
fn configure_widgets(&mut self, tk: &TkWidget);
#[cfg(feature = "layout")]
fn resize(&mut self, tk: &TkWidget, size: Coord);
fn handle_action(&mut self, tk: &TkWidget, action: Action, num: u32) -> GuiResponse;
fn callbacks(&self) -> Vec<(usize, Condition)>;
fn trigger_callback(&mut self, index: usize, tk: &TkWidget);
fn on_start(&mut self, tk: &TkWidget);
}
#[widget(class = Class::Window)]
#[derive(Widget)]
pub struct SimpleWindow<W: Widget + 'static> {
#[core] core: CoreData,
min_size: Coord,
#[cfg(feature = "cassowary")] solver: crate::cw::Solver,
#[widget] w: W,
fns: Vec<(Condition, &'static Fn(&mut W, &TkWidget))>,
}
impl<W: Widget> Debug for SimpleWindow<W> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "SimpleWindow {{ core: {:?}, min_size: {:?}, solver: <omitted>, w: {:?}, fns: [",
self.core, self.min_size, self.w)?;
let mut iter = self.fns.iter();
if let Some(first) = iter.next() {
write!(f, "({:?}, <FnMut>)", first.0)?;
for next in iter {
write!(f, ", ({:?}, <FnMut>)", next.0)?;
}
}
write!(f, "] }}")
}
}
impl<W: Widget + Clone> Clone for SimpleWindow<W> {
fn clone(&self) -> Self {
SimpleWindow {
core: self.core.clone(),
min_size: self.min_size,
#[cfg(feature = "cassowary")] solver: crate::cw::Solver::new(),
w: self.w.clone(),
fns: self.fns.clone(),
}
}
}
impl<W: Widget> SimpleWindow<W> {
pub fn new(w: W) -> SimpleWindow<W> {
SimpleWindow {
core: Default::default(),
min_size: (0, 0),
#[cfg(feature = "cassowary")] solver: crate::cw::Solver::new(),
w,
fns: Vec::new(),
}
}
pub fn add_callback(&mut self, f: &'static Fn(&mut W, &TkWidget),
conditions: &[Condition])
{
for c in conditions {
self.fns.push((*c, f));
}
}
}
impl<R, W: Widget + Handler<Response = R> + 'static> Window
for SimpleWindow<W>
where GuiResponse: From<R>, R: From<NoResponse>
{
fn as_widget(&self) -> &Widget { self }
fn as_widget_mut(&mut self) -> &mut Widget { self }
#[cfg(feature = "cassowary")]
fn configure_widgets(&mut self, tk: &TkWidget) {
use crate::cw;
assert!(self.number() > 0, "widget not enumerated");
let v_w = cw_var!(self, w);
let v_h = cw_var!(self, h);
self.solver.reset();
self.w.init_constraints(tk, &mut self.solver, true);
self.solver.add_edit_variable(v_w, cw::strength::MEDIUM * 100.0).unwrap();
self.solver.add_edit_variable(v_h, cw::strength::MEDIUM * 100.0).unwrap();
self.min_size = (self.solver.get_value(v_w) as i32, self.solver.get_value(v_h) as i32);
self.w.apply_constraints(tk, &self.solver, (0, 0));
}
#[cfg(feature = "cassowary")]
fn resize(&mut self, tk: &TkWidget, size: Coord) {
assert!(self.number() > 0, "widget not enumerated");
self.solver.suggest_value(cw_var!(self, w), size.0 as f64).unwrap();
self.solver.suggest_value(cw_var!(self, h), size.1 as f64).unwrap();
self.w.apply_constraints(tk, &self.solver, (0, 0));
}
fn handle_action(&mut self, tk: &TkWidget, action: Action, num: u32) -> GuiResponse {
if num < self.number() {
GuiResponse::from(self.w.handle_action(tk, action, num))
} else if num == self.number() {
match action {
Action::Close => GuiResponse::Close,
_ => err_unhandled(action),
}
} else {
err_num()
}
}
fn callbacks(&self) -> Vec<(usize, Condition)> {
self.fns.iter().map(|(cond, _)| *cond).enumerate().collect()
}
fn trigger_callback(&mut self, index: usize, tk: &TkWidget) {
let cb = &mut self.fns[index].1;
cb(&mut self.w, tk);
}
fn on_start(&mut self, tk: &TkWidget) {
for cb in &mut self.fns {
if cb.0 == Condition::Start {
(cb.1)(&mut self.w, tk);
}
}
}
}