use std::convert::TryInto;
use derive_builder::Builder;
use log;
use crate::prelude::*;
use super::{Frame, set_layout};
pub fn resize (
system : &input::System,
elements : &Tree <Element>,
node_id : &NodeId,
action_buffer : &mut Vec <(NodeId, Action)>
) {
log::trace!("resize...");
match system {
&input::System::Resized { width, height } => {
*coordinates::SCREEN_WH.write().unwrap() = [width, height];
let Widget (layout, _, canvas) = Frame::try_get (elements, node_id).unwrap();
let coordinate_kind = Some (canvas.coordinates.kind());
let layout = {
use controller::component::Layout;
let (mut free, area) = layout.variant.clone().try_into().unwrap();
free.size = {
let width = width.into();
let height = height.into();
Size { width, height }
};
free.offset = if canvas.coordinates.kind() == coordinates::Kind::Tile {
tile_offset (free.size, free.anchor)
} else {
pixel_offset (free.size, free.anchor)
};
Layout { variant: (free, area).into(), .. layout.clone() }
};
set_layout (elements, node_id, layout, coordinate_kind, action_buffer);
}
_ => {}
}
log::trace!("...resize");
}
#[derive(Builder)]
#[builder(pattern="owned", build_fn(private), setter(strip_option))]
#[builder(public)]
struct Pixel <'a, A : Application> {
#[builder(default)]
anchor : Option <Alignment>,
#[builder(default)]
appearances : Option <Appearances>,
#[builder(default)]
bindings : Option <&'a Bindings <A>>,
#[builder(default)]
border : Option <Border>,
#[builder(default)]
clear_color : canvas::ClearColor,
#[builder(default)]
dimensions : Option <dimensions::Pixel>,
#[builder(default)]
name : Option <String>,
#[builder(default)]
orientation : (Orientation, Area),
#[builder(default)]
system_control : Option <controls::System>
}
#[derive(Builder)]
#[builder(pattern="owned", build_fn(private), setter(strip_option))]
#[builder(public)]
struct Tile <'a, A : Application> {
#[builder(default)]
anchor : Option <Alignment>,
#[builder(default)]
appearances : Option <Appearances>,
#[builder(default)]
bindings : Option <&'a Bindings <A>>,
#[builder(default)]
border : Option <Border>,
#[builder(default)]
clear_color : canvas::ClearColor,
#[builder(default)]
dimensions : Option <dimensions::Tile>,
#[builder(default)]
name : Option <String>,
#[builder(default)]
orientation : (Orientation, Area),
#[builder(default)]
system_control : Option <controls::System>
}
impl <A : Application> PixelBuilder <'_, A> {
pub const fn new() -> Self {
PixelBuilder {
anchor: None,
appearances: None,
bindings: None,
border: None,
clear_color: None,
dimensions: None,
name: None,
orientation: None,
system_control: None
}
}
}
impl <A : Application> BuildElement for PixelBuilder <'_, A> {
fn build_element (self) -> Element {
log::trace!("pixel build element...");
let Pixel {
anchor, appearances, bindings, border, clear_color, dimensions, name,
orientation, system_control
} = self.build()
.map_err(|err| log::error!("frame screen tile builder error: {err:?}"))
.unwrap();
let controller = {
let layout = {
use controller::{Alignment, Area, Size};
use controller::component::{layout, Layout};
let size = dimensions.map_or (
Size::default_absolute(),
|dimensions| Size {
width: dimensions.width().into(),
height: dimensions.height().into()
}
);
let anchor = anchor.unwrap_or (Alignment::pixel());
let offset = pixel_offset (size, anchor);
let free = layout::Free { size, offset, anchor };
Layout { orientation, .. layout::Variant::from ((free, Area::default())).into() }
};
let bindings_empty = Bindings::empty();
let bindings = {
let mut bindings =
bindings.unwrap_or (&bindings_empty).get_bindings (&super::CONTROLS);
bindings.system = system_control.map (Into::into)
.or (Some (controls::system::Builtin::FrameScreenResize.into()));
bindings
};
let mut controller = Controller::with_bindings (&bindings);
controller.component = layout.into();
controller.appearances = appearances.unwrap_or_default();
controller
};
let view = {
let coordinates = Coordinates::Pixel (
position::Pixel::origin(),
dimensions.unwrap_or (dimensions::Pixel::default()));
let width = coordinates.dimensions_horizontal();
let height = coordinates.dimensions_vertical();
*coordinates::SCREEN_WH.write().unwrap() = [width, height];
let canvas = Canvas { coordinates, clear_color, border };
let appearance = controller.get_appearance().clone();
View { appearance, .. view::Component::from (canvas).into() }
};
let name = name.unwrap_or ("Frame".to_string());
log::trace!("...pixel build element");
Element::new (name, controller, Model::default(), view)
}
}
impl <A : Application> TileBuilder <'_, A> {
pub const fn new() -> Self {
TileBuilder {
anchor: None,
appearances: None,
bindings: None,
border: None,
clear_color: None,
dimensions: None,
name: None,
orientation: None,
system_control: None
}
}
}
impl <A : Application> BuildElement for TileBuilder <'_, A> {
fn build_element (self) -> Element {
log::trace!("tile build element...");
let Tile {
anchor, appearances, bindings, border, clear_color, dimensions, name, orientation,
system_control
} = self.build()
.map_err(|err| log::error!("frame screen tile builder error: {err:?}"))
.unwrap();
let controller = {
let layout = {
use controller::{Alignment, Area, Size};
use controller::component::{layout, Layout};
let size = dimensions.map_or (Size::default_absolute(),
|dimensions| Size {
width: dimensions.columns().into(),
height: dimensions.rows().into()
}
);
let anchor = anchor.unwrap_or (Alignment::tile());
let offset = tile_offset (size, anchor);
let free = layout::Free { size, offset, anchor };
let area = Area::default();
Layout { orientation, .. layout::Variant::from ((free, area)).into() }
};
let bindings_empty = Bindings::empty();
let bindings = {
let mut bindings = bindings.unwrap_or (&bindings_empty)
.get_bindings (&super::CONTROLS);
bindings.system = system_control.map (Into::into)
.or (Some (controls::system::Builtin::FrameScreenResize.into()));
bindings
};
let mut controller = Controller::with_bindings (&bindings);
controller.component = layout.into();
controller.appearances = appearances.unwrap_or_default();
controller
};
let view = {
let coordinates = Coordinates::Tile (
position::Tile::origin(),
dimensions.unwrap_or (dimensions::Tile::default()));
let width = coordinates.dimensions_horizontal();
let height = coordinates.dimensions_vertical();
*coordinates::SCREEN_WH.write().unwrap() = [width, height];
let canvas = Canvas { coordinates, clear_color, border };
let appearance = controller.get_appearance().clone();
View { appearance, .. view::Component::from (canvas).into() }
};
let name = name.unwrap_or ("Frame".to_string());
log::trace!("...tile build element");
Element::new (name, controller, Model::default(), view)
}
}
pub fn pixel_offset (size : Size, anchor : Alignment) -> Offset {
use controller::{alignment, offset, Offset};
let horizontal = match anchor.horizontal {
alignment::Horizontal::Left => 0.into(),
alignment::Horizontal::Center => -offset::Signed::from (size.width).half(),
alignment::Horizontal::Right => -offset::Signed::from (size.width)
};
let vertical = match anchor.vertical {
alignment::Vertical::Bottom => 0.into(),
alignment::Vertical::Middle => -offset::Signed::from (size.height).half(),
alignment::Vertical::Top => -offset::Signed::from (size.height)
};
Offset { horizontal, vertical }
}
pub fn tile_offset (size : Size, anchor : Alignment) -> Offset {
use controller::{alignment, offset, Offset};
let horizontal = match anchor.horizontal {
alignment::Horizontal::Left => 0.into(),
alignment::Horizontal::Center => -offset::Signed::from (size.width).half(),
alignment::Horizontal::Right => -offset::Signed::from (size.width)
};
let vertical = match anchor.vertical {
alignment::Vertical::Top => 0.into(),
alignment::Vertical::Middle => -offset::Signed::from (size.height).half(),
alignment::Vertical::Bottom => -offset::Signed::from (size.height)
};
Offset { horizontal, vertical }
}