1use crate::sys;
2use dear_imgui_rs::sys as imgui_sys;
3use dear_imgui_rs::{Context as ImGuiContext, Ui};
4use std::os::raw::c_void;
5
6pub struct Context {
8 raw: *mut sys::ImNodesContext,
9}
10
11impl Context {
12 pub fn try_create(_imgui: &ImGuiContext) -> dear_imgui_rs::ImGuiResult<Self> {
14 unsafe {
15 sys::imnodes_SetImGuiContext(imgui_sys::igGetCurrentContext());
16 }
17 let raw = unsafe { sys::imnodes_CreateContext() };
18 if raw.is_null() {
19 return Err(dear_imgui_rs::ImGuiError::context_creation(
20 "imnodes_CreateContext returned null",
21 ));
22 }
23 unsafe { sys::imnodes_SetCurrentContext(raw) };
24 Ok(Self { raw })
25 }
26
27 pub fn create(imgui: &ImGuiContext) -> Self {
29 Self::try_create(imgui).expect("Failed to create ImNodes context")
30 }
31
32 pub fn set_as_current(&self) {
34 unsafe { sys::imnodes_SetCurrentContext(self.raw) };
35 }
36}
37
38impl Drop for Context {
39 fn drop(&mut self) {
40 if !self.raw.is_null() {
41 unsafe { sys::imnodes_DestroyContext(self.raw) };
42 }
43 }
44}
45
46pub struct EditorContext {
50 raw: *mut sys::ImNodesEditorContext,
51}
52
53impl EditorContext {
54 pub fn try_create() -> dear_imgui_rs::ImGuiResult<Self> {
55 let raw = unsafe { sys::imnodes_EditorContextCreate() };
56 if raw.is_null() {
57 return Err(dear_imgui_rs::ImGuiError::context_creation(
58 "imnodes_EditorContextCreate returned null",
59 ));
60 }
61 Ok(Self { raw })
62 }
63
64 pub fn create() -> Self {
65 Self::try_create().expect("Failed to create ImNodes editor context")
66 }
67
68 pub fn set_current(&self) {
69 unsafe { sys::imnodes_EditorContextSet(self.raw) };
70 }
71
72 pub fn get_panning(&self) -> [f32; 2] {
73 unsafe { sys::imnodes_EditorContextSet(self.raw) };
74 let out = unsafe { crate::compat_ffi::imnodes_EditorContextGetPanning() };
75 [out.x, out.y]
76 }
77
78 pub fn reset_panning(&self, pos: [f32; 2]) {
79 unsafe { sys::imnodes_EditorContextSet(self.raw) };
80 unsafe {
81 sys::imnodes_EditorContextResetPanning(sys::ImVec2_c {
82 x: pos[0],
83 y: pos[1],
84 })
85 };
86 }
87
88 pub fn move_to_node(&self, node_id: i32) {
89 unsafe { sys::imnodes_EditorContextSet(self.raw) };
90 unsafe { sys::imnodes_EditorContextMoveToNode(node_id) };
91 }
92
93 pub fn save_state_to_ini_string(&self) -> String {
95 unsafe {
96 let mut size: usize = 0;
97 let ptr = sys::imnodes_SaveEditorStateToIniString(self.raw, &mut size as *mut usize);
98 if ptr.is_null() || size == 0 {
99 return String::new();
100 }
101 let slice = std::slice::from_raw_parts(ptr as *const u8, size);
102 String::from_utf8_lossy(slice).into_owned()
103 }
104 }
105
106 pub fn load_state_from_ini_string(&self, data: &str) {
108 unsafe {
109 sys::imnodes_LoadEditorStateFromIniString(
110 self.raw,
111 data.as_ptr() as *const i8,
112 data.len(),
113 )
114 }
115 }
116
117 pub fn save_state_to_ini_file(&self, file_name: &str) {
119 let c = std::ffi::CString::new(file_name).unwrap_or_default();
120 unsafe { sys::imnodes_SaveEditorStateToIniFile(self.raw, c.as_ptr()) }
121 }
122
123 pub fn load_state_from_ini_file(&self, file_name: &str) {
125 let c = std::ffi::CString::new(file_name).unwrap_or_default();
126 unsafe { sys::imnodes_LoadEditorStateFromIniFile(self.raw, c.as_ptr()) }
127 }
128}
129
130impl Drop for EditorContext {
131 fn drop(&mut self) {
132 if !self.raw.is_null() {
133 unsafe { sys::imnodes_EditorContextFree(self.raw) };
134 }
135 }
136}
137
138pub struct NodesUi<'ui> {
142 _ui: &'ui Ui,
143 _ctx: &'ui Context,
144}
145
146impl<'ui> NodesUi<'ui> {
147 pub(crate) fn new(ui: &'ui Ui, ctx: &'ui Context) -> Self {
148 ctx.set_as_current();
150 Self { _ui: ui, _ctx: ctx }
151 }
152
153 pub fn editor(&self, editor: Option<&'ui EditorContext>) -> NodeEditor<'ui> {
155 NodeEditor::begin(self._ui, editor)
156 }
157}
158
159pub struct NodeEditor<'ui> {
161 _ui: &'ui Ui,
162 ended: bool,
163}
164
165impl<'ui> NodeEditor<'ui> {
166 pub(crate) fn begin(ui: &'ui Ui, editor: Option<&EditorContext>) -> Self {
167 if let Some(ed) = editor {
168 unsafe { sys::imnodes_EditorContextSet(ed.raw) }
169 }
170 unsafe { sys::imnodes_BeginNodeEditor() };
171 Self {
172 _ui: ui,
173 ended: false,
174 }
175 }
176
177 pub fn minimap(&self, size_fraction: f32, location: crate::MiniMapLocation) {
179 unsafe {
180 sys::imnodes_MiniMap(
181 size_fraction,
182 location as sys::ImNodesMiniMapLocation,
183 None,
184 std::ptr::null_mut(),
185 )
186 }
187 }
188
189 pub fn minimap_with_callback<F: FnMut(i32)>(
191 &self,
192 size_fraction: f32,
193 location: crate::MiniMapLocation,
194 callback: &mut F,
195 ) {
196 unsafe extern "C" fn trampoline(node_id: i32, user: *mut c_void) {
197 unsafe {
198 let closure = &mut *(user as *mut &mut dyn FnMut(i32));
199 (closure)(node_id);
200 }
201 }
202 let mut cb_obj: &mut dyn FnMut(i32) = callback;
203 let user_ptr = &mut cb_obj as *mut _ as *mut c_void;
204 unsafe {
205 sys::imnodes_MiniMap(
206 size_fraction,
207 location as sys::ImNodesMiniMapLocation,
208 Some(trampoline),
209 user_ptr,
210 )
211 }
212 }
213
214 pub fn node(&self, id: i32) -> NodeToken<'_> {
216 unsafe { sys::imnodes_BeginNode(id) };
217 NodeToken {
218 _phantom: std::marker::PhantomData,
219 }
220 }
221
222 pub fn input_attr(&self, id: i32, shape: crate::PinShape) -> AttributeToken<'_> {
224 unsafe { sys::imnodes_BeginInputAttribute(id, shape as sys::ImNodesPinShape) };
225 AttributeToken {
226 kind: AttrKind::Input,
227 _phantom: std::marker::PhantomData,
228 }
229 }
230
231 pub fn output_attr(&self, id: i32, shape: crate::PinShape) -> AttributeToken<'_> {
233 unsafe { sys::imnodes_BeginOutputAttribute(id, shape as i32) };
234 AttributeToken {
235 kind: AttrKind::Output,
236 _phantom: std::marker::PhantomData,
237 }
238 }
239
240 pub fn static_attr(&self, id: i32) -> AttributeToken<'_> {
242 unsafe { sys::imnodes_BeginStaticAttribute(id) };
243 AttributeToken {
244 kind: AttrKind::Static,
245 _phantom: std::marker::PhantomData,
246 }
247 }
248
249 pub fn link(&self, id: i32, start_attr: i32, end_attr: i32) {
251 unsafe { sys::imnodes_Link(id, start_attr, end_attr) }
252 }
253
254 pub fn is_link_created(&self) -> Option<crate::LinkCreated> {
256 let mut start_attr = 0i32;
257 let mut end_attr = 0i32;
258 let mut from_snap = false;
259 let created = unsafe {
260 sys::imnodes_IsLinkCreated_BoolPtr(
261 &mut start_attr as *mut i32,
262 &mut end_attr as *mut i32,
263 &mut from_snap as *mut bool,
264 )
265 };
266 if created {
267 Some(crate::LinkCreated {
268 start_attr,
269 end_attr,
270 from_snap,
271 })
272 } else {
273 None
274 }
275 }
276
277 pub fn is_link_created_with_nodes(&self) -> Option<crate::LinkCreatedEx> {
279 let mut start_node = 0i32;
280 let mut start_attr = 0i32;
281 let mut end_node = 0i32;
282 let mut end_attr = 0i32;
283 let mut from_snap = false;
284 let created = unsafe {
285 sys::imnodes_IsLinkCreated_IntPtr(
286 &mut start_node as *mut i32,
287 &mut start_attr as *mut i32,
288 &mut end_node as *mut i32,
289 &mut end_attr as *mut i32,
290 &mut from_snap as *mut bool,
291 )
292 };
293 if created {
294 Some(crate::LinkCreatedEx {
295 start_node,
296 start_attr,
297 end_node,
298 end_attr,
299 from_snap,
300 })
301 } else {
302 None
303 }
304 }
305
306 pub fn selected_nodes(&self) -> Vec<i32> {
308 let n = unsafe { sys::imnodes_NumSelectedNodes() };
309 if n <= 0 {
310 return Vec::new();
311 }
312 let mut buf = vec![0i32; n as usize];
313 unsafe { sys::imnodes_GetSelectedNodes(buf.as_mut_ptr()) };
314 buf
315 }
316
317 pub fn selected_links(&self) -> Vec<i32> {
318 let n = unsafe { sys::imnodes_NumSelectedLinks() };
319 if n <= 0 {
320 return Vec::new();
321 }
322 let mut buf = vec![0i32; n as usize];
323 unsafe { sys::imnodes_GetSelectedLinks(buf.as_mut_ptr()) };
324 buf
325 }
326
327 pub fn clear_selection(&self) {
328 unsafe {
329 sys::imnodes_ClearNodeSelection_Nil();
330 sys::imnodes_ClearLinkSelection_Nil();
331 }
332 }
333
334 pub fn is_editor_hovered(&self) -> bool {
336 unsafe { sys::imnodes_IsEditorHovered() }
337 }
338 pub fn hovered_node(&self) -> Option<i32> {
339 let mut id = 0;
340 if unsafe { sys::imnodes_IsNodeHovered(&mut id) } {
341 Some(id)
342 } else {
343 None
344 }
345 }
346 pub fn hovered_link(&self) -> Option<i32> {
347 let mut id = 0;
348 if unsafe { sys::imnodes_IsLinkHovered(&mut id) } {
349 Some(id)
350 } else {
351 None
352 }
353 }
354 pub fn hovered_pin(&self) -> Option<i32> {
355 let mut id = 0;
356 if unsafe { sys::imnodes_IsPinHovered(&mut id) } {
357 Some(id)
358 } else {
359 None
360 }
361 }
362
363 pub fn is_attribute_active(&self) -> bool {
365 unsafe { sys::imnodes_IsAttributeActive() }
366 }
367 pub fn any_attribute_active(&self) -> Option<i32> {
368 let mut id = 0;
369 if unsafe { sys::imnodes_IsAnyAttributeActive(&mut id) } {
370 Some(id)
371 } else {
372 None
373 }
374 }
375
376 pub fn is_link_started(&self) -> Option<i32> {
378 let mut id = 0;
379 if unsafe { sys::imnodes_IsLinkStarted(&mut id) } {
380 Some(id)
381 } else {
382 None
383 }
384 }
385 pub fn is_link_dropped(&self, including_detached: bool) -> Option<i32> {
386 let mut id = 0;
387 if unsafe { sys::imnodes_IsLinkDropped(&mut id, including_detached) } {
388 Some(id)
389 } else {
390 None
391 }
392 }
393
394 pub fn set_style_flag(&self, flag: crate::StyleFlags, enabled: bool) {
396 unsafe {
397 let style = &mut *sys::imnodes_GetStyle();
398 let mut f = style.Flags as i32;
399 let bit = flag.bits();
400 if enabled {
401 f |= bit;
402 } else {
403 f &= !bit;
404 }
405 style.Flags = f;
406 }
407 }
408
409 pub fn enable_link_detach_with_ctrl(&self) {
411 unsafe {
412 let io = &mut *sys::imnodes_GetIO();
413 io.LinkDetachWithModifierClick.Modifier = sys::getIOKeyCtrlPtr();
414 }
415 }
416 pub fn enable_multiple_select_with_ctrl(&self) {
418 unsafe {
419 let io = &mut *sys::imnodes_GetIO();
420 io.MultipleSelectModifier.Modifier = sys::getIOKeyCtrlPtr();
421 }
422 }
423 pub fn enable_multiple_select_with_shift(&self) {
425 unsafe {
426 let io = &mut *sys::imnodes_GetIO();
427 io.MultipleSelectModifier.Modifier = sys::imnodes_getIOKeyShiftPtr();
428 }
429 }
430 pub fn emulate_three_button_mouse_with_alt(&self) {
432 unsafe {
433 let io = &mut *sys::imnodes_GetIO();
434 io.EmulateThreeButtonMouse.Modifier = sys::imnodes_getIOKeyAltPtr();
435 }
436 }
437 pub fn set_alt_mouse_button(&self, button: i32) {
439 unsafe {
440 (*sys::imnodes_GetIO()).AltMouseButton = button;
441 }
442 }
443 pub fn set_auto_panning_speed(&self, speed: f32) {
444 unsafe {
445 (*sys::imnodes_GetIO()).AutoPanningSpeed = speed;
446 }
447 }
448 pub fn style_colors_dark(&self) {
450 unsafe { sys::imnodes_StyleColorsDark(sys::imnodes_GetStyle()) }
451 }
452 pub fn style_colors_classic(&self) {
453 unsafe { sys::imnodes_StyleColorsClassic(sys::imnodes_GetStyle()) }
454 }
455 pub fn style_colors_light(&self) {
456 unsafe { sys::imnodes_StyleColorsLight(sys::imnodes_GetStyle()) }
457 }
458
459 pub fn set_node_pos_grid(&self, node_id: i32, pos: [f32; 2]) {
463 unsafe {
464 sys::imnodes_SetNodeGridSpacePos(
465 node_id,
466 sys::ImVec2_c {
467 x: pos[0],
468 y: pos[1],
469 },
470 )
471 }
472 }
473
474 pub fn get_node_pos_grid(&self, node_id: i32) -> [f32; 2] {
475 let out = unsafe { sys::imnodes_GetNodeGridSpacePos(node_id) };
476 [out.x, out.y]
477 }
478
479 pub fn set_grid_spacing(&self, spacing: f32) {
481 unsafe {
482 (*sys::imnodes_GetStyle()).GridSpacing = spacing;
483 }
484 }
485 pub fn set_link_thickness(&self, thickness: f32) {
486 unsafe {
487 (*sys::imnodes_GetStyle()).LinkThickness = thickness;
488 }
489 }
490 pub fn set_node_corner_rounding(&self, rounding: f32) {
491 unsafe {
492 (*sys::imnodes_GetStyle()).NodeCornerRounding = rounding;
493 }
494 }
495 pub fn set_node_padding(&self, padding: [f32; 2]) {
496 unsafe {
497 (*sys::imnodes_GetStyle()).NodePadding = sys::ImVec2_c {
498 x: padding[0],
499 y: padding[1],
500 };
501 }
502 }
503 pub fn set_pin_circle_radius(&self, r: f32) {
504 unsafe {
505 (*sys::imnodes_GetStyle()).PinCircleRadius = r;
506 }
507 }
508 pub fn set_pin_quad_side_length(&self, v: f32) {
509 unsafe {
510 (*sys::imnodes_GetStyle()).PinQuadSideLength = v;
511 }
512 }
513 pub fn set_pin_triangle_side_length(&self, v: f32) {
514 unsafe {
515 (*sys::imnodes_GetStyle()).PinTriangleSideLength = v;
516 }
517 }
518 pub fn set_pin_line_thickness(&self, v: f32) {
519 unsafe {
520 (*sys::imnodes_GetStyle()).PinLineThickness = v;
521 }
522 }
523 pub fn set_pin_hover_radius(&self, v: f32) {
524 unsafe {
525 (*sys::imnodes_GetStyle()).PinHoverRadius = v;
526 }
527 }
528 pub fn set_pin_offset(&self, offset: f32) {
529 unsafe {
530 (*sys::imnodes_GetStyle()).PinOffset = offset;
531 }
532 }
533 pub fn set_link_hover_distance(&self, v: f32) {
534 unsafe {
535 (*sys::imnodes_GetStyle()).LinkHoverDistance = v;
536 }
537 }
538 pub fn set_link_line_segments_per_length(&self, v: f32) {
539 unsafe {
540 (*sys::imnodes_GetStyle()).LinkLineSegmentsPerLength = v;
541 }
542 }
543 pub fn set_node_border_thickness(&self, v: f32) {
544 unsafe {
545 (*sys::imnodes_GetStyle()).NodeBorderThickness = v;
546 }
547 }
548 pub fn set_minimap_padding(&self, padding: [f32; 2]) {
549 unsafe {
550 (*sys::imnodes_GetStyle()).MiniMapPadding = sys::ImVec2_c {
551 x: padding[0],
552 y: padding[1],
553 };
554 }
555 }
556 pub fn set_minimap_offset(&self, offset: [f32; 2]) {
557 unsafe {
558 (*sys::imnodes_GetStyle()).MiniMapOffset = sys::ImVec2_c {
559 x: offset[0],
560 y: offset[1],
561 };
562 }
563 }
564
565 pub fn set_color(&self, elem: crate::style::ColorElement, color: [f32; 4]) {
566 let abgr = unsafe {
567 imgui_sys::igColorConvertFloat4ToU32(imgui_sys::ImVec4 {
568 x: color[0],
569 y: color[1],
570 z: color[2],
571 w: color[3],
572 })
573 };
574 unsafe { (*sys::imnodes_GetStyle()).Colors[elem as u32 as usize] = abgr };
575 }
576
577 pub fn get_color(&self, elem: crate::style::ColorElement) -> [f32; 4] {
579 let col = unsafe { (*sys::imnodes_GetStyle()).Colors[elem as u32 as usize] };
580 let out = unsafe { imgui_sys::igColorConvertU32ToFloat4(col) };
581 [out.x, out.y, out.z, out.w]
582 }
583
584 pub fn set_node_pos_screen(&self, node_id: i32, pos: [f32; 2]) {
586 unsafe {
587 sys::imnodes_SetNodeScreenSpacePos(
588 node_id,
589 sys::ImVec2_c {
590 x: pos[0],
591 y: pos[1],
592 },
593 )
594 }
595 }
596 pub fn set_node_pos_editor(&self, node_id: i32, pos: [f32; 2]) {
597 unsafe {
598 sys::imnodes_SetNodeEditorSpacePos(
599 node_id,
600 sys::ImVec2_c {
601 x: pos[0],
602 y: pos[1],
603 },
604 )
605 }
606 }
607 pub fn get_node_pos_screen(&self, node_id: i32) -> [f32; 2] {
608 let out = unsafe { crate::compat_ffi::imnodes_GetNodeScreenSpacePos(node_id) };
609 [out.x, out.y]
610 }
611 pub fn get_node_pos_editor(&self, node_id: i32) -> [f32; 2] {
612 let out = unsafe { crate::compat_ffi::imnodes_GetNodeEditorSpacePos(node_id) };
613 [out.x, out.y]
614 }
615
616 pub fn set_node_draggable(&self, node_id: i32, draggable: bool) {
618 unsafe { sys::imnodes_SetNodeDraggable(node_id, draggable) }
619 }
620 pub fn snap_node_to_grid(&self, node_id: i32) {
621 unsafe { sys::imnodes_SnapNodeToGrid(node_id) }
622 }
623 pub fn get_node_dimensions(&self, node_id: i32) -> [f32; 2] {
624 let out = unsafe { crate::compat_ffi::imnodes_GetNodeDimensions(node_id) };
625 [out.x, out.y]
626 }
627
628 pub fn is_link_destroyed(&self) -> Option<i32> {
630 let mut id = 0i32;
631 let destroyed = unsafe { sys::imnodes_IsLinkDestroyed(&mut id as *mut i32) };
632 if destroyed { Some(id) } else { None }
633 }
634}
635
636impl<'ui> Drop for NodeEditor<'ui> {
637 fn drop(&mut self) {
638 if !self.ended {
639 unsafe { sys::imnodes_EndNodeEditor() };
640 self.ended = true;
641 }
642 }
643}
644
645pub struct NodeToken<'a> {
647 pub(crate) _phantom: std::marker::PhantomData<&'a ()>,
648}
649impl<'a> NodeToken<'a> {
650 pub fn title_bar<F: FnOnce()>(&self, f: F) {
651 unsafe { sys::imnodes_BeginNodeTitleBar() };
652 f();
653 unsafe { sys::imnodes_EndNodeTitleBar() };
654 }
655 pub fn end(self) {}
656}
657impl<'a> Drop for NodeToken<'a> {
658 fn drop(&mut self) {
659 unsafe { sys::imnodes_EndNode() }
660 }
661}
662
663pub(crate) enum AttrKind {
664 Input,
665 Output,
666 Static,
667}
668
669pub struct AttributeToken<'a> {
670 pub(crate) kind: AttrKind,
671 pub(crate) _phantom: std::marker::PhantomData<&'a ()>,
672}
673
674impl<'a> AttributeToken<'a> {
675 pub fn end(self) {}
676}
677
678impl<'a> Drop for AttributeToken<'a> {
679 fn drop(&mut self) {
680 unsafe {
681 match self.kind {
682 AttrKind::Input => sys::imnodes_EndInputAttribute(),
683 AttrKind::Output => sys::imnodes_EndOutputAttribute(),
684 AttrKind::Static => sys::imnodes_EndStaticAttribute(),
685 }
686 }
687 }
688}
689
690pub struct PostEditor;
692
693impl<'ui> NodeEditor<'ui> {
694 pub fn end(mut self) -> PostEditor {
696 if !self.ended {
697 unsafe { sys::imnodes_EndNodeEditor() };
698 self.ended = true;
699 }
700 PostEditor
701 }
702}
703
704impl PostEditor {
705 pub fn save_state_to_ini_string(&self) -> String {
707 unsafe {
712 let mut size: usize = 0;
713 let ptr = sys::imnodes_SaveCurrentEditorStateToIniString(&mut size as *mut usize);
714 if ptr.is_null() || size == 0 {
715 return String::new();
716 }
717 let slice = std::slice::from_raw_parts(ptr as *const u8, size);
718 String::from_utf8_lossy(slice).into_owned()
719 }
720 }
721
722 pub fn load_state_from_ini_string(&self, data: &str) {
724 unsafe {
728 sys::imnodes_LoadCurrentEditorStateFromIniString(
729 data.as_ptr() as *const i8,
730 data.len(),
731 );
732 }
733 }
734 pub fn save_state_to_ini_file(&self, file_name: &str) {
736 let c = std::ffi::CString::new(file_name).unwrap_or_default();
737 unsafe { sys::imnodes_SaveCurrentEditorStateToIniFile(c.as_ptr()) }
740 }
741 pub fn load_state_from_ini_file(&self, file_name: &str) {
742 let c = std::ffi::CString::new(file_name).unwrap_or_default();
743 unsafe { sys::imnodes_LoadCurrentEditorStateFromIniFile(c.as_ptr()) }
745 }
746 pub fn select_node(&self, node_id: i32) {
748 unsafe { sys::imnodes_SelectNode(node_id) }
749 }
750 pub fn clear_node_selection_of(&self, node_id: i32) {
751 unsafe { sys::imnodes_ClearNodeSelection_Int(node_id) }
752 }
753 pub fn is_node_selected(&self, node_id: i32) -> bool {
754 unsafe { sys::imnodes_IsNodeSelected(node_id) }
755 }
756 pub fn select_link(&self, link_id: i32) {
757 unsafe { sys::imnodes_SelectLink(link_id) }
758 }
759 pub fn clear_link_selection_of(&self, link_id: i32) {
760 unsafe { sys::imnodes_ClearLinkSelection_Int(link_id) }
761 }
762 pub fn is_link_selected(&self, link_id: i32) -> bool {
763 unsafe { sys::imnodes_IsLinkSelected(link_id) }
764 }
765 pub fn selected_nodes(&self) -> Vec<i32> {
766 let n = unsafe { sys::imnodes_NumSelectedNodes() };
769 if n <= 0 {
770 return Vec::new();
771 }
772 let mut buf = vec![0i32; n as usize];
773 unsafe { sys::imnodes_GetSelectedNodes(buf.as_mut_ptr()) };
774 buf
775 }
776
777 pub fn selected_links(&self) -> Vec<i32> {
778 let n = unsafe { sys::imnodes_NumSelectedLinks() };
781 if n <= 0 {
782 return Vec::new();
783 }
784 let mut buf = vec![0i32; n as usize];
785 unsafe { sys::imnodes_GetSelectedLinks(buf.as_mut_ptr()) };
786 buf
787 }
788
789 pub fn clear_selection(&self) {
790 unsafe {
791 sys::imnodes_ClearNodeSelection_Nil();
792 sys::imnodes_ClearLinkSelection_Nil();
793 }
794 }
795
796 pub fn is_link_created(&self) -> Option<crate::LinkCreated> {
797 let mut start_attr = 0i32;
798 let mut end_attr = 0i32;
799 let mut from_snap = false;
800 let created = unsafe {
801 sys::imnodes_IsLinkCreated_BoolPtr(
802 &mut start_attr as *mut i32,
803 &mut end_attr as *mut i32,
804 &mut from_snap as *mut bool,
805 )
806 };
807 if created {
808 Some(crate::LinkCreated {
809 start_attr,
810 end_attr,
811 from_snap,
812 })
813 } else {
814 None
815 }
816 }
817
818 pub fn is_link_created_with_nodes(&self) -> Option<crate::LinkCreatedEx> {
819 let mut start_node = 0i32;
820 let mut start_attr = 0i32;
821 let mut end_node = 0i32;
822 let mut end_attr = 0i32;
823 let mut from_snap = false;
824 let created = unsafe {
825 sys::imnodes_IsLinkCreated_IntPtr(
826 &mut start_node as *mut i32,
827 &mut start_attr as *mut i32,
828 &mut end_node as *mut i32,
829 &mut end_attr as *mut i32,
830 &mut from_snap as *mut bool,
831 )
832 };
833 if created {
834 Some(crate::LinkCreatedEx {
835 start_node,
836 start_attr,
837 end_node,
838 end_attr,
839 from_snap,
840 })
841 } else {
842 None
843 }
844 }
845
846 pub fn is_link_destroyed(&self) -> Option<i32> {
847 let mut id = 0i32;
848 let destroyed = unsafe { sys::imnodes_IsLinkDestroyed(&mut id as *mut i32) };
849 if destroyed { Some(id) } else { None }
850 }
851
852 pub fn is_editor_hovered(&self) -> bool {
853 unsafe { sys::imnodes_IsEditorHovered() }
854 }
855 pub fn hovered_node(&self) -> Option<i32> {
856 let mut id = 0;
857 if unsafe { sys::imnodes_IsNodeHovered(&mut id) } {
858 Some(id)
859 } else {
860 None
861 }
862 }
863 pub fn hovered_link(&self) -> Option<i32> {
864 let mut id = 0;
865 if unsafe { sys::imnodes_IsLinkHovered(&mut id) } {
866 Some(id)
867 } else {
868 None
869 }
870 }
871 pub fn hovered_pin(&self) -> Option<i32> {
872 let mut id = 0;
873 if unsafe { sys::imnodes_IsPinHovered(&mut id) } {
874 Some(id)
875 } else {
876 None
877 }
878 }
879 pub fn is_attribute_active(&self) -> bool {
880 unsafe { sys::imnodes_IsAttributeActive() }
881 }
882 pub fn any_attribute_active(&self) -> Option<i32> {
883 let mut id = 0;
884 if unsafe { sys::imnodes_IsAnyAttributeActive(&mut id) } {
885 Some(id)
886 } else {
887 None
888 }
889 }
890 pub fn is_link_started(&self) -> Option<i32> {
891 let mut id = 0;
892 if unsafe { sys::imnodes_IsLinkStarted(&mut id) } {
893 Some(id)
894 } else {
895 None
896 }
897 }
898 pub fn is_link_dropped(&self, including_detached: bool) -> Option<i32> {
899 let mut id = 0;
900 if unsafe { sys::imnodes_IsLinkDropped(&mut id, including_detached) } {
901 Some(id)
902 } else {
903 None
904 }
905 }
906}