1use super::*;
2use crate::scale::Scale;
3use egui::{Rect, Style, Ui, Vec2};
4use std::marker::PhantomData;
5use std::sync::Arc;
6
7#[cfg(feature = "persistence")]
8use serde::{Deserialize, Serialize};
9
10const MIN_ZOOM: f32 = 0.2;
11const MAX_ZOOM: f32 = 2.0;
12
13#[derive(Clone, Copy, Debug)]
18#[cfg_attr(feature = "persistence", derive(Serialize, Deserialize))]
19pub enum NodeOrientation {
20 LeftToRight,
21 RightToLeft,
22}
23
24impl NodeOrientation {
25 pub fn flip(self) -> Self {
26 match self {
27 NodeOrientation::LeftToRight => NodeOrientation::RightToLeft,
28 NodeOrientation::RightToLeft => NodeOrientation::LeftToRight,
29 }
30 }
31}
32
33#[derive(Clone)]
34#[cfg_attr(feature = "persistence", derive(Serialize, Deserialize))]
35pub struct GraphEditorState<NodeData, DataType, ValueType, NodeTemplate, UserState> {
36 pub graph: Graph<NodeData, DataType, ValueType>,
37 pub node_order: Vec<NodeId>,
40 pub connection_in_progress: Option<(NodeId, AnyParameterId)>,
43 pub selected_nodes: Vec<NodeId>,
46 pub ongoing_box_selection: Option<egui::Pos2>,
48 pub node_positions: SecondaryMap<NodeId, egui::Pos2>,
50 pub node_orientations: SecondaryMap<NodeId, NodeOrientation>,
52 pub node_finder: Option<NodeFinder<NodeTemplate>>,
54 pub pan_zoom: PanZoom,
56 pub _user_state: PhantomData<fn() -> UserState>,
57}
58
59impl<NodeData, DataType: PartialEq, ValueType, NodeKind, UserState>
60 GraphEditorState<NodeData, DataType, ValueType, NodeKind, UserState>
61{
62 pub fn new(default_zoom: f32) -> Self {
63 Self {
64 pan_zoom: PanZoom::new(default_zoom),
65 ..Default::default()
66 }
67 }
68}
69impl<NodeData, DataType: PartialEq, ValueType, NodeKind, UserState> Default
70 for GraphEditorState<NodeData, DataType, ValueType, NodeKind, UserState>
71{
72 fn default() -> Self {
73 Self {
74 graph: Default::default(),
75 node_order: Default::default(),
76 connection_in_progress: Default::default(),
77 selected_nodes: Default::default(),
78 ongoing_box_selection: Default::default(),
79 node_positions: Default::default(),
80 node_orientations: Default::default(),
81 node_finder: Default::default(),
82 pan_zoom: Default::default(),
83 _user_state: Default::default(),
84 }
85 }
86}
87
88#[cfg(feature = "persistence")]
89fn _default_clip_rect() -> Rect {
90 Rect::NOTHING
91}
92
93#[derive(Clone)]
94#[cfg_attr(feature = "persistence", derive(Serialize, Deserialize))]
95pub struct PanZoom {
96 pub pan: Vec2,
97 pub zoom: f32,
98 #[cfg_attr(feature = "persistence", serde(skip, default = "_default_clip_rect"))]
99 pub clip_rect: Rect,
100 #[cfg_attr(feature = "persistence", serde(skip, default))]
101 pub zoomed_style: Arc<Style>,
102 #[cfg_attr(feature = "persistence", serde(skip, default))]
103 pub started: bool,
104}
105
106impl Default for PanZoom {
107 fn default() -> Self {
108 PanZoom {
109 pan: Vec2::ZERO,
110 zoom: 1.0,
111 clip_rect: Rect::NOTHING,
112 zoomed_style: Default::default(),
113 started: false,
114 }
115 }
116}
117
118impl PanZoom {
119 pub fn new(zoom: f32) -> PanZoom {
120 let style: Style = Default::default();
121 PanZoom {
122 pan: Vec2::ZERO,
123 zoom,
124 clip_rect: Rect::NOTHING,
125 zoomed_style: Arc::new(style.scaled(1.0)),
126 started: false,
127 }
128 }
129
130 pub fn zoom(&mut self, clip_rect: Rect, style: &Arc<Style>, zoom_delta: f32) {
131 self.clip_rect = clip_rect;
132 let new_zoom = (self.zoom * zoom_delta).clamp(MIN_ZOOM, MAX_ZOOM);
133 self.zoomed_style = Arc::new(style.scaled(new_zoom));
134 self.zoom = new_zoom;
135 }
136}
137
138pub fn show_zoomed<R, F>(
139 default_style: Arc<Style>,
140 zoomed_style: Arc<Style>,
141 ui: &mut Ui,
142 add_content: F,
143) -> R
144where
145 F: FnOnce(&mut Ui) -> R,
146{
147 *ui.style_mut() = (*zoomed_style).clone();
148 let response = add_content(ui);
149 *ui.style_mut() = (*default_style).clone();
150
151 response
152}