diff --git a/res/resources.xml b/res/resources.xml
index d866eb3..97a0e37 100644
--- a/res/resources.xml
+++ b/res/resources.xml
@@ -4,6 +4,7 @@
ui/ensemble_editor.ui
ui/instrument_editor.ui
ui/person_editor.ui
+ ui/person_selector.ui
ui/window.ui
ui/work_editor.ui
diff --git a/res/ui/person_selector.ui b/res/ui/person_selector.ui
new file mode 100644
index 0000000..06eb55e
--- /dev/null
+++ b/res/ui/person_selector.ui
@@ -0,0 +1,91 @@
+
+
+
+
+
+
diff --git a/src/database/tables.rs b/src/database/tables.rs
index a7dc43b..342a724 100644
--- a/src/database/tables.rs
+++ b/src/database/tables.rs
@@ -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,
diff --git a/src/dialogs/mod.rs b/src/dialogs/mod.rs
index ca9e250..9a6cefb 100644
--- a/src/dialogs/mod.rs
+++ b/src/dialogs/mod.rs
@@ -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::*;
\ No newline at end of file
+pub use work_editor::*;
diff --git a/src/dialogs/person_selector.rs b/src/dialogs/person_selector.rs
new file mode 100644
index 0000000..9fecb33
--- /dev/null
+++ b/src/dialogs/person_selector.rs
@@ -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
+where
+ F: Fn(Person) -> () + 'static,
+{
+ db: Rc,
+ window: gtk::Window,
+ callback: F,
+ persons: RefCell>,
+}
+
+impl PersonSelector
+where
+ F: Fn(Person) -> () + 'static,
+{
+ pub fn new>(db: Rc, parent: &P, callback: F) -> Rc {
+ 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::().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();
+ }
+}
diff --git a/src/dialogs/selector_row.rs b/src/dialogs/selector_row.rs
new file mode 100644
index 0000000..41d3b39
--- /dev/null
+++ b/src/dialogs/selector_row.rs
@@ -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::ClassStruct,
+ SelectorRowClass>
+ ) @extends gtk::Bin, gtk::Container, gtk::Widget;
+
+ match fn {
+ get_type => || SelectorRowPriv::get_type().to_glib(),
+ }
+}
+
+impl SelectorRow {
+ pub fn new>(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,
+ child: RefCell