mirror of
https://gitlab.freedesktop.org/pipewire/helvum
synced 2026-03-15 03:26:10 +08:00
Group nodes into columns by major type
This commit is contained in:
@@ -11,7 +11,7 @@ use pipewire::{channel::Sender, spa::Direction};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
view::{self},
|
view::{self},
|
||||||
GtkMessage, MediaType, PipewireLink, PipewireMessage,
|
GtkMessage, MediaType, NodeType, PipewireLink, PipewireMessage,
|
||||||
};
|
};
|
||||||
|
|
||||||
static STYLE: &str = include_str!("style.css");
|
static STYLE: &str = include_str!("style.css");
|
||||||
@@ -108,7 +108,7 @@ impl Application {
|
|||||||
@weak app => @default-return Continue(true),
|
@weak app => @default-return Continue(true),
|
||||||
move |msg| {
|
move |msg| {
|
||||||
match msg {
|
match msg {
|
||||||
PipewireMessage::NodeAdded{ id, name } => app.add_node(id, name.as_str()),
|
PipewireMessage::NodeAdded{ id, name, node_type } => app.add_node(id, name.as_str(), node_type),
|
||||||
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, active} => app.add_link(id, node_from, port_from, node_to, port_to, active),
|
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::LinkStateChanged { id, active } => app.link_state_changed(id, active), // TODO
|
||||||
@@ -125,12 +125,14 @@ impl Application {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Add a new node to the view.
|
/// Add a new node to the view.
|
||||||
fn add_node(&self, id: u32, name: &str) {
|
fn add_node(&self, id: u32, name: &str, node_type: Option<NodeType>) {
|
||||||
info!("Adding node to graph: id {}", id);
|
info!("Adding node to graph: id {}", id);
|
||||||
|
|
||||||
imp::Application::from_instance(self)
|
imp::Application::from_instance(self).graphview.add_node(
|
||||||
.graphview
|
id,
|
||||||
.add_node(id, view::Node::new(name));
|
view::Node::new(name),
|
||||||
|
node_type,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a new port to the view.
|
/// Add a new port to the view.
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ enum PipewireMessage {
|
|||||||
NodeAdded {
|
NodeAdded {
|
||||||
id: u32,
|
id: u32,
|
||||||
name: String,
|
name: String,
|
||||||
|
node_type: Option<NodeType>,
|
||||||
},
|
},
|
||||||
PortAdded {
|
PortAdded {
|
||||||
id: u32,
|
id: u32,
|
||||||
@@ -55,6 +56,12 @@ enum PipewireMessage {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum NodeType {
|
||||||
|
Input,
|
||||||
|
Output,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub enum MediaType {
|
pub enum MediaType {
|
||||||
Audio,
|
Audio,
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ use pipewire::{
|
|||||||
Context, Core, MainLoop,
|
Context, Core, MainLoop,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{GtkMessage, MediaType, PipewireMessage};
|
use crate::{GtkMessage, MediaType, NodeType, PipewireMessage};
|
||||||
use state::{Item, State};
|
use state::{Item, State};
|
||||||
|
|
||||||
enum ProxyItem {
|
enum ProxyItem {
|
||||||
@@ -112,6 +112,27 @@ fn handle_node(
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let media_class = |class: &str| {
|
||||||
|
if class.contains("Sink") || class.contains("Input") {
|
||||||
|
Some(NodeType::Input)
|
||||||
|
} else if class.contains("Source") || class.contains("Output") {
|
||||||
|
Some(NodeType::Output)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let node_type = props
|
||||||
|
.get("media.category")
|
||||||
|
.and_then(|class| {
|
||||||
|
if class.contains("Duplex") {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
props.get("media.class").and_then(media_class)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.or_else(|| props.get("media.class").and_then(media_class));
|
||||||
|
|
||||||
state.borrow_mut().insert(
|
state.borrow_mut().insert(
|
||||||
node.id,
|
node.id,
|
||||||
Item::Node {
|
Item::Node {
|
||||||
@@ -121,7 +142,11 @@ fn handle_node(
|
|||||||
);
|
);
|
||||||
|
|
||||||
sender
|
sender
|
||||||
.send(PipewireMessage::NodeAdded { id: node.id, name })
|
.send(PipewireMessage::NodeAdded {
|
||||||
|
id: node.id,
|
||||||
|
name,
|
||||||
|
node_type,
|
||||||
|
})
|
||||||
.expect("Failed to send message");
|
.expect("Failed to send message");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,9 @@ use gtk::{
|
|||||||
};
|
};
|
||||||
use log::{error, warn};
|
use log::{error, warn};
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::{cmp::Ordering, collections::HashMap};
|
||||||
|
|
||||||
|
use crate::NodeType;
|
||||||
|
|
||||||
mod imp {
|
mod imp {
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -239,14 +241,37 @@ impl GraphView {
|
|||||||
glib::Object::new(&[]).expect("Failed to create GraphView")
|
glib::Object::new(&[]).expect("Failed to create GraphView")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_node(&self, id: u32, node: Node) {
|
pub fn add_node(&self, id: u32, node: Node, node_type: Option<NodeType>) {
|
||||||
let private = imp::GraphView::from_instance(self);
|
let private = imp::GraphView::from_instance(self);
|
||||||
node.set_parent(self);
|
node.set_parent(self);
|
||||||
|
|
||||||
// Place widgets in colums of 4, growing down, then right.
|
// Place widgets in colums of 3, growing down
|
||||||
// TODO: Make a better positioning algorithm.
|
let x = if let Some(node_type) = node_type {
|
||||||
let x = ((private.nodes.borrow().len() / 4) as f32 * 400.0) + 20.0; // This relies on integer division rounding down.
|
match node_type {
|
||||||
let y = (private.nodes.borrow().len() as f32 % 4.0 * 100.0) + 20.0;
|
NodeType::Output => 20.0,
|
||||||
|
NodeType::Input => 820.0,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
420.0
|
||||||
|
};
|
||||||
|
|
||||||
|
let y = private
|
||||||
|
.nodes
|
||||||
|
.borrow()
|
||||||
|
.values()
|
||||||
|
.map(|node| {
|
||||||
|
//Map nodes to locations
|
||||||
|
self.get_node_position(&node.clone().upcast())
|
||||||
|
})
|
||||||
|
.filter(|&(x2, _y)| {
|
||||||
|
//Only look in our column
|
||||||
|
(x - x2).abs() < 50.0
|
||||||
|
})
|
||||||
|
.max_by(|y1, y2| {
|
||||||
|
//Get max in column
|
||||||
|
y1.partial_cmp(y2).unwrap_or(Ordering::Equal)
|
||||||
|
})
|
||||||
|
.map_or(20_f32, |(_x, y)| y + 100.0);
|
||||||
|
|
||||||
self.move_node(&node.clone().upcast(), x, y);
|
self.move_node(&node.clone().upcast(), x, y);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user