dear_imgui_rs/layout/spacing.rs
1use super::validation::{assert_finite_f32, assert_finite_vec2};
2use crate::scope::{NativeScopePop, NativeScopeToken};
3use crate::{Ui, sys};
4
5/// Tracks an indentation scope started with [`Ui::begin_indent`] or
6/// [`Ui::begin_indent_by`].
7///
8/// Tokens from the same window may be ended in any order because each token removes its own
9/// captured width. Cross-window cleanup is deferred until the originating window becomes current
10/// again. [`Ui::with_indent`] and [`Ui::with_indent_by`] remain the canonical APIs for ordinary
11/// scoped use.
12#[must_use]
13pub struct IndentToken<'ui> {
14 scope: NativeScopeToken<'ui>,
15}
16
17impl IndentToken<'_> {
18 /// Ends the indentation scope explicitly.
19 pub fn end(self) {}
20}
21
22impl Drop for IndentToken<'_> {
23 fn drop(&mut self) {
24 self.scope.finish();
25 }
26}
27
28impl Ui {
29 /// Call between widgets or groups to layout them horizontally.
30 ///
31 /// X position is given in window coordinates.
32 ///
33 /// This is equivalent to calling [same_line_with_pos](Self::same_line_with_pos)
34 /// with the `pos` set to 0.0, which uses `Style::item_spacing`.
35 #[doc(alias = "SameLine")]
36 pub fn same_line(&self) {
37 self.same_line_with_pos(0.0);
38 }
39
40 /// Call between widgets or groups to layout them horizontally.
41 ///
42 /// X position is given in window coordinates.
43 ///
44 /// This is equivalent to calling [same_line_with_spacing](Self::same_line_with_spacing)
45 /// with the `spacing` set to -1.0, which means no extra spacing.
46 #[doc(alias = "SameLine")]
47 pub fn same_line_with_pos(&self, pos_x: f32) {
48 self.same_line_with_spacing(pos_x, -1.0)
49 }
50
51 /// Call between widgets or groups to layout them horizontally.
52 ///
53 /// X position is given in window coordinates.
54 #[doc(alias = "SameLine")]
55 pub fn same_line_with_spacing(&self, pos_x: f32, spacing_w: f32) {
56 assert_finite_f32("Ui::same_line_with_spacing()", "pos_x", pos_x);
57 assert_finite_f32("Ui::same_line_with_spacing()", "spacing_w", spacing_w);
58 self.run_with_bound_context(|| unsafe { sys::igSameLine(pos_x, spacing_w) });
59 }
60
61 /// Undo a `same_line` call or force a new line when in horizontal layout mode
62 #[doc(alias = "NewLine")]
63 pub fn new_line(&self) {
64 self.run_with_bound_context(|| unsafe { sys::igNewLine() });
65 }
66
67 /// Adds vertical spacing
68 #[doc(alias = "Spacing")]
69 pub fn spacing(&self) {
70 self.run_with_bound_context(|| unsafe { sys::igSpacing() });
71 }
72
73 /// Fills a space of `size` in pixels with nothing on the current window.
74 ///
75 /// Can be used to move the cursor on the window.
76 #[doc(alias = "Dummy")]
77 pub fn dummy(&self, size: impl Into<[f32; 2]>) {
78 let size = size.into();
79 assert_finite_vec2("Ui::dummy()", "size", size);
80 let size_vec: sys::ImVec2 = size.into();
81 self.run_with_bound_context(|| unsafe { sys::igDummy(size_vec) });
82 }
83
84 /// Moves content position to the right by `Style::indent_spacing`
85 ///
86 /// This is equivalent to [indent_by](Self::indent_by) with `width` set to
87 /// `Style::indent_spacing`.
88 #[doc(alias = "Indent")]
89 pub fn indent(&self) {
90 self.indent_by(0.0)
91 }
92
93 /// Moves content position to the right by `width`
94 #[doc(alias = "Indent")]
95 pub fn indent_by(&self, width: f32) {
96 assert_finite_f32("Ui::indent_by()", "width", width);
97 self.run_with_bound_context(|| unsafe { sys::igIndent(width) });
98 }
99
100 /// Starts an indentation scope using [`Style::indent_spacing`](crate::Style::indent_spacing).
101 ///
102 /// The returned token restores the exact width captured at creation and may be dropped in any
103 /// order relative to other indentation tokens from the same window.
104 #[doc(alias = "Indent")]
105 pub fn begin_indent(&self) -> IndentToken<'_> {
106 self.begin_indent_by(0.0)
107 }
108
109 /// Starts an indentation scope with a custom width.
110 ///
111 /// Passing `0.0` snapshots the current [`Style::indent_spacing`](crate::Style::indent_spacing)
112 /// so a later style change cannot alter restoration.
113 #[doc(alias = "Indent")]
114 pub fn begin_indent_by(&self, width: f32) -> IndentToken<'_> {
115 assert_finite_f32("Ui::begin_indent_by()", "width", width);
116 let width = self.run_with_bound_context(|| unsafe {
117 let width = if width == 0.0 {
118 (*sys::igGetStyle()).IndentSpacing
119 } else {
120 width
121 };
122 sys::igIndent(width);
123 width
124 });
125 IndentToken {
126 scope: self
127 .begin_provenance_native_scope(NativeScopePop::Unindent(width), "IndentToken"),
128 }
129 }
130
131 /// Runs `f` in an indentation scope using [`Style::indent_spacing`](crate::Style::indent_spacing).
132 ///
133 /// The indentation is restored if `f` returns early or panics. Prefer this closure-based
134 /// scope over manually pairing [`Self::indent`] and [`Self::unindent`].
135 #[doc(alias = "Indent", alias = "Unindent")]
136 pub fn with_indent<R>(&self, f: impl FnOnce() -> R) -> R {
137 let indent = self.begin_indent();
138 let result = f();
139 drop(indent);
140 result
141 }
142
143 /// Runs `f` in an indentation scope with a custom width.
144 ///
145 /// The indentation is restored if `f` returns early or panics.
146 #[doc(alias = "Indent", alias = "Unindent")]
147 pub fn with_indent_by<R>(&self, width: f32, f: impl FnOnce() -> R) -> R {
148 let indent = self.begin_indent_by(width);
149 let result = f();
150 drop(indent);
151 result
152 }
153
154 /// Moves content position to the left by `Style::indent_spacing`
155 ///
156 /// This is equivalent to [unindent_by](Self::unindent_by) with `width` set to
157 /// `Style::indent_spacing`.
158 #[doc(alias = "Unindent")]
159 pub fn unindent(&self) {
160 self.unindent_by(0.0)
161 }
162
163 /// Moves content position to the left by `width`
164 #[doc(alias = "Unindent")]
165 pub fn unindent_by(&self, width: f32) {
166 assert_finite_f32("Ui::unindent_by()", "width", width);
167 self.run_with_bound_context(|| unsafe { sys::igUnindent(width) });
168 }
169}
170
171impl Ui {
172 /// Vertically align upcoming text baseline to FramePadding.y (align text to framed items).
173 #[doc(alias = "AlignTextToFramePadding")]
174 pub fn align_text_to_frame_padding(&self) {
175 self.run_with_bound_context(|| unsafe { sys::igAlignTextToFramePadding() });
176 }
177}