use rin::graphics::*;
use rin::events::*;
use rin::math::*;
use rin::window;
use std::rc::Rc;
use traits::*;
use rin::color::*;
use rin::color::consts::*;
use control_shape::ControlShape;
use utils;
use rin::window::Events;
use std::string::ToString;
use std::fmt::Debug;
pub struct Label {
name: String,
label: Property<'static, String>,
font: Rc<Ttf>,
color: Rgb<f32>,
non_attended: StreamRc<'static, window::Event>,
text_geometry: Property<'static, Vec<Vertex2DTex>>,
width: Property<'static, f32>,
height: Property<'static, f32>,
position: Property<'static, Pnt2>,
rendered: Sender<'static, ()>,
}
pub struct LabelBuilder{
name: String,
label: Property<'static, String>,
events: StreamRc<'static, window::Event>,
shape: ControlShape,
}
pub struct LabelBuilderFromProperty{
name: String,
label: Property<'static, String>,
events: StreamRc<'static, window::Event>,
shape: ControlShape,
}
impl LabelBuilder{
pub fn new<S: StreamT<'static, window::Event>, T: ToString>(name: &str, parameter: T, events: S) -> LabelBuilder{
let pos = Property::new(origin());
let height = Property::new(15.);
let width = Property::new(200.);
let margin = 0.;
LabelBuilder{
name: name.to_owned(),
label: Property::new(parameter.to_string()),
events: events.rc(),
shape: ControlShape::new(pos, width, height, margin, margin, WHITE),
}
}
pub fn create(self) -> Label{
let font = self.shape.font().unwrap_or_else(|| ::utils::default_font());
let (rendered_sender, rendered_stream) = utils::rendered_stream(self.events.clone().unique());
let rendered = rendered_stream.to_property(false);
let line_height = font.line_height();
let descender = font.descender();
let line_gap = font.line_gap();
let height = Property::new(line_height);
let width = self.shape.width();
let position = self.shape.position();
let label = self.label;
let filtered_update = self.events.clone()
.filter_by(rendered)
.update()
.rc();
let text_geometry = {
let font = font.clone();
let position = position.clone();
let label = label.clone();
filtered_update.clone()
.map(move |_| (*position, (*label).clone()))
.dedup()
.map(move |(pos, text)| font
.mesh(&text, pos.x, pos.y + line_height + descender, CoordinateOrigin::TopLeft)
.into())
.to_property(vec![])
};
let height = {
let label = label.clone();
let spacing = line_gap - descender;
filtered_update
.map(move |_| (*label).clone())
.dedup()
.map(move |label| {
let breaklines = label.chars().filter(|c| *c == '\n').count();
line_height * (breaklines + 1) as f32 + spacing
})
.dedup()
.to_property(*height)
};
Label{
name: self.name,
label,
font,
color: self.shape.color(),
non_attended: self.events,
text_geometry,
width,
height,
position,
rendered: rendered_sender,
}
}
}
impl LabelBuilderFromProperty{
pub fn new<S: StreamT<'static, window::Event>, T: ToString + Clone + Debug>(name: &str, parameter: Property<'static, T>, events: S) -> LabelBuilderFromProperty{
let pos = Property::new(origin());
let size = Property::new(15.);
let margin = 0.;
LabelBuilderFromProperty{
name: name.to_owned(),
label: parameter.map(|t| t.to_string()),
events: events.rc(),
shape: ControlShape::new(pos, size.clone(), size, margin, margin, WHITE),
}
}
pub fn create(self) -> Label{
LabelBuilder{
name: self.name,
label: self.label,
events: self.events,
shape: self.shape
}.create()
}
}
impl Label{
pub fn set_text(&mut self, text: String){
self.label.set(text)
}
pub fn text(&self) -> &str{
self.label.value()
}
}
impl ControlBuilder for LabelBuilder{
type Control = Label;
fn shape(&mut self) -> &mut ControlShape{
&mut self.shape
}
fn create(self) -> Label{
self.create()
}
}
impl ControlBuilder for LabelBuilderFromProperty{
type Control = Label;
fn shape(&mut self) -> &mut ControlShape{
&mut self.shape
}
fn create(self) -> Label{
self.create()
}
}
impl ControlBuilt<String> for Label{
type Builder = LabelBuilder;
}
impl<T: ToString + Clone + Debug> ControlBuilt<Property<'static, T>> for Label{
type Builder = LabelBuilderFromProperty;
}
impl ControlDefaultProperty for String{
type Builder = LabelBuilder;
}
impl<T: ToString> BuilderFromProperty<T> for LabelBuilder{
fn from_parameter<S: StreamT<'static, window::Event>>(parameter: T, name: &str, events: S) -> LabelBuilder{
LabelBuilder::new(name, parameter, events)
}
}
impl<T: ToString + Clone + Debug> BuilderFromProperty<Property<'static, T>> for LabelBuilderFromProperty{
fn from_parameter<S: StreamT<'static, window::Event>>(parameter: Property<'static, T>, name: &str, events: S) -> LabelBuilderFromProperty{
LabelBuilderFromProperty::new(name, parameter, events)
}
}
impl ControlGeometry for Label{
fn flexible() -> bool{
true
}
fn geometry(&self, _container: Option<&Rect<f32>>) -> Option<Vec<Vertex2DColor>>{
None
}
fn text_geometry(&self, _container: Option<&Rect<f32>>) -> Option<Vec<Vertex2DTex>>{
self.rendered.send(());
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 ControlEvents for Label{
fn non_attended(&self) -> StreamRc<'static, window::Event>{
self.non_attended.clone()
}
}
impl Control for Label{
fn name(&self) -> &str{
&self.name
}
}
#[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::Label{
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(|m| mesh(m, 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);
}
}
}
}