use serde::{Deserialize, Serialize};
use jellyflow_core::core::{CanvasPoint, EdgeId, Graph, GroupId, NodeId};
use super::default_zoom;
use super::pure::NodeGraphPureViewState;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct NodeGraphViewState {
#[serde(default)]
pub pan: CanvasPoint,
#[serde(default = "default_zoom")]
pub zoom: f32,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub selected_nodes: Vec<NodeId>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub selected_edges: Vec<EdgeId>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub selected_groups: Vec<GroupId>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub draw_order: Vec<NodeId>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub edge_draw_order: Vec<EdgeId>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub group_draw_order: Vec<GroupId>,
}
impl Default for NodeGraphViewState {
fn default() -> Self {
Self {
pan: CanvasPoint::default(),
zoom: default_zoom(),
selected_nodes: Vec::new(),
selected_edges: Vec::new(),
selected_groups: Vec::new(),
draw_order: Vec::new(),
edge_draw_order: Vec::new(),
group_draw_order: Vec::new(),
}
}
}
impl NodeGraphViewState {
pub fn set_viewport(&mut self, pan: CanvasPoint, zoom: f32) {
self.pan = sanitize_pan(pan);
self.zoom = sanitize_zoom(zoom);
}
pub fn set_selection(&mut self, nodes: Vec<NodeId>, edges: Vec<EdgeId>, groups: Vec<GroupId>) {
self.selected_nodes = nodes;
self.selected_edges = edges;
self.selected_groups = groups;
}
pub fn sanitize_for_graph(&mut self, graph: &Graph) {
self.sanitize_viewport();
let visible_node = |id: &NodeId| graph.nodes.get(id).is_some_and(|node| !node.hidden);
self.selected_nodes.retain(visible_node);
let visible_edge = |id: &EdgeId| {
let Some(edge) = graph.edges.get(id) else {
return false;
};
if edge.hidden {
return false;
}
let Some(from) = graph.ports.get(&edge.from) else {
return false;
};
let Some(to) = graph.ports.get(&edge.to) else {
return false;
};
visible_node(&from.node) && visible_node(&to.node)
};
self.selected_edges.retain(|id| visible_edge(id));
self.selected_groups
.retain(|id| graph.groups.contains_key(id));
self.draw_order.retain(visible_node);
self.edge_draw_order.retain(|id| visible_edge(id));
self.group_draw_order
.retain(|id| graph.groups.contains_key(id));
}
pub fn sanitize_viewport(&mut self) {
self.pan = sanitize_pan(self.pan);
self.zoom = sanitize_zoom(self.zoom);
}
}
fn sanitize_pan(pan: CanvasPoint) -> CanvasPoint {
if pan.is_finite() {
pan
} else {
CanvasPoint::default()
}
}
fn sanitize_zoom(zoom: f32) -> f32 {
if zoom.is_finite() && zoom > 0.0 {
zoom
} else {
default_zoom()
}
}
impl From<NodeGraphPureViewState> for NodeGraphViewState {
fn from(value: NodeGraphPureViewState) -> Self {
Self {
pan: value.pan,
zoom: value.zoom,
selected_nodes: value.selected_nodes,
selected_edges: value.selected_edges,
selected_groups: value.selected_groups,
draw_order: value.draw_order,
edge_draw_order: value.edge_draw_order,
group_draw_order: value.group_draw_order,
}
}
}
impl From<NodeGraphViewState> for NodeGraphPureViewState {
fn from(value: NodeGraphViewState) -> Self {
Self {
pan: value.pan,
zoom: value.zoom,
selected_nodes: value.selected_nodes,
selected_edges: value.selected_edges,
selected_groups: value.selected_groups,
draw_order: value.draw_order,
edge_draw_order: value.edge_draw_order,
group_draw_order: value.group_draw_order,
}
}
}
impl From<&NodeGraphViewState> for NodeGraphPureViewState {
fn from(value: &NodeGraphViewState) -> Self {
Self {
pan: value.pan,
zoom: value.zoom,
selected_nodes: value.selected_nodes.clone(),
selected_edges: value.selected_edges.clone(),
selected_groups: value.selected_groups.clone(),
draw_order: value.draw_order.clone(),
edge_draw_order: value.edge_draw_order.clone(),
group_draw_order: value.group_draw_order.clone(),
}
}
}