Skip to content

Commit

Permalink
Turn PwVolumeBox into a common parent class.
Browse files Browse the repository at this point in the history
  • Loading branch information
saivert committed Oct 4, 2023
1 parent 85efa4d commit 2da60b1
Show file tree
Hide file tree
Showing 10 changed files with 401 additions and 210 deletions.
2 changes: 2 additions & 0 deletions data/resources/resources.gresource.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
<file preprocess="xml-stripblanks" alias="gtk/window.ui">ui/window.ui</file>
<file preprocess="xml-stripblanks" alias="gtk/help-overlay.ui">ui/help-overlay.ui</file>
<file preprocess="xml-stripblanks" alias="gtk/output-dropdown.ui">ui/output-dropdown.ui</file>
<file preprocess="xml-stripblanks" alias="gtk/sinkbox.ui">ui/sinkbox.ui</file>
<file preprocess="xml-stripblanks" alias="gtk/outputbox.ui">ui/outputbox.ui</file>
</gresource>
<gresource prefix="/com/saivert/pwvucontrol/icons/scalable/actions">
<file preprocess="xml-stripblanks" alias="com.saivert.pwvucontrol.svg">../icons/com.saivert.pwvucontrol.svg</file>
Expand Down
19 changes: 19 additions & 0 deletions data/resources/ui/outputbox.ui
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- SPDX-License-Identifier: GPL-3.0-or-later -->
<interface>
<requires lib="gtk" version="4.0" />
<requires lib="Adw" version="1.0" />
<template class="PwOutputBox" parent="PwVolumeBox">
<child type="extra">
<object class="GtkLabel" id="onlabel">
<property name="label" translatable="yes">on</property>
<!-- <property name="visible" bind-source="outputdevice_dropdown"
bind-property="visible" bind-flags="sync-create" /> -->
</object>

<object class="PwOutputDropDown" id="output_dropdown">
</object>
</child>
</template>

</interface>
21 changes: 21 additions & 0 deletions data/resources/ui/sinkbox.ui
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- SPDX-License-Identifier: GPL-3.0-or-later -->
<interface>
<requires lib="gtk" version="4.0" />
<requires lib="Adw" version="1.0" />
<template class="PwSinkBox" parent="PwVolumeBox">
<child type="extra">
<object class="GtkToggleButton" id="default_sink_toggle">
<property name="hexpand">0</property>
<property name="valign">center</property>
<signal name="toggled" handler="default_sink_toggle_toggled" swapped="true" />
<style>
<class name="suffixes" />
<class name="expander-row-arrow" />
</style>
<property name="icon-name">emblem-default-symbolic</property>
</object>
</child>
</template>

</interface>
16 changes: 0 additions & 16 deletions data/resources/ui/volumebox.ui
Original file line number Diff line number Diff line change
Expand Up @@ -267,21 +267,5 @@
</object>


<object class="GtkLabel" id="onlabel">
<property name="label" translatable="yes">on</property>
<!-- <property name="visible" bind-source="outputdevice_dropdown"
bind-property="visible" bind-flags="sync-create" /> -->
</object>

<object class="GtkToggleButton" id="default_sink_toggle">
<property name="hexpand">0</property>
<property name="valign">center</property>
<signal name="toggled" handler="default_sink_toggle_toggled" swapped="true"/>
<style>
<class name="suffixes" />
<class name="expander-row-arrow" />
</style>
<property name="icon-name">emblem-default-symbolic</property>
</object>

</interface>
6 changes: 4 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ mod volumebox;
mod window;
mod manager;
mod withdefaultlistmodel;

mod output_dropdown;
mod sinkbox;
mod outputbox;

use std::{ffi::{OsStr, OsString}, path::PathBuf};

Expand Down Expand Up @@ -95,7 +97,7 @@ fn main() -> gtk::glib::ExitCode {
Some("resources.gresource"),
))
.or(gio::Resource::load(RESOURCES_FILE))
.expect(&gettext("Could not load resources"));
.unwrap_or_else(|_| { panic!("{}", gettext("Could not load resources")) });

// Load resources
gio::resources_register(&resources);
Expand Down
35 changes: 13 additions & 22 deletions src/volumebox/output_dropdown.rs → src/output_dropdown.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
// SPDX-License-Identifier: GPL-3.0-or-later

