diff --git a/src/bin/list_samples.rs b/src/bin/list_samples.rs index 00ca965..0a7c70c 100644 --- a/src/bin/list_samples.rs +++ b/src/bin/list_samples.rs @@ -1,3 +1,6 @@ +use itertools::Itertools; +use sample_amp::{establish_connection, list_tags}; + fn main() { let connection = &mut establish_connection(); println!( diff --git a/src/main.rs b/src/main.rs index fc18bb1..4d62465 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,10 @@ use diesel::prelude::*; use gtk::gdk::Display; -use gtk::glib::BoxedAnyObject; use gtk::prelude::*; use relm4::{factory::FactoryVecDeque, prelude::*}; -use std::cell::Ref; mod library_list; +mod sample_list; use library_list::LibraryListItem; mod app_msg; use app_msg::AppMsg; @@ -13,24 +12,58 @@ use sample_amp::establish_connection; use sample_amp::models::Library; use sample_amp::schema::libraries; +use crate::sample_list::SampleListModel; + struct AppModel { - samples: gtk::MultiSelection, + sample_list: Controller, libraries: FactoryVecDeque, connection: SqliteConnection, } -struct Sample { - name: String, - bpm: f32, - key: String, // todo: key struct? -} - #[relm4::component] impl SimpleComponent for AppModel { + type Input = AppMsg; + + type Output = (); type Init = (); - type Input = AppMsg; - type Output = (); + fn init( + _: Self::Init, + window: &Self::Root, + sender: ComponentSender, + ) -> relm4::ComponentParts { + let mut model = AppModel { + connection: establish_connection(), + libraries: FactoryVecDeque::new(gtk::ListBox::default(), sender.input_sender()), + sample_list: SampleListModel::builder().launch(()).detach(), + }; + + let sample_view = model.sample_list.widget(); + + // todo: cleaner + let library_results = libraries::dsl::libraries + .select(Library::as_select()) + .load(&mut model.connection) + .expect("Error loading libraries"); + + model.libraries.guard().push_back("All".to_string()); + for lib in library_results { + model.libraries.guard().push_back(lib.name); + } + + let library_view = model.libraries.widget(); + let widgets = view_output!(); + + ComponentParts { model, widgets } + } + + fn update(&mut self, message: Self::Input, _sender: ComponentSender) { + match message { + AppMsg::Close => { + relm4::main_application().quit(); + } + } + } view! { gtk::Window { @@ -56,31 +89,8 @@ impl SimpleComponent for AppModel { set_orientation: gtk::Orientation::Vertical, set_hexpand: true, - gtk::ScrolledWindow { - set_vexpand: true, - set_css_classes: &["sample-list-view"], - gtk::ColumnView { - set_model: Some(&model.samples), - append_column = >k::ColumnViewColumn { - set_title: Some("Name"), - set_resizable: true, - set_expand: true, - set_factory: Some(&factory_name) - }, - append_column = >k::ColumnViewColumn { - set_title: Some("BPM"), - set_factory: Some(&factory_bpm) - }, - append_column = >k::ColumnViewColumn { - set_title: Some("Key"), - set_factory: Some(&factory_key) - }, - append_column = >k::ColumnViewColumn { - set_title: Some("Tags"), - set_resizable: true, - } - } - }, + #[local_ref] + sample_view -> gtk::ScrolledWindow {}, gtk::Box { set_height_request: 100, @@ -94,89 +104,6 @@ impl SimpleComponent for AppModel { } } } - - fn init( - _: Self::Init, - window: &Self::Root, - sender: ComponentSender, - ) -> relm4::ComponentParts { - let factory_name = gtk::SignalListItemFactory::new(); - factory_name.connect_bind(move |_factory, item| { - let item = item.downcast_ref::().unwrap(); - let obj = item.item().and_downcast::().unwrap(); - let sample: Ref = obj.borrow(); - let cell = gtk::Label::new(Some(&sample.name.to_string())); - cell.set_halign(gtk::Align::Start); - item.set_child(Some(&cell)) - }); - - let factory_bpm = gtk::SignalListItemFactory::new(); - factory_bpm.connect_bind(move |_factory, item| { - let item = item.downcast_ref::().unwrap(); - let obj = item.item().and_downcast::().unwrap(); - let sample: Ref = obj.borrow(); - let cell = gtk::Label::new(Some(&sample.bpm.to_string())); - cell.set_halign(gtk::Align::End); - item.set_child(Some(&cell)) - }); - - let factory_key = gtk::SignalListItemFactory::new(); - factory_key.connect_bind(move |_factory, item| { - let item = item.downcast_ref::().unwrap(); - let obj = item.item().and_downcast::().unwrap(); - let sample: Ref = obj.borrow(); - let cell = gtk::Label::new(Some(&sample.key.to_string())); - cell.set_halign(gtk::Align::Start); - item.set_child(Some(&cell)) - }); - - let samples = gtk::gio::ListStore::new(gtk::glib::types::Type::OBJECT); - let sample_a = BoxedAnyObject::new(Sample { - name: "01 MOOLOO-108 bpm a.wav".to_string(), - bpm: 108.0, - key: "A".to_string(), - }); - samples.append(&sample_a); - let sample_b = BoxedAnyObject::new(Sample { - name: "03 FAST AND FURIOUS-144.3 bpm a.wav".to_string(), - bpm: 144.3, - key: "A".to_string(), - }); - samples.append(&sample_b); - - let samples = gtk::MultiSelection::new(Some(samples)); - - let mut model = AppModel { - samples, - connection: establish_connection(), - libraries: FactoryVecDeque::new(gtk::ListBox::default(), sender.input_sender()), - }; - - // todo: cleaner - - let library_results = libraries::dsl::libraries - .select(Library::as_select()) - .load(&mut model.connection) - .expect("Error loading libraries"); - - model.libraries.guard().push_back("All".to_string()); - for lib in library_results { - model.libraries.guard().push_back(lib.name); - } - - let library_view = model.libraries.widget(); - let widgets = view_output!(); - - ComponentParts { model, widgets } - } - - fn update(&mut self, message: Self::Input, _sender: ComponentSender) { - match message { - AppMsg::Close => { - relm4::main_application().quit(); - } - } - } } fn load_css() { diff --git a/src/sample_list.rs b/src/sample_list.rs new file mode 100644 index 0000000..bf1db26 --- /dev/null +++ b/src/sample_list.rs @@ -0,0 +1,110 @@ +use std::cell::Ref; + +use gtk::{glib::BoxedAnyObject, prelude::*}; +use relm4::prelude::*; + +struct Sample { + name: String, + bpm: f32, + key: String, // todo: key struct? +} + +#[derive(Debug)] +pub struct SampleListMsg {} + +pub struct SampleListModel { + samples: gtk::MultiSelection, +} + +#[relm4::component(pub)] +impl SimpleComponent for SampleListModel { + type Input = SampleListMsg; + + type Output = (); + type Init = (); + + view! { + #[root] + gtk::ScrolledWindow { + set_vexpand: true, + set_css_classes: &["sample-list-view"], + gtk::ColumnView { + set_model: Some(&model.samples), + append_column = >k::ColumnViewColumn { + set_title: Some("Name"), + set_resizable: true, + set_expand: true, + set_factory: Some(&factory_name) + }, + append_column = >k::ColumnViewColumn { + set_title: Some("BPM"), + set_factory: Some(&factory_bpm) + }, + append_column = >k::ColumnViewColumn { + set_title: Some("Key"), + set_factory: Some(&factory_key) + }, + append_column = >k::ColumnViewColumn { + set_title: Some("Tags"), + set_resizable: true, + } + } + } + } + + fn init( + _: Self::Init, + window: &Self::Root, + _sender: ComponentSender, + ) -> relm4::ComponentParts { + let factory_name = gtk::SignalListItemFactory::new(); + factory_name.connect_bind(move |_factory, item| { + let item = item.downcast_ref::().unwrap(); + let obj = item.item().and_downcast::().unwrap(); + let sample: Ref = obj.borrow(); + let cell = gtk::Label::new(Some(&sample.name.to_string())); + cell.set_halign(gtk::Align::Start); + item.set_child(Some(&cell)) + }); + + let factory_bpm = gtk::SignalListItemFactory::new(); + factory_bpm.connect_bind(move |_factory, item| { + let item = item.downcast_ref::().unwrap(); + let obj = item.item().and_downcast::().unwrap(); + let sample: Ref = obj.borrow(); + let cell = gtk::Label::new(Some(&sample.bpm.to_string())); + cell.set_halign(gtk::Align::End); + item.set_child(Some(&cell)) + }); + + let factory_key = gtk::SignalListItemFactory::new(); + factory_key.connect_bind(move |_factory, item| { + let item = item.downcast_ref::().unwrap(); + let obj = item.item().and_downcast::().unwrap(); + let sample: Ref = obj.borrow(); + let cell = gtk::Label::new(Some(&sample.key.to_string())); + cell.set_halign(gtk::Align::Start); + item.set_child(Some(&cell)) + }); + + let samples = gtk::gio::ListStore::new(gtk::glib::types::Type::OBJECT); + let sample_a = BoxedAnyObject::new(Sample { + name: "01 MOOLOO-108 bpm a.wav".to_string(), + bpm: 108.0, + key: "A".to_string(), + }); + samples.append(&sample_a); + let sample_b = BoxedAnyObject::new(Sample { + name: "03 FAST AND FURIOUS-144.3 bpm a.wav".to_string(), + bpm: 144.3, + key: "A".to_string(), + }); + samples.append(&sample_b); + let samples = gtk::MultiSelection::new(Some(samples)); + + let model = SampleListModel { samples }; + + let widgets = view_output!(); + ComponentParts { model, widgets } + } +}