diff --git a/Cargo.lock b/Cargo.lock index a252307..3340ab5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -699,7 +699,7 @@ dependencies = [ [[package]] name = "dashboard" -version = "0.1.1" +version = "0.1.2" dependencies = [ "cairo-rs", "chrono", diff --git a/fitnesstrax/app/src/components/mod.rs b/fitnesstrax/app/src/components/mod.rs index 19ee548..9f1cf16 100644 --- a/fitnesstrax/app/src/components/mod.rs +++ b/fitnesstrax/app/src/components/mod.rs @@ -20,6 +20,9 @@ pub use day::{DayDetail, DaySummary}; mod edit_view; pub use edit_view::EditView; +mod singleton; +pub use singleton::Singleton; + mod text_entry; pub use text_entry::{ParseError, TextEntry}; diff --git a/fitnesstrax/app/src/components/singleton.rs b/fitnesstrax/app/src/components/singleton.rs new file mode 100644 index 0000000..5dec01f --- /dev/null +++ b/fitnesstrax/app/src/components/singleton.rs @@ -0,0 +1,68 @@ +/* +Copyright 2024, 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 . +*/ + +//! A Widget container for a single components +use glib::Object; +use gtk::{prelude::*, subclass::prelude::*}; +use std::cell::RefCell; + +pub struct SingletonPrivate { + widget: RefCell, +} + +impl Default for SingletonPrivate { + fn default() -> Self { + Self { + widget: RefCell::new(gtk::Label::new(None).upcast()), + } + } +} + +#[glib::object_subclass] +impl ObjectSubclass for SingletonPrivate { + const NAME: &'static str = "Singleton"; + type Type = Singleton; + type ParentType = gtk::Box; +} + +impl ObjectImpl for SingletonPrivate {} +impl WidgetImpl for SingletonPrivate {} +impl BoxImpl for SingletonPrivate {} + +glib::wrapper! { + /// The Singleton component contains exactly one child widget. The swap function makes it easy + /// to handle the job of swapping that child out for a different one. + pub struct Singleton(ObjectSubclass) @extends gtk::Box, gtk::Widget; +} + +impl Singleton { + /// Construct a Singleton object. The Singleton defaults to an invisible child. + pub fn new() -> Self { + let s: Self = Object::builder().build(); + + s.append(&*s.imp().widget.borrow()); + + s + } + + /// Replace the currently visible child widget with a new one. The old widget will be + /// discarded. + pub fn swap(&self, new_widget: >k::Widget) { + self.remove(&*self.imp().widget.borrow()); + self.append(new_widget); + *self.imp().widget.borrow_mut() = new_widget.clone(); + } +} diff --git a/fitnesstrax/app/src/components/text_entry.rs b/fitnesstrax/app/src/components/text_entry.rs index 2220ec9..750ca2e 100644 --- a/fitnesstrax/app/src/components/text_entry.rs +++ b/fitnesstrax/app/src/components/text_entry.rs @@ -24,12 +24,12 @@ pub struct TextEntry { value: Rc>>, widget: gtk::Entry, renderer: Rc String>>, - validator: Rc Result>>, + parser: 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 + pub fn new(placeholder: &str, value: Option, renderer: R, parser: V) -> Self where R: Fn(&T) -> String + 'static, V: Fn(&str) -> Result + 'static, @@ -44,7 +44,7 @@ impl TextEntry { value: Rc::new(RefCell::new(value)), widget, renderer: Rc::new(Box::new(renderer)), - validator: Rc::new(Box::new(validator)), + parser: Rc::new(Box::new(parser)), }; s.widget.buffer().connect_text_notify({ @@ -61,7 +61,7 @@ impl TextEntry { self.widget.remove_css_class("error"); return; } - match (self.validator)(buffer.text().as_str()) { + match (self.parser)(buffer.text().as_str()) { Ok(v) => { *self.value.borrow_mut() = Some(v); self.widget.remove_css_class("error"); diff --git a/fitnesstrax/app/src/components/weight.rs b/fitnesstrax/app/src/components/weight.rs index f32d11e..3108bc7 100644 --- a/fitnesstrax/app/src/components/weight.rs +++ b/fitnesstrax/app/src/components/weight.rs @@ -14,7 +14,7 @@ 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 crate::components::{EditView, ParseError, TextEntry}; +use crate::components::{EditView, ParseError, Singleton, TextEntry}; use chrono::{Local, NaiveDate}; use dimensioned::si; use ft_core::Weight; @@ -27,6 +27,7 @@ pub struct WeightViewPrivate { record: RefCell>, widget: RefCell>>>, + container: Singleton, on_edit_finished: RefCell)>>, } @@ -37,6 +38,7 @@ impl Default for WeightViewPrivate { date: RefCell::new(Local::now().date_naive()), record: RefCell::new(None), widget: RefCell::new(EditView::Unconfigured), + container: Singleton::new(), on_edit_finished: RefCell::new(Box::new(|_| {})), } } @@ -68,6 +70,8 @@ impl WeightView { { let s: Self = Object::builder().build(); + s.append(&s.imp().container); + *s.imp().on_edit_finished.borrow_mut() = Box::new(on_edit_finished); *s.imp().date.borrow_mut() = date; @@ -126,6 +130,12 @@ impl WeightView { } fn swap(&self, new_view: EditView>>) { + match new_view { + EditView::Unconfigured => {} + EditView::View(view) => self.imp().container.swap(&view.upcast()), + EditView::Edit(editor) => self.imp().container.swap(&editor.widget()), + } + /* let mut widget = self.imp().widget.borrow_mut(); match *widget { EditView::Unconfigured => {} @@ -139,6 +149,7 @@ impl WeightView { EditView::Edit(ref editor) => self.append(&editor.widget()), } *widget = new_view; + */ } pub fn blur(&self) {