use traits::*;
use group_v::*;
use utils;
use rin::graphics::*;
use rin::events::*;
use rin::math::*;
use rin::color::*;
use rin::color::consts::*;
use rin::window::{self, Events};
use std::rc::Rc;
use std::ops::{Deref,DerefMut};
use ::ParameterGroup;
use control_shape::ControlShape;
pub struct Panel{
font: Rc<Ttf>,
text_geometry: Property<'static, Vec<Vertex2DTex>>,
geometry: Property<'static, Vec<Vertex2DColor>>,
group: GroupV,
width: Property<'static, f32>,
height: Property<'static, f32>,
position: Property<'static, Pnt2>,
rendered: Sender<'static, ()>,
}
fn geometry(pos: Pnt2, w: f32, height: f32, line_height: f32, margin: f32, color: Rgb<f32>) -> Vec<Vertex2DColor>{
let x = pos.x;
let y = pos.y;
let h = height + margin;
let alpha = 0.7;
let bg_color = &rgba!(rgb!(1.0, 1.0, 1.0) - color, alpha);
let bg_bg_color = &rgba!(color, 0.5);
let line_y = y + line_height * 1.2 + margin;
let line_w = 2.;
let line_alpha = 0.5;
let line_color = &rgba!(color, line_alpha);
vec![
vertex2dcolor(vec2(x,y), bg_bg_color),
vertex2dcolor(vec2(x+w,y), bg_bg_color),
vertex2dcolor(vec2(x+w,y+h), bg_bg_color),
vertex2dcolor(vec2(x+w,y+h), bg_bg_color),
vertex2dcolor(vec2(x,y+h), bg_bg_color),
vertex2dcolor(vec2(x,y), bg_bg_color),
vertex2dcolor(vec2(x,y), bg_color),
vertex2dcolor(vec2(x+w,y), bg_color),
vertex2dcolor(vec2(x+w,y+h), bg_color),
vertex2dcolor(vec2(x+w,y+h), bg_color),
vertex2dcolor(vec2(x,y+h), bg_color),
vertex2dcolor(vec2(x,y), bg_color),
vertex2dcolor(vec2(x,line_y), line_color),
vertex2dcolor(vec2(x+w,line_y), line_color),
vertex2dcolor(vec2(x+w,line_y+line_w), line_color),
vertex2dcolor(vec2(x+w,line_y+line_w), line_color),
vertex2dcolor(vec2(x,line_y+line_w), line_color),
vertex2dcolor(vec2(x,line_y), line_color),
]
}
pub struct PanelBuilder{
label: String,
shape: ControlShape,
events: StreamRc<'static, window::Event>,
}
impl PanelBuilder{
pub fn new<S: StreamT<'static, window::Event>>(name: &str, pos: Property<'static, Pnt2>, events: S) -> PanelBuilder{
let margin = 10.;
let line_height = 10.;
let header_height = Property::new(line_height * 1.2 + margin);
let shape = ControlShape::new(pos, Property::new(200.), header_height, margin, margin, WHITE);
PanelBuilder{
label: name.to_owned(),
shape,
events: events.rc(),
}
}
pub fn create(self) -> Panel{
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 text = self.label.clone();
let v_margin = self.shape.v_margin();
let h_margin = self.shape.v_margin();
let line_height = font.line_height();
let height = if self.shape.label_visible(){
line_height * 1.2 + v_margin * 2.
}else{
0.
};
let width = self.shape.width();
let line_height = font.line_height();
let color = self.shape.color();
let filtered_update = self.events.clone().filter_by(rendered).update().rc();
let position = self.shape.position();
let geometry = if self.shape.label_visible() {
filtered_update.clone().map(move |_| (*position, *width))
.dedup()
.map(move |(pos, width)| geometry(pos, width, height, line_height, v_margin, color))
.to_property(vec![])
}else{
Property::default()
};
let text_geometry = if self.shape.label_visible(){
let font = font.clone();
let position = self.shape.position();
filtered_update.map(move |_| *position).dedup().map(move |pos|{
let text_y = pos.y + line_height * 1.2;
font.mesh(&text, pos.x + h_margin, text_y, CoordinateOrigin::TopLeft).into()
})
.to_property(vec![])
}else{
Property::default()
};
let group_shape = self.shape.contained(Property::new(height), Property::new(0.), Property::new(0.), Property::new(0.));
let group_builder = GroupBuilder::from_control_shape(&self.label, group_shape, self.events);
let group = group_builder.create();
let width = self.shape.width();
let height = group.height().clone().map(move |gh| height + gh + h_margin * 2.);
let position = self.shape.position();
Panel{
font: font,
text_geometry: text_geometry,
geometry: geometry,
group: group,
width,
height,
position,
rendered: rendered_sender,
}
}
}
impl ControlBuilder for PanelBuilder {
type Control = Panel;
fn shape(&mut self) -> &mut ControlShape {
&mut self.shape
}
fn create(self) -> Panel{
self.create()
}
}
pub struct PanelBuilderFromParameterGroup<P: ParameterGroup>{
builder: PanelBuilder,
group: P,
}
impl<P: ParameterGroup> PanelBuilderFromParameterGroup<P>{
pub fn new<S: StreamT<'static, window::Event>>(name: &str, pos: Property<'static, Pnt2>, events: S, group: P) -> PanelBuilderFromParameterGroup<P>{
let builder = PanelBuilder::new(name, pos, events);
PanelBuilderFromParameterGroup{
builder,
group,
}
}
}
impl<P: ParameterGroup> ControlBuilder for PanelBuilderFromParameterGroup<P> {
type Control = Panel;
fn shape(&mut self) -> &mut ControlShape {
self.builder.shape()
}
fn create(self) -> Panel{
let mut panel = self.builder.create();
self.group.add_parameters(&mut panel);
panel
}
}
impl Panel{
pub fn new(name: &str, pos: Pnt2, width: f32, events: Stream<'static,window::Event>) -> Panel{
PanelBuilder::new(name, Property::new(pos), events)
.width(width)
.create()
}
}
impl ControlGeometry for Panel{
fn flexible() -> bool{
true
}
fn geometry(&self, container: Option<&Rect<f32>>) -> Option<Vec<Vertex2DColor>>{
self.rendered.send(());
let mut geometry = self.geometry.to_value();
if let Some(group_geometry) = self.group.geometry(container){
geometry.extend(group_geometry);
}
Some(geometry)
}
fn text_geometry(&self, container: Option<&Rect<f32>>) -> Option<Vec<Vertex2DTex>>{
let mut text_geometry = (*self.text_geometry).clone();
if let Some(group_geometry) = self.group.text_geometry(container){
text_geometry.extend_from_slice(&group_geometry);
}
Some(text_geometry)
}
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.group.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 Panel{
fn non_attended(&self) -> StreamRc<'static, window::Event>{
self.group.non_attended()
}
}
impl Control for Panel{
fn name(&self) -> &str{
self.group.name()
}
}
impl Deref for Panel{
type Target = GroupV;
fn deref(&self) -> &GroupV{
&self.group
}
}
impl DerefMut for Panel{
fn deref_mut(&mut self) -> &mut GroupV{
&mut self.group
}
}
impl<P: ParameterGroup> ControlDefaultProperty for P {
type Builder = PanelBuilderFromParameterGroup<P>;
}
impl<P: ParameterGroup> BuilderFromProperty<P> for PanelBuilderFromParameterGroup<P> {
fn from_parameter<S: StreamT<'static, window::Event>>(parameter: P, name: &str, events: S) -> PanelBuilderFromParameterGroup<P> {
PanelBuilderFromParameterGroup::new(name, Property::new(pnt2!(0.)), events, parameter)
}
}
#[cfg(any(feature = "gl", feature = "gles", feature="webgl"))]
mod gl{
use rin::gl::{self, Renderer2d};
use rin::graphics::*;
use traits::ControlGeometry;
use utils;
use rin::gl::RenderSurface;
use rin::math::{convert, Rect};
impl gl::Render3d for super::Panel{
fn render<R: RenderSurface>(&self, gl: &gl::Renderer<R>){
let viewport = *gl.context().state().viewport();
let viewport: Rect<i32> = viewport.into();
let viewport: Rect<f32> = convert(viewport);
let viewport = Some(&viewport);
if let Some(geometry) = self.geometry(viewport).map(|g| mesh(g, PrimitiveType::Triangles)){
let gl = gl.with_properties(&[
gl::Property::Blend(true),
gl::Property::BlendEquation(gl::FUNC_ADD),
gl::Property::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA),
]);
gl.draw_mesh(&geometry);
}
if let (Some(text_geometry), Some(font)) = (self.text_geometry(viewport), self.font()){
let font_material = utils::gl::font_material(&gl, font, self.color());
let text_geometry = mesh(text_geometry, PrimitiveType::Triangles);
gl.draw_mesh_with_material(&text_geometry, font_material);
}
}
}
}