#[macro_use]
extern crate conrod_derive;
pub use ack::Ack;
pub use yesno::YesNo;
use conrod_core::{
self,
widget_ids,
widget::{self, Widget},
text,
color::{Color, Colorable},
FontSize,
Borderable,
position,
Positionable,
Sizeable,
Labelable,
Scalar,
builder_methods,
builder_method,
};
#[derive(Clone, Debug, WidgetCommon)]
pub struct Prompt<'a, I> {
#[conrod(common_builder)]
common: widget::CommonBuilder,
text: &'a str,
input: I,
style: Style,
}
impl<'a, I> Prompt<'a, I> {
pub fn new(text: &'a str, input: I) -> Self {
Prompt {
common: widget::CommonBuilder::default(),
text: text,
input,
style: Style::default(),
}
}
pub fn with_style(text: &'a str, input: I, style: Style) -> Self {
Prompt {
common: widget::CommonBuilder::default(),
text: text,
input,
style,
}
}
pub fn label_font_id(mut self, font_id: text::font::Id) -> Self {
self.style.label_font_id = Some(Some(font_id));
self
}
}
impl<'a> Prompt<'a, ack::Ack<'a>> {
pub fn ack(text: &'a str) -> Self {
Prompt::new(text, ack::Ack::new())
}
}
impl<'a> Prompt<'a, yesno::YesNo<'a>> {
pub fn yes_no(text: &'a str) -> Self {
Prompt::new(text, yesno::YesNo::new())
}
}
impl<'a> Prompt<'a, widget::TextBox<'a>> {
pub fn text_box(text: &'a str, box_text: &'a str) -> Self {
Prompt::new(text, widget::TextBox::new(box_text))
}
}
#[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 = "5.0")]
pub padding: Option<Scalar>,
#[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 = "text::Justify::Left")]
pub label_justify: Option<text::Justify>,
#[conrod(default = "position::Relative::Align(position::Align::Middle)")]
pub label_x: Option<position::Relative>,
#[conrod(default = "position::Relative::Align(position::Align::Middle)")]
pub label_y: Option<position::Relative>,
}
widget_ids! {
pub struct Ids {
container,
message,
input,
}
}
impl<'a, I> Widget for Prompt<'a, I> where I: Widget {
type State = Ids;
type Style = Style;
type Event = I::Event;
fn init_state(&self, id_gen: widget::id::Generator) -> Self::State {
Ids::new(id_gen)
}
fn style(&self) -> Self::Style {
self.style
}
fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
let widget::UpdateArgs { id, state, style, rect, ui, .. } = args;
let dim = rect.dim();
let color = style.color(&ui.theme);
let border_color = style.border_color(&ui.theme);
let border = style.border(&ui.theme);
widget::Canvas::new()
.wh(dim)
.middle_of(id)
.graphics_for(id)
.color(color)
.border(border)
.border_color(border_color)
.floating(true)
.set(state.container, ui);
let label_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 msg_padding = style.padding(&ui.theme);
let msg_widget = widget::Text::new(self.text)
.and_then(font_id, widget::Text::font_id)
.mid_top_of(state.container)
.padded_w_of(state.container, msg_padding)
.font_size(font_size)
.graphics_for(id)
.color(label_color);
msg_widget.set(state.message, ui);
let widget_event = self.input
.parent(state.container)
.mid_bottom_with_margin_on(state.container, msg_padding)
.set(state.input, ui);
widget_event
}
}
impl<'a, I> Labelable<'a> for Prompt<'a, I> {
builder_methods! {
label { text = &'a str }
label_color { style.label_color = Some(Color) }
label_font_size { style.label_font_size = Some(FontSize) }
}
}
impl<'a, I> Colorable for Prompt<'a, I> {
builder_method!(color { style.color = Some(Color) });
}
impl<'a, I> Borderable for Prompt<'a, I> {
builder_methods! {
border { style.border = Some(Scalar) }
border_color { style.border_color = Some(Color) }
}
}
pub mod ack {
use super::*;
use widget::button::Style;
widget_ids! {
pub struct Ids {
button,
}
}
#[derive(Debug, WidgetCommon)]
pub struct Ack<'a> {
#[conrod(common_builder)]
common: widget::CommonBuilder,
label: &'a str,
style: Style,
}
impl<'a> Ack<'a> {
pub fn new() -> Self {
Ack {
common: widget::CommonBuilder::default(),
label: "OK",
style: Style::default(),
}
}
pub fn label_font_id(mut self, font_id: text::font::Id) -> Self {
self.style.label_font_id = Some(Some(font_id));
self
}
}
impl<'a> Widget for Ack<'a> {
type State = Ids;
type Style = Style;
type Event = Option<()>;
fn init_state(&self, id_gen: widget::id::Generator) -> Self::State {
Ids::new(id_gen)
}
fn style(&self) -> Self::Style {
self.style
}
fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
let widget::UpdateArgs { id, state, style, rect, ui, .. } = args;
let dim = rect.dim();
let label_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 times_clicked = widget::Button::new()
.enabled(true)
.label(self.label)
.and_then(font_id, widget::Button::label_font_id)
.label_color(label_color)
.label_font_size(font_size)
.middle_of(id)
.wh(dim)
.set(state.button, ui);
if times_clicked.was_clicked() {
Some(())
} else {
None
}
}
}
impl<'a> Labelable<'a> for Ack<'a> {
builder_methods! {
label { label = &'a str }
label_color { style.label_color = Some(Color) }
label_font_size { style.label_font_size = Some(FontSize) }
}
}
}
pub mod yesno {
use super::*;
#[derive(Debug, WidgetCommon)]
pub struct YesNo<'a> {
#[conrod(common_builder)]
common: widget::CommonBuilder,
yes_label: &'a str,
no_label: &'a str,
style: Style,
}
#[derive(Copy, Clone, Debug, Default, PartialEq, WidgetStyle)]
pub struct Style {
pub yes: widget::button::Style,
pub no: widget::button::Style,
}
impl<'a> YesNo<'a> {
pub fn new() -> Self {
YesNo {
common: widget::CommonBuilder::default(),
yes_label: "Yes",
no_label: "No",
style: Style::default(),
}
}
pub fn yes_label_font_id(mut self, font_id: text::font::Id) -> Self {
self.style.yes.label_font_id = Some(Some(font_id));
self
}
pub fn no_label_font_id(mut self, font_id: text::font::Id) -> Self {
self.style.no.label_font_id = Some(Some(font_id));
self
}
builder_methods! {
yes_label { yes_label = &'a str }
yes_label_color { style.yes.label_color = Some(Color) }
yes_label_font_size { style.yes.label_font_size = Some(FontSize) }
no_label { no_label = &'a str }
no_label_color { style.no.label_color = Some(Color) }
no_label_font_size { style.no.label_font_size = Some(FontSize) }
}
}
widget_ids! {
pub struct Ids {
canvas,
left,
right,
yes,
no,
}
}
impl<'a> Widget for YesNo<'a> {
type State = Ids;
type Style = Style;
type Event = Option<bool>;
fn init_state(&self, id_gen: widget::id::Generator) -> Self::State {
Ids::new(id_gen)
}
fn style(&self) -> Self::Style {
self.style
}
fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
let widget::UpdateArgs { id, state, style, rect, ui, .. } = args;
let dim = rect.dim();
widget::Canvas::new()
.middle_of(id)
.graphics_for(id)
.wh(dim)
.flow_right(&[
(state.left, widget::Canvas::new()),
(state.right, widget::Canvas::new()),
])
.set(state.canvas, ui);
let yes_label_color = style.yes.label_color(&ui.theme);
let yes_font_size = style.yes.label_font_size(&ui.theme);
let yes_font_id = style.yes.label_font_id(&ui.theme).or(ui.fonts.ids().next());
let yes_label_x = style.yes.label_x(&ui.theme);
let yes_label_y = style.yes.label_y(&ui.theme);
let yes = widget::Button::new()
.enabled(true)
.label(self.yes_label)
.and_then(yes_font_id, widget::Button::label_font_id)
.label_color(yes_label_color)
.label_font_size(yes_font_size)
.label_x(yes_label_x)
.label_y(yes_label_y)
.middle_of(state.left)
.wh_of(state.left)
.set(state.yes, ui);
let no_label_color = style.no.label_color(&ui.theme);
let no_font_size = style.no.label_font_size(&ui.theme);
let no_font_id = style.no.label_font_id(&ui.theme).or(ui.fonts.ids().next());
let no_label_x = style.no.label_x(&ui.theme);
let no_label_y = style.no.label_y(&ui.theme);
let no = widget::Button::new()
.enabled(true)
.label(self.no_label)
.and_then(no_font_id, widget::Button::label_font_id)
.label_color(no_label_color)
.label_font_size(no_font_size)
.label_x(no_label_x)
.label_y(no_label_y)
.middle_of(state.right)
.wh_of(state.right)
.set(state.no, ui);
if yes.was_clicked() {
Some(true)
} else if no.was_clicked() {
Some(false)
} else {
None
}
}
}
}