mirror of
https://github.com/johrpan/musicus.git
synced 2025-10-26 11:47:25 +01:00
Add basic person selector
This commit is contained in:
parent
ed225f61ad
commit
ea2dcbb4db
7 changed files with 347 additions and 2 deletions
|
|
@ -8,6 +8,16 @@ pub struct Person {
|
|||
pub last_name: String,
|
||||
}
|
||||
|
||||
impl Person {
|
||||
pub fn name_fl(&self) -> String {
|
||||
format!("{} {}", self.first_name, self.last_name)
|
||||
}
|
||||
|
||||
pub fn name_lf(&self) -> String {
|
||||
format!("{}, {}", self.last_name, self.first_name)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Insertable, Queryable, Debug, Clone)]
|
||||
pub struct Instrument {
|
||||
pub id: i64,
|
||||
|
|
|
|||
|
|
@ -7,5 +7,10 @@ pub use instrument_editor::*;
|
|||
pub mod person_editor;
|
||||
pub use person_editor::*;
|
||||
|
||||
pub mod person_selector;
|
||||
pub use person_selector::*;
|
||||
|
||||
pub mod selector_row;
|
||||
|
||||
pub mod work_editor;
|
||||
pub use work_editor::*;
|
||||
pub use work_editor::*;
|
||||
|
|
|
|||
75
src/dialogs/person_selector.rs
Normal file
75
src/dialogs/person_selector.rs
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
use super::selector_row::SelectorRow;
|
||||
use super::PersonEditor;
|
||||
use crate::database::*;
|
||||
use gio::prelude::*;
|
||||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use gtk_macros::get_widget;
|
||||
use std::cell::RefCell;
|
||||
use std::convert::TryInto;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct PersonSelector<F>
|
||||
where
|
||||
F: Fn(Person) -> () + 'static,
|
||||
{
|
||||
db: Rc<Database>,
|
||||
window: gtk::Window,
|
||||
callback: F,
|
||||
persons: RefCell<Vec<Person>>,
|
||||
}
|
||||
|
||||
impl<F> PersonSelector<F>
|
||||
where
|
||||
F: Fn(Person) -> () + 'static,
|
||||
{
|
||||
pub fn new<P: IsA<gtk::Window>>(db: Rc<Database>, parent: &P, callback: F) -> Rc<Self> {
|
||||
let builder =
|
||||
gtk::Builder::from_resource("/de/johrpan/musicus_editor/ui/person_selector.ui");
|
||||
|
||||
get_widget!(builder, gtk::Window, window);
|
||||
get_widget!(builder, gtk::Button, add_button);
|
||||
get_widget!(builder, gtk::Entry, search_entry);
|
||||
get_widget!(builder, gtk::ListBox, list);
|
||||
|
||||
let persons = db.get_persons();
|
||||
|
||||
for (index, person) in persons.iter().enumerate() {
|
||||
let label = gtk::Label::new(Some(&person.name_lf()));
|
||||
label.set_halign(gtk::Align::Start);
|
||||
let row = SelectorRow::new(index.try_into().unwrap(), &label);
|
||||
row.show_all();
|
||||
list.insert(&row, -1);
|
||||
}
|
||||
|
||||
let result = Rc::new(PersonSelector {
|
||||
db: db,
|
||||
window: window,
|
||||
callback: callback,
|
||||
persons: RefCell::new(persons),
|
||||
});
|
||||
|
||||
list.connect_row_activated(clone!(@strong result => move |_, row| {
|
||||
result.window.close();
|
||||
let row = row.get_child().unwrap().downcast::<SelectorRow>().unwrap();
|
||||
let index: usize = row.get_index().try_into().unwrap();
|
||||
(result.callback)(result.persons.borrow()[index].clone());
|
||||
}));
|
||||
|
||||
add_button.connect_clicked(clone!(@strong result => move |_| {
|
||||
let editor = PersonEditor::new(result.db.clone(), &result.window, None, clone!(@strong result => move |person| {
|
||||
result.window.close();
|
||||
(result.callback)(person);
|
||||
}));
|
||||
editor.show();
|
||||
}));
|
||||
|
||||
result.window.set_transient_for(Some(parent));
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
pub fn show(&self) {
|
||||
self.window.show();
|
||||
}
|
||||
}
|
||||
150
src/dialogs/selector_row.rs
Normal file
150
src/dialogs/selector_row.rs
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
use glib::prelude::*;
|
||||
use glib::subclass;
|
||||
use glib::subclass::prelude::*;
|
||||
use glib::translate::*;
|
||||
use glib::{glib_object_impl, glib_object_subclass, glib_wrapper};
|
||||
use gtk::prelude::*;
|
||||
use gtk::subclass::prelude::*;
|
||||
use std::cell::{Cell, RefCell};
|
||||
|
||||
glib_wrapper! {
|
||||
pub struct SelectorRow(
|
||||
Object<subclass::simple::InstanceStruct<SelectorRowPriv>,
|
||||
subclass::simple::ClassStruct<SelectorRowPriv>,
|
||||
SelectorRowClass>
|
||||
) @extends gtk::Bin, gtk::Container, gtk::Widget;
|
||||
|
||||
match fn {
|
||||
get_type => || SelectorRowPriv::get_type().to_glib(),
|
||||
}
|
||||
}
|
||||
|
||||
impl SelectorRow {
|
||||
pub fn new<T: IsA<gtk::Widget>>(index: u64, child: &T) -> Self {
|
||||
glib::Object::new(
|
||||
Self::static_type(),
|
||||
&[("index", &index), ("child", child.upcast_ref())],
|
||||
)
|
||||
.expect("Failed to create SelectorRow GObject!")
|
||||
.downcast()
|
||||
.expect("SelectorRow GObject is of the wrong type!")
|
||||
}
|
||||
|
||||
pub fn get_index(&self) -> u64 {
|
||||
self.get_property("index").unwrap().get().unwrap().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SelectorRowPriv {
|
||||
index: Cell<u64>,
|
||||
child: RefCell<Option<gtk::Widget>>,
|
||||
}
|
||||
|
||||
static PROPERTIES: [subclass::Property; 2] = [
|
||||
subclass::Property("index", |name| {
|
||||
glib::ParamSpec::uint64(
|
||||
name,
|
||||
"Index",
|
||||
"Index",
|
||||
0,
|
||||
u64::MAX,
|
||||
0,
|
||||
glib::ParamFlags::READWRITE,
|
||||
)
|
||||
}),
|
||||
subclass::Property("child", |name| {
|
||||
glib::ParamSpec::object(
|
||||
name,
|
||||
"Child",
|
||||
"Child",
|
||||
gtk::Widget::static_type(),
|
||||
glib::ParamFlags::READWRITE,
|
||||
)
|
||||
}),
|
||||
];
|
||||
|
||||
impl ObjectSubclass for SelectorRowPriv {
|
||||
const NAME: &'static str = "SelectorRow";
|
||||
type ParentType = gtk::Bin;
|
||||
type Instance = subclass::simple::InstanceStruct<Self>;
|
||||
type Class = subclass::simple::ClassStruct<Self>;
|
||||
|
||||
glib_object_subclass!();
|
||||
|
||||
fn class_init(klass: &mut Self::Class) {
|
||||
klass.install_properties(&PROPERTIES);
|
||||
}
|
||||
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
index: Cell::new(0),
|
||||
child: RefCell::new(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ObjectImpl for SelectorRowPriv {
|
||||
glib_object_impl!();
|
||||
|
||||
fn constructed(&self, object: &glib::Object) {
|
||||
self.parent_constructed(object);
|
||||
|
||||
let row = object.downcast_ref::<SelectorRow>().unwrap();
|
||||
row.set_border_width(6);
|
||||
|
||||
let child = self.child.borrow();
|
||||
match child.as_ref() {
|
||||
Some(child) => row.add(child),
|
||||
None => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_property(&self, object: &glib::Object, id: usize, value: &glib::Value) {
|
||||
let prop = &PROPERTIES[id];
|
||||
|
||||
match *prop {
|
||||
subclass::Property("index", ..) => {
|
||||
let index = value
|
||||
.get_some()
|
||||
.expect("Wrong type for SelectorRow GObject index property!");
|
||||
self.index.set(index);
|
||||
}
|
||||
subclass::Property("child", ..) => {
|
||||
let child = value
|
||||
.get()
|
||||
.expect("Wrong type for SelectorRow GObject child property!");
|
||||
|
||||
let row = object.downcast_ref::<SelectorRow>().unwrap();
|
||||
|
||||
{
|
||||
let old = self.child.borrow();
|
||||
match old.as_ref() {
|
||||
Some(old) => row.remove(old),
|
||||
None => (),
|
||||
}
|
||||
}
|
||||
|
||||
self.child.replace(child.clone());
|
||||
match child {
|
||||
Some(child) => row.add(&child),
|
||||
None => (),
|
||||
}
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_property(&self, _obj: &glib::Object, id: usize) -> Result<glib::Value, ()> {
|
||||
let prop = &PROPERTIES[id];
|
||||
|
||||
match *prop {
|
||||
subclass::Property("index", ..) => Ok(self.index.get().to_value()),
|
||||
subclass::Property("child", ..) => Ok(self.child.borrow().to_value()),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WidgetImpl for SelectorRowPriv {}
|
||||
impl ContainerImpl for SelectorRowPriv {}
|
||||
impl BinImpl for SelectorRowPriv {}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
use super::person_selector::PersonSelector;
|
||||
use crate::database::*;
|
||||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
|
|
@ -40,11 +41,13 @@ impl PartOrSection {
|
|||
}
|
||||
|
||||
pub struct WorkEditor {
|
||||
db: Rc<Database>,
|
||||
window: gtk::Window,
|
||||
save_button: gtk::Button,
|
||||
id: i64,
|
||||
title_entry: gtk::Entry,
|
||||
composer: RefCell<Option<Person>>,
|
||||
composer_label: gtk::Label,
|
||||
instruments: RefCell<Vec<Instrument>>,
|
||||
structure: RefCell<Vec<PartOrSection>>,
|
||||
}
|
||||
|
|
@ -120,11 +123,13 @@ impl WorkEditor {
|
|||
});
|
||||
|
||||
let result = Rc::new(WorkEditor {
|
||||
db: db,
|
||||
window: window,
|
||||
save_button: save_button,
|
||||
id: id,
|
||||
title_entry: title_entry,
|
||||
composer: composer,
|
||||
composer_label: composer_label,
|
||||
instruments: instruments,
|
||||
structure: structure,
|
||||
});
|
||||
|
|
@ -161,10 +166,18 @@ impl WorkEditor {
|
|||
sections: sections,
|
||||
};
|
||||
|
||||
db.update_work(work.clone().into());
|
||||
result.db.update_work(work.clone().into());
|
||||
callback(work);
|
||||
}));
|
||||
|
||||
composer_button.connect_clicked(clone!(@strong result => move |_| {
|
||||
PersonSelector::new(result.db.clone(), &result.window, clone!(@strong result => move |person| {
|
||||
result.composer.replace(Some(person.clone()));
|
||||
result.composer_label.set_text(&person.name_fl());
|
||||
result.save_button.set_sensitive(true);
|
||||
})).show();
|
||||
}));
|
||||
|
||||
result.window.set_transient_for(Some(parent));
|
||||
|
||||
result
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue