use traits::*;
use rin::graphics::*;
use rin::events::*;
use rin::math::*;
use rin::color::*;
use rin::color::consts::*;
use rin::window::{self, Events, MouseEvents};
use std::rc::Rc;
use control_shape::ControlShape;
use utils;
pub struct GroupH{
rendered: Sender<'static, ()>,
controls: Vec<Box<Control>>,
controls_width_pcts: Vec<Option<Property<'static, f32>>>,
name: String,
font: Rc<Ttf>,
color: Rgb<f32>,
non_attended: StreamRc<'static, window::Event>,
width: Property<'static, f32>,
height: Property<'static, f32>,
position: Property<'static, Pnt2>,
events: StreamRc<'static, window::Event>,
h_margin: f32,
v_margin: f32,
}
impl ControlGeometry for GroupH{
fn flexible() -> bool{
true
}
fn geometry(&self, container: Option<&Rect<f32>>) -> Option<Vec<Vertex2DColor>>{
self.rendered.send(());
let rect = self.rect();
let rect = container.map(|container| container.intersection(&rect)).unwrap_or(rect);
let geometry = self.controls.iter()
.skip_while(|control| !control.rect().overlaps(&rect))
.take_while(|control| control.rect().overlaps(&rect))
.filter_map(|control| control.geometry(Some(&rect)))
.flat_map(|geometry| geometry.into_iter())
.collect::<Vec<_>>();
if geometry.is_empty(){
None
}else{
Some(geometry)
}
}
fn text_geometry(&self, container: Option<&Rect<f32>>) -> Option<Vec<Vertex2DTex>>{
let rect = self.rect();
let rect = container.map(|container| container.intersection(&rect)).unwrap_or(rect);
let geometry = self.controls.iter()
.skip_while(|control| !control.rect().overlaps(&rect))
.take_while(|control| control.rect().overlaps(&rect))
.filter_map(|control| control.text_geometry(Some(&rect)))
.flat_map(|geometry| geometry.into_iter())
.collect::<Vec<_>>();
if geometry.is_empty(){
None
}else{
Some(geometry)
}
}
fn texture_geometry(&self, container: Option<&Rect<f32>>) -> Option<Vec<Vertex2DTex>>{
let rect = self.rect();
let rect = container.map(|container| container.intersection(&rect)).unwrap_or(rect);
let geometry = self.controls.iter()
.skip_while(|control| !control.rect().overlaps(&rect))
.take_while(|control| control.rect().overlaps(&rect))
.filter_map(|control| control.texture_geometry(Some(&rect)))
.flat_map(|geometry| geometry.into_iter())
.collect::<Vec<_>>();
if geometry.is_empty(){
None
}else{
Some(geometry)
}
}
fn font(&self) -> Option<&Ttf>{
Some(&self.font)
}
fn color(&self) -> &Rgb<f32>{
&self.color
}
fn position(&self) -> &Property<'static, Pnt2>{
&self.position
}
fn width(&self) -> &Property<'static, f32>{
&self.width
}
fn height(&self) -> &Property<'static, f32>{
&self.height
}
}
impl ControlEvents for GroupH{
fn non_attended(&self) -> StreamRc<'static, window::Event>{
self.non_attended.clone()
}
}
impl Control for GroupH{
fn name(&self) -> &str{
&self.name
}
}
impl GroupH{
pub fn control<C: Control>(&self, idx: usize) -> Option<&C>{
self.controls[idx].downcast_ref()
}
pub fn control_mut<C: Control>(&mut self, idx: usize) -> Option<&mut C>{
self.controls[idx].downcast_mut()
}
pub fn add<P,S>(&mut self, name: &str, parameter: S) -> &mut GroupH
where S: IntoStyled<Property = P>,
P: ControlDefaultProperty,
{
self.new_control(name, parameter);
self
}
pub fn new_control<P,S>(&mut self, name: &str, parameter: S) -> &mut <<P as ControlDefaultProperty>::Builder as ControlBuilder>::Control
where S: for<'a> IntoStyled<Property = P>,
P: ControlDefaultProperty,
{
self.create_control::<P, P::Builder>(name, parameter.into_styled())
}
fn create_control<P, B>(&mut self, name: &str, styled: Styled<P>) -> &mut B::Control
where P: IntoControlBuilder<B>,
B: ControlBuilder
{
let h_margin = self.h_margin;
let position = if let Some(control) = self.controls.last(){
control.position().clone().zip(control.width().clone())
.map(move |(p,w)| pnt2(p.x + w + h_margin, p.y))
}else{
self.position.clone()
};
let (width, width_pct) = if !B::Control::flexible(){
(None, None)
}else{
let num_flexibles = self.controls_width_pcts.iter()
.filter(|pct| pct.is_some())
.count();
let non_flexible_width = self.controls_width_pcts.iter()
.zip(self.controls.iter())
.filter_map(|(pct, control)| if pct.is_none(){
Some(**control.width())
}else{
None
}).sum::<f32>();
let num_controls = self.controls.len();
let rem_pct = self.width.clone().map(move |w| {
let w = w - h_margin * (num_controls + 1) as f32;
(w - non_flexible_width) / w
});
let pct = if num_flexibles == 0 {
rem_pct
}else{
let pct_per_element = rem_pct.map(move |pct| pct / num_flexibles as f32);
for pct in self.controls_width_pcts.iter_mut(){
if let Some(pct) = pct.as_mut(){
pct.swap_parent(pct_per_element.clone().stream());
pct.set(*pct_per_element);
}
}
pct_per_element
};
let control_width = self.width.clone().zip(pct.clone()).map(|(w, pct)| clamp(w * pct, 0., w));
(Some(control_width), Some(pct))
};
let c = styled.parameter.into_builder(name, self.events.clone())
.position_property(position)
.height_property(self.height.clone())
.width_property_opt(width)
.h_margin(self.h_margin)
.v_margin(self.v_margin)
.color(self.color)
.font(self.font.clone())
.hide_label()
.from_json_style(&styled.style)
.create();
self.controls.push(Box::new(c));
self.controls_width_pcts.push(width_pct);
let control: &mut B::Control = self.controls.last_mut().unwrap().downcast_mut().unwrap();
control
}
}
pub struct GroupHBuilder {
control_shape: ControlShape,
name: String,
events: StreamRc<'static, window::Event>,
}
impl GroupHBuilder{
pub fn new<S: StreamT<'static, window::Event>>(name: &str, pos: Property<'static, Pnt2>, events: S) -> GroupHBuilder{
let width = Property::new(200.);
let height = Property::new(15.);
let margin = 0.;
GroupHBuilder{
name: name.to_string(),
events: events.rc(),
control_shape: ControlShape::new(pos, width, height, margin, margin, WHITE),
}
}
}
impl ControlBuilder for GroupHBuilder{
type Control = GroupH;
fn shape(&mut self) -> &mut ControlShape {
&mut self.control_shape
}
fn create(self) -> GroupH{
let (rendered_sender, rendered_stream) = utils::rendered_stream(self.events.clone().unique());
let rendered = rendered_stream.to_property(false);
let font = self.control_shape.font().unwrap_or_else(|| ::utils::default_font());
let h_margin = self.control_shape.h_margin();
let v_margin = self.control_shape.v_margin();
let rect = self.control_shape.position()
.zip(self.control_shape.width())
.zip(self.control_shape.height())
.flatten()
.map(|(pos, width, height)| Rect{
pos: convert(pos),
width: width as f64,
height: height as f64
});
let is_over = self.events.clone()
.mouse()
.moved()
.map(move |p| p.inside(&rect))
.to_property(false);
let non_attended = self.events.clone()
.filter(move |e|{
if let window::Event::MousePressed{..} = e {
!*rendered || !*is_over
}else{
true
}
}).rc();
GroupH {
controls: vec![],
controls_width_pcts: vec![],
name: self.name,
color: self.control_shape.color(),
font,
position: self.control_shape.position(),
width: self.control_shape.width(),
height: self.control_shape.height(),
h_margin,
v_margin,
events: self.events,
rendered: rendered_sender,
non_attended,
}
}
}
pub struct Tuple<T>{
param: T,
names: &'static [&'static str],
}
impl<T> Tuple<T>{
pub fn new(param: T, names: &'static [&'static str]) -> Tuple<T>{
Tuple{
param,
names
}
}
}
pub struct TupleBuilder<T>{
group: Tuple<T>,
builder: GroupHBuilder,
}
macro_rules! impl_group {
($($p: ident),*) => {
impl<$($p),*> $crate::ControlBuilder for $crate::group_h::TupleBuilder<($($p),*)>
where $($p: $crate::IntoStyled,)*
$(<$p as $crate::IntoStyled>::Property: ControlDefaultProperty),*
{
type Control = $crate::GroupH;
fn shape(&mut self) -> &mut ControlShape {
self.builder.shape()
}
fn create(self) -> $crate::GroupH {
let mut group = self.builder
.v_margin(0.)
.h_margin(0.)
.hide_label()
.create();
#[allow(non_snake_case)]
let ($($p),*) = self.group.param;
let mut i = 0;
$(
group.add(self.group.names[i], $p);
#[allow(unused_assignments)]
{
i += 1;
}
)*
group
}
}
impl<$($p),*> $crate::ControlDefaultProperty for $crate::group_h::Tuple<($($p),*)>
where $($p: $crate::IntoStyled,)*
$(<$p as $crate::IntoStyled>::Property: ControlDefaultProperty),*
{
type Builder = $crate::group_h::TupleBuilder<($($p),*)>;
}
impl<$($p),*> $crate::BuilderFromProperty<$crate::group_h::Tuple<($($p),*)>> for $crate::group_h::TupleBuilder<($($p),*)>
where $($p: $crate::IntoStyled,)*
$(<$p as $crate::IntoStyled>::Property: ControlDefaultProperty),*
{
fn from_parameter<S>(group: $crate::group_h::Tuple<($($p),*)>, name: &str, events: S) -> $crate::group_h::TupleBuilder<($($p),*)>
where S: StreamT<'static, window::Event>
{
$crate::group_h::TupleBuilder{
builder: $crate::GroupHBuilder::new(name, Property::new(origin()), events),
group,
}
}
}
};
}
impl_group!(A, B);
impl_group!(A, B, C);
impl_group!(A, B, C, D);
impl_group!(A, B, C, D, E);
impl_group!(A, B, C, D, E, F);
impl_group!(A, B, C, D, E, F, G);
impl_group!(A, B, C, D, E, F, G, H);
impl_group!(A, B, C, D, E, F, G, H, I);
impl_group!(A, B, C, D, E, F, G, H, I, J);
impl_group!(A, B, C, D, E, F, G, H, I, J, K);
impl_group!(A, B, C, D, E, F, G, H, I, J, K, L);
impl_group!(A, B, C, D, E, F, G, H, I, J, K, L, M);
impl_group!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
impl_group!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
impl_group!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
#[macro_export]
macro_rules! group_h {
($p1: expr, $($p: expr),*) => {
$crate::group_h::Tuple::new(($p1, $($p),*), &[stringify!($p1), $(stringify!($p)),*])
};
}