Compare commits
2 commits
96bd4f8cab
...
0f876324aa
Author | SHA1 | Date | |
---|---|---|---|
0f876324aa | |||
f522b96116 |
10 changed files with 235 additions and 133 deletions
53
Cargo.lock
generated
53
Cargo.lock
generated
|
@ -113,6 +113,7 @@ checksum = "f7a532c1f99a0f596f6960a60d1e119e91582b24b39e2d83a190e61262c3ef0c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"diesel_derives",
|
"diesel_derives",
|
||||||
"libsqlite3-sys",
|
"libsqlite3-sys",
|
||||||
|
"r2d2",
|
||||||
"time",
|
"time",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -798,6 +799,29 @@ dependencies = [
|
||||||
"system-deps",
|
"system-deps",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parking_lot"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
|
||||||
|
dependencies = [
|
||||||
|
"lock_api",
|
||||||
|
"parking_lot_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parking_lot_core"
|
||||||
|
version = "0.9.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"redox_syscall",
|
||||||
|
"smallvec",
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project"
|
name = "pin-project"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
@ -898,6 +922,26 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "r2d2"
|
||||||
|
version = "0.8.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"parking_lot",
|
||||||
|
"scheduled-thread-pool",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_syscall"
|
||||||
|
version = "0.3.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "relm4"
|
name = "relm4"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
|
@ -993,6 +1037,15 @@ dependencies = [
|
||||||
"relm4-icons",
|
"relm4-icons",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scheduled-thread-pool"
|
||||||
|
version = "0.2.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19"
|
||||||
|
dependencies = [
|
||||||
|
"parking_lot",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scopeguard"
|
name = "scopeguard"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
|
|
@ -10,7 +10,7 @@ gtk = { version = "0.6.6", package = "gtk4" }
|
||||||
relm4 = { version = "0.6.0", features = ["libadwaita"] }
|
relm4 = { version = "0.6.0", features = ["libadwaita"] }
|
||||||
relm4-components = "0.6.0"
|
relm4-components = "0.6.0"
|
||||||
relm4-icons = { version = "0.6.0", features = ["plus", "minus"] }
|
relm4-icons = { version = "0.6.0", features = ["plus", "minus"] }
|
||||||
diesel = { version = "2.1.0", features = ["sqlite", "returning_clauses_for_sqlite_3_35"] }
|
diesel = { version = "2.1.0", features = ["sqlite", "returning_clauses_for_sqlite_3_35", "r2d2"] }
|
||||||
libsqlite3-sys = { version = "0.26.0", features = ["bundled"] }
|
libsqlite3-sys = { version = "0.26.0", features = ["bundled"] }
|
||||||
dotenvy = "0.15"
|
dotenvy = "0.15"
|
||||||
nom = "7.1.3"
|
nom = "7.1.3"
|
||||||
|
|
|
@ -5,7 +5,7 @@ fn main() {
|
||||||
let suggestions =
|
let suggestions =
|
||||||
TagSuggestions::read_from_file("tag_terms.txt").expect("expected tag file to load");
|
TagSuggestions::read_from_file("tag_terms.txt").expect("expected tag file to load");
|
||||||
|
|
||||||
let connection = &mut establish_connection();
|
let connection = &mut get_connection_pool().get().expect("Expected a connection");
|
||||||
|
|
||||||
let file_str = env::args().nth(1).expect("Need just one argument.");
|
let file_str = env::args().nth(1).expect("Need just one argument.");
|
||||||
let tags = suggestions.get_suggestions(&file_str);
|
let tags = suggestions.get_suggestions(&file_str);
|
||||||
|
|
|
@ -2,7 +2,7 @@ use sample_amp::*;
|
||||||
use std::io::{stdin, stdout, Write};
|
use std::io::{stdin, stdout, Write};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let connection = &mut establish_connection();
|
let connection = &mut get_connection_pool().get().expect("Expected a connection.");
|
||||||
|
|
||||||
let mut name = String::new();
|
let mut name = String::new();
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
|
use itertools::Itertools;
|
||||||
|
use sample_amp::{get_connection_pool, list_tags};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let connection = &mut establish_connection();
|
let connection = &mut get_connection_pool().get().expect("Expected a connection");
|
||||||
println!(
|
println!(
|
||||||
"Found tags: {}",
|
"Found tags: {}",
|
||||||
list_tags(connection).iter().map(|t| &t.name).join(", ")
|
list_tags(connection).iter().map(|t| &t.name).join(", ")
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use sample_amp::{establish_connection, list_tags};
|
use sample_amp::{get_connection_pool, list_tags};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let connection = &mut establish_connection();
|
let connection = &mut get_connection_pool().get().expect("Expected a connection.");
|
||||||
println!(
|
println!(
|
||||||
"Found tags: {}",
|
"Found tags: {}",
|
||||||
list_tags(connection).iter().map(|t| &t.name).join(", ")
|
list_tags(connection).iter().map(|t| &t.name).join(", ")
|
||||||
|
|
|
@ -5,7 +5,7 @@ use sample_amp::*;
|
||||||
fn main() {
|
fn main() {
|
||||||
use self::schema::libraries::dsl::*;
|
use self::schema::libraries::dsl::*;
|
||||||
|
|
||||||
let connection = &mut establish_connection();
|
let connection = &mut get_connection_pool().get().expect("Expected a connection");
|
||||||
let results = libraries
|
let results = libraries
|
||||||
.limit(5)
|
.limit(5)
|
||||||
.select(Library::as_select())
|
.select(Library::as_select())
|
||||||
|
|
16
src/lib.rs
16
src/lib.rs
|
@ -1,4 +1,7 @@
|
||||||
use diesel::prelude::*;
|
use diesel::{
|
||||||
|
prelude::*,
|
||||||
|
r2d2::{ConnectionManager, Pool},
|
||||||
|
};
|
||||||
use dotenvy::dotenv;
|
use dotenvy::dotenv;
|
||||||
use models::{NewSample, Sample, Tag};
|
use models::{NewSample, Sample, Tag};
|
||||||
use std::{env, path::Path};
|
use std::{env, path::Path};
|
||||||
|
@ -9,12 +12,17 @@ pub mod models;
|
||||||
pub mod schema;
|
pub mod schema;
|
||||||
pub mod tag_terms;
|
pub mod tag_terms;
|
||||||
|
|
||||||
pub fn establish_connection() -> SqliteConnection {
|
pub fn get_connection_pool() -> Pool<ConnectionManager<SqliteConnection>> {
|
||||||
dotenv().ok();
|
dotenv().ok();
|
||||||
|
|
||||||
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
|
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
|
||||||
SqliteConnection::establish(&database_url)
|
|
||||||
.unwrap_or_else(|_| panic!("Error connecting to {}", database_url))
|
let manager = ConnectionManager::<SqliteConnection>::new(database_url);
|
||||||
|
|
||||||
|
Pool::builder()
|
||||||
|
.test_on_check_out(true)
|
||||||
|
.build(manager)
|
||||||
|
.expect("Could not build connection pool")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_library(conn: &mut SqliteConnection, name: &str) -> Library {
|
pub fn create_library(conn: &mut SqliteConnection, name: &str) -> Library {
|
||||||
|
|
172
src/main.rs
172
src/main.rs
|
@ -1,36 +1,70 @@
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
|
use diesel::r2d2::{ConnectionManager, Pool};
|
||||||
use gtk::gdk::Display;
|
use gtk::gdk::Display;
|
||||||
use gtk::glib::BoxedAnyObject;
|
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
use relm4::{factory::FactoryVecDeque, prelude::*};
|
use relm4::{factory::FactoryVecDeque, prelude::*};
|
||||||
use std::cell::Ref;
|
|
||||||
|
|
||||||
mod library_list;
|
mod library_list;
|
||||||
|
mod sample_list;
|
||||||
use library_list::LibraryListItem;
|
use library_list::LibraryListItem;
|
||||||
mod app_msg;
|
mod app_msg;
|
||||||
use app_msg::AppMsg;
|
use app_msg::AppMsg;
|
||||||
use sample_amp::establish_connection;
|
use sample_amp::get_connection_pool;
|
||||||
use sample_amp::models::Library;
|
use sample_amp::models::Library;
|
||||||
use sample_amp::schema::libraries;
|
use sample_amp::schema::libraries;
|
||||||
|
|
||||||
struct AppModel {
|
use crate::sample_list::SampleListModel;
|
||||||
samples: gtk::MultiSelection,
|
|
||||||
libraries: FactoryVecDeque<LibraryListItem>,
|
|
||||||
connection: SqliteConnection,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Sample {
|
struct AppModel {
|
||||||
name: String,
|
sample_list: Controller<SampleListModel>,
|
||||||
bpm: f32,
|
libraries: FactoryVecDeque<LibraryListItem>,
|
||||||
key: String, // todo: key struct?
|
pool: Pool<ConnectionManager<SqliteConnection>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[relm4::component]
|
#[relm4::component]
|
||||||
impl SimpleComponent for AppModel {
|
impl SimpleComponent for AppModel {
|
||||||
|
type Input = AppMsg;
|
||||||
|
|
||||||
|
type Output = ();
|
||||||
type Init = ();
|
type Init = ();
|
||||||
|
|
||||||
type Input = AppMsg;
|
fn init(
|
||||||
type Output = ();
|
_: Self::Init,
|
||||||
|
window: &Self::Root,
|
||||||
|
sender: ComponentSender<Self>,
|
||||||
|
) -> relm4::ComponentParts<Self> {
|
||||||
|
let mut model = AppModel {
|
||||||
|
pool: get_connection_pool(),
|
||||||
|
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.pool.get().expect("Expected a 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<Self>) {
|
||||||
|
match message {
|
||||||
|
AppMsg::Close => {
|
||||||
|
relm4::main_application().quit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
view! {
|
view! {
|
||||||
gtk::Window {
|
gtk::Window {
|
||||||
|
@ -56,31 +90,8 @@ impl SimpleComponent for AppModel {
|
||||||
set_orientation: gtk::Orientation::Vertical,
|
set_orientation: gtk::Orientation::Vertical,
|
||||||
set_hexpand: true,
|
set_hexpand: true,
|
||||||
|
|
||||||
gtk::ScrolledWindow {
|
#[local_ref]
|
||||||
set_vexpand: true,
|
sample_view -> gtk::ScrolledWindow {},
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
gtk::Box {
|
gtk::Box {
|
||||||
set_height_request: 100,
|
set_height_request: 100,
|
||||||
|
@ -94,89 +105,6 @@ impl SimpleComponent for AppModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init(
|
|
||||||
_: Self::Init,
|
|
||||||
window: &Self::Root,
|
|
||||||
sender: ComponentSender<Self>,
|
|
||||||
) -> relm4::ComponentParts<Self> {
|
|
||||||
let factory_name = gtk::SignalListItemFactory::new();
|
|
||||||
factory_name.connect_bind(move |_factory, item| {
|
|
||||||
let item = item.downcast_ref::<gtk::ListItem>().unwrap();
|
|
||||||
let obj = item.item().and_downcast::<BoxedAnyObject>().unwrap();
|
|
||||||
let sample: Ref<Sample> = 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::<gtk::ListItem>().unwrap();
|
|
||||||
let obj = item.item().and_downcast::<BoxedAnyObject>().unwrap();
|
|
||||||
let sample: Ref<Sample> = 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::<gtk::ListItem>().unwrap();
|
|
||||||
let obj = item.item().and_downcast::<BoxedAnyObject>().unwrap();
|
|
||||||
let sample: Ref<Sample> = 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<Self>) {
|
|
||||||
match message {
|
|
||||||
AppMsg::Close => {
|
|
||||||
relm4::main_application().quit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_css() {
|
fn load_css() {
|
||||||
|
|
110
src/sample_list.rs
Normal file
110
src/sample_list.rs
Normal file
|
@ -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<Self>,
|
||||||
|
) -> relm4::ComponentParts<Self> {
|
||||||
|
let factory_name = gtk::SignalListItemFactory::new();
|
||||||
|
factory_name.connect_bind(move |_factory, item| {
|
||||||
|
let item = item.downcast_ref::<gtk::ListItem>().unwrap();
|
||||||
|
let obj = item.item().and_downcast::<BoxedAnyObject>().unwrap();
|
||||||
|
let sample: Ref<Sample> = 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::<gtk::ListItem>().unwrap();
|
||||||
|
let obj = item.item().and_downcast::<BoxedAnyObject>().unwrap();
|
||||||
|
let sample: Ref<Sample> = 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::<gtk::ListItem>().unwrap();
|
||||||
|
let obj = item.item().and_downcast::<BoxedAnyObject>().unwrap();
|
||||||
|
let sample: Ref<Sample> = 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 }
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue