use super::{Context, ImNodesScope, NodeEditor};
use crate::sys;
use dear_imgui_rs::Ui;
use std::marker::PhantomData;
use std::os::raw::c_char;
use std::rc::Rc;
pub struct PostEditor<'ui> {
#[allow(dead_code)]
pub(super) _ui: &'ui Ui,
#[allow(dead_code)]
pub(super) _ctx: &'ui Context,
pub(super) scope: ImNodesScope,
pub(super) editor_hovered: bool,
pub(super) hovered_node: Option<i32>,
pub(super) hovered_link: Option<i32>,
pub(super) hovered_pin: Option<i32>,
pub(super) link_created: Option<crate::LinkCreated>,
pub(super) link_created_ex: Option<crate::LinkCreatedEx>,
pub(super) link_destroyed: Option<i32>,
pub(super) any_attribute_active: Option<i32>,
pub(super) link_started: Option<i32>,
pub(super) link_dropped_excluding_detached: Option<i32>,
pub(super) link_dropped_including_detached: Option<i32>,
pub(super) _not_send_sync: PhantomData<Rc<()>>,
}
impl<'ui> NodeEditor<'ui> {
pub fn end(mut self) -> PostEditor<'ui> {
if !self.ended {
self.bind();
unsafe { sys::imnodes_EndNodeEditor() };
self.ended = true;
}
self.bind();
let editor_hovered = unsafe { sys::imnodes_IsEditorHovered() };
let mut hovered_node = 0i32;
let hovered_node = if unsafe { sys::imnodes_IsNodeHovered(&mut hovered_node) } {
Some(hovered_node)
} else {
None
};
let mut hovered_link = 0i32;
let hovered_link = if unsafe { sys::imnodes_IsLinkHovered(&mut hovered_link) } {
Some(hovered_link)
} else {
None
};
let mut hovered_pin = 0i32;
let hovered_pin = if unsafe { sys::imnodes_IsPinHovered(&mut hovered_pin) } {
Some(hovered_pin)
} else {
None
};
let link_created_ex = {
let mut start_node = 0i32;
let mut start_attr = 0i32;
let mut end_node = 0i32;
let mut end_attr = 0i32;
let mut from_snap = false;
let created = unsafe {
sys::imnodes_IsLinkCreated_IntPtr(
&mut start_node as *mut i32,
&mut start_attr as *mut i32,
&mut end_node as *mut i32,
&mut end_attr as *mut i32,
&mut from_snap as *mut bool,
)
};
if created {
Some(crate::LinkCreatedEx {
start_node,
start_attr,
end_node,
end_attr,
from_snap,
})
} else {
None
}
};
let link_created = link_created_ex.map(|ex| crate::LinkCreated {
start_attr: ex.start_attr,
end_attr: ex.end_attr,
from_snap: ex.from_snap,
});
let link_destroyed = {
let mut id = 0i32;
if unsafe { sys::imnodes_IsLinkDestroyed(&mut id as *mut i32) } {
Some(id)
} else {
None
}
};
let any_attribute_active = {
let mut id = 0i32;
if unsafe { sys::imnodes_IsAnyAttributeActive(&mut id) } {
Some(id)
} else {
None
}
};
let link_started = {
let mut id = 0i32;
if unsafe { sys::imnodes_IsLinkStarted(&mut id) } {
Some(id)
} else {
None
}
};
let link_dropped_excluding_detached = {
let mut id = 0i32;
if unsafe { sys::imnodes_IsLinkDropped(&mut id, false) } {
Some(id)
} else {
None
}
};
let link_dropped_including_detached = if let Some(id) = link_dropped_excluding_detached {
Some(id)
} else {
let mut id = 0i32;
if unsafe { sys::imnodes_IsLinkDropped(&mut id, true) } {
Some(id)
} else {
None
}
};
PostEditor {
_ui: self._ui,
_ctx: self._ctx,
scope: self.scope.clone(),
editor_hovered,
hovered_node,
hovered_link,
hovered_pin,
link_created,
link_created_ex,
link_destroyed,
any_attribute_active,
link_started,
link_dropped_excluding_detached,
link_dropped_including_detached,
_not_send_sync: PhantomData,
}
}
}
impl<'ui> PostEditor<'ui> {
#[inline]
fn bind(&self) {
self.scope.bind();
}
pub fn save_state_to_ini_string(&self) -> String {
unsafe {
self.bind();
let mut size: usize = 0;
let ptr = sys::imnodes_SaveCurrentEditorStateToIniString(&mut size as *mut usize);
if ptr.is_null() || size == 0 {
return String::new();
}
let mut slice = std::slice::from_raw_parts(ptr as *const u8, size);
if slice.last() == Some(&0) {
slice = &slice[..slice.len().saturating_sub(1)];
}
String::from_utf8_lossy(slice).into_owned()
}
}
pub fn load_state_from_ini_string(&self, data: &str) {
unsafe {
self.bind();
sys::imnodes_LoadCurrentEditorStateFromIniString(
data.as_ptr() as *const c_char,
data.len(),
);
}
}
pub fn save_state_to_ini_file(&self, file_name: &str) {
let file_name = if file_name.contains('\0') {
""
} else {
file_name
};
self.bind();
dear_imgui_rs::with_scratch_txt(file_name, |ptr| unsafe {
sys::imnodes_SaveCurrentEditorStateToIniFile(ptr)
})
}
pub fn load_state_from_ini_file(&self, file_name: &str) {
let file_name = if file_name.contains('\0') {
""
} else {
file_name
};
self.bind();
dear_imgui_rs::with_scratch_txt(file_name, |ptr| unsafe {
sys::imnodes_LoadCurrentEditorStateFromIniFile(ptr)
})
}
pub fn select_node(&self, node_id: i32) {
self.bind();
unsafe { sys::imnodes_SelectNode(node_id) }
}
pub fn clear_node_selection_of(&self, node_id: i32) {
self.bind();
unsafe { sys::imnodes_ClearNodeSelection_Int(node_id) }
}
pub fn is_node_selected(&self, node_id: i32) -> bool {
self.bind();
unsafe { sys::imnodes_IsNodeSelected(node_id) }
}
pub fn select_link(&self, link_id: i32) {
self.bind();
unsafe { sys::imnodes_SelectLink(link_id) }
}
pub fn clear_link_selection_of(&self, link_id: i32) {
self.bind();
unsafe { sys::imnodes_ClearLinkSelection_Int(link_id) }
}
pub fn is_link_selected(&self, link_id: i32) -> bool {
self.bind();
unsafe { sys::imnodes_IsLinkSelected(link_id) }
}
pub fn selected_nodes(&self) -> Vec<i32> {
self.bind();
let n = unsafe { sys::imnodes_NumSelectedNodes() };
if n <= 0 {
return Vec::new();
}
let mut buf = vec![0i32; n as usize];
unsafe { sys::imnodes_GetSelectedNodes(buf.as_mut_ptr()) };
buf
}
pub fn selected_links(&self) -> Vec<i32> {
self.bind();
let n = unsafe { sys::imnodes_NumSelectedLinks() };
if n <= 0 {
return Vec::new();
}
let mut buf = vec![0i32; n as usize];
unsafe { sys::imnodes_GetSelectedLinks(buf.as_mut_ptr()) };
buf
}
pub fn clear_selection(&self) {
self.bind();
unsafe {
sys::imnodes_ClearNodeSelection_Nil();
sys::imnodes_ClearLinkSelection_Nil();
}
}
pub fn is_link_created(&self) -> Option<crate::LinkCreated> {
self.link_created
}
pub fn is_link_created_with_nodes(&self) -> Option<crate::LinkCreatedEx> {
self.link_created_ex
}
pub fn is_link_destroyed(&self) -> Option<i32> {
self.link_destroyed
}
pub fn is_editor_hovered(&self) -> bool {
self.editor_hovered
}
pub fn hovered_node(&self) -> Option<i32> {
self.hovered_node
}
pub fn hovered_link(&self) -> Option<i32> {
self.hovered_link
}
pub fn hovered_pin(&self) -> Option<i32> {
self.hovered_pin
}
pub fn set_node_pos_screen(&self, node_id: i32, pos: [f32; 2]) {
self.bind();
unsafe {
sys::imnodes_SetNodeScreenSpacePos(
node_id,
sys::ImVec2_c {
x: pos[0],
y: pos[1],
},
)
}
}
pub fn set_node_pos_grid(&self, node_id: i32, pos: [f32; 2]) {
self.bind();
unsafe {
sys::imnodes_SetNodeGridSpacePos(
node_id,
sys::ImVec2_c {
x: pos[0],
y: pos[1],
},
)
}
}
pub fn is_attribute_active(&self) -> bool {
self.any_attribute_active.is_some()
}
pub fn any_attribute_active(&self) -> Option<i32> {
self.any_attribute_active
}
pub fn is_link_started(&self) -> Option<i32> {
self.link_started
}
pub fn is_link_dropped(&self, including_detached: bool) -> Option<i32> {
if including_detached {
self.link_dropped_including_detached
} else {
self.link_dropped_excluding_detached
}
}
}