use std::any::Any;
use std::sync::{Arc, Mutex};
use webrender::api::*;
use crate::elements::element::*;
use crate::gui::font;
use crate::gui::properties;
use crate::util::*;
pub struct VBox {
ext_id: u64,
children: Vec<Arc<Mutex<Element>>>,
props: properties::Properties,
bounds: properties::Extent,
handlers: EventHandlers,
}
impl VBox {
pub fn new() -> Self {
let mut props = properties::Properties::new();
props.default();
VBox {
ext_id: 0,
children: Vec::new(),
props,
bounds: properties::Extent {
x: 0.0,
y: 0.0,
w: 0.0,
h: 0.0,
dpi: 0.0,
},
handlers: EventHandlers::new(),
}
}
fn get_height_sums(&mut self) -> (f32, f32) {
let top = self.props.get_top();
let bottom = self.props.get_bottom();
let mut stretchy: f32 = 0.0;
let mut pixel: f32 = 0.0;
match top {
properties::Unit::Stretch(_s) => stretchy += _s,
properties::Unit::Pixel(_p) => pixel += _p,
_ => (),
}
match bottom {
properties::Unit::Stretch(_s) => stretchy += _s,
properties::Unit::Pixel(_p) => pixel += _p,
_ => (),
}
for elm in self.children.iter() {
if let Ok(ref _e) = elm.lock() {
let _p = _e.get_bounds().h;
match _e.get_properties().get_height() {
properties::Unit::Stretch(_s) => stretchy += _s,
_ => {
if !_p.is_nan() && !_p.is_infinite() {
pixel += _p;
}
}
}
}
}
(pixel, stretchy)
}
fn get_width_sums(&mut self) -> (f32, f32) {
let left = self.props.get_left();
let right = self.props.get_right();
let width = self.props.get_width();
let mut stretchy: f32 = 0.0;
let mut pixel: f32 = 0.0;
match left {
properties::Unit::Stretch(_s) => stretchy += _s,
properties::Unit::Pixel(_p) => pixel += _p,
_ => (),
}
match right {
properties::Unit::Stretch(_s) => stretchy += _s,
properties::Unit::Pixel(_p) => pixel += _p,
_ => (),
}
match width {
properties::Unit::Stretch(_s) => stretchy += _s,
properties::Unit::Pixel(_p) => pixel += _p,
_ => (),
}
(pixel, stretchy)
}
}
impl Default for VBox {
fn default() -> Self {
Self::new()
}
}
impl Element for VBox {
fn get_ext_id(&self) -> u64 {
self.ext_id
}
fn set(&mut self, prop: properties::Property) {
self.props.set(prop);
}
fn get_properties(&self) -> properties::Properties {
self.props.clone()
}
fn render(
&mut self,
api: &RenderApi,
builder: &mut DisplayListBuilder,
extent: properties::Extent,
font_store: &mut font::FontStore,
_props: Option<Arc<properties::Properties>>,
gen: &mut properties::IdGenerator,
) {
let bgcolor = self.props.get_bg_color();
let top = self.props.get_top();
let bottom = self.props.get_bottom();
let left = self.props.get_left();
let right = self.props.get_right();
let width = self.props.get_width();
let height = self.props.get_height();
let (wp_sum, ws_sum) = self.get_width_sums();
let mut remaining_width = extent.w - wp_sum;
if remaining_width < 0.0 {
remaining_width = 0.0;
}
let mut w_stretchy_factor = remaining_width / ws_sum;
if w_stretchy_factor.is_nan() {
w_stretchy_factor = 0.0;
}
let (hp_sum, hs_sum) = self.get_height_sums();
let mut remaining_height = extent.h - hp_sum;
if remaining_height < 0.0 {
remaining_height = 0.0;
}
let mut h_stretchy_factor = remaining_height / hs_sum;
if h_stretchy_factor.is_nan() {
h_stretchy_factor = 0.0;
}
let _id = gen.get();
self.ext_id = _id;
let mut info = LayoutPrimitiveInfo::new(
(self.bounds.x, self.bounds.y).by(self.bounds.w, self.bounds.h),
);
info.tag = Some((_id, 0));
builder.push_rect(&info, bgcolor);
let mut next_x = 0.0;
let mut next_y = 0.0;
match top {
properties::Unit::Stretch(_s) => next_y = h_stretchy_factor * _s,
properties::Unit::Pixel(_p) => next_y = _p,
_ => (),
}
match left {
properties::Unit::Stretch(_s) => next_x = w_stretchy_factor * _s,
properties::Unit::Pixel(_p) => next_x = _p,
_ => (),
}
match height {
properties::Unit::Stretch(_s) => remaining_height = _s * h_stretchy_factor,
properties::Unit::Pixel(_p) => remaining_height = _p,
_ => (),
}
match width {
properties::Unit::Stretch(_s) => remaining_width = _s * w_stretchy_factor,
properties::Unit::Pixel(_p) => remaining_width = _p,
_ => (),
}
for elm in self.children.iter_mut() {
let mut child_extent = properties::Extent {
x: next_x + extent.x,
y: next_y + extent.y,
w: remaining_width,
h: remaining_height,
dpi: extent.dpi,
};
match elm.lock() {
Ok(ref mut elm) => {
let e_height = elm.get_properties().get_height();
match e_height {
properties::Unit::Pixel(_p) => {
child_extent.h = _p;
}
properties::Unit::Stretch(_s) => {
child_extent.h = h_stretchy_factor;
}
_ => (),
}
elm.render(api, builder, child_extent, font_store, None, gen);
let _ex = elm.get_bounds();
next_y += _ex.h;
}
Err(_err_str) => panic!("unable to lock element : {}", _err_str),
}
}
match bottom {
properties::Unit::Stretch(_s) => next_y += h_stretchy_factor * _s,
properties::Unit::Pixel(_p) => next_y += _p,
_ => (),
}
next_x += remaining_width;
match right {
properties::Unit::Stretch(_s) => next_x += w_stretchy_factor * _s,
properties::Unit::Pixel(_p) => next_x += _p,
_ => (),
}
self.bounds = properties::Extent {
x: extent.x,
y: extent.y,
w: next_x,
h: next_y,
dpi: extent.dpi,
};
}
fn get_bounds(&self) -> properties::Extent {
self.bounds.clone()
}
fn on_primitive_event(&mut self, ext_ids: &[ItemTag], e: PrimitiveEvent) -> bool {
let mut handled = false;
for _child_elm in self.children.iter_mut() {
match (&e, _child_elm.lock()) {
(PrimitiveEvent::SetFocus(_), Ok(ref mut _child_elm)) => {
if ext_ids.len() > 1
&& ext_ids[0].0 == self.ext_id
&& ext_ids[1].0 == _child_elm.get_ext_id()
{
_child_elm
.on_primitive_event(&ext_ids[1..], PrimitiveEvent::SetFocus(true));
} else {
_child_elm.on_primitive_event(&[], PrimitiveEvent::SetFocus(false));
}
}
(PrimitiveEvent::Char(_c), Ok(ref mut _child_elm)) => {
handled = _child_elm.on_primitive_event(&[], e.clone());
if handled {
break;
}
}
(PrimitiveEvent::HoverBegin(_), Ok(ref mut _child_elm)) => {
_child_elm.on_primitive_event(&[], e.clone());
}
(PrimitiveEvent::HoverEnd(_), Ok(ref mut _child_elm)) => {
_child_elm.on_primitive_event(&[], e.clone());
}
(_, Ok(ref mut _child_elm)) => {
if !handled {
if ext_ids.len() == 1 {
handled = _child_elm.on_primitive_event(&[], e.clone());
} else if ext_ids.len() > 1 {
handled = _child_elm.on_primitive_event(&ext_ids[1..], e.clone());
}
}
}
(_, Err(_err_str)) => {
panic!("unable to lock element : {}", _err_str)
}
}
}
if !handled {
if let PrimitiveEvent::Button(_p, _b, _s, m) = e {
handled = self.exec_handler(ElementEvent::Clicked, &m);
}
}
handled
}
fn set_handler(&mut self, _e: ElementEvent, _f: EventFn) {
self.handlers.insert(_e, _f);
}
fn exec_handler(&mut self, _e: ElementEvent, _d: &Any) -> bool {
let h = self.handlers.get_mut(&_e).cloned();
if let Some(mut h) = h {
h.call(self, _d)
} else {
false
}
}
fn as_any(&self) -> &Any {
self
}
fn as_any_mut(&mut self) -> &mut Any {
self
}
}
impl HasChildren for VBox {
#[allow(unused)]
fn get_child(&self, i: u32) -> Option<Arc<Mutex<Element>>> {
None
}
#[allow(unused)]
fn append(&mut self, e: Arc<Mutex<Element>>) -> Option<Arc<Mutex<Element>>> {
self.children.push(e);
None
}
}