/* Copyright 2023, Savanni D'Gerinel This file is part of FitnessTrax. FitnessTrax is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. FitnessTrax is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with FitnessTrax. If not, see . */ use gtk::prelude::*; use std::{cell::RefCell, rc::Rc}; pub struct ParseError; #[derive(Clone)] pub struct TextEntry { value: Rc>>, widget: gtk::Entry, renderer: Rc String>>, validator: Rc Result>>, } // 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| 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; } pub fn grab_focus(&self) { self.widget.grab_focus(); } pub fn widget(&self) -> gtk::Widget { self.widget.clone().upcast::() } }