use position::{self, Align};
use text;
use widget;
use {Borderable, Color, Colorable, FontSize, Labelable, Positionable, Scalar, Widget};
#[derive(Clone, WidgetCommon_)]
pub struct Toggle<'a> {
#[conrod(common_builder)]
common: widget::CommonBuilder,
value: bool,
maybe_label: Option<&'a str>,
style: Style,
pub enabled: bool,
}
#[derive(Copy, Clone, Debug, Default, PartialEq, WidgetStyle_)]
pub struct Style {
#[conrod(default = "theme.shape_color")]
pub color: Option<Color>,
#[conrod(default = "theme.border_width")]
pub border: Option<Scalar>,
#[conrod(default = "theme.border_color")]
pub border_color: Option<Color>,
#[conrod(default = "theme.label_color")]
pub label_color: Option<Color>,
#[conrod(default = "theme.font_size_medium")]
pub label_font_size: Option<FontSize>,
#[conrod(default = "theme.font_id")]
pub label_font_id: Option<Option<text::font::Id>>,
#[conrod(default = "position::Relative::Align(Align::Middle)")]
pub label_x: Option<position::Relative>,
#[conrod(default = "position::Relative::Align(Align::Middle)")]
pub label_y: Option<position::Relative>,
}
widget_ids! {
struct Ids {
rectangle,
label,
}
}
pub struct State {
ids: Ids,
}
#[derive(Clone, Debug)]
#[allow(missing_copy_implementations)]
pub struct TimesClicked {
state: bool,
count: u16,
}
impl Iterator for TimesClicked {
type Item = bool;
fn next(&mut self) -> Option<Self::Item> {
if self.count > 0 {
self.count -= 1;
self.state = !self.state;
Some(self.state)
} else {
None
}
}
}
impl<'a> Toggle<'a> {
pub fn new(value: bool) -> Toggle<'a> {
Toggle {
common: widget::CommonBuilder::default(),
style: Style::default(),
maybe_label: None,
value: value,
enabled: true,
}
}
pub fn label_font_id(mut self, font_id: text::font::Id) -> Self {
self.style.label_font_id = Some(Some(font_id));
self
}
pub fn label_x(mut self, x: position::Relative) -> Self {
self.style.label_x = Some(x);
self
}
pub fn label_y(mut self, y: position::Relative) -> Self {
self.style.label_y = Some(y);
self
}
builder_methods! {
pub enabled { enabled = bool }
}
}
impl<'a> Widget for Toggle<'a> {
type State = State;
type Style = Style;
type Event = TimesClicked;
fn init_state(&self, id_gen: widget::id::Generator) -> Self::State {
State {
ids: Ids::new(id_gen),
}
}
fn style(&self) -> Self::Style {
self.style.clone()
}
fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
let widget::UpdateArgs {
id,
state,
style,
rect,
ui,
..
} = args;
let Toggle {
value,
enabled,
maybe_label,
..
} = self;
let times_clicked = TimesClicked {
state: value,
count: if enabled {
let input = ui.widget_input(id);
(input.clicks().left().count() + input.taps().count()) as u16
} else {
0
},
};
let dim = rect.dim();
let border = style.border(ui.theme());
let color = {
let color = style.color(ui.theme());
let new_value = times_clicked.clone().last().unwrap_or(value);
let color = if new_value {
color
} else {
color.with_luminance(0.1)
};
match ui.widget_input(id).mouse() {
Some(mouse) => {
if mouse.buttons.left().is_down() {
color.clicked()
} else {
color.highlighted()
}
}
None => color,
}
};
let border_color = style.border_color(ui.theme());
widget::BorderedRectangle::new(dim)
.middle_of(id)
.graphics_for(id)
.color(color)
.border(border)
.border_color(border_color)
.set(state.ids.rectangle, ui);
if let Some(label) = maybe_label {
let color = style.label_color(ui.theme());
let font_size = style.label_font_size(ui.theme());
let font_id = style.label_font_id(&ui.theme).or(ui.fonts.ids().next());
let x = style.label_x(&ui.theme);
let y = style.label_y(&ui.theme);
widget::Text::new(label)
.and_then(font_id, widget::Text::font_id)
.x_position_relative_to(id, x)
.y_position_relative_to(id, y)
.graphics_for(id)
.color(color)
.font_size(font_size)
.set(state.ids.label, ui);
}
times_clicked
}
}
impl<'a> Colorable for Toggle<'a> {
builder_method!(color { style.color = Some(Color) });
}
impl<'a> Borderable for Toggle<'a> {
builder_methods! {
border { style.border = Some(Scalar) }
border_color { style.border_color = Some(Color) }
}
}
impl<'a> Labelable<'a> for Toggle<'a> {
builder_methods! {
label { maybe_label = Some(&'a str) }
label_color { style.label_color = Some(Color) }
label_font_size { style.label_font_size = Some(FontSize) }
}
}