/* 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 glib::Object; use gtk::{prelude::*, subclass::prelude::*}; use std::{ cell::RefCell, path::{Path, PathBuf}, rc::Rc, }; pub struct FileChooserRowPrivate { path: RefCell>, label: gtk::Label, } #[glib::object_subclass] impl ObjectSubclass for FileChooserRowPrivate { const NAME: &'static str = "FileChooser"; type Type = FileChooserRow; type ParentType = gtk::Box; fn new() -> Self { Self { path: RefCell::new(None), label: gtk::Label::builder().hexpand(true).build(), } } } impl ObjectImpl for FileChooserRowPrivate {} impl WidgetImpl for FileChooserRowPrivate {} impl BoxImpl for FileChooserRowPrivate {} glib::wrapper! { pub struct FileChooserRow(ObjectSubclass) @extends gtk::Box, gtk::Widget, @implements gtk::Orientable; } impl FileChooserRow { pub fn new(on_selected: F) -> Self where F: Fn(PathBuf) + 'static, { let s: Self = Object::builder().build(); s.set_orientation(gtk::Orientation::Horizontal); // The database selection row should be a box that shows a default database path, along with a // button that triggers a file chooser dialog. Once the dialog returns, the box should be // updated to reflect the chosen path. s.imp().label.set_text("No database selected"); let db_file_chooser_button = gtk::Button::builder().label("Select Database").build(); let on_selected = Rc::new(Box::new(on_selected)); db_file_chooser_button.connect_clicked({ let s = s.clone(); move |_| { let no_window: Option<>k::Window> = None; let not_cancellable: Option<&gio::Cancellable> = None; let s = s.clone(); let on_selected = on_selected.clone(); gtk::FileDialog::builder().build().open( no_window, not_cancellable, move |file_id| match file_id { Ok(file_id) => match file_id.path() { Some(path) => { s.imp().label.set_text(path.to_str().unwrap()); on_selected(path.clone()); *s.imp().path.borrow_mut() = Some(path); } None => { *s.imp().path.borrow_mut() = None; s.imp().label.set_text("No database selected"); } }, Err(err) => println!("file opening failed: {}", err), }, ); } }); s.append(&s.imp().label); s.append(&db_file_chooser_button); s } pub fn path(&self) -> Option { self.imp().path.borrow().clone() } }