egui_nodes/
style.rs

1use super::*;
2
3/// Represents different color style values used by a Context
4#[derive(Debug, Clone, Copy)]
5pub enum ColorStyle {
6    NodeBackground = 0,
7    NodeBackgroundHovered,
8    NodeBackgroundSelected,
9    NodeOutline,
10    TitleBar,
11    TitleBarHovered,
12    TitleBarSelected,
13    Link,
14    LinkHovered,
15    LinkSelected,
16    Pin,
17    PinHovered,
18    BoxSelector,
19    BoxSelectorOutline,
20    GridBackground,
21    GridLine,
22    Count,
23}
24
25/// Represents different style values used by a Context
26#[derive(Debug, Clone, Copy)]
27pub enum StyleVar {
28    GridSpacing = 0,
29    NodeCornerRounding,
30    NodePaddingHorizontal,
31    NodePaddingVertical,
32    NodeBorderThickness,
33    LinkThickness,
34    LinkLineSegmentsPerLength,
35    LinkHoverDistance,
36    PinCircleRadius,
37    PinQuadSideLength,
38    PinTriangleSideLength,
39    PinLineThickness,
40    PinHoverRadius,
41    PinOffset,
42}
43
44/// Controls some style aspects
45#[derive(Debug)]
46pub enum StyleFlags {
47    None = 0,
48    NodeOutline = 1 << 0,
49    GridLines = 1 << 2,
50}
51
52impl ColorStyle {
53    /// dark color style
54    pub fn colors_dark() -> [egui::Color32; ColorStyle::Count as usize] {
55        let mut colors = [egui::Color32::BLACK; ColorStyle::Count as usize];
56        colors[ColorStyle::NodeBackground as usize] =
57            egui::Color32::from_rgba_unmultiplied(50, 50, 50, 255);
58        colors[ColorStyle::NodeBackgroundHovered as usize] =
59            egui::Color32::from_rgba_unmultiplied(75, 75, 75, 255);
60        colors[ColorStyle::NodeBackgroundSelected as usize] =
61            egui::Color32::from_rgba_unmultiplied(75, 75, 75, 255);
62        colors[ColorStyle::NodeOutline as usize] =
63            egui::Color32::from_rgba_unmultiplied(100, 100, 100, 255);
64        colors[ColorStyle::TitleBar as usize] =
65            egui::Color32::from_rgba_unmultiplied(41, 74, 122, 255);
66        colors[ColorStyle::TitleBarHovered as usize] =
67            egui::Color32::from_rgba_unmultiplied(66, 150, 250, 255);
68        colors[ColorStyle::TitleBarSelected as usize] =
69            egui::Color32::from_rgba_unmultiplied(66, 150, 250, 255);
70        colors[ColorStyle::Link as usize] =
71            egui::Color32::from_rgba_unmultiplied(61, 133, 224, 200);
72        colors[ColorStyle::LinkHovered as usize] =
73            egui::Color32::from_rgba_unmultiplied(66, 150, 250, 255);
74        colors[ColorStyle::LinkSelected as usize] =
75            egui::Color32::from_rgba_unmultiplied(66, 150, 250, 255);
76        colors[ColorStyle::Pin as usize] = egui::Color32::from_rgba_unmultiplied(53, 150, 250, 180);
77        colors[ColorStyle::PinHovered as usize] =
78            egui::Color32::from_rgba_unmultiplied(53, 150, 250, 255);
79        colors[ColorStyle::BoxSelector as usize] =
80            egui::Color32::from_rgba_unmultiplied(61, 133, 224, 30);
81        colors[ColorStyle::BoxSelectorOutline as usize] =
82            egui::Color32::from_rgba_unmultiplied(61, 133, 224, 150);
83        colors[ColorStyle::GridBackground as usize] =
84            egui::Color32::from_rgba_unmultiplied(40, 40, 50, 200);
85        colors[ColorStyle::GridLine as usize] =
86            egui::Color32::from_rgba_unmultiplied(200, 200, 200, 40);
87        colors
88    }
89
90    /// classic color style
91    pub fn colors_classic() -> [egui::Color32; ColorStyle::Count as usize] {
92        let mut colors = [egui::Color32::BLACK; ColorStyle::Count as usize];
93        colors[ColorStyle::NodeBackground as usize] =
94            egui::Color32::from_rgba_unmultiplied(50, 50, 50, 255);
95        colors[ColorStyle::NodeBackgroundHovered as usize] =
96            egui::Color32::from_rgba_unmultiplied(75, 75, 75, 255);
97        colors[ColorStyle::NodeBackgroundSelected as usize] =
98            egui::Color32::from_rgba_unmultiplied(75, 75, 75, 255);
99        colors[ColorStyle::NodeOutline as usize] =
100            egui::Color32::from_rgba_unmultiplied(100, 100, 100, 255);
101        colors[ColorStyle::TitleBar as usize] =
102            egui::Color32::from_rgba_unmultiplied(69, 69, 138, 255);
103        colors[ColorStyle::TitleBarHovered as usize] =
104            egui::Color32::from_rgba_unmultiplied(82, 82, 161, 255);
105        colors[ColorStyle::TitleBarSelected as usize] =
106            egui::Color32::from_rgba_unmultiplied(82, 82, 161, 255);
107        colors[ColorStyle::Link as usize] =
108            egui::Color32::from_rgba_unmultiplied(255, 255, 255, 100);
109        colors[ColorStyle::LinkHovered as usize] =
110            egui::Color32::from_rgba_unmultiplied(105, 99, 204, 153);
111        colors[ColorStyle::LinkSelected as usize] =
112            egui::Color32::from_rgba_unmultiplied(105, 99, 204, 153);
113        colors[ColorStyle::Pin as usize] = egui::Color32::from_rgba_unmultiplied(89, 102, 156, 170);
114        colors[ColorStyle::PinHovered as usize] =
115            egui::Color32::from_rgba_unmultiplied(102, 122, 179, 200);
116        colors[ColorStyle::BoxSelector as usize] =
117            egui::Color32::from_rgba_unmultiplied(82, 82, 161, 100);
118        colors[ColorStyle::BoxSelectorOutline as usize] =
119            egui::Color32::from_rgba_unmultiplied(82, 82, 161, 255);
120        colors[ColorStyle::GridBackground as usize] =
121            egui::Color32::from_rgba_unmultiplied(40, 40, 50, 200);
122        colors[ColorStyle::GridLine as usize] =
123            egui::Color32::from_rgba_unmultiplied(200, 200, 200, 40);
124        colors
125    }
126
127    /// light color style
128    pub fn colors_light() -> [egui::Color32; ColorStyle::Count as usize] {
129        let mut colors = [egui::Color32::BLACK; ColorStyle::Count as usize];
130        colors[ColorStyle::NodeBackground as usize] =
131            egui::Color32::from_rgba_unmultiplied(240, 240, 240, 255);
132        colors[ColorStyle::NodeBackgroundHovered as usize] =
133            egui::Color32::from_rgba_unmultiplied(240, 240, 240, 255);
134        colors[ColorStyle::NodeBackgroundSelected as usize] =
135            egui::Color32::from_rgba_unmultiplied(240, 240, 240, 255);
136        colors[ColorStyle::NodeOutline as usize] =
137            egui::Color32::from_rgba_unmultiplied(100, 100, 100, 255);
138        colors[ColorStyle::TitleBar as usize] =
139            egui::Color32::from_rgba_unmultiplied(248, 248, 248, 255);
140        colors[ColorStyle::TitleBarHovered as usize] =
141            egui::Color32::from_rgba_unmultiplied(209, 209, 209, 255);
142        colors[ColorStyle::TitleBarSelected as usize] =
143            egui::Color32::from_rgba_unmultiplied(209, 209, 209, 255);
144        colors[ColorStyle::Link as usize] =
145            egui::Color32::from_rgba_unmultiplied(66, 150, 250, 100);
146        colors[ColorStyle::LinkHovered as usize] =
147            egui::Color32::from_rgba_unmultiplied(66, 150, 250, 242);
148        colors[ColorStyle::LinkSelected as usize] =
149            egui::Color32::from_rgba_unmultiplied(66, 150, 250, 242);
150        colors[ColorStyle::Pin as usize] = egui::Color32::from_rgba_unmultiplied(66, 150, 250, 160);
151        colors[ColorStyle::PinHovered as usize] =
152            egui::Color32::from_rgba_unmultiplied(66, 150, 250, 255);
153        colors[ColorStyle::BoxSelector as usize] =
154            egui::Color32::from_rgba_unmultiplied(90, 170, 250, 30);
155        colors[ColorStyle::BoxSelectorOutline as usize] =
156            egui::Color32::from_rgba_unmultiplied(90, 170, 250, 150);
157        colors[ColorStyle::GridBackground as usize] =
158            egui::Color32::from_rgba_unmultiplied(225, 225, 225, 255);
159        colors[ColorStyle::GridLine as usize] =
160            egui::Color32::from_rgba_unmultiplied(180, 180, 180, 100);
161        colors
162    }
163}
164
165/// The style used by a context
166/// Example:
167/// ``` rust
168/// # use egui_nodes::{Context, Style, ColorStyle};
169/// let mut ctx = Context::default();
170/// let style = Style { colors: ColorStyle::colors_classic(), ..Default::default() };
171/// ctx.style = style;
172/// ```
173#[derive(Debug)]
174pub struct Style {
175    pub grid_spacing: f32,
176    pub node_corner_rounding: f32,
177    pub node_padding_horizontal: f32,
178    pub node_padding_vertical: f32,
179    pub node_border_thickness: f32,
180
181    pub link_thickness: f32,
182    pub link_line_segments_per_length: f32,
183    pub link_hover_distance: f32,
184
185    pub pin_circle_radius: f32,
186    pub pin_quad_side_length: f32,
187    pub pin_triangle_side_length: f32,
188    pub pin_line_thickness: f32,
189    pub pin_hover_radius: f32,
190    pub pin_offset: f32,
191
192    pub flags: usize,
193    pub colors: [egui::Color32; ColorStyle::Count as usize],
194}
195
196impl Default for Style {
197    fn default() -> Self {
198        Self {
199            grid_spacing: 32.0,
200            node_corner_rounding: 4.0,
201            node_padding_horizontal: 8.0,
202            node_padding_vertical: 8.0,
203            node_border_thickness: 1.0,
204            link_thickness: 3.0,
205            link_line_segments_per_length: 0.1,
206            link_hover_distance: 10.0,
207            pin_circle_radius: 4.0,
208            pin_quad_side_length: 7.0,
209            pin_triangle_side_length: 9.5,
210            pin_line_thickness: 1.0,
211            pin_hover_radius: 10.0,
212            pin_offset: 0.0,
213            flags: StyleFlags::NodeOutline as usize | StyleFlags::GridLines as usize,
214            colors: ColorStyle::colors_dark(),
215        }
216    }
217}
218
219impl Style {
220    pub(crate) fn get_screen_space_pin_coordinates(
221        &self,
222        node_rect: &egui::Rect,
223        attribute_rect: &egui::Rect,
224        kind: AttributeType,
225    ) -> egui::Pos2 {
226        let x = match kind {
227            AttributeType::Input => node_rect.min.x - self.pin_offset,
228            _ => node_rect.max.x + self.pin_offset,
229        };
230        egui::pos2(x, 0.5 * (attribute_rect.min.y + attribute_rect.max.y))
231    }
232
233    pub(crate) fn draw_pin_shape(
234        &self,
235        pin_pos: egui::Pos2,
236        pin_shape: PinShape,
237        pin_color: egui::Color32,
238        shape: egui::layers::ShapeIdx,
239        ui: &mut egui::Ui,
240    ) {
241        let painter = ui.painter();
242        match pin_shape {
243            PinShape::Circle => painter.set(
244                shape,
245                egui::Shape::circle_stroke(
246                    pin_pos,
247                    self.pin_circle_radius,
248                    (self.pin_line_thickness, pin_color),
249                ),
250            ),
251            PinShape::CircleFilled => painter.set(
252                shape,
253                egui::Shape::circle_filled(pin_pos, self.pin_circle_radius, pin_color),
254            ),
255            PinShape::Quad => painter.set(
256                shape,
257                egui::Shape::rect_stroke(
258                    egui::Rect::from_center_size(
259                        pin_pos,
260                        [self.pin_quad_side_length / 2.0; 2].into(),
261                    ),
262                    0.0,
263                    (self.pin_line_thickness, pin_color),
264                    egui::StrokeKind::Inside,
265                ),
266            ),
267            PinShape::QuadFilled => painter.set(
268                shape,
269                egui::Shape::rect_filled(
270                    egui::Rect::from_center_size(
271                        pin_pos,
272                        [self.pin_quad_side_length / 2.0; 2].into(),
273                    ),
274                    0.0,
275                    pin_color,
276                ),
277            ),
278            PinShape::Triangle => {
279                let sqrt_3 = 3f32.sqrt();
280                let left_offset = -0.166_666_7 * sqrt_3 * self.pin_triangle_side_length;
281                let right_offset = 0.333_333_3 * sqrt_3 * self.pin_triangle_side_length;
282                let verticacl_offset = 0.5 * self.pin_triangle_side_length;
283                painter.set(
284                    shape,
285                    egui::Shape::closed_line(
286                        vec![
287                            pin_pos + (left_offset, verticacl_offset).into(),
288                            pin_pos + (right_offset, 0.0).into(),
289                            pin_pos + (left_offset, -verticacl_offset).into(),
290                        ],
291                        (self.pin_line_thickness, pin_color),
292                    ),
293                )
294            }
295            PinShape::TriangleFilled => {
296                let sqrt_3 = 3f32.sqrt();
297                let left_offset = -0.166_666_7 * sqrt_3 * self.pin_triangle_side_length;
298                let right_offset = 0.333_333_3 * sqrt_3 * self.pin_triangle_side_length;
299                let verticacl_offset = 0.5 * self.pin_triangle_side_length;
300                painter.set(
301                    shape,
302                    egui::Shape::convex_polygon(
303                        vec![
304                            pin_pos + (left_offset, verticacl_offset).into(),
305                            pin_pos + (right_offset, 0.0).into(),
306                            pin_pos + (left_offset, -verticacl_offset).into(),
307                        ],
308                        pin_color,
309                        egui::Stroke::NONE,
310                    ),
311                )
312            }
313        }
314    }
315
316    pub(crate) fn format_node(&self, node: &mut NodeData, args: NodeArgs) {
317        node.color_style.background =
318            args.background.unwrap_or(self.colors[ColorStyle::NodeBackground as usize]);
319        node.color_style.background_hovered = args
320            .background_hovered
321            .unwrap_or(self.colors[ColorStyle::NodeBackgroundHovered as usize]);
322        node.color_style.background_selected = args
323            .background_selected
324            .unwrap_or(self.colors[ColorStyle::NodeBackgroundSelected as usize]);
325        node.color_style.outline =
326            args.outline.unwrap_or(self.colors[ColorStyle::NodeOutline as usize]);
327        node.color_style.titlebar =
328            args.titlebar.unwrap_or(self.colors[ColorStyle::TitleBar as usize]);
329        node.color_style.titlebar_hovered =
330            args.titlebar_hovered.unwrap_or(self.colors[ColorStyle::TitleBarHovered as usize]);
331        node.color_style.titlebar_selected =
332            args.titlebar_selected.unwrap_or(self.colors[ColorStyle::TitleBarSelected as usize]);
333        node.layout_style.corner_rounding =
334            args.corner_rounding.unwrap_or(self.node_corner_rounding);
335        node.layout_style.padding = args.padding.unwrap_or_else(|| {
336            egui::vec2(self.node_padding_horizontal, self.node_padding_vertical)
337        });
338        node.layout_style.border_thickness =
339            args.border_thickness.unwrap_or(self.node_border_thickness);
340    }
341
342    pub(crate) fn format_pin(&self, pin: &mut PinData, args: PinArgs, flags: usize) {
343        pin.shape = args.shape;
344        pin.flags = args.flags.unwrap_or(flags);
345        pin.color_style.background =
346            args.background.unwrap_or(self.colors[ColorStyle::Pin as usize]);
347        pin.color_style.hovered =
348            args.hovered.unwrap_or(self.colors[ColorStyle::PinHovered as usize]);
349    }
350
351    pub(crate) fn format_link(&self, link: &mut LinkData, args: LinkArgs) {
352        link.color_style.base = args.base.unwrap_or(self.colors[ColorStyle::Link as usize]);
353        link.color_style.hovered =
354            args.hovered.unwrap_or(self.colors[ColorStyle::LinkHovered as usize]);
355        link.color_style.selected =
356            args.selected.unwrap_or(self.colors[ColorStyle::LinkSelected as usize]);
357    }
358}