use rin::graphics::*;
use rin::color::*;
use rin::window;
use rin::events::{StreamRc, StreamT, Property};
use rin::math::{Rect, Pnt2};
use mopa;
use control_shape::ControlShape;
use std::rc::Rc;
pub trait ControlGeometry{
fn flexible() -> bool where Self: Sized;
fn geometry(&self, container: Option<&Rect<f32>>) -> Option<Vec<Vertex2DColor>>;
fn text_geometry(&self, container: Option<&Rect<f32>>) -> Option<Vec<Vertex2DTex>>;
fn texture_geometry(&self, container: Option<&Rect<f32>>) -> Option<Vec<Vertex2DTex>>;
fn font(&self) -> Option<&Ttf>;
fn color(&self) -> &Rgb<f32>;
fn position(&self) -> &Property<'static, Pnt2>;
fn width(&self) -> &Property<'static, f32>;
fn height(&self) -> &Property<'static, f32>;
fn rect(&self) -> Rect<f32>{
Rect{
pos: self.position().to_value(),
width: self.width().to_value(),
height: self.height().to_value(),
}
}
}
pub trait ControlEvents{
fn non_attended(&self) -> StreamRc<'static, window::Event>;
}
pub trait Control: ControlGeometry + ControlEvents + mopa::Any{
fn name(&self) -> &str;
}
pub trait ControlBuilt<P: IntoControlBuilder<Self::Builder>> : Control where Self: Sized{
type Builder: ControlBuilder<Control = Self>;
}
pub trait ControlBuilder{
type Control: Control;
fn shape(&mut self) -> &mut ControlShape;
fn create(self) -> Self::Control;
fn position(mut self, pos: Pnt2) -> Self where Self: Sized {
self.shape().set_position(pos);
self
}
fn position_property(mut self, pos: Property<'static, Pnt2>) -> Self where Self: Sized {
self.shape().set_position_property(pos);
self
}
fn position_property_opt(mut self, pos: Option<Property<'static, Pnt2>>) -> Self where Self: Sized {
if let Some(pos) = pos {
self.shape().set_position_property(pos);
}
self
}
fn width(mut self, width: f32) -> Self where Self: Sized {
self.shape().set_width(width);
self
}
fn width_opt(mut self, width: Option<f32>) -> Self where Self: Sized {
if let Some(width) = width {
self.shape().set_width(width);
}
self
}
fn width_property(mut self, width: Property<'static, f32>) -> Self where Self: Sized {
self.shape().set_width_property(width);
self
}
fn width_property_opt(mut self, width: Option<Property<'static, f32>>) -> Self where Self: Sized {
if let Some(width) = width {
self.shape().set_width_property(width);
}
self
}
fn height(mut self, height: f32) -> Self where Self: Sized {
self.shape().set_height(height);
self
}
fn height_opt(mut self, height: Option<f32>) -> Self where Self: Sized {
if let Some(height) = height {
self.shape().set_width(height);
}
self
}
fn height_property(mut self, height: Property<'static, f32>) -> Self where Self: Sized {
self.shape().set_height_property(height);
self
}
fn height_property_opt(mut self, height: Option<Property<'static, f32>>) -> Self where Self: Sized {
if let Some(height) = height {
self.shape().set_height_property(height);
}
self
}
fn inner_margin(mut self, margin: f32) -> Self where Self: Sized {
self.shape().set_inner_margin(margin);
self
}
fn v_margin(mut self, margin: f32) -> Self where Self: Sized {
self.shape().set_v_margin(margin);
self
}
fn v_margin_opt(mut self, margin: Option<f32>) -> Self where Self: Sized {
if let Some(margin) = margin{
self.shape().set_v_margin(margin);
}
self
}
fn h_margin(mut self, margin: f32) -> Self where Self: Sized {
self.shape().set_h_margin(margin);
self
}
fn h_margin_opt(mut self, margin: Option<f32>) -> Self where Self: Sized {
if let Some(margin) = margin{
self.shape().set_h_margin(margin);
}
self
}
fn font(mut self, font: Rc<Ttf>) -> Self where Self: Sized {
self.shape().set_font(font);
self
}
fn color<C: ToRgb>(mut self, color: C) -> Self where Self: Sized {
self.shape().set_color(color);
self
}
fn color_opt(mut self, color: Option<Rgb<f32>>) -> Self where Self: Sized {
if let Some(color) = color {
self.shape().set_color(color);
}
self
}
fn hide_label(mut self) -> Self where Self: Sized {
self.shape().hide_label();
self
}
fn hide_label_opt(mut self, hide: Option<bool>) -> Self where Self: Sized {
if let Some(hide) = hide {
if hide {
self.shape().hide_label();
}else{
self.shape().show_label();
}
}
self
}
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>,
}
let des: Des = serde_json::from_str(style).unwrap();
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)
}
}
pub trait BuilderFromProperty<P>: ControlBuilder{
fn from_parameter<S: StreamT<'static, window::Event>>(parameter: P, name: &str, events: S) -> Self;
}
pub trait IntoControlBuilder<B: ControlBuilder>{
fn into_builder<S: StreamT<'static, window::Event>>(self, name: &str, events: S) -> B;
}
impl<B:BuilderFromProperty<P>,P> IntoControlBuilder<B> for P{
fn into_builder<S: StreamT<'static, window::Event>>(self, name: &str, events: S) -> B{
B::from_parameter(self, name, events)
}
}
pub trait ControlDefaultProperty where Self: Sized{
type Builder: ControlBuilder + BuilderFromProperty<Self>;
}
mopafy!(Control);
#[cfg(any(feature = "gl", feature = "gles", feature="webgl"))]
mod gl {
use rin::gl::{self, Renderer2d};
use rin::graphics::*;
use utils;
use rin::gl::RenderSurface;
use rin::math::{convert, Rect};
impl gl::Render3d for super::ControlGeometry{
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);
}
}
}
}
use std::marker;
pub struct As<C>(marker::PhantomData<C>);
pub struct AsControl<C, P>{
property: P,
marker: marker::PhantomData<C>
}
impl<C> As<C>{
pub fn new<P>(property: P) -> AsControl<C, P>{
AsControl{
property,
marker: marker::PhantomData,
}
}
}
impl<C: ControlBuilt<P>, P> ControlDefaultProperty for AsControl<C, P>
where <C as ControlBuilt<P>>::Builder: BuilderFromProperty<P>
{
type Builder = C::Builder;
}
impl<B: ControlBuilder, P> BuilderFromProperty<AsControl<B::Control, P>> for B
where B: BuilderFromProperty<P>{
fn from_parameter<S: StreamT<'static, window::Event>>(parameter: AsControl<B::Control,P>, name: &str, events: S) -> Self{
B::from_parameter(parameter.property, name, events)
}
}
#[macro_export]
macro_rules! as_control {
($control: ty, $property: expr) => {
$crate::As::<$control>::new($property)
};
}
pub struct Styled<P>{
pub(crate) parameter: P,
pub(crate) style: String
}
pub fn styled<P>(parameter: P, style: &str) -> Styled<P>{
Styled{
parameter,
style: style.to_owned()
}
}
pub trait IntoStyled{
type Property;
fn into_styled(self) -> Styled<Self::Property>;
}
impl<P> IntoStyled for Styled<P>{
type Property = P;
fn into_styled(self) -> Styled<P>{
self
}
}
impl<P: ControlDefaultProperty> IntoStyled for P{
type Property = P;
fn into_styled(self) -> Styled<P>{
Styled{
parameter: self,
style: "{}".to_owned(),
}
}
}