use rin::graphics::*;
use rin::events::*;
use rin::math::*;
use rin::window;
use rin::window::events::*;
use std::rc::Rc;
use traits::*;
use rin::color::*;
use rin::color::consts::*;
use control_shape::ControlShape;
use utils;
pub struct Toggle{
label: String,
_parameter: Property<'static, bool>,
font: Rc<Ttf>,
value: StreamRc<'static, bool>,
rendered: Sender<'static, ()>,
color: Rgb<f32>,
non_attended: StreamRc<'static, window::Event>,
geometry: Option<Property<'static, Vec<Vertex2DColor>>>,
text_geometry: Property<'static, Vec<Vertex2DTex>>,
texture_geometry: Option<Property<'static, Vec<Vertex2DTex>>>,
height: Property<'static, f32>,
width: Property<'static, f32>,
position: Property<'static, Pnt2>,
}
pub struct ToggleBuilder{
label: String,
parameter: Property<'static, bool>,
events: StreamRc<'static, window::Event>,
shape: ControlShape,
texture_enabled: Option<utils::TextureHandle>,
texture_hovered: Option<utils::TextureHandle>,
texture_pressed: Option<utils::TextureHandle>,
texture_hovered_pressed: Option<utils::TextureHandle>,
}
fn geometry(rect: Rect<f32>, toggle_color: &Rgba<f32>) -> Vec<Vertex2DColor>{
let x = rect.pos.x;
let y = rect.pos.y;
let w = rect.width;
let h = rect.height;
vec![
vertex2dcolor(vec2(x,y), toggle_color),
vertex2dcolor(vec2(x+w,y), toggle_color),
vertex2dcolor(vec2(x+w,y+h), toggle_color),
vertex2dcolor(vec2(x+w,y+h), toggle_color),
vertex2dcolor(vec2(x,y+h), toggle_color),
vertex2dcolor(vec2(x,y), toggle_color),
]
}
fn texture_geometry(rect: Rect<f32>, tex_handle: &utils::TextureHandle) -> Vec<Vertex2DTex>{
let x = rect.pos.x;
let y = rect.pos.y;
let w = rect.width;
let h = rect.height;
vec![
vertex2dtex(vec2(x,y), tex_handle.transform_uv(&vec2(0., 0.))),
vertex2dtex(vec2(x+w,y), tex_handle.transform_uv(&vec2(1., 0.))),
vertex2dtex(vec2(x+w,y+h), tex_handle.transform_uv(&vec2(1., 1.))),
vertex2dtex(vec2(x+w,y+h), tex_handle.transform_uv(&vec2(1., 1.))),
vertex2dtex(vec2(x,y+h), tex_handle.transform_uv(&vec2(0., 1.))),
vertex2dtex(vec2(x,y), tex_handle.transform_uv(&vec2(0., 0.))),
]
}
impl ToggleBuilder{
pub fn new<S: StreamT<'static, window::Event>>(name: &str, parameter: Property<'static, bool>, events: S) -> ToggleBuilder{
let pos = Property::new(origin());
let size = Property::new(15.);
let margin = 0.;
ToggleBuilder{
label: name.to_string(),
parameter: parameter,
events: events.rc(),
shape: ControlShape::new(pos, size.clone(), size, margin, margin, WHITE),
texture_enabled: None,
texture_hovered: None,
texture_pressed: None,
texture_hovered_pressed: None,
}
}
pub fn image_enabled(mut self, img: utils::TextureHandle) -> ToggleBuilder{
self.texture_enabled = Some(img);
self
}
pub fn image_hovered(mut self, img: utils::TextureHandle) -> ToggleBuilder{
self.texture_hovered = Some(img);
self
}
pub fn image_pressed(mut self, img: utils::TextureHandle) -> ToggleBuilder{
self.texture_pressed = Some(img);
self
}
pub fn image_hovered_pressed(mut self, img: utils::TextureHandle) -> ToggleBuilder{
self.texture_hovered_pressed = Some(img);
self
}
pub fn create(mut self) -> Toggle{
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 events = self.events.clone();
let side = self.shape.height();
let position = self.shape.position();
let rect = position.clone()
.zip(side.clone())
.map(|(pos, side)| Rect{pos, width: side, height: side});
let filtered_update = self.events.clone()
.filter_by(rendered.clone())
.update()
.rc();
let text_geometry = if self.shape.label_visible() {
let text = format!("{}", self.label);
let font = font.clone();
let rect = rect.clone();
let line_height = font.line_height();
let descender = font.descender();
let em_height = font.bounding_box("M", 0., 0., CoordinateOrigin::TopLeft).height;
filtered_update.clone().map(move |_| *rect).dedup()
.map(move |rect| font
.mesh(&text, rect.pos.x + 25., rect.pos.y + (rect.height + em_height) * 0.5, CoordinateOrigin::TopLeft)
.into())
.to_property(vec![])
}else{
Property::new(vec![])
};
let label_w = if self.shape.label_visible() {
font.bounding_box(&self.label, 0., 0., CoordinateOrigin::TopLeft).width
}else{
0.
};
let h_margin = self.shape.h_margin();
let full_rect = rect.clone().map(move |mut rect| {
rect.width += h_margin + label_w;
rect
});
let over = events.clone().mouse().moved()
.to_property(pnt2(0., 0.))
.zip(full_rect.clone().map(|rect| convert(rect)))
.zip(rendered.clone())
.flatten()
.map(move |(pos, rect, rendered)| rendered && pos.inside(&rect));
let full_width = full_rect.map(|r| r.width);
let parameter = self.parameter.clone();
let value = events.mouse().pressed(MouseButton::Left)
.filter_by(over.clone())
.map(move |_| !*parameter)
.connect_to_property(&mut self.parameter);
let over_copy = over.clone();
let non_attended = self.events.clone()
.filter(move |e| {
if let window::Event::MousePressed{..} = e {
!*over_copy
}else{
true
}
});
let geometry = if self.texture_enabled.is_none() {
let color = self.shape.color();
let parameter = self.parameter.clone();
let rect = rect.clone();
let over = over.clone();
Some(filtered_update.clone()
.map(move |_| (*parameter, *over, *rect))
.dedup()
.map(move |(value, over, rect)| {
let alpha = if value && over {
0.9
} else if value || over {
0.7
} else {
0.1
};
(alpha, rect)
})
.map(move |(alpha, rect)| {
geometry(rect, &rgba!(color, alpha))
}).to_property(vec![]))
}else{
None
};
let texture_geometry = if let Some(texture_enabled) = self.texture_enabled {
let texture_hovered = self.texture_hovered.or(self.texture_enabled).unwrap();
let texture_pressed = self.texture_pressed.unwrap_or(texture_hovered);
let texture_hovered_pressed = self.texture_hovered_pressed.unwrap_or(texture_pressed);
let rect = rect.clone();
let parameter = self.parameter.clone();
Some(filtered_update.clone()
.map(move |_| {
let texture = if *parameter && *over {
texture_hovered_pressed
} else if *parameter {
texture_pressed
}else if *over {
texture_hovered
} else {
texture_enabled
};
(texture, *rect)
}).dedup()
.map(|(texture, rect)| texture_geometry(rect, &texture))
.to_property(vec![]))
}else{
None
};
Toggle{
label: self.label,
_parameter: self.parameter.clone(),
font: font,
value: value.rc(),
color: self.shape.color(),
rendered: rendered_sender,
non_attended: non_attended.rc(),
geometry: geometry,
text_geometry: text_geometry,
texture_geometry,
height: side,
width: full_width,
position,
}
}
}
impl ControlBuilder for ToggleBuilder{
type Control = Toggle;
fn shape(&mut self) -> &mut ControlShape {
&mut self.shape
}
fn width(self, _width: f32) -> ToggleBuilder{
self
}
fn create(self) -> Toggle{
self.create()
}
fn from_json_style(self, style: &str) -> Self where Self: Sized {
#[derive(Deserialize, Default)]
struct Des{
width: Option<f32>,
height: Option<f32>,
v_margin: Option<f32>,
h_margin: Option<f32>,
color: Option<Rgb<f32>>,
hide_label: Option<bool>,
image_enabled: Option<String>,
image_hovered: Option<String>,
image_pressed: Option<String>,
image_hovered_pressed: Option<String>,
image_enabled_handle: Option<utils::TextureHandle>,
image_hovered_handle: Option<utils::TextureHandle>,
image_pressed_handle: Option<utils::TextureHandle>,
image_hovered_pressed_handle: Option<utils::TextureHandle>,
}
let des: Des = serde_json::from_str(style).unwrap();
let builder = self.width_opt(des.width)
.height_opt(des.height)
.v_margin_opt(des.v_margin)
.h_margin_opt(des.h_margin)
.color_opt(des.color)
.hide_label_opt(des.hide_label);
let builder = if let Some(img) = des.image_enabled {
let img = utils::load_texture(img).unwrap();
builder.image_enabled(img)
}else if let Some(img) = des.image_enabled_handle{
builder.image_enabled(img)
}else{
builder
};
let builder = if let Some(img) = des.image_pressed {
let img = utils::load_texture(img).unwrap();
builder.image_pressed(img)
}else if let Some(img) = des.image_pressed_handle{
builder.image_pressed(img)
}else{
builder
};
let builder = if let Some(img) = des.image_hovered {
let img = utils::load_texture(img).unwrap();
builder.image_hovered(img)
}else if let Some(img) = des.image_hovered_handle{
builder.image_hovered(img)
}else{
builder
};
if let Some(img) = des.image_hovered_pressed {
let img = utils::load_texture(img).unwrap();
builder.image_hovered_pressed(img)
}else if let Some(img) = des.image_hovered_pressed_handle{
builder.image_hovered_pressed(img)
}else{
builder
}
}
}
impl ControlBuilt<Property<'static, bool>> for Toggle{
type Builder = ToggleBuilder;
}
impl ControlDefaultProperty for Property<'static, bool>{
type Builder = ToggleBuilder;
}
impl BuilderFromProperty<Property<'static, bool>> for ToggleBuilder{
fn from_parameter<S: StreamT<'static, window::Event>>(parameter: Property<'static, bool>, name: &str, events: S) -> ToggleBuilder{
ToggleBuilder::new(name, parameter, events)
}
}
impl Toggle{
pub fn stream(&self) -> StreamRc<'static, bool>{
self.value.clone()
}
}
impl ControlGeometry for Toggle{
fn flexible() -> bool{
false
}
fn geometry(&self, _container: Option<&Rect<f32>>) -> Option<Vec<Vertex2DColor>>{
self.rendered.send(());
self.geometry.as_ref().map(|g| g.to_value())
}
fn text_geometry(&self, _container: Option<&Rect<f32>>) -> Option<Vec<Vertex2DTex>>{
Some((*self.text_geometry).clone())
}
fn texture_geometry(&self, _container: Option<&Rect<f32>>) -> Option<Vec<Vertex2DTex>>{
self.texture_geometry.as_ref().map(|t| t.to_value())
}
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 Toggle{
fn non_attended(&self) -> StreamRc<'static, window::Event>{
self.non_attended.clone()
}
}
impl Control for Toggle{
fn name(&self) -> &str{
&self.label
}
}
#[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, InsideRect};
impl gl::Render3d for super::Toggle{
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);
if self.rect().inside(&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);
}
}
}
}
}