From aaf47503fe507a748ca1d20e5450b7d6528f0841 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Cerveau?= Date: Fri, 11 Aug 2023 11:34:47 +0200 Subject: [PATCH] graphmanager: add link name Allow to set and display a link name --- src/graphmanager/graphview.rs | 96 +++++++++++++++++++++++++++-------- src/graphmanager/link.rs | 49 ++++++++++-------- src/graphmanager/mod.rs | 8 ++- 3 files changed, 107 insertions(+), 46 deletions(-) diff --git a/src/graphmanager/graphview.rs b/src/graphmanager/graphview.rs index cf67cec..b280d04 100644 --- a/src/graphmanager/graphview.rs +++ b/src/graphmanager/graphview.rs @@ -144,7 +144,7 @@ mod imp { let target = widget.pick(x, y, gtk::PickFlags::DEFAULT).expect("port pick() did not return a widget"); if let Some(target) = target.ancestor(Port::static_type()) { let port = target.dynamic_cast::().expect("click event is not on the Port"); - let node = port.ancestor(Node::static_type()).expect("Unable to reach parent").dynamic_cast::().expect("Unable to cast to Node"); + let node = port.ancestor(Node::static_type()).expect("Unable to reach parent").dynamic_cast::().expect("Unable to cast to Node"); obj.emit_by_name::<()>("port-right-clicked", &[&port.id(), &node.id(), &graphene::Point::new(x as f32,y as f32)]); } else if let Some(target) = target.ancestor(Node::static_type()) { let node = target.dynamic_cast::().expect("click event is not on the Node"); @@ -204,7 +204,6 @@ mod imp { node_to.id(), port_from.id(), port_to.id(), - true, )); } widget.set_selected_port(None); @@ -225,7 +224,13 @@ mod imp { info!("double clicked node id {}", node.id()); obj.emit_by_name::<()>("node-double-clicked", &[&node.id(), &graphene::Point::new(x as f32,y as f32)]); } + } else if _n_press % 2 == 0 { + if let Some(link) = widget.point_on_link(&graphene::Point::new(x.floor() as f32,y.floor() as f32)) { + info!("double clicked link id {}", link.id()); + obj.emit_by_name::<()>("link-double-clicked", &[&link.id(), &graphene::Point::new(x as f32,y as f32)]); + } } + // Click to something else than a port widget.set_selected_port(None); } @@ -289,6 +294,9 @@ mod imp { Signal::builder("port-added") .param_types([u32::static_type(), u32::static_type(), u32::static_type()]) .build(), + Signal::builder("link-double-clicked") + .param_types([u32::static_type(), graphene::Point::static_type()]) + .build(), ] }); SIGNALS.as_ref() @@ -310,8 +318,9 @@ mod imp { if let Some((from_x, from_y, to_x, to_y)) = self.link_coordinates(link) { self.draw_link( snapshot, - link.active, + link.active(), link.selected(), + link.name().as_str(), link.thickness as f64, &graphene::Point::new(from_x as f32, from_y as f32), &graphene::Point::new(to_x as f32, to_y as f32), @@ -335,6 +344,7 @@ mod imp { snapshot, false, false, + "", 2.0, &graphene::Point::new(from_x as f32, from_y as f32), &graphene::Point::new(to_x as f32, to_y as f32), @@ -403,12 +413,13 @@ mod imp { let (to_x, to_y) = self.link_to_coordinates(link.node_to, link.port_to); Some((from_x, from_y, to_x, to_y)) } - + #[allow(clippy::too_many_arguments)] fn draw_link( &self, snapshot: >k::Snapshot, active: bool, selected: bool, + name: &str, thickness: f64, point_from: &graphene::Point, point_to: &graphene::Point, @@ -441,6 +452,13 @@ mod imp { if let Err(e) = link_cr.stroke() { warn!("Failed to draw graphview links: {}", e); }; + warn!("the link name is {}", name); + if !name.is_empty() { + let x = (point_from.x() + point_to.x()) / 2.0 + 20.0; + let y = (point_from.y() + point_to.y()) / 2.0 + 20.0; + link_cr.move_to(x as f64, y as f64); + let _ = link_cr.show_text(name); + } } } } @@ -739,7 +757,6 @@ impl GraphView { node_to_id: u32, port_from_id: u32, port_to_id: u32, - active: bool, ) -> Link { self.create_link_with_id( self.next_link_id(), @@ -747,7 +764,6 @@ impl GraphView { node_to_id, port_from_id, port_to_id, - active, ) } @@ -766,7 +782,7 @@ impl GraphView { pub fn set_link_state(&self, link_id: u32, active: bool) { let private = imp::GraphView::from_obj(self); if let Some(link) = private.links.borrow_mut().get_mut(&link_id) { - link.active = active; + link.set_active(active); self.queue_draw(); } else { warn!("Link state changed on unknown link (id={})", link_id); @@ -781,12 +797,37 @@ impl GraphView { let links = private.links.borrow(); let links_list: Vec<_> = links .iter() - .filter(|(_, link)| link.active == link_state) + .filter(|(_, link)| link.active() == link_state) .map(|(_, node)| node.clone()) .collect(); links_list } + /// Get the link with the specified link id inside the graphview. + /// + /// Returns `None` if the link is not in the graphview. + pub fn link(&self, id: u32) -> Option { + let private = imp::GraphView::from_obj(self); + private.links.borrow().get(&id).cloned() + } + + /// Set the link state with ink id and link state (boolean) + /// + pub fn set_link_name(&self, link_id: u32, name: &str) { + let private = imp::GraphView::from_obj(self); + let mut updated = false; + if let Some(link) = private.links.borrow_mut().get_mut(&link_id) { + link.set_name(name); + self.queue_draw(); + updated = true; + } else { + warn!("Link name changed on unknown link (id={})", link_id); + } + if updated { + self.graph_updated(); + } + } + /// Retrieves the node/port id connected to the input port id /// pub fn port_connected_to(&self, port_id: u32) -> Option<(u32, u32)> { @@ -799,6 +840,18 @@ impl GraphView { None } + /// Retrieves the link connected to the port id + /// + pub fn port_link(&self, port_id: u32) -> Option { + let private = imp::GraphView::from_obj(self); + for (_id, link) in private.links.borrow().iter() { + if port_id == link.port_from { + return Some(link.clone()); + } + } + None + } + /// Delete the selected element (link, node, port) /// pub fn delete_selected(&self) { @@ -891,7 +944,8 @@ impl GraphView { .attr("node_to", &link.node_to.to_string()) .attr("port_from", &link.port_from.to_string()) .attr("port_to", &link.port_to.to_string()) - .attr("active", &link.active.to_string()), + .attr("name", &link.name()) + .attr("active", &link.active().to_string()), )?; writer.write(XMLWEvent::end_element())?; } @@ -1022,14 +1076,21 @@ impl GraphView { let active: &String = attrs .get::(&String::from("active")) .expect("Unable to find link state"); - current_link = Some(self.create_link_with_id( + let default_value = String::from(""); + let name: &String = attrs + .get::(&String::from("name")) + .unwrap_or(&default_value); + let link = self.create_link_with_id( id.parse::().unwrap(), node_from.parse::().unwrap(), node_to.parse::().unwrap(), port_from.parse::().unwrap(), port_to.parse::().unwrap(), - active.parse::().unwrap(), - )); + ); + + link.set_active(active.parse::().unwrap()); + link.set_name(name.parse::().unwrap().as_str()); + current_link = Some(link); } _ => warn!("name unknown: {}", name), } @@ -1113,17 +1174,8 @@ impl GraphView { node_to_id: u32, port_from_id: u32, port_to_id: u32, - active: bool, ) -> Link { - Link::new( - link_id, - node_from_id, - node_to_id, - port_from_id, - port_to_id, - active, - false, - ) + Link::new(link_id, node_from_id, node_to_id, port_from_id, port_to_id) } fn remove_link(&self, id: u32) { diff --git a/src/graphmanager/link.rs b/src/graphmanager/link.rs index f313712..86469d6 100644 --- a/src/graphmanager/link.rs +++ b/src/graphmanager/link.rs @@ -8,7 +8,7 @@ // SPDX-License-Identifier: GPL-3.0-only use super::SelectionExt; -use std::cell::Cell; +use std::cell::{Cell, RefCell}; #[derive(Debug, Clone)] pub struct Link { @@ -17,44 +17,49 @@ pub struct Link { pub node_to: u32, pub port_from: u32, pub port_to: u32, - pub active: bool, + pub active: Cell, pub selected: Cell, pub thickness: u32, + pub name: RefCell, +} + +impl Link { + pub fn name(&self) -> String { + self.name.borrow().clone() + } + + pub fn set_name(&self, name: &str) { + self.name.replace(name.to_string()); + } + pub fn id(&self) -> u32 { + self.id + } + pub fn active(&self) -> bool { + self.active.get() + } + pub fn set_active(&self, active: bool) { + self.active.set(active) + } } pub trait LinkExt { /// Create a new link /// - fn new( - id: u32, - node_from: u32, - node_to: u32, - port_from: u32, - port_to: u32, - active: bool, - selected: bool, - ) -> Self; + fn new(id: u32, node_from: u32, node_to: u32, port_from: u32, port_to: u32) -> Self; } impl LinkExt for Link { - fn new( - id: u32, - node_from: u32, - node_to: u32, - port_from: u32, - port_to: u32, - active: bool, - selected: bool, - ) -> Self { + fn new(id: u32, node_from: u32, node_to: u32, port_from: u32, port_to: u32) -> Self { Self { id, node_from, node_to, port_from, port_to, - active, - selected: Cell::new(selected), + active: Cell::new(true), + selected: Cell::new(false), thickness: 4, + name: RefCell::new("".to_string()), } } } diff --git a/src/graphmanager/mod.rs b/src/graphmanager/mod.rs index 5f196fb..190ab54 100644 --- a/src/graphmanager/mod.rs +++ b/src/graphmanager/mod.rs @@ -104,11 +104,15 @@ mod test { // Ports have been created by create_node_with_port //Create link between node1 and node 2 - let link = graphview.create_link(1, 2, 1, 2, true); + let link = graphview.create_link(1, 2, 1, 2); + assert_eq!(&link.name(), ""); + assert!(&link.active()); + link.set_name("link1"); + assert_eq!(&link.name(), "link1"); graphview.add_link(link); //Create link between node2 and node 3 - let link = graphview.create_link(2, 3, 3, 4, true); + let link = graphview.create_link(2, 3, 3, 4); graphview.add_link(link); // Save the graphview in XML into a buffer