use rin::graphics::*;
use rin::events::*;
use rin::math::*;
use num_traits::{FromPrimitive,ToPrimitive};
use std::ops::Sub;
use rin::window::{self,Events};
use std::fmt::Display;
use std::rc::Rc;
use traits::*;
use rin::color::*;
use rin::color::consts::*;
use std::fmt::Debug;
use rin::events::RangedParameter;
use control_shape::ControlShape;
use utils;
pub struct ReadnOnlyRange<T: Clone + Debug + 'static>{
label: String,
_parameter: RangedParameter<'static, T>,
font: Rc<Ttf>,
color: Rgb<f32>,
geometry: Property<'static, Vec<Vertex2DColor>>,
text_geometry: Property<'static, Vec<Vertex2DTex>>,
events: StreamRc<'static, window::Event>,
width: Property<'static, f32>,
height: Property<'static, f32>,
position: Property<'static, Pnt2>,
rendered: Sender<'static, ()>,
}
pub struct ReadnOnlyRangeBuilder<T: Clone + Debug + 'static>{
label: String,
parameter: RangedParameter<'static, T>,
events: StreamRc<'static, window::Event>,
shape: ControlShape,
}
fn geometry(rect: Rect<f32>, pct: f32, color: Rgb<f32>, alpha: f32) -> Vec<Vertex2DColor>{
let x = rect.pos.x;
let y = rect.pos.y;
let w = rect.width ;
let h = rect.height;
let w_value = clamp(pct as f32, 0., 1.) * w;
let border_color = &rgba!(color, 0.1);
let slider_color = &rgba!(color, alpha);
vec![
vertex2dcolor(vec2(x,y), border_color),
vertex2dcolor(vec2(x+w,y), border_color),
vertex2dcolor(vec2(x+w,y+h), border_color),
vertex2dcolor(vec2(x+w,y+h), border_color),
vertex2dcolor(vec2(x,y+h), border_color),
vertex2dcolor(vec2(x,y), border_color),
vertex2dcolor(vec2(x,y), slider_color),
vertex2dcolor(vec2(x+w_value,y), slider_color),
vertex2dcolor(vec2(x+w_value,y+h), slider_color),
vertex2dcolor(vec2(x+w_value,y+h), slider_color),
vertex2dcolor(vec2(x,y+h), slider_color),
vertex2dcolor(vec2(x,y), slider_color),
]
}
impl<T: FromPrimitive + Sub<Output=T> + Clone + ToPrimitive + Display + PartialEq + Debug + 'static> ReadnOnlyRangeBuilder<T>{
pub fn new<S: StreamT<'static, window::Event>>(name: &str, parameter: RangedParameter<'static, T>, events: S) -> ReadnOnlyRangeBuilder<T>{
let pos = Property::new(origin());
let width = Property::new(200.);
let height = Property::new(15.);
let margin = 0.;
ReadnOnlyRangeBuilder{
label: name.to_string(),
parameter: parameter,
events: events.rc(),
shape: ControlShape::new(pos, width, height, margin, margin, WHITE),
}
}
pub fn create(self) -> ReadnOnlyRange<T>{
let (rendered_sender, rendered_stream) = utils::rendered_stream(self.events.clone().unique());
let rendered = rendered_stream.to_property(false);
let font = self.shape.font().unwrap_or_else(|| ::utils::default_font());
let color = self.shape.color();
let width = self.shape.width();
let height = self.shape.height();
let position = self.shape.position();
let rect = position.clone()
.zip(width.clone())
.zip(height.clone())
.flatten()
.map(|(pos, width, height)| Rect{pos, width, height});
let parameter = self.parameter.clone();
let filtered_update = self.events.clone()
.filter_by(rendered)
.update()
.rc();
let geometry = {
let rect = rect.clone();
filtered_update.clone()
.filter_map(move |_| parameter.pct().map(|pct| (pct, *rect)))
.dedup()
.map(move |(pct, rect)| {
let alpha = 0.5;
(pct as f32, alpha, rect)
})
.map(move |(pct, alpha, rect)| geometry(rect, pct, color, alpha))
.to_property(vec![])
};
let font_copy = font.clone();
let label = self.label.to_string();
let rect = rect.clone();
let parameter = self.parameter.clone();
let text_geometry = if self.shape.label_visible(){
filtered_update
.filter_map(move |_| parameter.to_value().map(|v| (v, *rect)))
.dedup()
.map(move |(value, rect)| {
let text = format!("{}: {}", label, value);
font_copy.mesh(&text, rect.pos.x, rect.pos.y + rect.height + 15., CoordinateOrigin::TopLeft).into()
})
.to_property(vec![])
}else{
Property::default()
};
let height = if self.shape.label_visible(){
let line_height = font.line_height();
height.map(move |h| h + line_height)
}else{
height
};
ReadnOnlyRange{
label: self.label.to_string(),
_parameter: self.parameter.clone(),
font: font,
color,
geometry,
text_geometry,
events: self.events.clone(),
width,
height,
position,
rendered: rendered_sender
}
}
}
impl<T: Clone + Debug + 'static> ControlGeometry for ReadnOnlyRange<T>{
fn flexible() -> bool{
true
}
fn geometry(&self, _container: Option<&Rect<f32>>) -> Option<Vec<Vertex2DColor>>{
self.rendered.send(());
Some(self.geometry.to_value())
}
fn text_geometry(&self, _container: Option<&Rect<f32>>) -> Option<Vec<Vertex2DTex>>{
Some(self.text_geometry.to_value())
}
fn texture_geometry(&self, _container: Option<&Rect<f32>>) -> Option<Vec<Vertex2DTex>>{
None
}
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<T: Clone + Debug + 'static> ControlEvents for ReadnOnlyRange<T>{
fn non_attended(&self) -> StreamRc<'static, window::Event>{
self.events.clone()
}
}
use std::any::Any;
impl<T: Any + Clone + Debug + 'static> Control for ReadnOnlyRange<T>{
fn name(&self) -> &str{
&self.label
}
}
impl<T: Debug> ControlBuilder for ReadnOnlyRangeBuilder<T>
where T: FromPrimitive + Sub<Output=T> + Clone + ToPrimitive + Display + PartialEq + Debug + 'static{
type Control = ReadnOnlyRange<T>;
fn shape(&mut self) -> &mut ControlShape {
&mut self.shape
}
fn create(self) -> ReadnOnlyRange<T>{
self.create()
}
}
impl<T: Debug> ControlBuilt<RangedParameter<'static, T>> for ReadnOnlyRange<T>
where T: FromPrimitive + Sub<Output=T> + Clone + ToPrimitive + Display + PartialEq + Debug + 'static{
type Builder = ReadnOnlyRangeBuilder<T>;
}
impl<T: Debug> ControlDefaultProperty for RangedParameter<'static, T>
where T: FromPrimitive + Sub<Output=T> + Clone + ToPrimitive + Display + PartialEq + Debug + 'static{
type Builder = ReadnOnlyRangeBuilder<T>;
}
impl<T: Debug> BuilderFromProperty<RangedParameter<'static, T>> for ReadnOnlyRangeBuilder<T>
where T: FromPrimitive + Sub<Output=T> + Clone + ToPrimitive + Display + PartialEq + Debug + 'static{
fn from_parameter<S: StreamT<'static, window::Event>>(parameter: RangedParameter<'static, T>, name: &str, events: S) -> ReadnOnlyRangeBuilder<T>{
ReadnOnlyRangeBuilder::new(name, parameter, events)
}
}