use glib::{self, closure_local};
use crate::{
withdefaultlistmodel::WithDefaultListModel,
pwnodeobject::PwNodeObject,
application::PwvucontrolApplication,
};
use glib::closure_local;
use gtk::{self, prelude::*, subclass::prelude::*};
use std::cell::{Cell, RefCell};
use crate::{withdefaultlistmodel::WithDefaultListModel, pwnodeobject::PwNodeObject, application::PwvucontrolApplication};
use wireplumber as wp;

mod imp {

use super::*;
use glib::Properties;
use gtk::{self, CompositeTemplate};


#[derive(Debug, Default, CompositeTemplate, Properties)]
#[derive(Debug, Default, gtk::CompositeTemplate, glib::Properties)]
#[properties(wrapper_type = super::PwOutputDropDown)]
#[template(resource = "/com/saivert/pwvucontrol/gtk/output-dropdown.ui")]
pub struct PwOutputDropDown {
Expand Down Expand Up @@ -65,19 +65,11 @@ mod imp {
let manager = app.manager();


fn setup_handler(item: &glib::Object, ellipsized: bool) {
fn setup_handler(item: &glib::Object) {
let item: &gtk::ListItem = item.downcast_ref().expect("ListItem");
let box_ = gtk::Box::new(gtk::Orientation::Horizontal, 0);
let label = gtk::Label::new(None);
box_.append(&label);
label.set_xalign(0.0);
if ellipsized {
label.set_ellipsize(gtk::pango::EllipsizeMode::End);
} else {
let icon = gtk::Image::from_icon_name("object-select-symbolic");
icon.set_accessible_role(gtk::AccessibleRole::Presentation);
box_.append(&icon);
}
label.set_ellipsize(gtk::pango::EllipsizeMode::End);

item.property_expression("item")
.chain_closure::<Option<String>>(closure_local!(
Expand All @@ -96,11 +88,11 @@ mod imp {
))
.bind(&label, "label", gtk::Widget::NONE);

item.set_child(Some(&box_));
item.set_child(Some(&label));
}

let factory = gtk::SignalListItemFactory::new();
factory.connect_setup(|_, item| setup_handler(item, true));
factory.connect_setup(|_, item| setup_handler(item));

// We need to store the DropDown widget's internal default factory so we can reset the list-factory later
// which would otherwise just use the factory we set
Expand All @@ -113,16 +105,15 @@ mod imp {

self.outputdevice_dropdown.set_enable_search(true);


self.outputdevice_dropdown
.set_expression(Some(gtk::ClosureExpression::new::<Option<String>>(
gtk::Expression::NONE,
closure_local!(move |item: glib::Object| {
if let Some(item) = item.downcast_ref::<PwNodeObject>() {
item.name()
} else if let Some(item) = item.downcast_ref::<gtk::StringObject>() {
Some(item.string().to_string())
} else {
None
item.downcast_ref::<gtk::StringObject>().map(|item| item.string().to_string())
}
}),
)));
Expand Down
171 changes: 171 additions & 0 deletions src/outputbox.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
// SPDX-License-Identifier: GPL-3.0-or-later

use crate::{
application::PwvucontrolApplication,
pwnodeobject::PwNodeObject,
volumebox::{PwVolumeBox, PwVolumeBoxImpl},
output_dropdown::PwOutputDropDown,
};
use glib::{closure_local, clone};
use gtk::{prelude::*, subclass::prelude::*};
use wireplumber as wp;

mod imp {
use super::*;

#[derive(Default, gtk::CompositeTemplate)]
#[template(resource = "/com/saivert/pwvucontrol/gtk/outputbox.ui")]
pub struct PwOutputBox {
#[template_child]
pub output_dropdown: TemplateChild<PwOutputDropDown>,
}

#[glib::object_subclass]
impl ObjectSubclass for PwOutputBox {
const NAME: &'static str = "PwOutputBox";
type Type = super::PwOutputBox;
type ParentType = PwVolumeBox;

fn class_init(klass: &mut Self::Class) {
klass.bind_template();
}

fn instance_init(obj: &glib::subclass::InitializingObject<Self>) {
obj.init_template();
}
}

impl ObjectImpl for PwOutputBox {
fn constructed(&self) {

let app = PwvucontrolApplication::default();
let manager = app.manager();

let obj = self.obj();
let parent: &PwVolumeBox = obj.upcast_ref();
let item = parent.row_data().expect("nodeobj");

parent.add_default_node_change_handler(clone!(@weak self as widget => move || {
widget.obj().update_output_device_dropdown();
}));

self.parent_constructed();


if let Some(metadata) = manager.imp().metadata.borrow().as_ref() {
let boundid = item.boundid();
let widget = self.obj();
let changed_closure = closure_local!(@watch widget =>
move |_obj: &wp::pw::Metadata, id: u32, key: Option<String>, _type: Option<String>, _value: Option<String>| {
let key = key.unwrap_or_default();
if id == boundid && key.contains("target.") {
wp::log::info!("metadata changed handler id: {boundid} {key:?} {_value:?}!");
widget.update_output_device_dropdown();
}
});
metadata.connect_closure("changed", false, changed_closure);
}

// Create our custom output dropdown widget and add it to the layout
self.output_dropdown.set_nodeobj(Some(&item));

glib::idle_add_local_once(clone!(@weak self as widget => move || {
widget.obj().update_output_device_dropdown();
}));
}

}
impl WidgetImpl for PwOutputBox {}
impl ListBoxRowImpl for PwOutputBox {}
impl PwVolumeBoxImpl for PwOutputBox {}

impl PwOutputBox {

}
}

glib::wrapper! {
pub struct PwOutputBox(ObjectSubclass<imp::PwOutputBox>)
@extends gtk::Widget, gtk::ListBoxRow, PwVolumeBox,
@implements gtk::Actionable;
}

impl PwOutputBox {
pub(crate) fn new(row_data: &impl glib::IsA<PwNodeObject>) -> Self {
glib::Object::builder()
.property("row-data", row_data)
// .property(
// "channelmodel",
// gio::ListStore::new::<crate::pwchannelobject::PwChannelObject>(),
// )
.build()
}

pub(crate) fn update_output_device_dropdown(&self) {
let app = PwvucontrolApplication::default();
let manager = app.manager();

let sinkmodel = &manager.imp().sinkmodel;

let imp = self.imp();
let parent: &PwVolumeBox = self.upcast_ref();

let output_dropdown = imp.output_dropdown.get();

let id = parent.imp().default_node.get();

let string = if let Ok(node) = sinkmodel.get_node(id) {
format!("Default ({})", node.name().unwrap())
} else {
"Default".to_string()
};
output_dropdown.set_default_text(&string);

let item = parent.row_data().expect("row_data in pwvolumebox");

if let Some(deftarget) = item.default_target() {
// let model: gio::ListModel = imp
// .outputdevice_dropdown
// .model()
// .expect("Model from dropdown")
// .downcast()
// .unwrap();
// let pos = model.iter::<glib::Object>().enumerate().find_map(|o| {
// if let Ok(Ok(node)) = o.1.map(|x| x.downcast::<PwNodeObject>()) {
// if node.boundid() == deftarget.boundid() {
// return Some(o.0);
// }
// }
// None
// });

if let Some(pos) = sinkmodel.get_node_pos_from_id(deftarget.boundid()) {
wp::log::info!(
"switching to preferred target pos={pos} boundid={} serial={}",
deftarget.boundid(),
deftarget.serial()
);
output_dropdown.set_selected_no_send(pos+1);
}
} else {
output_dropdown.set_selected_no_send(0);

// let id = self.imp().default_node.get();
// wp::log::info!("default_node is {id}");
// if id != u32::MAX {
// if let Some(pos) = sinkmodel.get_node_pos_from_id(id) {
// wp::log::info!("switching to default target");
// if true
// /* imp.outputdevice_dropdown.selected() != pos */
// {
// wp::log::info!("actually switching to default target");
// imp.outputdevice_dropdown_block_signal.set(true);
// imp.outputdevice_dropdown.set_selected(pos);
// imp.outputdevice_dropdown_block_signal.set(false);
// }
// }
// }
}
}

}
Loading

0 comments on commit 2da60b1

Please sign in to comment.