view: Draw a dashed line for links that are not active

This commit is contained in:
Tom A. Wagner
2021-07-08 13:37:37 +02:00
parent be9339472e
commit 179665778d
4 changed files with 64 additions and 12 deletions

View File

@@ -110,7 +110,8 @@ impl Application {
match msg { match msg {
PipewireMessage::NodeAdded{ id, name } => app.add_node(id, name.as_str()), PipewireMessage::NodeAdded{ id, name } => app.add_node(id, name.as_str()),
PipewireMessage::PortAdded{ id, node_id, name, direction, media_type } => app.add_port(id, name.as_str(), node_id, direction, media_type), PipewireMessage::PortAdded{ id, node_id, name, direction, media_type } => app.add_port(id, name.as_str(), node_id, direction, media_type),
PipewireMessage::LinkAdded{ id, node_from, port_from, node_to, port_to} => app.add_link(id, node_from, port_from, node_to, port_to), PipewireMessage::LinkAdded{ id, node_from, port_from, node_to, port_to, active} => app.add_link(id, node_from, port_from, node_to, port_to, active),
PipewireMessage::LinkStateChanged { id, active } => app.link_state_changed(id, active), // TODO
PipewireMessage::NodeRemoved { id } => app.remove_node(id), PipewireMessage::NodeRemoved { id } => app.remove_node(id),
PipewireMessage::PortRemoved { id, node_id } => app.remove_port(id, node_id), PipewireMessage::PortRemoved { id, node_id } => app.remove_port(id, node_id),
PipewireMessage::LinkRemoved { id } => app.remove_link(id) PipewireMessage::LinkRemoved { id } => app.remove_link(id)
@@ -124,7 +125,7 @@ impl Application {
} }
/// Add a new node to the view. /// Add a new node to the view.
pub fn add_node(&self, id: u32, name: &str) { fn add_node(&self, id: u32, name: &str) {
info!("Adding node to graph: id {}", id); info!("Adding node to graph: id {}", id);
imp::Application::from_instance(self) imp::Application::from_instance(self)
@@ -133,7 +134,7 @@ impl Application {
} }
/// Add a new port to the view. /// Add a new port to the view.
pub fn add_port( fn add_port(
&self, &self,
id: u32, id: u32,
name: &str, name: &str,
@@ -168,7 +169,15 @@ impl Application {
} }
/// Add a new link to the view. /// Add a new link to the view.
pub fn add_link(&self, id: u32, node_from: u32, port_from: u32, node_to: u32, port_to: u32) { fn add_link(
&self,
id: u32,
node_from: u32,
port_from: u32,
node_to: u32,
port_to: u32,
active: bool,
) {
info!("Adding link to graph: id {}", id); info!("Adding link to graph: id {}", id);
// FIXME: Links should be colored depending on the data they carry (video, audio, midi) like ports are. // FIXME: Links should be colored depending on the data they carry (video, audio, midi) like ports are.
@@ -182,9 +191,22 @@ impl Application {
node_to, node_to,
port_to, port_to,
}, },
active,
); );
} }
fn link_state_changed(&self, id: u32, active: bool) {
info!(
"Link state changed: Link (id={}) is now {}",
id,
if active { "active" } else { "inactive" }
);
imp::Application::from_instance(self)
.graphview
.set_link_state(id, active);
}
// Toggle a link between the two specified ports on the remote pipewire server. // Toggle a link between the two specified ports on the remote pipewire server.
fn toggle_link(&self, port_from: u32, port_to: u32) { fn toggle_link(&self, port_from: u32, port_to: u32) {
let imp = imp::Application::from_instance(self); let imp = imp::Application::from_instance(self);

View File

@@ -37,6 +37,11 @@ enum PipewireMessage {
port_from: u32, port_from: u32,
node_to: u32, node_to: u32,
port_to: u32, port_to: u32,
active: bool,
},
LinkStateChanged {
id: u32,
active: bool,
}, },
NodeRemoved { NodeRemoved {
id: u32, id: u32,

View File

@@ -5,7 +5,7 @@ use std::{cell::RefCell, collections::HashMap, rc::Rc};
use gtk::glib::{self, clone}; use gtk::glib::{self, clone};
use log::{debug, info, warn}; use log::{debug, info, warn};
use pipewire::{ use pipewire::{
link::{Link, LinkListener}, link::{Link, LinkChangeMask, LinkListener, LinkState},
prelude::*, prelude::*,
properties, properties,
registry::{GlobalObject, Registry}, registry::{GlobalObject, Registry},
@@ -193,7 +193,13 @@ fn handle_link(
let mut state = state.borrow_mut(); let mut state = state.borrow_mut();
if let Some(Item::Link { .. }) = state.get(id) { if let Some(Item::Link { .. }) = state.get(id) {
// Info was an update - figure out if we should notify the gtk thread // Info was an update - figure out if we should notify the gtk thread
// TODO if info.change_mask().contains(LinkChangeMask::STATE) {
sender.send(PipewireMessage::LinkStateChanged {
id,
active: matches!(info.state(), LinkState::Active)
}).expect("Failed to send message");
}
// TODO -- check other values that might have changed
} else { } else {
// First time we get info. We can now notify the gtk thread of a new link. // First time we get info. We can now notify the gtk thread of a new link.
let node_from = info.output_node_id(); let node_from = info.output_node_id();
@@ -210,7 +216,8 @@ fn handle_link(
node_from, node_from,
port_from, port_from,
node_to, node_to,
port_to port_to,
active: matches!(info.state(), LinkState::Active)
}).expect( }).expect(
"Failed to send message" "Failed to send message"
); );

View File

@@ -20,7 +20,8 @@ mod imp {
#[derive(Default)] #[derive(Default)]
pub struct GraphView { pub struct GraphView {
pub(super) nodes: RefCell<HashMap<u32, Node>>, pub(super) nodes: RefCell<HashMap<u32, Node>>,
pub(super) links: RefCell<HashMap<u32, crate::PipewireLink>>, /// Stores the link and whether it is currently active.
pub(super) links: RefCell<HashMap<u32, (crate::PipewireLink, bool)>>,
} }
#[glib::object_subclass] #[glib::object_subclass]
@@ -150,10 +151,17 @@ mod imp {
.expect("Failed to get cairo context"); .expect("Failed to get cairo context");
link_cr.set_line_width(2.0); link_cr.set_line_width(2.0);
link_cr.set_source_rgb(0.0, 0.0, 0.0); link_cr.set_source_rgb(0.0, 0.0, 0.0);
for link in self.links.borrow().values() { for (link, active) in self.links.borrow().values() {
if let Some((from_x, from_y, to_x, to_y)) = self.get_link_coordinates(link) { if let Some((from_x, from_y, to_x, to_y)) = self.get_link_coordinates(link) {
link_cr.move_to(from_x, from_y); link_cr.move_to(from_x, from_y);
// Use dashed line for inactive links, full line otherwise.
if *active {
link_cr.set_dash(&[], 0.0);
} else {
link_cr.set_dash(&[10.0, 5.0], 0.0);
}
// Place curve control offset by half the x distance between the two points. // Place curve control offset by half the x distance between the two points.
// This makes the curve scale well for varying distances between the two ports, // This makes the curve scale well for varying distances between the two ports,
// especially when the output port is farther right than the input port. // especially when the output port is farther right than the input port.
@@ -276,12 +284,22 @@ impl GraphView {
} }
} }
pub fn add_link(&self, link_id: u32, link: crate::PipewireLink) { pub fn add_link(&self, link_id: u32, link: crate::PipewireLink, active: bool) {
let private = imp::GraphView::from_instance(self); let private = imp::GraphView::from_instance(self);
private.links.borrow_mut().insert(link_id, link); private.links.borrow_mut().insert(link_id, (link, active));
self.queue_draw(); self.queue_draw();
} }
pub fn set_link_state(&self, link_id: u32, active: bool) {
let private = imp::GraphView::from_instance(self);
if let Some((_, state)) = private.links.borrow_mut().get_mut(&link_id) {
*state = active;
self.queue_draw();
} else {
warn!("Link state changed on unknown link (id={})", link_id);
}
}
pub fn remove_link(&self, id: u32) { pub fn remove_link(&self, id: u32) {
let private = imp::GraphView::from_instance(self); let private = imp::GraphView::from_instance(self);
let mut links = private.links.borrow_mut(); let mut links = private.links.borrow_mut();