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 /// Pops an item width change made with [`Ui::push_item_width`].
58 #[doc(alias = "PopItemWidth")]
59 drop { unsafe { sys::igPopItemWidth() } }
60);
61
62create_token!(
63 /// Tracks a change made with [`Ui::push_text_wrap_pos`] that can be popped
64 /// by calling [`TextWrapPosStackToken::end`] or dropping.
65 #[doc(alias = "PopTextWrapPos")]
66 pub struct TextWrapPosStackToken<'ui>;
67
68 /// Pops a text wrap position change made with [`Ui::push_text_wrap_pos`].
69 #[doc(alias = "PopTextWrapPos")]
70 drop { unsafe { sys::igPopTextWrapPos() } }
71);
72
73#[cfg(test)]
74mod tests {
75 fn setup_context() -> crate::Context {
76 let mut ctx = crate::Context::create();
77 ctx.io_mut().set_display_size([128.0, 128.0]);
78 ctx.io_mut().set_delta_time(1.0 / 60.0);
79 let _ = ctx.font_atlas().build();
80 ctx
81 }
82
83 #[test]
84 fn text_item_width_scope_matches_measurement_and_restores_previous_width() {
85 let mut ctx = setup_context();
86 let ui = ctx.frame();
87
88 ui.window("text_item_width").build(|| {
89 let original_width = ui.calc_item_width();
90 let text_width = ui.calc_text_size("measured width")[0];
91
92 {
93 let _width = ui.push_item_width_text("measured width");
94 assert_eq!(ui.calc_item_width(), text_width);
95 }
96
97 assert_eq!(ui.calc_item_width(), original_width);
98 });
99 }
100}