From f98690292954fe692657503b7873a9fe75676099 Mon Sep 17 00:00:00 2001 From: "Tom A. Wagner" Date: Wed, 19 Jul 2023 15:06:51 +0200 Subject: [PATCH] graph: Move link data into new GObject subclass --- src/application.rs | 5 +- src/ui/graph/graph_view.rs | 40 ++++++++----- src/ui/graph/link.rs | 114 +++++++++++++++++++++++++++++++++++++ src/ui/graph/mod.rs | 4 +- src/ui/graph/zoomentry.rs | 8 +-- src/ui/mod.rs | 2 +- 6 files changed, 147 insertions(+), 26 deletions(-) create mode 100644 src/ui/graph/link.rs diff --git a/src/application.rs b/src/application.rs index cbd887f..2b2da92 100644 --- a/src/application.rs +++ b/src/application.rs @@ -25,10 +25,7 @@ use gtk::{ use log::info; use pipewire::{channel::Sender, spa::Direction}; -use crate::{ - ui, - GtkMessage, MediaType, NodeType, PipewireLink, PipewireMessage, -}; +use crate::{ui, GtkMessage, MediaType, NodeType, PipewireLink, PipewireMessage}; static STYLE: &str = include_str!("style.css"); diff --git a/src/ui/graph/graph_view.rs b/src/ui/graph/graph_view.rs index c602a3c..6980cfe 100644 --- a/src/ui/graph/graph_view.rs +++ b/src/ui/graph/graph_view.rs @@ -14,8 +14,6 @@ // // SPDX-License-Identifier: GPL-3.0-only -use super::{Node, Port}; - use gtk::{ glib::{self, clone}, graphene, @@ -28,6 +26,7 @@ use log::{error, warn}; use std::{cmp::Ordering, collections::HashMap}; +use super::{Link, Node, Port}; use crate::NodeType; const CANVAS_SIZE: f64 = 5000.0; @@ -59,7 +58,7 @@ mod imp { /// Stores nodes and their positions. pub(super) nodes: RefCell>, /// Stores the link and whether it is currently active. - pub(super) links: RefCell>, + pub(super) links: RefCell>, pub hadjustment: RefCell>, pub vadjustment: RefCell>, pub zoom_factor: Cell, @@ -431,13 +430,13 @@ mod imp { rgba.alpha().into(), ); - for (link, active) in self.links.borrow().values() { + for link in self.links.borrow().values() { // TODO: Do not draw links when they are outside the view if let Some((from_x, from_y, to_x, to_y)) = self.get_link_coordinates(link) { link_cr.move_to(from_x, from_y); // Use dashed line for inactive links, full line otherwise. - if *active { + if link.active() { link_cr.set_dash(&[], 0.0); } else { link_cr.set_dash(&[10.0, 5.0], 0.0); @@ -478,11 +477,10 @@ mod imp { /// /// # Returns /// `Some((from_x, from_y, to_x, to_y))` if all objects the links refers to exist as widgets. - fn get_link_coordinates(&self, link: &crate::PipewireLink) -> Option<(f64, f64, f64, f64)> { + fn get_link_coordinates(&self, link: &Link) -> Option<(f64, f64, f64, f64)> { let widget = &*self.obj(); - let nodes = self.nodes.borrow(); - let output_port = &nodes.get(&link.node_from)?.0.get_port(link.port_from)?; + let output_port = link.output_port()?; let output_port_padding = (output_port.allocated_width() - output_port.width()) as f64 / 2.0; @@ -493,7 +491,7 @@ mod imp { (output_port.height() / 2) as f64, )?; - let input_port = &nodes.get(&link.node_to)?.0.get_port(link.port_to)?; + let input_port = link.input_port()?; let input_port_padding = (input_port.allocated_width() - input_port.width()) as f64 / 2.0; @@ -671,16 +669,28 @@ impl GraphView { } pub fn add_link(&self, link_id: u32, link: crate::PipewireLink, active: bool) { - self.imp() - .links - .borrow_mut() - .insert(link_id, (link, active)); + let nodes = self.imp().nodes.borrow(); + + let output_port = nodes + .get(&link.node_from) + .and_then(|(node, _)| node.get_port(link.port_from)); + + let input_port = nodes + .get(&link.node_to) + .and_then(|(node, _)| node.get_port(link.port_to)); + + let link = Link::new(); + link.set_input_port(input_port.as_ref()); + link.set_output_port(output_port.as_ref()); + link.set_active(active); + + self.imp().links.borrow_mut().insert(link_id, link); self.queue_draw(); } pub fn set_link_state(&self, link_id: u32, active: bool) { - if let Some((_, state)) = self.imp().links.borrow_mut().get_mut(&link_id) { - *state = active; + if let Some(link) = self.imp().links.borrow_mut().get_mut(&link_id) { + link.set_active(active); self.queue_draw(); } else { warn!("Link state changed on unknown link (id={})", link_id); diff --git a/src/ui/graph/link.rs b/src/ui/graph/link.rs new file mode 100644 index 0000000..d179b6d --- /dev/null +++ b/src/ui/graph/link.rs @@ -0,0 +1,114 @@ +// Copyright 2021 Tom A. Wagner +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 3 as published by +// the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// SPDX-License-Identifier: GPL-3.0-only + +use gtk::{glib, prelude::*, subclass::prelude::*}; + +use super::Port; + +mod imp { + use super::*; + + use std::cell::Cell; + + use once_cell::sync::Lazy; + + #[derive(Default)] + pub struct Link { + pub output_port: glib::WeakRef, + pub input_port: glib::WeakRef, + pub active: Cell, + } + + #[glib::object_subclass] + impl ObjectSubclass for Link { + const NAME: &'static str = "HelvumLink"; + type Type = super::Link; + type ParentType = glib::Object; + } + + impl ObjectImpl for Link { + fn properties() -> &'static [glib::ParamSpec] { + static PROPERTIES: Lazy> = Lazy::new(|| { + vec![ + glib::ParamSpecObject::builder::("output-port") + .flags(glib::ParamFlags::READWRITE) + .build(), + glib::ParamSpecObject::builder::("input-port") + .flags(glib::ParamFlags::READWRITE) + .build(), + glib::ParamSpecBoolean::builder("active") + .default_value(false) + .flags(glib::ParamFlags::READWRITE) + .build(), + ] + }); + + PROPERTIES.as_ref() + } + + fn property(&self, _id: usize, pspec: &glib::ParamSpec) -> glib::Value { + match pspec.name() { + "output-port" => self.output_port.upgrade().to_value(), + "input-port" => self.input_port.upgrade().to_value(), + "active" => self.active.get().to_value(), + _ => unimplemented!(), + } + } + + fn set_property(&self, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) { + match pspec.name() { + "output-port" => self.output_port.set(value.get().unwrap()), + "input-port" => self.input_port.set(value.get().unwrap()), + "active" => self.active.set(value.get().unwrap()), + _ => unimplemented!(), + } + } + } +} + +glib::wrapper! { + pub struct Link(ObjectSubclass); +} + +impl Link { + pub fn new() -> Self { + glib::Object::new() + } + + pub fn output_port(&self) -> Option { + self.property("output-port") + } + + pub fn set_output_port(&self, port: Option<&Port>) { + self.set_property("output-port", port); + } + + pub fn input_port(&self) -> Option { + self.property("input-port") + } + + pub fn set_input_port(&self, port: Option<&Port>) { + self.set_property("input-port", port); + } + + pub fn active(&self) -> bool { + self.property("active") + } + + pub fn set_active(&self, active: bool) { + self.set_property("active", active); + } +} diff --git a/src/ui/graph/mod.rs b/src/ui/graph/mod.rs index c904553..691b9ff 100644 --- a/src/ui/graph/mod.rs +++ b/src/ui/graph/mod.rs @@ -20,5 +20,7 @@ mod node; pub use node::*; mod port; pub use port::*; +mod link; +pub use link::*; mod zoomentry; -pub use zoomentry::*; \ No newline at end of file +pub use zoomentry::*; diff --git a/src/ui/graph/zoomentry.rs b/src/ui/graph/zoomentry.rs index 59e0941..420a13e 100644 --- a/src/ui/graph/zoomentry.rs +++ b/src/ui/graph/zoomentry.rs @@ -109,11 +109,9 @@ mod imp { fn properties() -> &'static [glib::ParamSpec] { static PROPERTIES: Lazy> = Lazy::new(|| { - vec![ - glib::ParamSpecObject::builder::("zoomed-widget") - .flags(glib::ParamFlags::READWRITE | glib::ParamFlags::CONSTRUCT) - .build(), - ] + vec![glib::ParamSpecObject::builder::("zoomed-widget") + .flags(glib::ParamFlags::READWRITE | glib::ParamFlags::CONSTRUCT) + .build()] }); PROPERTIES.as_ref() diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 532b6bd..37f2896 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -18,4 +18,4 @@ //! //! This module contains gtk widgets needed to present the graphical user interface. -pub mod graph; \ No newline at end of file +pub mod graph;