1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
use egui::Color32;
use crate::{
state_computed::{StateComputedEdge, StateComputedNode},
Edge, Node,
};
/// Represents graph interaction settings.
#[derive(Debug, Clone, Default)]
pub struct SettingsInteraction {
pub(crate) dragging_enabled: bool,
pub(crate) clicking_enabled: bool,
pub(crate) folding_enabled: bool,
pub(crate) selection_enabled: bool,
pub(crate) selection_multi_enabled: bool,
pub(crate) selection_depth: i32,
pub(crate) folding_depth: usize,
}
impl SettingsInteraction {
/// Creates new [`SettingsInteraction`] with default values.
pub fn new() -> Self {
Self::default()
}
/// Node dragging. To drag a node with your mouse or finger.
///
/// Default: `false`
pub fn with_dragging_enabled(mut self, enabled: bool) -> Self {
self.dragging_enabled = enabled;
self
}
/// Allows clicking on nodes.
///
/// Default: `false`
pub fn with_clicking_enabled(mut self, enabled: bool) -> Self {
self.clicking_enabled = enabled;
self
}
/// Allows to fold nodes.
///
/// Default: `false`
pub fn with_folding_enabled(mut self, enabled: bool) -> Self {
self.folding_enabled = enabled;
self
}
/// Selects clicked node, enables clicks.
///
/// Select by clicking on node, deselect by clicking again.
///
/// Clicking on empty space deselects all nodes.
///
/// Default: `false`
pub fn with_selection_enabled(mut self, enabled: bool) -> Self {
self.selection_enabled = enabled;
self
}
/// Multiselection for nodes, enables click and select.
///
/// Default: `false`
pub fn with_selection_multi_enabled(mut self, enabled: bool) -> Self {
self.selection_multi_enabled = enabled;
self
}
/// How deep into the neighbours of selected nodes should the selection go.
///
/// * `selection_depth == 0` means only selected nodes are selected.
/// * `selection_depth > 0` means children of selected nodes are selected up to `selection_depth` generation.
/// * `selection_depth < 0` means parents of selected nodes are selected up to `selection_depth` generation.
/// * passing `i32::MAX` and `i32::MIN` selects all available generations of children or parents.
///
/// Default: `0`
pub fn with_selection_depth(mut self, depth: i32) -> Self {
self.selection_depth = depth;
self
}
/// Defines the generation depth up to which the children of the folded node will be folded.
///
/// * `folding_depth == 0` means only the folded node is folded.
/// * `folding_depth > 0` means children of the folded node are folded up to `folding_depth` generation.
/// * `folding_depth == usize::MAX` folds all available generations of children.
///
/// Default: `0`
pub fn with_folding_depth(mut self, depth: usize) -> Self {
self.folding_depth = depth;
self
}
}
/// Represents graph navigation settings.
#[derive(Debug, Clone)]
pub struct SettingsNavigation {
pub(crate) fit_to_screen_enabled: bool,
pub(crate) zoom_and_pan_enabled: bool,
pub(crate) screen_padding: f32,
pub(crate) zoom_speed: f32,
}
impl Default for SettingsNavigation {
fn default() -> Self {
Self {
screen_padding: 0.3,
zoom_speed: 0.1,
fit_to_screen_enabled: true,
zoom_and_pan_enabled: false,
}
}
}
impl SettingsNavigation {
/// Creates new [`SettingsNavigation`] with default values.
pub fn new() -> Self {
Self::default()
}
/// Fits the graph to the screen.
///
/// With this enabled, the graph will be scaled and panned to fit the screen on every frame.
///
/// You can configure the padding around the graph with `screen_padding` setting.
///
/// Default: `true`
pub fn with_fit_to_screen_enabled(mut self, enabled: bool) -> Self {
self.fit_to_screen_enabled = enabled;
self
}
/// Zoom with ctrl + mouse wheel, pan with mouse drag.
///
/// Default: `false`
pub fn with_zoom_and_pan_enabled(mut self, enabled: bool) -> Self {
self.zoom_and_pan_enabled = enabled;
self
}
/// Padding around the graph when fitting to the screen.
pub fn with_screen_padding(mut self, padding: f32) -> Self {
self.screen_padding = padding;
self
}
/// Controls the speed of the zoom.
pub fn with_zoom_speed(mut self, speed: f32) -> Self {
self.zoom_speed = speed;
self
}
}
/// `SettingsStyle` stores settings for the style of the graph.
#[derive(Debug, Clone)]
pub struct SettingsStyle {
pub(crate) labels_always: bool,
pub(crate) edge_radius_weight: f32,
pub(crate) folded_radius_weight: f32,
/// Used to color children of the selected nodes.
pub(crate) color_selection_child: Color32,
/// Used to color parents of the selected nodes.
pub(crate) color_selection_parent: Color32,
/// Used to color selected nodes.
pub(crate) color_selection: Color32,
/// Color of nodes being dragged.
pub(crate) color_drag: Color32,
/// Text color for light background.
pub(crate) color_text_light: Color32,
/// Text color for dark background.
pub(crate) color_text_dark: Color32,
/// Loop size for looped edges.
pub(crate) edge_looped_size: f32,
color_node: Color32,
color_edge: Color32,
}
impl Default for SettingsStyle {
fn default() -> Self {
Self {
edge_radius_weight: 1.,
edge_looped_size: 3.,
folded_radius_weight: 2.,
color_selection: Color32::from_rgba_unmultiplied(0, 255, 127, 153), // Spring Green
color_selection_child: Color32::from_rgba_unmultiplied(100, 149, 237, 153), // Cornflower Blue
color_selection_parent: Color32::from_rgba_unmultiplied(255, 105, 180, 153), // Hot Pink
color_node: Color32::from_rgb(200, 200, 200), // Light Gray
color_edge: Color32::from_rgb(128, 128, 128), // Gray
color_drag: Color32::from_rgba_unmultiplied(240, 128, 128, 153), // Light Coral
color_text_light: Color32::WHITE,
color_text_dark: Color32::BLACK,
labels_always: Default::default(),
}
}
}
impl SettingsStyle {
/// Creates new [`SettingsStyle`] with default values.
/// ```
/// use egui_graphs::SettingsStyle;
/// let settings = SettingsStyle::new();
/// ```
pub fn new() -> Self {
Self::default()
}
/// Whether to show labels always or when interacted.
///
/// Default is false.
pub fn with_labels_always(mut self, always: bool) -> Self {
self.labels_always = always;
self
}
/// For every node folded the folding root node radius is getting bigger by this value.
///
/// Default: `2.`
pub fn with_folded_radius_weight(mut self, weight: f32) -> Self {
self.folded_radius_weight = weight;
self
}
/// For every edge connected to node its radius is getting bigger by this value.
///
/// Default: `1.`
pub fn with_edge_radius_weight(mut self, weight: f32) -> Self {
self.edge_radius_weight = weight;
self
}
/// Sets default color for node.
pub fn with_node_color(mut self, color: Color32) -> Self {
self.color_node = color;
self
}
/// Sets default color for edge.
pub fn with_edge_color(mut self, color: Color32) -> Self {
self.color_edge = color;
self
}
pub fn color_node_stroke(&self, ctx: &egui::Context) -> Color32 {
if ctx.style().visuals.dark_mode {
self.color_node
} else {
self.color_edge
}
}
pub(crate) fn color_node_fill<N: Clone>(
&self,
ctx: &egui::Context,
n: &Node<N>,
comp: &StateComputedNode,
) -> Color32 {
if n.folded() {
return Color32::TRANSPARENT;
}
if n.color().is_some() {
return n.color().unwrap();
}
if n.dragged() {
return self.color_drag;
}
if n.selected() {
return self.color_selection;
}
if comp.selected_child {
return self.color_selection_child;
}
if comp.selected_parent {
return self.color_selection_parent;
}
if ctx.style().visuals.dark_mode {
self.color_node
} else {
self.color_edge
}
}
pub(crate) fn color_label(&self, ctx: &egui::Context) -> Color32 {
match ctx.style().visuals.dark_mode {
true => self.color_text_light,
false => self.color_text_dark,
}
}
pub(crate) fn color_edge<E: Clone>(&self, ctx: &egui::Context, e: &Edge<E>) -> Color32 {
if e.color().is_some() {
return e.color().unwrap();
}
if ctx.style().visuals.dark_mode {
return self.color_edge;
}
self.color_node
}
pub(crate) fn color_edge_highlight(&self, comp: &StateComputedEdge) -> Option<Color32> {
if comp.selected_child {
return Some(self.color_selection_child);
}
if comp.selected_parent {
return Some(self.color_selection_parent);
}
None
}
}