diff --git a/fitnesstrax/app/src/components/day.rs b/fitnesstrax/app/src/components/day.rs index 4692ac3..9e5a28b 100644 --- a/fitnesstrax/app/src/components/day.rs +++ b/fitnesstrax/app/src/components/day.rs @@ -248,9 +248,12 @@ impl Default for WeightViewPrivate { .halign(gtk::Align::Start) .can_focus(true) .build(); - let edit = TextEntry::>::new("weight", None, &|w: &str| { - w.parse::().map(|w| w * si::KG).map_err(|_| ParseError) - }); + let edit = TextEntry::>::new( + "weight", + None, + |w: &si::Kilogram| w.to_string(), + |w: &str| w.parse::().map(|w| w * si::KG).map_err(|_| ParseError), + ); let current = view.clone(); diff --git a/fitnesstrax/app/src/components/text_entry.rs b/fitnesstrax/app/src/components/text_entry.rs index 690e5d8..2220ec9 100644 --- a/fitnesstrax/app/src/components/text_entry.rs +++ b/fitnesstrax/app/src/components/text_entry.rs @@ -23,43 +23,65 @@ pub struct ParseError; pub struct TextEntry { value: Rc>>, widget: gtk::Entry, + renderer: Rc String>>, + validator: Rc Result>>, } -impl TextEntry { - pub fn new( - placeholder: &str, - value: Option, - validator: &'static dyn Fn(&str) -> Result, - ) -> Self { +// I do not understand why the data should be 'static. +impl TextEntry { + pub fn new(placeholder: &str, value: Option, renderer: R, validator: V) -> Self + where + R: Fn(&T) -> String + 'static, + V: Fn(&str) -> Result + 'static, + { let widget = gtk::Entry::builder().placeholder_text(placeholder).build(); + match value { + Some(ref v) => widget.set_text(&renderer(&v)), + None => {} + } let s = Self { value: Rc::new(RefCell::new(value)), widget, + renderer: Rc::new(Box::new(renderer)), + validator: Rc::new(Box::new(validator)), }; s.widget.buffer().connect_text_notify({ let s = s.clone(); - move |buffer| { - if buffer.text().is_empty() { - *s.value.borrow_mut() = None; - } - match validator(buffer.text().as_str()) { - Ok(v) => *s.value.borrow_mut() = Some(v), - // need to change the border to provide a visual indicator of an error - Err(_) => {} - } - } + move |buffer| s.handle_text_change(buffer) }); s } + fn handle_text_change(&self, buffer: >k::EntryBuffer) { + if buffer.text().is_empty() { + *self.value.borrow_mut() = None; + self.widget.remove_css_class("error"); + return; + } + match (self.validator)(buffer.text().as_str()) { + Ok(v) => { + *self.value.borrow_mut() = Some(v); + self.widget.remove_css_class("error"); + } + // need to change the border to provide a visual indicator of an error + Err(_) => { + self.widget.add_css_class("error"); + } + } + } + pub fn value(&self) -> Option { self.value.borrow().clone() } pub fn set_value(&self, value: Option) { + match value { + Some(ref v) => self.widget.set_text(&(self.renderer)(&v)), + None => {} + } *self.value.borrow_mut() = value; }