dear-node-editor 0.15.0

Safe Rust bindings for imgui-node-editor for Dear ImGui
Documentation
use crate::{StyleColor, from_vec2, sys, vec2, vec4};

#[derive(Clone, Debug, PartialEq)]
pub struct NodeEditorStyle {
    pub node_padding: [f32; 4],
    pub node_rounding: f32,
    pub node_border_width: f32,
    pub hovered_node_border_width: f32,
    pub hovered_node_border_offset: f32,
    pub selected_node_border_width: f32,
    pub selected_node_border_offset: f32,
    pub pin_rounding: f32,
    pub pin_border_width: f32,
    pub link_strength: f32,
    pub source_direction: [f32; 2],
    pub target_direction: [f32; 2],
    pub scroll_duration: f32,
    pub flow_marker_distance: f32,
    pub flow_speed: f32,
    pub flow_duration: f32,
    pub pivot_alignment: [f32; 2],
    pub pivot_size: [f32; 2],
    pub pivot_scale: [f32; 2],
    pub pin_corners: f32,
    pub pin_radius: f32,
    pub pin_arrow_size: f32,
    pub pin_arrow_width: f32,
    pub group_rounding: f32,
    pub group_border_width: f32,
    pub highlight_connected_links: f32,
    pub snap_link_to_pin_dir: f32,
    pub colors: [[f32; 4]; StyleColor::COUNT],
}

impl NodeEditorStyle {
    #[doc(alias = "GetStyle")]
    pub(crate) fn current() -> Self {
        let mut colors = [[0.0; 4]; StyleColor::COUNT];
        for color in StyleColor::ALL {
            colors[color.index()] = from_vec4(unsafe { sys::dne_get_style_color(color.raw()) });
        }

        Self {
            node_padding: from_vec4(unsafe { sys::dne_get_style_node_padding() }),
            node_rounding: unsafe { sys::dne_get_style_node_rounding() },
            node_border_width: unsafe { sys::dne_get_style_node_border_width() },
            hovered_node_border_width: unsafe { sys::dne_get_style_hovered_node_border_width() },
            hovered_node_border_offset: unsafe { sys::dne_get_style_hovered_node_border_offset() },
            selected_node_border_width: unsafe { sys::dne_get_style_selected_node_border_width() },
            selected_node_border_offset: unsafe {
                sys::dne_get_style_selected_node_border_offset()
            },
            pin_rounding: unsafe { sys::dne_get_style_pin_rounding() },
            pin_border_width: unsafe { sys::dne_get_style_pin_border_width() },
            link_strength: unsafe { sys::dne_get_style_link_strength() },
            source_direction: from_vec2(unsafe { sys::dne_get_style_source_direction() }),
            target_direction: from_vec2(unsafe { sys::dne_get_style_target_direction() }),
            scroll_duration: unsafe { sys::dne_get_style_scroll_duration() },
            flow_marker_distance: unsafe { sys::dne_get_style_flow_marker_distance() },
            flow_speed: unsafe { sys::dne_get_style_flow_speed() },
            flow_duration: unsafe { sys::dne_get_style_flow_duration() },
            pivot_alignment: from_vec2(unsafe { sys::dne_get_style_pivot_alignment() }),
            pivot_size: from_vec2(unsafe { sys::dne_get_style_pivot_size() }),
            pivot_scale: from_vec2(unsafe { sys::dne_get_style_pivot_scale() }),
            pin_corners: unsafe { sys::dne_get_style_pin_corners() },
            pin_radius: unsafe { sys::dne_get_style_pin_radius() },
            pin_arrow_size: unsafe { sys::dne_get_style_pin_arrow_size() },
            pin_arrow_width: unsafe { sys::dne_get_style_pin_arrow_width() },
            group_rounding: unsafe { sys::dne_get_style_group_rounding() },
            group_border_width: unsafe { sys::dne_get_style_group_border_width() },
            highlight_connected_links: unsafe { sys::dne_get_style_highlight_connected_links() },
            snap_link_to_pin_dir: unsafe { sys::dne_get_style_snap_link_to_pin_dir() },
            colors,
        }
    }

