1use super::core::NodeEditorFrame;
2use super::validation::{assert_finite_f32, assert_finite_vec2};
3use crate::{LinkId, NodeId, PinId, from_vec2, sys, vec2};
4use dear_imgui_rs::MouseButton;
5
6impl<'ui> NodeEditorFrame<'ui> {
7 pub fn set_node_position(&self, node: NodeId, position: [f32; 2]) {
8 assert_finite_vec2("NodeEditorFrame::set_node_position()", "position", position);
9 unsafe { sys::dne_set_node_position(node.raw(), vec2(position)) };
10 }
11
12 pub fn node_position(&self, node: NodeId) -> [f32; 2] {
13 from_vec2(unsafe { sys::dne_get_node_position(node.raw()) })
14 }
15
16 pub fn node_size(&self, node: NodeId) -> [f32; 2] {
17 from_vec2(unsafe { sys::dne_get_node_size(node.raw()) })
18 }
19
20 pub fn set_node_z_position(&self, node: NodeId, z: f32) {
21 assert_finite_f32("NodeEditorFrame::set_node_z_position()", "z", z);
22 unsafe { sys::dne_set_node_z_position(node.raw(), z) };
23 }
24
25 pub fn node_z_position(&self, node: NodeId) -> f32 {
26 unsafe { sys::dne_get_node_z_position(node.raw()) }
27 }
28
29 pub fn restore_node_state(&self, node: NodeId) {
30 unsafe { sys::dne_restore_node_state(node.raw()) };
31 }
32
33 pub fn center_node_on_screen(&self, node: NodeId) {
34 unsafe { sys::dne_center_node_on_screen(node.raw()) };
35 }
36
37 pub fn navigate_to_content(&self, duration: f32) {
38 assert_finite_f32(
39 "NodeEditorFrame::navigate_to_content()",
40 "duration",
41 duration,
42 );
43 unsafe { sys::dne_navigate_to_content(duration) };
44 }
45
46 pub fn navigate_to_selection(&self, zoom_in: bool, duration: f32) {
47 assert_finite_f32(
48 "NodeEditorFrame::navigate_to_selection()",
49 "duration",
50 duration,
51 );
52 unsafe { sys::dne_navigate_to_selection(zoom_in, duration) };
53 }
54
55 pub fn is_active(&self) -> bool {
56 unsafe { sys::dne_is_active() }
57 }
58
59 pub fn has_selection_changed(&self) -> bool {
60 unsafe { sys::dne_has_selection_changed() }
61 }
62
63 pub fn selected_object_count(&self) -> usize {
64 unsafe { sys::dne_get_selected_object_count() }.max(0) as usize
65 }
66
67 pub fn selected_nodes(&self) -> Vec<NodeId> {
68 let count = self.selected_object_count();
69 collect_node_ids(count, |ptr, len| unsafe {
70 sys::dne_get_selected_nodes(ptr, len)
71 })
72 }
73
74 pub fn selected_links(&self) -> Vec<LinkId> {
75 let count = self.selected_object_count();
76 collect_link_ids(count, |ptr, len| unsafe {
77 sys::dne_get_selected_links(ptr, len)
78 })
79 }
80
81 pub fn is_node_selected(&self, node: NodeId) -> bool {
82 unsafe { sys::dne_is_node_selected(node.raw()) }
83 }
84
85 pub fn is_link_selected(&self, link: LinkId) -> bool {
86 unsafe { sys::dne_is_link_selected(link.raw()) }
87 }
88
89 pub fn clear_selection(&self) {
90 unsafe { sys::dne_clear_selection() };
91 }
92
93 pub fn select_node(&self, node: NodeId) {
94 unsafe { sys::dne_select_node(node.raw(), false) };
95 }
96
97 pub fn add_node_to_selection(&self, node: NodeId) {
98 unsafe { sys::dne_select_node(node.raw(), true) };
99 }
100
101 pub fn select_link(&self, link: LinkId) {
102 unsafe { sys::dne_select_link(link.raw(), false) };
103 }
104
105 pub fn add_link_to_selection(&self, link: LinkId) {
106 unsafe { sys::dne_select_link(link.raw(), true) };
107 }
108
109 pub fn deselect_node(&self, node: NodeId) {
110 unsafe { sys::dne_deselect_node(node.raw()) };
111 }
112
113 pub fn deselect_link(&self, link: LinkId) {
114 unsafe { sys::dne_deselect_link(link.raw()) };
115 }
116
117 pub fn delete_node(&self, node: NodeId) -> bool {
118 unsafe { sys::dne_delete_node(node.raw()) }
119 }
120
121 pub fn delete_link(&self, link: LinkId) -> bool {
122 unsafe { sys::dne_delete_link(link.raw()) }
123 }
124
125 pub fn node_has_any_links(&self, node: NodeId) -> bool {
126 unsafe { sys::dne_has_any_links_node(node.raw()) }
127 }
128
129 pub fn pin_has_any_links(&self, pin: PinId) -> bool {
130 unsafe { sys::dne_has_any_links_pin(pin.raw()) }
131 }
132
133 pub fn break_node_links(&self, node: NodeId) -> usize {
134 unsafe { sys::dne_break_links_node(node.raw()) }.max(0) as usize
135 }
136
137 pub fn break_pin_links(&self, pin: PinId) -> usize {
138 unsafe { sys::dne_break_links_pin(pin.raw()) }.max(0) as usize
139 }
140
141 pub fn hovered_node(&self) -> Option<NodeId> {
142 optional_id(NodeId, |ptr| unsafe { sys::dne_get_hovered_node(ptr) })
143 }
144
145 pub fn hovered_pin(&self) -> Option<PinId> {
146 optional_id(PinId, |ptr| unsafe { sys::dne_get_hovered_pin(ptr) })
147 }
148
149 pub fn hovered_link(&self) -> Option<LinkId> {
150 optional_id(LinkId, |ptr| unsafe { sys::dne_get_hovered_link(ptr) })
151 }
152
153 pub fn double_clicked_node(&self) -> Option<NodeId> {
154 optional_id(NodeId, |ptr| unsafe {
155 sys::dne_get_double_clicked_node(ptr)
156 })
157 }
158
159 pub fn double_clicked_pin(&self) -> Option<PinId> {
160 optional_id(PinId, |ptr| unsafe { sys::dne_get_double_clicked_pin(ptr) })
161 }
162
163 pub fn double_clicked_link(&self) -> Option<LinkId> {
164 optional_id(LinkId, |ptr| unsafe {
165 sys::dne_get_double_clicked_link(ptr)
166 })
167 }
168
169 pub fn show_node_context_menu(&self) -> Option<NodeId> {
170 optional_id(NodeId, |ptr| unsafe {
171 sys::dne_show_node_context_menu(ptr)
172 })
173 }
174
175 pub fn show_pin_context_menu(&self) -> Option<PinId> {
176 optional_id(PinId, |ptr| unsafe { sys::dne_show_pin_context_menu(ptr) })
177 }
178
179 pub fn show_link_context_menu(&self) -> Option<LinkId> {
180 optional_id(LinkId, |ptr| unsafe {
181 sys::dne_show_link_context_menu(ptr)
182 })
183 }
184
185 pub fn show_background_context_menu(&self) -> bool {
186 unsafe { sys::dne_show_background_context_menu() }
187 }
188
189 pub fn set_shortcuts_enabled(&self, enabled: bool) {
190 unsafe { sys::dne_enable_shortcuts(enabled) };
191 }
192
193 pub fn shortcuts_enabled(&self) -> bool {
194 unsafe { sys::dne_are_shortcuts_enabled() }
195 }
196
197 pub fn current_zoom(&self) -> f32 {
198 unsafe { sys::dne_get_current_zoom() }
199 }
200
201 pub fn is_background_clicked(&self) -> bool {
202 unsafe { sys::dne_is_background_clicked() }
203 }
204
205 pub fn is_background_double_clicked(&self) -> bool {
206 unsafe { sys::dne_is_background_double_clicked() }
207 }
208
209 pub fn background_click_button(&self) -> Option<MouseButton> {
210 mouse_button_from_index(unsafe { sys::dne_get_background_click_button_index() })
211 }
212
213 pub fn background_double_click_button(&self) -> Option<MouseButton> {
214 mouse_button_from_index(unsafe { sys::dne_get_background_double_click_button_index() })
215 }
216
217 pub fn link_pins(&self, link: LinkId) -> Option<(PinId, PinId)> {
218 let mut start = 0usize;
219 let mut end = 0usize;
220 unsafe { sys::dne_get_link_pins(link.raw(), &mut start, &mut end) }
221 .then_some((PinId(start), PinId(end)))
222 }
223
224 pub fn pin_had_any_links(&self, pin: PinId) -> bool {
225 unsafe { sys::dne_pin_had_any_links(pin.raw()) }
226 }
227
228 pub fn screen_size(&self) -> [f32; 2] {
229 from_vec2(unsafe { sys::dne_get_screen_size() })
230 }
231
232 pub fn screen_to_canvas(&self, pos: [f32; 2]) -> [f32; 2] {
233 assert_finite_vec2("NodeEditorFrame::screen_to_canvas()", "pos", pos);
234 from_vec2(unsafe { sys::dne_screen_to_canvas(vec2(pos)) })
235 }
236
237 pub fn canvas_to_screen(&self, pos: [f32; 2]) -> [f32; 2] {
238 assert_finite_vec2("NodeEditorFrame::canvas_to_screen()", "pos", pos);
239 from_vec2(unsafe { sys::dne_canvas_to_screen(vec2(pos)) })
240 }
241
242 pub fn node_count(&self) -> usize {
243 unsafe { sys::dne_get_node_count() }.max(0) as usize
244 }
245
246 pub fn ordered_node_ids(&self) -> Vec<NodeId> {
247 let count = self.node_count();
248 collect_node_ids(count, |ptr, len| unsafe {
249 sys::dne_get_ordered_node_ids(ptr, len)
250 })
251 }
252}
253
254fn optional_id<T>(make: fn(usize) -> T, f: impl FnOnce(*mut usize) -> bool) -> Option<T> {
255 let mut raw = 0usize;
256 f(&mut raw).then_some(make(raw))
257}
258
259pub(super) fn collect_node_ids(
260 count: usize,
261 f: impl FnOnce(*mut usize, i32) -> i32,
262) -> Vec<NodeId> {
263 collect_ids(count, f).into_iter().map(NodeId).collect()
264}
265
266pub(super) fn collect_link_ids(
267 count: usize,
268 f: impl FnOnce(*mut usize, i32) -> i32,
269) -> Vec<LinkId> {
270 collect_ids(count, f).into_iter().map(LinkId).collect()
271}
272
273fn collect_ids(count: usize, f: impl FnOnce(*mut usize, i32) -> i32) -> Vec<usize> {
274 if count == 0 {
275 return Vec::new();
276 }
277 let count = count.min(i32::MAX as usize);
278 let mut values = vec![0usize; count];
279 let written = f(values.as_mut_ptr(), values.len() as i32).max(0) as usize;
280 values.truncate(written.min(count));
281 values
282}
283
284fn mouse_button_from_index(index: sys::ImGuiMouseButton) -> Option<MouseButton> {
285 match index {
286 value if value == MouseButton::Left as i32 => Some(MouseButton::Left),
287 value if value == MouseButton::Right as i32 => Some(MouseButton::Right),
288 value if value == MouseButton::Middle as i32 => Some(MouseButton::Middle),
289 value if value == MouseButton::Extra1 as i32 => Some(MouseButton::Extra1),
290 value if value == MouseButton::Extra2 as i32 => Some(MouseButton::Extra2),
291 _ => None,
292 }
293}
294
295#[cfg(test)]
296mod tests {
297 use super::*;
298
299 #[test]
300 fn mouse_button_indices_map_known_imgui_buttons() {
301 assert_eq!(mouse_button_from_index(0), Some(MouseButton::Left));
302 assert_eq!(mouse_button_from_index(1), Some(MouseButton::Right));
303 assert_eq!(mouse_button_from_index(2), Some(MouseButton::Middle));
304 assert_eq!(mouse_button_from_index(3), Some(MouseButton::Extra1));
305 assert_eq!(mouse_button_from_index(4), Some(MouseButton::Extra2));
306 assert_eq!(mouse_button_from_index(-1), None);
307 assert_eq!(mouse_button_from_index(99), None);
308 }
309}