1use super::core::NodeEditorFrame;
2use super::validation::{
3 assert_finite_f32, assert_finite_rect, assert_finite_vec2, assert_finite_vec4,
4 assert_non_negative_finite_f32, assert_non_negative_finite_vec2, assert_style_var_type,
5};
6use crate::{
7 EditorContext, FlowDirection, LinkId, NodeEditorStyle, NodeId, PinId, PinKind, StyleColor,
8 StyleVar, StyleVarType, from_vec2, sys, vec2, vec4,
9};
10use dear_imgui_rs::{DrawListMut, Ui};
11use std::{cell::Cell, marker::PhantomData, rc::Rc};
12
13impl<'ui> NodeEditorFrame<'ui> {
14 pub fn begin_node<'a>(&'a self, node: NodeId) -> NodeToken<'a> {
15 let _current_editor = self.bind("NodeEditorFrame::begin_node()");
16 unsafe { sys::dne_begin_node(node.raw()) };
17 NodeToken {
18 editor: self._editor,
19 ended: false,
20 _not_send_sync: PhantomData,
21 }
22 }
23
24 pub fn node<R>(&self, node: NodeId, f: impl FnOnce(&NodeToken<'_>) -> R) -> R {
25 let token = self.begin_node(node);
26 let result = f(&token);
27 token.end();
28 result
29 }
30
31 pub fn begin_group_hint<'a>(&'a self, node: NodeId) -> Option<GroupHintToken<'a>> {
32 let _current_editor = self.bind("NodeEditorFrame::begin_group_hint()");
33 unsafe { sys::dne_begin_group_hint(node.raw()) }.then_some(GroupHintToken {
34 editor: self._editor,
35 ui: self._ui,
36 ended: false,
37 _not_send_sync: PhantomData,
38 })
39 }
40
41 pub fn node_background_draw_list(&self, node: NodeId) -> DrawListMut<'_> {
42 let _current_editor = self.bind("NodeEditorFrame::node_background_draw_list()");
43 let draw_list = unsafe { sys::dne_get_node_background_draw_list(node.raw()) };
44 unsafe { DrawListMut::from_raw_mut(self._ui, draw_list.cast()) }
45 }
46
47 #[doc(alias = "GetStyle")]
48 pub fn style(&self) -> NodeEditorStyle {
49 self._editor.style()
50 }
51
52 pub fn group(&self, size: [f32; 2]) {
53 assert_non_negative_finite_vec2("NodeEditorFrame::group()", "size", size);
54 let _current_editor = self.bind("NodeEditorFrame::group()");
55 unsafe { sys::dne_group(vec2(size)) };
56 }
57
58 pub fn set_group_size(&self, node: NodeId, size: [f32; 2]) {
59 assert_non_negative_finite_vec2("NodeEditorFrame::set_group_size()", "size", size);
60 let _current_editor = self.bind("NodeEditorFrame::set_group_size()");
61 unsafe { sys::dne_set_group_size(node.raw(), vec2(size)) };
62 }
63
64 pub fn link(&self, link: LinkId, start_pin: PinId, end_pin: PinId) -> bool {
65 self.link_colored(link, start_pin, end_pin, [1.0, 1.0, 1.0, 1.0], 1.0)
66 }
67
68 pub fn link_colored(
69 &self,
70 link: LinkId,
71 start_pin: PinId,
72 end_pin: PinId,
73 color: [f32; 4],
74 thickness: f32,
75 ) -> bool {
76 assert_finite_vec4("NodeEditorFrame::link_colored()", "color", color);
77 assert_non_negative_finite_f32("NodeEditorFrame::link_colored()", "thickness", thickness);
78 let _current_editor = self.bind("NodeEditorFrame::link_colored()");
79 unsafe {
80 sys::dne_link(
81 link.raw(),
82 start_pin.raw(),
83 end_pin.raw(),
84 vec4(color),
85 thickness,
86 )
87 }
88 }
89
90 pub fn flow(&self, link: LinkId, direction: FlowDirection) {
91 let _current_editor = self.bind("NodeEditorFrame::flow()");
92 unsafe { sys::dne_flow(link.raw(), direction.raw()) };
93 }
94
95 pub fn push_style_color<'a>(
96 &'a self,
97 color: StyleColor,
98 value: [f32; 4],
99 ) -> StyleColorToken<'a> {
100 assert_finite_vec4("NodeEditorFrame::push_style_color()", "value", value);
101 let _current_editor = self.bind("NodeEditorFrame::push_style_color()");
102 unsafe { sys::dne_push_style_color(color.raw(), vec4(value)) };
103 StyleColorToken {
104 editor: self._editor,
105 count: 1,
106 popped: false,
107 _not_send_sync: PhantomData,
108 }
109 }
110
111 pub fn push_style_var_float<'a>(&'a self, var: StyleVar, value: f32) -> StyleVarToken<'a> {
112 assert_style_var_type(
113 "NodeEditorFrame::push_style_var_float()",
114 var,
115 StyleVarType::Float,
116 );
117 assert_finite_f32("NodeEditorFrame::push_style_var_float()", "value", value);
118 let _current_editor = self.bind("NodeEditorFrame::push_style_var_float()");
119 unsafe { sys::dne_push_style_var_float(var.raw(), value) };
120 StyleVarToken {
121 editor: self._editor,
122 count: 1,
123 popped: false,
124 _not_send_sync: PhantomData,
125 }
126 }
127
128 pub fn push_style_var_vec2<'a>(&'a self, var: StyleVar, value: [f32; 2]) -> StyleVarToken<'a> {
129 assert_style_var_type(
130 "NodeEditorFrame::push_style_var_vec2()",
131 var,
132 StyleVarType::Vec2,
133 );
134 assert_finite_vec2("NodeEditorFrame::push_style_var_vec2()", "value", value);
135 let _current_editor = self.bind("NodeEditorFrame::push_style_var_vec2()");
136 unsafe { sys::dne_push_style_var_vec2(var.raw(), vec2(value)) };
137 StyleVarToken {
138 editor: self._editor,
139 count: 1,
140 popped: false,
141 _not_send_sync: PhantomData,
142 }
143 }
144
145 pub fn push_style_var_vec4<'a>(&'a self, var: StyleVar, value: [f32; 4]) -> StyleVarToken<'a> {
146 assert_style_var_type(
147 "NodeEditorFrame::push_style_var_vec4()",
148 var,
149 StyleVarType::Vec4,
150 );
151 assert_finite_vec4("NodeEditorFrame::push_style_var_vec4()", "value", value);
152 let _current_editor = self.bind("NodeEditorFrame::push_style_var_vec4()");
153 unsafe { sys::dne_push_style_var_vec4(var.raw(), vec4(value)) };
154 StyleVarToken {
155 editor: self._editor,
156 count: 1,
157 popped: false,
158 _not_send_sync: PhantomData,
159 }
160 }
161
162 pub fn suspend<'a>(&'a self) -> SuspensionToken<'a> {
163 assert!(
164 !self.suspended.replace(true),
165 "NodeEditorFrame::suspend() cannot be called while the editor is already suspended"
166 );
167 let _current_editor = self.bind("NodeEditorFrame::suspend()");
168 unsafe { sys::dne_suspend() };
169 SuspensionToken {
170 editor: self._editor,
171 suspended: &self.suspended,
172 resumed: false,
173 }
174 }
175
176 pub fn is_suspended(&self) -> bool {
177 let _current_editor = self.bind("NodeEditorFrame::is_suspended()");
178 self.suspended.get() || unsafe { sys::dne_is_suspended() }
179 }
180}
181
182pub struct NodeToken<'a> {
183 editor: &'a EditorContext,
184 ended: bool,
185 _not_send_sync: PhantomData<Rc<()>>,
186}
187
188impl NodeToken<'_> {
189 pub fn begin_pin<'a>(&'a self, pin: PinId, kind: PinKind) -> PinToken<'a> {
190 let _current_editor = self.editor.bind_current("NodeToken::begin_pin()");
191 unsafe { sys::dne_begin_pin(pin.raw(), kind.raw()) };
192 PinToken {
193 editor: self.editor,
194 ended: false,
195 _not_send_sync: PhantomData,
196 }
197 }
198
199 pub fn pin<R>(&self, pin: PinId, kind: PinKind, f: impl FnOnce(&PinToken<'_>) -> R) -> R {
200 let token = self.begin_pin(pin, kind);
201 let result = f(&token);
202 token.end();
203 result
204 }
205
206 pub fn end(mut self) {
207 self.end_inner();
208 }
209
210 fn end_inner(&mut self) {
211 if !self.ended {
212 let _current_editor = self.editor.bind_current("NodeToken::end()");
213 unsafe { sys::dne_end_node() };
214 self.ended = true;
215 }
216 }
217}
218
219impl Drop for NodeToken<'_> {
220 fn drop(&mut self) {
221 self.end_inner();
222 }
223}
224
225pub struct PinToken<'a> {
226 editor: &'a EditorContext,
227 ended: bool,
228 _not_send_sync: PhantomData<Rc<()>>,
229}
230
231impl PinToken<'_> {
232 pub fn end(mut self) {
233 self.end_inner();
234 }
235
236 pub fn rect(&self, min: [f32; 2], max: [f32; 2]) {
237 assert_finite_rect("PinToken::rect()", min, max);
238 let _current_editor = self.editor.bind_current("PinToken::rect()");
239 unsafe { sys::dne_pin_rect(vec2(min), vec2(max)) };
240 }
241
242 pub fn pivot_rect(&self, min: [f32; 2], max: [f32; 2]) {
243 assert_finite_rect("PinToken::pivot_rect()", min, max);
244 let _current_editor = self.editor.bind_current("PinToken::pivot_rect()");
245 unsafe { sys::dne_pin_pivot_rect(vec2(min), vec2(max)) };
246 }
247
248 pub fn pivot_size(&self, size: [f32; 2]) {
249 assert_non_negative_finite_vec2("PinToken::pivot_size()", "size", size);
250 let _current_editor = self.editor.bind_current("PinToken::pivot_size()");
251 unsafe { sys::dne_pin_pivot_size(vec2(size)) };
252 }
253
254 pub fn pivot_scale(&self, scale: [f32; 2]) {
255 assert_finite_vec2("PinToken::pivot_scale()", "scale", scale);
256 let _current_editor = self.editor.bind_current("PinToken::pivot_scale()");
257 unsafe { sys::dne_pin_pivot_scale(vec2(scale)) };
258 }
259
260 pub fn pivot_alignment(&self, alignment: [f32; 2]) {
261 assert_finite_vec2("PinToken::pivot_alignment()", "alignment", alignment);
262 let _current_editor = self.editor.bind_current("PinToken::pivot_alignment()");
263 unsafe { sys::dne_pin_pivot_alignment(vec2(alignment)) };
264 }
265
266 fn end_inner(&mut self) {
267 if !self.ended {
268 let _current_editor = self.editor.bind_current("PinToken::end()");
269 unsafe { sys::dne_end_pin() };
270 self.ended = true;
271 }
272 }
273}
274
275impl Drop for PinToken<'_> {
276 fn drop(&mut self) {
277 self.end_inner();
278 }
279}
280
281pub struct GroupHintToken<'a> {
282 editor: &'a EditorContext,
283 ui: &'a Ui,
284 ended: bool,
285 _not_send_sync: PhantomData<Rc<()>>,
286}
287
288impl<'a> GroupHintToken<'a> {
289 pub fn min(&self) -> [f32; 2] {
290 let _current_editor = self.editor.bind_current("GroupHintToken::min()");
291 from_vec2(unsafe { sys::dne_get_group_min() })
292 }
293
294 pub fn max(&self) -> [f32; 2] {
295 let _current_editor = self.editor.bind_current("GroupHintToken::max()");
296 from_vec2(unsafe { sys::dne_get_group_max() })
297 }
298
299 pub fn foreground_draw_list(&self) -> DrawListMut<'_> {
300 let _current_editor = self
301 .editor
302 .bind_current("GroupHintToken::foreground_draw_list()");
303 let draw_list = unsafe { sys::dne_get_hint_foreground_draw_list() };
304 unsafe { DrawListMut::from_raw_mut(self.ui, draw_list.cast()) }
305 }
306
307 pub fn background_draw_list(&self) -> DrawListMut<'_> {
308 let _current_editor = self
309 .editor
310 .bind_current("GroupHintToken::background_draw_list()");
311 let draw_list = unsafe { sys::dne_get_hint_background_draw_list() };
312 unsafe { DrawListMut::from_raw_mut(self.ui, draw_list.cast()) }
313 }
314
315 pub fn end(mut self) {
316 self.end_inner();
317 }
318
319 fn end_inner(&mut self) {
320 if !self.ended {
321 let _current_editor = self.editor.bind_current("GroupHintToken::end()");
322 unsafe { sys::dne_end_group_hint() };
323 self.ended = true;
324 }
325 }
326}
327
328impl Drop for GroupHintToken<'_> {
329 fn drop(&mut self) {
330 self.end_inner();
331 }
332}
333
334pub struct SuspensionToken<'a> {
335 editor: &'a EditorContext,
336 suspended: &'a Cell<bool>,
337 resumed: bool,
338}
339
340impl SuspensionToken<'_> {
341 pub fn resume(mut self) {
342 self.resume_inner();
343 }
344
345 fn resume_inner(&mut self) {
346 if !self.resumed {
347 let _current_editor = self.editor.bind_current("SuspensionToken::resume()");
348 unsafe { sys::dne_resume() };
349 self.suspended.set(false);
350 self.resumed = true;
351 }
352 }
353}
354
355impl Drop for SuspensionToken<'_> {
356 fn drop(&mut self) {
357 self.resume_inner();
358 }
359}
360
361pub struct StyleColorToken<'a> {
362 editor: &'a EditorContext,
363 count: i32,
364 popped: bool,
365 _not_send_sync: PhantomData<Rc<()>>,
366}
367
368impl StyleColorToken<'_> {
369 pub fn pop(mut self) {
370 self.pop_inner();
371 }
372
373 fn pop_inner(&mut self) {
374 if !self.popped {
375 let _current_editor = self.editor.bind_current("StyleColorToken::pop()");
376 unsafe { sys::dne_pop_style_color(self.count) };
377 self.popped = true;
378 }
379 }
380}
381
382impl Drop for StyleColorToken<'_> {
383 fn drop(&mut self) {
384 self.pop_inner();
385 }
386}
387
388pub struct StyleVarToken<'a> {
389 editor: &'a EditorContext,
390 count: i32,
391 popped: bool,
392 _not_send_sync: PhantomData<Rc<()>>,
393}
394
395impl StyleVarToken<'_> {
396 pub fn pop(mut self) {
397 self.pop_inner();
398 }
399
400 fn pop_inner(&mut self) {
401 if !self.popped {
402 let _current_editor = self.editor.bind_current("StyleVarToken::pop()");
403 unsafe { sys::dne_pop_style_var(self.count) };
404 self.popped = true;
405 }
406 }
407}
408
409impl Drop for StyleVarToken<'_> {
410 fn drop(&mut self) {
411 self.pop_inner();
412 }
413}