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