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