Skip to main content

dear_node_editor/frame/
tokens.rs

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}