From 4bae12c0118a181a3d4b18c0e6ec2fa7456384d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Cerveau?= Date: Tue, 18 Jan 2022 16:00:37 +0100 Subject: [PATCH] graphview: introduce PortPresence The port presence helps to know if the port can be deleted or not. XML Format break. --- src/graphmanager/graphview.rs | 46 ++++++++++++++++++++++++++++++----- src/graphmanager/mod.rs | 2 +- src/graphmanager/node.rs | 22 ++++++++++++++--- src/graphmanager/port.rs | 44 ++++++++++++++++++++++++++++++--- 4 files changed, 100 insertions(+), 14 deletions(-) diff --git a/src/graphmanager/graphview.rs b/src/graphmanager/graphview.rs index 7587569..6943d3f 100644 --- a/src/graphmanager/graphview.rs +++ b/src/graphmanager/graphview.rs @@ -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::from("direction")) .expect("Unable to find port direction"); + let default_value = PortPresence::Always.to_string(); + let presence: &String = attrs + .get::(&String::from("presence")) + .unwrap_or(&default_value); current_port = Some(Port::new( id.parse::().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); } diff --git a/src/graphmanager/mod.rs b/src/graphmanager/mod.rs index e5b529d..c352fbb 100644 --- a/src/graphmanager/mod.rs +++ b/src/graphmanager/mod.rs @@ -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}; diff --git a/src/graphmanager/node.rs b/src/graphmanager/node.rs index 8ddb51d..1505b11 100644 --- a/src/graphmanager/node.rs +++ b/src/graphmanager/node.rs @@ -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) { diff --git a/src/graphmanager/port.rs b/src/graphmanager/port.rs index f4f88ec..bf67670 100644 --- a/src/graphmanager/port.rs +++ b/src/graphmanager/port.rs @@ -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, pub(super) id: OnceCell, pub(super) direction: OnceCell, pub(super) selected: Cell, + pub(super) presence: OnceCell, } #[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();