use {Color, Colorable, FontSize, Borderable, Positionable, Sizeable, Widget};
use event;
use input;
use position::{Range, Rect, Scalar};
use text;
use widget;
pub struct TextBox<'a> {
common: widget::CommonBuilder,
text: &'a str,
style: Style,
}
widget_style!{
style Style {
- text_padding: Scalar { 5.0 }
- color: Color { theme.shape_color }
- border: Scalar { theme.border_width }
- border_color: Color { theme.border_color }
- text_color: Color { theme.label_color }
- font_size: FontSize { theme.font_size_medium }
- justify: text::Justify { text::Justify::Left }
- font_id: Option<text::font::Id> { theme.font_id }
}
}
widget_ids! {
struct Ids {
text_edit,
rectangle,
}
}
pub struct State {
ids: Ids,
}
impl<'a> TextBox<'a> {
pub fn new(text: &'a str) -> Self {
TextBox {
common: widget::CommonBuilder::new(),
text: text,
style: Style::new(),
}
}
pub fn left_justify(self) -> Self {
self.justify(text::Justify::Left)
}
pub fn center_justify(self) -> Self {
self.justify(text::Justify::Center)
}
pub fn right_justify(self) -> Self {
self.justify(text::Justify::Right)
}
pub fn font_id(mut self, font_id: text::font::Id) -> Self {
self.style.font_id = Some(Some(font_id));
self
}
builder_methods!{
pub text_color { style.text_color = Some(Color) }
pub font_size { style.font_size = Some(FontSize) }
pub justify { style.justify = Some(text::Justify) }
pub pad_text { style.text_padding = Some(Scalar) }
}
}
#[derive(Clone, Debug)]
pub enum Event {
Update(String),
Enter,
}
impl<'a> Widget for TextBox<'a> {
type State = State;
type Style = Style;
type Event = Vec<Event>;
fn common(&self) -> &widget::CommonBuilder {
&self.common
}
fn common_mut(&mut self) -> &mut widget::CommonBuilder {
&mut self.common
}
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, rect, style, mut ui, .. } = args;
let TextBox { text, .. } = self;
let font_size = style.font_size(ui.theme());
let border = style.border(ui.theme());
let text_padding = style.text_padding(ui.theme());
let justify = style.justify(ui.theme());
let text_rect = {
let w = rect.x.pad(border + text_padding).len();
let h = font_size as Scalar + 1.0;
let x = Range::new(0.0, w).align_middle_of(rect.x);
let y = Range::new(0.0, h).align_middle_of(rect.y);
Rect { x: x, y: y }
};
let color = style.color(ui.theme());
let border_color = style.border_color(ui.theme());
widget::BorderedRectangle::new(rect.dim())
.xy(rect.xy())
.graphics_for(id)
.parent(id)
.border(border)
.color(color)
.border_color(border_color)
.set(state.ids.rectangle, ui);
let mut events = Vec::new();
let text_color = style.text_color(ui.theme());
let font_id = style.font_id(&ui.theme).or(ui.fonts.ids().next());
if let Some(new_string) = widget::TextEdit::new(text)
.and_then(font_id, widget::TextEdit::font_id)
.wh(text_rect.dim())
.xy(text_rect.xy())
.font_size(font_size)
.color(text_color)
.justify(justify)
.parent(id)
.set(state.ids.text_edit, ui)
{
events.push(Event::Update(new_string));
}
for widget_event in ui.widget_input(state.ids.text_edit).events() {
match widget_event {
event::Widget::Press(press) => match press.button {
event::Button::Keyboard(key) => match key {
input::Key::Return => events.push(Event::Enter),
_ => (),
},
_ => (),
},
_ => (),
}
}
events
}
}
impl<'a> Borderable for TextBox<'a> {
builder_methods!{
border { style.border = Some(Scalar) }
border_color { style.border_color = Some(Color) }
}
}
impl<'a> Colorable for TextBox<'a> {
builder_method!(color { style.color = Some(Color) });
}