dear_imnodes/context/
post.rs1use super::{Context, ImNodesScope, NodeEditor};
2use crate::sys;
3use dear_imgui_rs::Ui;
4use std::marker::PhantomData;
5use std::os::raw::c_char;
6use std::rc::Rc;
7
8pub struct PostEditor<'ui> {
10 #[allow(dead_code)]
11 pub(super) _ui: &'ui Ui,
12 #[allow(dead_code)]
13 pub(super) _ctx: &'ui Context,
14 pub(super) scope: ImNodesScope,
15 pub(super) editor_hovered: bool,
16 pub(super) hovered_node: Option<i32>,
17 pub(super) hovered_link: Option<i32>,
18 pub(super) hovered_pin: Option<i32>,
19 pub(super) link_created: Option<crate::LinkCreated>,
20 pub(super) link_created_ex: Option<crate::LinkCreatedEx>,
21 pub(super) link_destroyed: Option<i32>,
22 pub(super) any_attribute_active: Option<i32>,
23 pub(super) link_started: Option<i32>,
24 pub(super) link_dropped_excluding_detached: Option<i32>,
25 pub(super) link_dropped_including_detached: Option<i32>,
26 pub(super) _not_send_sync: PhantomData<Rc<()>>,
27}
28
29impl<'ui> NodeEditor<'ui> {
30 pub fn end(mut self) -> PostEditor<'ui> {
32 if !self.ended {
33 self.bind();
34 unsafe { sys::imnodes_EndNodeEditor() };
35 self.ended = true;
36 }
37
38 self.bind();
42 let editor_hovered = unsafe { sys::imnodes_IsEditorHovered() };
43 let mut hovered_node = 0i32;
44 let hovered_node = if unsafe { sys::imnodes_IsNodeHovered(&mut hovered_node) } {
45 Some(hovered_node)
46 } else {
47 None
48 };
49 let mut hovered_link = 0i32;
50 let hovered_link = if unsafe { sys::imnodes_IsLinkHovered(&mut hovered_link) } {
51 Some(hovered_link)
52 } else {
53 None
54 };
55 let mut hovered_pin = 0i32;
56 let hovered_pin = if unsafe { sys::imnodes_IsPinHovered(&mut hovered_pin) } {
57 Some(hovered_pin)
58 } else {
59 None
60 };
61
62 let link_created_ex = {
65 let mut start_node = 0i32;
66 let mut start_attr = 0i32;
67 let mut end_node = 0i32;
68 let mut end_attr = 0i32;
69 let mut from_snap = false;
70 let created = unsafe {
71 sys::imnodes_IsLinkCreated_IntPtr(
72 &mut start_node as *mut i32,
73 &mut start_attr as *mut i32,
74 &mut end_node as *mut i32,
75 &mut end_attr as *mut i32,
76 &mut from_snap as *mut bool,
77 )
78 };
79 if created {
80 Some(crate::LinkCreatedEx {
81 start_node,
82 start_attr,
83 end_node,
84 end_attr,
85 from_snap,
86 })
87 } else {
88 None
89 }
90 };
91 let link_created = link_created_ex.map(|ex| crate::LinkCreated {
92 start_attr: ex.start_attr,
93 end_attr: ex.end_attr,
94 from_snap: ex.from_snap,
95 });
96
97 let link_destroyed = {
98 let mut id = 0i32;
99 if unsafe { sys::imnodes_IsLinkDestroyed(&mut id as *mut i32) } {
100 Some(id)
101 } else {
102 None
103 }
104 };
105
106 let any_attribute_active = {
107 let mut id = 0i32;
108 if unsafe { sys::imnodes_IsAnyAttributeActive(&mut id) } {
109 Some(id)
110 } else {
111 None
112 }
113 };
114
115 let link_started = {
116 let mut id = 0i32;
117 if unsafe { sys::imnodes_IsLinkStarted(&mut id) } {
118 Some(id)
119 } else {
120 None
121 }
122 };
123
124 let link_dropped_excluding_detached = {
127 let mut id = 0i32;
128 if unsafe { sys::imnodes_IsLinkDropped(&mut id, false) } {
129 Some(id)
130 } else {
131 None
132 }
133 };
134 let link_dropped_including_detached = if let Some(id) = link_dropped_excluding_detached {
135 Some(id)
136 } else {
137 let mut id = 0i32;
138 if unsafe { sys::imnodes_IsLinkDropped(&mut id, true) } {
139 Some(id)
140 } else {
141 None
142 }
143 };
144
145 PostEditor {
146 _ui: self._ui,
147 _ctx: self._ctx,
148 scope: self.scope.clone(),
149 editor_hovered,
150 hovered_node,
151 hovered_link,
152 hovered_pin,
153 link_created,
154 link_created_ex,
155 link_destroyed,
156 any_attribute_active,
157 link_started,
158 link_dropped_excluding_detached,
159 link_dropped_including_detached,
160 _not_send_sync: PhantomData,
161 }
162 }
163}
164
165impl<'ui> PostEditor<'ui> {
166 #[inline]
167 fn bind(&self) {
168 self.scope.bind();
169 }
170
171 pub fn save_state_to_ini_string(&self) -> String {
173 unsafe {
178 self.bind();
179 let mut size: usize = 0;
180 let ptr = sys::imnodes_SaveCurrentEditorStateToIniString(&mut size as *mut usize);
181 if ptr.is_null() || size == 0 {
182 return String::new();
183 }
184 let mut slice = std::slice::from_raw_parts(ptr as *const u8, size);
185 if slice.last() == Some(&0) {
186 slice = &slice[..slice.len().saturating_sub(1)];
187 }
188 String::from_utf8_lossy(slice).into_owned()
189 }
190 }
191
192 pub fn load_state_from_ini_string(&self, data: &str) {
194 unsafe {
198 self.bind();
199 sys::imnodes_LoadCurrentEditorStateFromIniString(
200 data.as_ptr() as *const c_char,
201 data.len(),
202 );
203 }
204 }
205
206 pub fn save_state_to_ini_file(&self, file_name: &str) {
208 let file_name = if file_name.contains('\0') {
209 ""
210 } else {
211 file_name
212 };
213 self.bind();
215 dear_imgui_rs::with_scratch_txt(file_name, |ptr| unsafe {
216 sys::imnodes_SaveCurrentEditorStateToIniFile(ptr)
217 })
218 }
219
220 pub fn load_state_from_ini_file(&self, file_name: &str) {
221 let file_name = if file_name.contains('\0') {
222 ""
223 } else {
224 file_name
225 };
226 self.bind();
228 dear_imgui_rs::with_scratch_txt(file_name, |ptr| unsafe {
229 sys::imnodes_LoadCurrentEditorStateFromIniFile(ptr)
230 })
231 }
232
233 pub fn select_node(&self, node_id: i32) {
235 self.bind();
236 unsafe { sys::imnodes_SelectNode(node_id) }
237 }
238
239 pub fn clear_node_selection_of(&self, node_id: i32) {
240 self.bind();
241 unsafe { sys::imnodes_ClearNodeSelection_Int(node_id) }
242 }
243
244 pub fn is_node_selected(&self, node_id: i32) -> bool {
245 self.bind();
246 unsafe { sys::imnodes_IsNodeSelected(node_id) }
247 }
248
249 pub fn select_link(&self, link_id: i32) {
250 self.bind();
251 unsafe { sys::imnodes_SelectLink(link_id) }
252 }
253
254 pub fn clear_link_selection_of(&self, link_id: i32) {
255 self.bind();
256 unsafe { sys::imnodes_ClearLinkSelection_Int(link_id) }
257 }
258
259 pub fn is_link_selected(&self, link_id: i32) -> bool {
260 self.bind();
261 unsafe { sys::imnodes_IsLinkSelected(link_id) }
262 }
263
264 pub fn selected_nodes(&self) -> Vec<i32> {
265 self.bind();
268 let n = unsafe { sys::imnodes_NumSelectedNodes() };
269 if n <= 0 {
270 return Vec::new();
271 }
272 let mut buf = vec![0i32; n as usize];
273 unsafe { sys::imnodes_GetSelectedNodes(buf.as_mut_ptr()) };
274 buf
275 }
276
277 pub fn selected_links(&self) -> Vec<i32> {
278 self.bind();
281 let n = unsafe { sys::imnodes_NumSelectedLinks() };
282 if n <= 0 {
283 return Vec::new();
284 }
285 let mut buf = vec![0i32; n as usize];
286 unsafe { sys::imnodes_GetSelectedLinks(buf.as_mut_ptr()) };
287 buf
288 }
289
290 pub fn clear_selection(&self) {
291 self.bind();
292 unsafe {
293 sys::imnodes_ClearNodeSelection_Nil();
294 sys::imnodes_ClearLinkSelection_Nil();
295 }
296 }
297
298 pub fn is_link_created(&self) -> Option<crate::LinkCreated> {
299 self.link_created
300 }
301
302 pub fn is_link_created_with_nodes(&self) -> Option<crate::LinkCreatedEx> {
303 self.link_created_ex
304 }
305
306 pub fn is_link_destroyed(&self) -> Option<i32> {
307 self.link_destroyed
308 }
309
310 pub fn is_editor_hovered(&self) -> bool {
311 self.editor_hovered
312 }
313
314 pub fn hovered_node(&self) -> Option<i32> {
315 self.hovered_node
316 }
317
318 pub fn hovered_link(&self) -> Option<i32> {
319 self.hovered_link
320 }
321
322 pub fn hovered_pin(&self) -> Option<i32> {
323 self.hovered_pin
324 }
325
326 pub fn set_node_pos_screen(&self, node_id: i32, pos: [f32; 2]) {
328 self.bind();
329 unsafe {
330 sys::imnodes_SetNodeScreenSpacePos(
331 node_id,
332 sys::ImVec2_c {
333 x: pos[0],
334 y: pos[1],
335 },
336 )
337 }
338 }
339
340 pub fn set_node_pos_grid(&self, node_id: i32, pos: [f32; 2]) {
342 self.bind();
343 unsafe {
344 sys::imnodes_SetNodeGridSpacePos(
345 node_id,
346 sys::ImVec2_c {
347 x: pos[0],
348 y: pos[1],
349 },
350 )
351 }
352 }
353
354 pub fn is_attribute_active(&self) -> bool {
355 self.any_attribute_active.is_some()
356 }
357
358 pub fn any_attribute_active(&self) -> Option<i32> {
359 self.any_attribute_active
360 }
361
362 pub fn is_link_started(&self) -> Option<i32> {
363 self.link_started
364 }
365
366 pub fn is_link_dropped(&self, including_detached: bool) -> Option<i32> {
367 if including_detached {
368 self.link_dropped_including_detached
369 } else {
370 self.link_dropped_excluding_detached
371 }
372 }
373}