Skip to main content

dear_imgui_rs/stacks/
layout.rs

1use crate::{Ui, sys};
2
3/// # Parameter stacks (current window)
4impl Ui {
5    /// Changes the item width by pushing a change to the item width stack.
6    ///
7    /// Returns an `ItemWidthStackToken`. The pushed width item is popped when either
8    /// `ItemWidthStackToken` goes out of scope, or `.end()` is called.
9    ///
10    /// - `> 0.0`: width is `item_width` pixels
11    /// - `= 0.0`: default to ~2/3 of window width
12    /// - `< 0.0`: `item_width` pixels relative to the right of window (-1.0 always aligns width to
13    ///   the right side)
14    #[doc(alias = "PushItemWidth")]
15    pub fn push_item_width(&self, item_width: f32) -> ItemWidthStackToken<'_> {
16        self.run_with_bound_context(|| unsafe { sys::igPushItemWidth(item_width) });
17        ItemWidthStackToken::new(self)
18    }
19
20    /// Sets the width of the next item(s) to be the same as the width of the given text.
21    ///
22    /// Text is measured with [`Ui::calc_text_size`] using its default options.
23    ///
24    /// Returns an `ItemWidthStackToken`. The pushed width item is popped when either
25    /// `ItemWidthStackToken` goes out of scope, or `.end()` is called.
26    #[doc(alias = "PushItemWidth")]
27    pub fn push_item_width_text(&self, text: impl AsRef<str>) -> ItemWidthStackToken<'_> {
28        let text = text.as_ref();
29        self.run_with_bound_context(|| unsafe {
30            let text_width = self.calc_text_size_bound(text, false, -1.0)[0];
31            sys::igPushItemWidth(text_width);
32        });
33        ItemWidthStackToken::new(self)
34    }
35
36    /// Sets the position where text will wrap around.
37    ///
38    /// Returns a `TextWrapPosStackToken`. The pushed wrap position is popped when either
39    /// `TextWrapPosStackToken` goes out of scope, or `.end()` is called.
40    ///
41    /// - `wrap_pos_x < 0.0`: no wrapping
42    /// - `wrap_pos_x = 0.0`: wrap to end of window (or column)
43    /// - `wrap_pos_x > 0.0`: wrap at `wrap_pos_x` position in window local space
44    #[doc(alias = "PushTextWrapPos")]
45    pub fn push_text_wrap_pos(&self, wrap_pos_x: f32) -> TextWrapPosStackToken<'_> {
46        self.run_with_bound_context(|| unsafe { sys::igPushTextWrapPos(wrap_pos_x) });
47        TextWrapPosStackToken::new(self)
48    }
49}
50
51create_token!(
52    /// Tracks a change made with [`Ui::push_item_width`] that can be popped
53    /// by calling [`ItemWidthStackToken::end`] or dropping.
54    #[doc(alias = "PopItemWidth")]
55    pub struct ItemWidthStackToken<'ui>;
56
57    pop crate::scope::NativeScopePop::PopItemWidth;
58
59    /// Pops an item width change made with [`Ui::push_item_width`].
60    #[doc(alias = "PopItemWidth")]
61    drop { unsafe { sys::igPopItemWidth() } }
62);
63
64create_token!(
65    /// Tracks a change made with [`Ui::push_text_wrap_pos`] that can be popped
66    /// by calling [`TextWrapPosStackToken::end`] or dropping.
67    #[doc(alias = "PopTextWrapPos")]
68    pub struct TextWrapPosStackToken<'ui>;
69
70    pop crate::scope::NativeScopePop::PopTextWrap;
71
72    /// Pops a text wrap position change made with [`Ui::push_text_wrap_pos`].
73    #[doc(alias = "PopTextWrapPos")]
74    drop { unsafe { sys::igPopTextWrapPos() } }
75);
76
77#[cfg(test)]
78mod tests {
79    fn setup_context() -> crate::Context {
80        let mut ctx = crate::Context::create();
81        ctx.io_mut().set_display_size([128.0, 128.0]);
82        ctx.io_mut().set_delta_time(1.0 / 60.0);
83        ctx.font_atlas()
84            .try_claim_legacy_renderer()
85            .expect("legacy renderer font atlas should be available")
86            .build();
87        ctx
88    }
89
90    #[test]
91    fn text_item_width_scope_matches_measurement_and_restores_previous_width() {
92        let mut ctx = setup_context();
93        let ui = ctx.frame();
94
95        ui.window("text_item_width").build(|| {
96            let original_width = ui.calc_item_width();
97            let text_width = ui.calc_text_size("measured width")[0];
98
99            {
100                let _width = ui.push_item_width_text("measured width");
101                assert_eq!(ui.calc_item_width(), text_width);
102            }
103
104            assert_eq!(ui.calc_item_width(), original_width);
105        });
106    }
107}