mirror of
https://github.com/Xetibo/ReSet.git
synced 2025-07-01 15:57:46 +02:00
feat: Add dropdowns
This commit is contained in:
parent
c619284146
commit
0c286af82c
13 changed files with 297 additions and 54 deletions
|
@ -1,4 +1,3 @@
|
|||
use std::cell::RefCell;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
|
@ -8,10 +7,12 @@ use adw::prelude::{ButtonExt, RangeExt};
|
|||
use dbus::blocking::Connection;
|
||||
use dbus::Error;
|
||||
use glib::subclass::types::ObjectSubclassIsExt;
|
||||
use glib::{clone, Propagation};
|
||||
use glib::{clone, Cast, Propagation};
|
||||
use gtk::StringObject;
|
||||
use ReSet_Lib::audio::audio::OutputStream;
|
||||
|
||||
use super::outputStreamEntryImpl;
|
||||
use super::sourceBox::SourceBox;
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct OutputStreamEntry(ObjectSubclass<outputStreamEntryImpl::OutputStreamEntry>)
|
||||
|
@ -20,12 +21,13 @@ glib::wrapper! {
|
|||
}
|
||||
|
||||
impl OutputStreamEntry {
|
||||
pub fn new(stream: OutputStream) -> Self {
|
||||
pub fn new(source_box: Arc<SourceBox>, stream: OutputStream) -> Self {
|
||||
let obj: Self = Object::builder().build();
|
||||
// TODO use event callback for progress bar -> this is the "im speaking" indicator
|
||||
// TODO map mute to callback
|
||||
// TODO map dropdown
|
||||
{
|
||||
let box_imp = source_box.imp();
|
||||
let imp = obj.imp();
|
||||
let name = stream.application_name.clone() + ": " + stream.name.as_str();
|
||||
imp.resetSourceName.set_text(name.as_str());
|
||||
|
@ -40,17 +42,75 @@ impl OutputStreamEntry {
|
|||
let fraction = (value / 655.36).round();
|
||||
let percentage = (fraction).to_string() + "%";
|
||||
imp.resetVolumePercentage.set_text(&percentage);
|
||||
let stream = imp.stream.borrow();
|
||||
let mut stream = imp.stream.try_borrow();
|
||||
while stream.is_err() {
|
||||
stream = imp.stream.try_borrow();
|
||||
}
|
||||
let stream = stream.unwrap();
|
||||
let index = stream.index;
|
||||
let channels = stream.channels;
|
||||
set_outputstream_volume(value, index, channels);
|
||||
Propagation::Proceed
|
||||
}),
|
||||
);
|
||||
{
|
||||
let mut list = box_imp.resetModelList.try_borrow();
|
||||
while list.is_err() {
|
||||
list = box_imp.resetModelList.try_borrow();
|
||||
}
|
||||
let list = list.unwrap();
|
||||
imp.resetSelectedSource.set_model(Some(&*list));
|
||||
let mut map = box_imp.resetSourceMap.try_borrow();
|
||||
while map.is_err() {
|
||||
map = box_imp.resetSourceMap.try_borrow();
|
||||
}
|
||||
let map = map.unwrap();
|
||||
let mut name = box_imp.resetDefaultSource.try_borrow();
|
||||
while name.is_err() {
|
||||
name = box_imp.resetDefaultSource.try_borrow();
|
||||
}
|
||||
let name = name.unwrap();
|
||||
let name = &name.alias;
|
||||
let index = map.get(name);
|
||||
if index.is_some() {
|
||||
imp.resetSelectedSource.set_selected(index.unwrap().1);
|
||||
}
|
||||
}
|
||||
imp.resetSelectedSource.connect_selected_notify(
|
||||
clone!(@weak imp, @weak box_imp => move |dropdown| {
|
||||
let selected = dropdown.selected_item();
|
||||
if selected.is_none() {
|
||||
return;
|
||||
}
|
||||
let selected = selected.unwrap();
|
||||
let selected = selected.downcast_ref::<StringObject>().unwrap();
|
||||
let selected = selected.string().to_string();
|
||||
let mut source = box_imp.resetSourceMap.try_borrow();
|
||||
while source.is_err() {
|
||||
source = box_imp.resetSourceMap.try_borrow();
|
||||
}
|
||||
let source = source.unwrap();
|
||||
let source = source.get(&selected);
|
||||
if source.is_none() {
|
||||
return;
|
||||
}
|
||||
let mut stream = imp.stream.try_borrow();
|
||||
while stream.is_err() {
|
||||
stream = imp.stream.try_borrow();
|
||||
}
|
||||
let stream = stream.unwrap();
|
||||
let source = source.unwrap().0;
|
||||
set_source_of_output_stream(stream.index, source);
|
||||
}),
|
||||
);
|
||||
imp.resetSourceMute
|
||||
.connect_clicked(clone!(@weak imp => move |_| {
|
||||
let stream = imp.stream.clone();
|
||||
let mut stream = stream.borrow_mut();
|
||||
let mut stream = stream.try_borrow_mut();
|
||||
while stream.is_err() {
|
||||
stream = imp.stream.try_borrow_mut();
|
||||
}
|
||||
let mut stream = stream.unwrap();
|
||||
stream.muted = !stream.muted;
|
||||
let muted = stream.muted;
|
||||
let index = stream.index;
|
||||
|
@ -100,3 +160,21 @@ fn toggle_output_stream_mute(index: u32, muted: bool) -> bool {
|
|||
}
|
||||
res.unwrap().0
|
||||
}
|
||||
|
||||
fn set_source_of_output_stream(stream: u32, source: u32) -> bool {
|
||||
let conn = Connection::new_session().unwrap();
|
||||
let proxy = conn.with_proxy(
|
||||
"org.xetibo.ReSet",
|
||||
"/org/xetibo/ReSet",
|
||||
Duration::from_millis(1000),
|
||||
);
|
||||
let res: Result<(bool,), Error> = proxy.method_call(
|
||||
"org.xetibo.ReSet",
|
||||
"SetSourceOfOutputStream",
|
||||
(stream, source),
|
||||
);
|
||||
if res.is_err() {
|
||||
return false;
|
||||
}
|
||||
res.unwrap().0
|
||||
}
|
||||
|
|
|
@ -2,9 +2,9 @@ use std::cell::RefCell;
|
|||
use std::sync::Arc;
|
||||
|
||||
use crate::components::input::outputStreamEntry;
|
||||
use ReSet_Lib::audio::audio::OutputStream;
|
||||
use gtk::subclass::prelude::*;
|
||||
use gtk::{glib, Button, CompositeTemplate, Label, ProgressBar, Scale, DropDown};
|
||||
use gtk::{glib, Button, CompositeTemplate, DropDown, Label, ProgressBar, Scale};
|
||||
use ReSet_Lib::audio::audio::OutputStream;
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[derive(Default, CompositeTemplate)]
|
||||
|
@ -23,6 +23,7 @@ pub struct OutputStreamEntry {
|
|||
#[template_child]
|
||||
pub resetVolumeMeter: TemplateChild<ProgressBar>,
|
||||
pub stream: Arc<RefCell<OutputStream>>,
|
||||
pub associatedSource: Arc<RefCell<(u32, String)>>,
|
||||
}
|
||||
|
||||
#[glib::object_subclass]
|
||||
|
@ -45,4 +46,3 @@ impl BoxImpl for OutputStreamEntry {}
|
|||
impl ObjectImpl for OutputStreamEntry {}
|
||||
|
||||
impl WidgetImpl for OutputStreamEntry {}
|
||||
|
||||
|
|
|
@ -11,13 +11,13 @@ use adw::prelude::{BoxExt, ButtonExt, ListBoxRowExt, RangeExt};
|
|||
use dbus::blocking::Connection;
|
||||
use dbus::Error;
|
||||
use glib::subclass::prelude::ObjectSubclassIsExt;
|
||||
use glib::{Propagation, Variant};
|
||||
use gtk::gio;
|
||||
use glib::{clone, Cast, Propagation, Variant};
|
||||
use gtk::prelude::ActionableExt;
|
||||
use gtk::{gio, StringObject};
|
||||
use ReSet_Lib::audio::audio::{OutputStream, Source};
|
||||
|
||||
use super::outputStreamEntry::OutputStreamEntry;
|
||||
use super::sourceEntry::{toggle_source_mute, SourceEntry};
|
||||
use super::sourceEntry::{set_default_source, toggle_source_mute, SourceEntry};
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct SourceBox(ObjectSubclass<sourceBoxImpl::SourceBox>)
|
||||
|
@ -51,13 +51,23 @@ impl SourceBox {
|
|||
pub fn populate_sources(output_box: Arc<SourceBox>) {
|
||||
gio::spawn_blocking(move || {
|
||||
let output_box_imp = output_box.imp();
|
||||
let sinks = get_sources();
|
||||
let sources = get_sources();
|
||||
{
|
||||
let list = output_box_imp.resetModelList.borrow_mut();
|
||||
let mut map = output_box_imp.resetSourceMap.borrow_mut();
|
||||
let mut i: u32 = 0;
|
||||
for source in sources.iter() {
|
||||
list.append(&source.alias);
|
||||
map.insert(source.alias.clone(), (source.index, i, source.name.clone()));
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
output_box_imp
|
||||
.resetDefaultSource
|
||||
.replace(get_default_source());
|
||||
glib::spawn_future(async move {
|
||||
glib::idle_add_once(move || {
|
||||
// TODO handle default mapping
|
||||
// TODO handle events
|
||||
let output_box_ref_slider = output_box.clone();
|
||||
let output_box_ref_mute = output_box.clone();
|
||||
let output_box_ref = output_box.clone();
|
||||
|
@ -71,15 +81,49 @@ pub fn populate_sources(output_box: Arc<SourceBox>) {
|
|||
let percentage = (fraction).to_string() + "%";
|
||||
output_box_imp.resetVolumePercentage.set_text(&percentage);
|
||||
output_box_imp.resetVolumeSlider.set_value(*volume as f64);
|
||||
for stream in sinks {
|
||||
for stream in sources {
|
||||
let mut is_default = false;
|
||||
if output_box_imp.resetDefaultSource.borrow().name == stream.name {
|
||||
is_default = true;
|
||||
}
|
||||
let entry = ListEntry::new(&SourceEntry::new(is_default, output_box_imp.resetDefaultCheckButton.clone(), stream));
|
||||
let entry = ListEntry::new(&SourceEntry::new(
|
||||
is_default,
|
||||
output_box_imp.resetDefaultCheckButton.clone(),
|
||||
stream,
|
||||
));
|
||||
entry.set_activatable(false);
|
||||
output_box_imp.resetSources.append(&entry);
|
||||
}
|
||||
let list = output_box_imp.resetModelList.borrow();
|
||||
output_box_imp.resetSourceDropdown.set_model(Some(&*list));
|
||||
let map = output_box_imp.resetSourceMap.borrow();
|
||||
let name = output_box_imp.resetDefaultSource.borrow();
|
||||
let name = &name.alias;
|
||||
let index = map.get(name);
|
||||
if index.is_some() {
|
||||
output_box_imp
|
||||
.resetSourceDropdown
|
||||
.set_selected(index.unwrap().1);
|
||||
}
|
||||
output_box_imp.resetSourceDropdown.connect_selected_notify(
|
||||
clone!(@weak output_box_imp => move |dropdown| {
|
||||
let selected = dropdown.selected_item();
|
||||
if selected.is_none() {
|
||||
return;
|
||||
}
|
||||
let selected = selected.unwrap();
|
||||
let selected = selected.downcast_ref::<StringObject>().unwrap();
|
||||
let selected = selected.string().to_string();
|
||||
|
||||
let source = output_box_imp.resetSourceMap.borrow();
|
||||
let source = source.get(&selected);
|
||||
if source.is_none() {
|
||||
return;
|
||||
}
|
||||
let sink = Arc::new(source.unwrap().2.clone());
|
||||
set_default_source(sink);
|
||||
}),
|
||||
);
|
||||
}
|
||||
output_box_ref
|
||||
.imp()
|
||||
|
@ -121,7 +165,7 @@ pub fn populate_sources(output_box: Arc<SourceBox>) {
|
|||
});
|
||||
}
|
||||
|
||||
pub fn populate_outputstreams(listeners: Arc<Listeners>, output_box: Arc<SourceBox>) {
|
||||
pub fn populate_outputstreams(_listeners: Arc<Listeners>, output_box: Arc<SourceBox>) {
|
||||
// TODO add listener
|
||||
let output_box_ref = output_box.clone();
|
||||
|
||||
|
@ -131,7 +175,7 @@ pub fn populate_outputstreams(listeners: Arc<Listeners>, output_box: Arc<SourceB
|
|||
glib::idle_add_once(move || {
|
||||
let output_box_imp = output_box_ref.imp();
|
||||
for stream in streams {
|
||||
let entry = ListEntry::new(&OutputStreamEntry::new(stream));
|
||||
let entry = ListEntry::new(&OutputStreamEntry::new(output_box.clone(), stream));
|
||||
entry.set_activatable(false);
|
||||
output_box_imp.resetOutputStreams.append(&entry);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use crate::components::base::listEntry::ListEntry;
|
||||
use crate::components::input::sourceBox;
|
||||
use gtk::subclass::prelude::*;
|
||||
use gtk::{glib, CompositeTemplate, DropDown, TemplateChild, CheckButton};
|
||||
use gtk::{glib, CheckButton, CompositeTemplate, DropDown, StringList, TemplateChild};
|
||||
use gtk::{prelude::*, Button, Label, ProgressBar, Scale};
|
||||
use ReSet_Lib::audio::audio::{OutputStream, Source};
|
||||
|
||||
|
@ -37,6 +38,9 @@ pub struct SourceBox {
|
|||
pub resetDefaultSource: Arc<RefCell<Source>>,
|
||||
pub resetSourceList: Arc<Mutex<Vec<Source>>>,
|
||||
pub resetOutputStreamList: Arc<Mutex<Vec<OutputStream>>>,
|
||||
pub resetModelList: Arc<RefCell<StringList>>,
|
||||
// first u32 is the index of the source, the second the index in the model list
|
||||
pub resetSourceMap: Arc<RefCell<HashMap<String, (u32, u32, String)>>>,
|
||||
}
|
||||
|
||||
#[glib::object_subclass]
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use std::cell::RefCell;
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
@ -25,13 +24,10 @@ impl SourceEntry {
|
|||
pub fn new(is_default: bool, check_group: Arc<CheckButton>, stream: Source) -> Self {
|
||||
let obj: Self = Object::builder().build();
|
||||
// TODO use event callback for progress bar -> this is the "im speaking" indicator
|
||||
// TODO map the slider to volume
|
||||
// TODO properly use volume fraction
|
||||
// TODO map mute to callback
|
||||
// TODO map dropdown
|
||||
// TODO handle events
|
||||
{
|
||||
let imp = obj.imp();
|
||||
imp.resetSourceName.set_text(stream.name.clone().as_str());
|
||||
imp.resetSourceName.set_text(stream.alias.clone().as_str());
|
||||
let name = Arc::new(stream.name.clone());
|
||||
let volume = stream.volume.first().unwrap_or_else(|| &(0 as u32));
|
||||
let fraction = (*volume as f64 / 655.36).round();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue