graphview: introduce PortPresence

The port presence helps to know
if the port can be deleted or not.

XML Format break.
This commit is contained in:
Stéphane Cerveau 2022-01-18 16:00:37 +01:00
parent ef2a6ea1ba
commit 4bae12c011
4 changed files with 100 additions and 14 deletions

View file

@ -24,7 +24,11 @@ use xml::reader::XmlEvent as XMLREvent;
use xml::writer::EmitterConfig;
use xml::writer::XmlEvent as XMLWEvent;
use super::{link::Link, node::Node, node::NodeType, port::Port, port::PortDirection};
use super::{
link::Link,
node::{Node, NodeType},
port::{Port, PortDirection, PortPresence},
};
use once_cell::sync::Lazy;
use std::fs::File;
use std::io::BufReader;
@ -436,13 +440,25 @@ impl GraphView {
let _i = 0;
for _i in 0..input {
let port_id = self.next_port_id();
self.add_port(id, port_id, "in", PortDirection::Input);
self.add_port(
id,
port_id,
"in",
PortDirection::Input,
PortPresence::Always,
);
}
let _i = 0;
for _i in 0..output {
let port_id = self.next_port_id();
self.add_port(id, port_id, "out", PortDirection::Output);
self.add_port(
id,
port_id,
"out",
PortDirection::Output,
PortPresence::Always,
);
}
self.graph_updated();
}
@ -524,6 +540,7 @@ impl GraphView {
port_id: u32,
port_name: &str,
port_direction: PortDirection,
port_nature: PortPresence,
) {
let private = imp::GraphView::from_instance(self);
info!(
@ -531,7 +548,7 @@ impl GraphView {
port_id, node_id
);
if let Some(node) = private.nodes.borrow_mut().get_mut(&node_id) {
node.add_port(port_id, port_name, port_direction);
node.add_port(port_id, port_name, port_direction, port_nature);
} else {
error!(
"Node with id {} not found when trying to add port with id {} to graph",
@ -540,9 +557,19 @@ impl GraphView {
}
}
pub fn can_remove_port(&self, node_id: u32, port_id: u32) -> bool {
let private = imp::GraphView::from_instance(self);
let nodes = private.nodes.borrow();
if let Some(node) = nodes.get(&node_id) {
return node.can_remove_port(port_id);
}
warn!("Unable to find a node with the id {}", node_id);
false
}
/// Remove the port with id from node with id.
///
pub fn remove_port(&self, port_id: u32, node_id: u32) {
pub fn remove_port(&self, node_id: u32, port_id: u32) {
let private = imp::GraphView::from_instance(self);
let nodes = private.nodes.borrow();
if let Some(node) = nodes.get(&node_id) {
@ -835,7 +862,8 @@ impl GraphView {
XMLWEvent::start_element("Port")
.attr("name", &port.name())
.attr("id", &port.id().to_string())
.attr("direction", &port.direction().to_string()),
.attr("direction", &port.direction().to_string())
.attr("presence", &port.presence().to_string()),
)?;
writer.write(XMLWEvent::end_element())?;
}
@ -944,10 +972,15 @@ impl GraphView {
let direction: &String = attrs
.get::<String>(&String::from("direction"))
.expect("Unable to find port direction");
let default_value = PortPresence::Always.to_string();
let presence: &String = attrs
.get::<String>(&String::from("presence"))
.unwrap_or(&default_value);
current_port = Some(Port::new(
id.parse::<u32>().unwrap(),
name,
PortDirection::from_str(direction),
PortPresence::from_str(presence),
));
}
"Link" => {
@ -1009,6 +1042,7 @@ impl GraphView {
id,
&port.name(),
port.direction(),
port.presence(),
);
self.update_current_port_id(id);
}

View file

@ -8,4 +8,4 @@ pub use link::Link;
pub use node::Node;
pub use node::NodeType;
pub use port::Port;
pub use port::PortDirection;
pub use port::{PortDirection, PortPresence};

View file

@ -23,7 +23,7 @@ use gtk::subclass::prelude::*;
use log::trace;
use super::Port;
use super::PortDirection;
use super::{PortDirection, PortPresence};
use std::cell::{Cell, Ref, RefCell};
use std::collections::HashMap;
@ -210,9 +210,15 @@ impl Node {
self.set_description(&description);
}
pub fn add_port(&mut self, id: u32, name: &str, direction: PortDirection) {
pub fn add_port(
&mut self,
id: u32,
name: &str,
direction: PortDirection,
presence: PortPresence,
) {
let private = imp::Node::from_instance(self);
let port = Port::new(id, name, direction);
let port = Port::new(id, name, direction, presence);
match port.direction() {
PortDirection::Input => {
private.inputs.append(&port);
@ -248,6 +254,16 @@ impl Node {
private.ports.borrow().get(id).cloned()
}
pub fn can_remove_port(&self, id: u32) -> bool {
let private = imp::Node::from_instance(self);
if let Some(port) = private.ports.borrow().get(&id) {
if port.presence() != PortPresence::Always {
return true;
}
}
false
}
pub fn remove_port(&self, id: u32) {
let private = imp::Node::from_instance(self);
if let Some(port) = private.ports.borrow_mut().remove(&id) {

View file

@ -25,7 +25,7 @@ use gtk::{
use std::cell::Cell;
use std::{borrow::Borrow, fmt};
#[derive(Debug, Clone, PartialEq, Copy)]
#[derive(Debug, Clone, PartialOrd, PartialEq, Copy)]
pub enum PortDirection {
Input,
Output,
@ -44,23 +44,50 @@ impl PortDirection {
match port_direction_name {
"Input" => PortDirection::Input,
"Output" => PortDirection::Output,
"All" => PortDirection::Output,
"All" => PortDirection::All,
_ => PortDirection::Unknown,
}
}
}
/// Port's presence
#[derive(Debug, Clone, PartialEq, PartialOrd, Copy)]
pub enum PortPresence {
/// Can not be removed from his parent independantly
Always,
/// Can be removed from a node
Sometimes,
Unknown,
}
impl fmt::Display for PortPresence {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self)
}
}
impl PortPresence {
pub fn from_str(port_direction_name: &str) -> PortPresence {
match port_direction_name {
"Always" => PortPresence::Always,
"Sometimes" => PortPresence::Sometimes,
_ => PortPresence::Unknown,
}
}
}
mod imp {
use super::*;
use once_cell::unsync::OnceCell;
/// Graphical representation of a pipewire port.
/// Graphical representation of a port.
#[derive(Default, Clone)]
pub struct Port {
pub(super) label: OnceCell<gtk::Label>,
pub(super) id: OnceCell<u32>,
pub(super) direction: OnceCell<PortDirection>,
pub(super) selected: Cell<bool>,
pub(super) presence: OnceCell<PortPresence>,
}
#[glib::object_subclass]
@ -93,7 +120,7 @@ glib::wrapper! {
}
impl Port {
pub fn new(id: u32, name: &str, direction: PortDirection) -> Self {
pub fn new(id: u32, name: &str, direction: PortDirection, presence: PortPresence) -> Self {
// Create the widget and initialize needed fields
let port: Self = glib::Object::new(&[]).expect("Failed to create Port");
port.add_css_class("port");
@ -109,6 +136,10 @@ impl Port {
} else {
port.add_css_class("port-out");
}
private
.presence
.set(presence)
.expect("Port presence already set");
let label = gtk::Label::new(Some(name));
label.set_parent(&port);
@ -130,6 +161,11 @@ impl Port {
*private.direction.get().expect("Port direction is not set")
}
pub fn presence(&self) -> PortPresence {
let private = imp::Port::from_instance(self);
*private.presence.get().expect("Port presence is not set")
}
pub fn name(&self) -> String {
let private = imp::Port::from_instance(self);
let label = private.label.borrow().get().unwrap();