    pub(crate) fn apply(&self) {
        validate_style(self);
        unsafe {
            sys::dne_set_style_node_padding(vec4(self.node_padding));
            sys::dne_set_style_node_rounding(self.node_rounding);
            sys::dne_set_style_node_border_width(self.node_border_width);
            sys::dne_set_style_hovered_node_border_width(self.hovered_node_border_width);
            sys::dne_set_style_hovered_node_border_offset(self.hovered_node_border_offset);
            sys::dne_set_style_selected_node_border_width(self.selected_node_border_width);
            sys::dne_set_style_selected_node_border_offset(self.selected_node_border_offset);
            sys::dne_set_style_pin_rounding(self.pin_rounding);
            sys::dne_set_style_pin_border_width(self.pin_border_width);
            sys::dne_set_style_link_strength(self.link_strength);
            sys::dne_set_style_source_direction(vec2(self.source_direction));
            sys::dne_set_style_target_direction(vec2(self.target_direction));
            sys::dne_set_style_scroll_duration(self.scroll_duration);
            sys::dne_set_style_flow_marker_distance(self.flow_marker_distance);
            sys::dne_set_style_flow_speed(self.flow_speed);
            sys::dne_set_style_flow_duration(self.flow_duration);
            sys::dne_set_style_pivot_alignment(vec2(self.pivot_alignment));
            sys::dne_set_style_pivot_size(vec2(self.pivot_size));
            sys::dne_set_style_pivot_scale(vec2(self.pivot_scale));
            sys::dne_set_style_pin_corners(self.pin_corners);
            sys::dne_set_style_pin_radius(self.pin_radius);
            sys::dne_set_style_pin_arrow_size(self.pin_arrow_size);
            sys::dne_set_style_pin_arrow_width(self.pin_arrow_width);
            sys::dne_set_style_group_rounding(self.group_rounding);
            sys::dne_set_style_group_border_width(self.group_border_width);
            sys::dne_set_style_highlight_connected_links(self.highlight_connected_links);
            sys::dne_set_style_snap_link_to_pin_dir(self.snap_link_to_pin_dir);
            for color in StyleColor::ALL {
                sys::dne_set_style_color(color.raw(), vec4(self.colors[color.index()]));
            }
        }
    }

    pub fn color(&self, color: StyleColor) -> [f32; 4] {
        self.colors[color.index()]
    }

    pub fn set_color(&mut self, color: StyleColor, value: [f32; 4]) {
        assert_finite_vec4("NodeEditorStyle::set_color()", "value", value);
        self.colors[color.index()] = value;
    }
}

pub(crate) fn current_style_color(color: StyleColor) -> [f32; 4] {
    from_vec4(unsafe { sys::dne_get_style_color(color.raw()) })
}

pub(crate) fn apply_style_color(color: StyleColor, value: [f32; 4]) {
    assert_finite_vec4("EditorContext::set_style_color()", "value", value);
    unsafe { sys::dne_set_style_color(color.raw(), vec4(value)) };
}

fn validate_style(style: &NodeEditorStyle) {
    assert_finite_vec4(
        "NodeEditorStyle::apply()",
        "node_padding",
        style.node_padding,
    );
    for (name, value) in [
        ("node_rounding", style.node_rounding),
        ("node_border_width", style.node_border_width),
        ("hovered_node_border_width", style.hovered_node_border_width),
        (
            "hovered_node_border_offset",
            style.hovered_node_border_offset,
        ),
        (
            "selected_node_border_width",
            style.selected_node_border_width,
        ),
        (
            "selected_node_border_offset",
            style.selected_node_border_offset,
        ),
        ("pin_rounding", style.pin_rounding),
        ("pin_border_width", style.pin_border_width),
        ("link_strength", style.link_strength),
        ("scroll_duration", style.scroll_duration),
        ("flow_marker_distance", style.flow_marker_distance),
        ("flow_speed", style.flow_speed),
        ("flow_duration", style.flow_duration),
        ("pin_corners", style.pin_corners),
        ("pin_radius", style.pin_radius),
        ("pin_arrow_size", style.pin_arrow_size),
        ("pin_arrow_width", style.pin_arrow_width),
        ("group_rounding", style.group_rounding),
        ("group_border_width", style.group_border_width),
        ("highlight_connected_links", style.highlight_connected_links),
        ("snap_link_to_pin_dir", style.snap_link_to_pin_dir),
    ] {
        assert_finite_f32("NodeEditorStyle::apply()", name, value);
    }
    assert_finite_vec2(
        "NodeEditorStyle::apply()",
        "source_direction",
        style.source_direction,
    );
    assert_finite_vec2(
        "NodeEditorStyle::apply()",
        "target_direction",
        style.target_direction,
    );
    assert_finite_vec2(
        "NodeEditorStyle::apply()",
        "pivot_alignment",
        style.pivot_alignment,
    );
    assert_finite_vec2("NodeEditorStyle::apply()", "pivot_size", style.pivot_size);
    assert_finite_vec2("NodeEditorStyle::apply()", "pivot_scale", style.pivot_scale);
    for color in style.colors {
        assert_finite_vec4("NodeEditorStyle::apply()", "color", color);
    }
}

fn assert_finite_f32(caller: &str, name: &str, value: f32) {
    assert!(value.is_finite(), "{caller} {name} must be finite");
}

fn assert_finite_vec2(caller: &str, name: &str, value: [f32; 2]) {
    assert!(
        value.iter().all(|component| component.is_finite()),
        "{caller} {name} components must be finite"
    );
}

fn assert_finite_vec4(caller: &str, name: &str, value: [f32; 4]) {
    assert!(
        value.iter().all(|component| component.is_finite()),
        "{caller} {name} components must be finite"
    );
}

fn from_vec4(value: sys::ImVec4_c) -> [f32; 4] {
    [value.x, value.y, value.z, value.w]
}