1use crate::style::{
2 StyleColor, StyleVar, StyleVarVec2, validate_style_color, validate_style_var,
3 validate_style_var_component,
4};
5use crate::{Ui, sys};
6
7impl Ui {
8 #[doc(alias = "PushStyleColor")]
24 pub fn push_style_color(
25 &self,
26 style_color: StyleColor,
27 color: impl Into<[f32; 4]>,
28 ) -> ColorStackToken<'_> {
29 let color_array = color.into();
30 validate_style_color("Ui::push_style_color()", "color", color_array);
31 self.run_with_bound_context(|| unsafe {
32 sys::igPushStyleColor_Vec4(
33 style_color as i32,
34 sys::ImVec4 {
35 x: color_array[0],
36 y: color_array[1],
37 z: color_array[2],
38 w: color_array[3],
39 },
40 )
41 });
42 ColorStackToken::new(self)
43 }
44
45 #[doc(alias = "PushStyleVar")]
61 pub fn push_style_var(&self, style_var: StyleVar) -> StyleStackToken<'_> {
62 validate_style_var("Ui::push_style_var()", style_var);
63 self.run_with_bound_context(|| unsafe { push_style_var(style_var) });
64 StyleStackToken::new(self)
65 }
66
67 #[doc(alias = "PushStyleVarX")]
69 pub fn push_style_var_x(&self, style_var: StyleVarVec2, value: f32) -> StyleStackToken<'_> {
70 validate_style_var_component("Ui::push_style_var_x()", style_var, value);
71 self.run_with_bound_context(|| unsafe { sys::igPushStyleVarX(style_var.raw(), value) });
72 StyleStackToken::new(self)
73 }
74
75 #[doc(alias = "PushStyleVarY")]
77 pub fn push_style_var_y(&self, style_var: StyleVarVec2, value: f32) -> StyleStackToken<'_> {
78 validate_style_var_component("Ui::push_style_var_y()", style_var, value);
79 self.run_with_bound_context(|| unsafe { sys::igPushStyleVarY(style_var.raw(), value) });
80 StyleStackToken::new(self)
81 }
82}
83
84create_token!(
85 #[doc(alias = "PopStyleColor")]
88 pub struct ColorStackToken<'ui>;
89
90 drop { unsafe { sys::igPopStyleColor(1) } }
92);
93
94impl ColorStackToken<'_> {
95 pub fn pop(self) {
97 self.end()
98 }
99}
100
101create_token!(
102 #[doc(alias = "PopStyleVar")]
105 pub struct StyleStackToken<'ui>;
106
107 drop { unsafe { sys::igPopStyleVar(1) } }
109);
110
111impl StyleStackToken<'_> {
112 pub fn pop(self) {
114 self.end()
115 }
116}
117
118unsafe fn push_style_var(style_var: StyleVar) {
120 use StyleVar::*;
121 match style_var {
122 Alpha(v) => unsafe { sys::igPushStyleVar_Float(sys::ImGuiStyleVar_Alpha as i32, v) },
123 DisabledAlpha(v) => unsafe {
124 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_DisabledAlpha as i32, v)
125 },
126 WindowPadding(v) => {
127 let p: [f32; 2] = v;
128 let vec = sys::ImVec2 { x: p[0], y: p[1] };
129 unsafe { sys::igPushStyleVar_Vec2(sys::ImGuiStyleVar_WindowPadding as i32, vec) }
130 }
131 WindowRounding(v) => unsafe {
132 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_WindowRounding as i32, v)
133 },
134 WindowBorderSize(v) => unsafe {
135 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_WindowBorderSize as i32, v)
136 },
137 WindowMinSize(v) => {
138 let p: [f32; 2] = v;
139 let vec = sys::ImVec2 { x: p[0], y: p[1] };
140 unsafe { sys::igPushStyleVar_Vec2(sys::ImGuiStyleVar_WindowMinSize as i32, vec) }
141 }
142 WindowTitleAlign(v) => {
143 let p: [f32; 2] = v;
144 let vec = sys::ImVec2 { x: p[0], y: p[1] };
145 unsafe { sys::igPushStyleVar_Vec2(sys::ImGuiStyleVar_WindowTitleAlign as i32, vec) }
146 }
147 ChildRounding(v) => unsafe {
148 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_ChildRounding as i32, v)
149 },
150 ChildBorderSize(v) => unsafe {
151 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_ChildBorderSize as i32, v)
152 },
153 PopupRounding(v) => unsafe {
154 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_PopupRounding as i32, v)
155 },
156 PopupBorderSize(v) => unsafe {
157 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_PopupBorderSize as i32, v)
158 },
159 FramePadding(v) => {
160 let p: [f32; 2] = v;
161 let vec = sys::ImVec2 { x: p[0], y: p[1] };
162 unsafe { sys::igPushStyleVar_Vec2(sys::ImGuiStyleVar_FramePadding as i32, vec) }
163 }
164 FrameRounding(v) => unsafe {
165 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_FrameRounding as i32, v)
166 },
167 FrameBorderSize(v) => unsafe {
168 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_FrameBorderSize as i32, v)
169 },
170 ItemSpacing(v) => {
171 let p: [f32; 2] = v;
172 let vec = sys::ImVec2 { x: p[0], y: p[1] };
173 unsafe { sys::igPushStyleVar_Vec2(sys::ImGuiStyleVar_ItemSpacing as i32, vec) }
174 }
175 ItemInnerSpacing(v) => {
176 let p: [f32; 2] = v;
177 let vec = sys::ImVec2 { x: p[0], y: p[1] };
178 unsafe { sys::igPushStyleVar_Vec2(sys::ImGuiStyleVar_ItemInnerSpacing as i32, vec) }
179 }
180 IndentSpacing(v) => unsafe {
181 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_IndentSpacing as i32, v)
182 },
183 CellPadding(v) => {
184 let p: [f32; 2] = v;
185 let vec = sys::ImVec2 { x: p[0], y: p[1] };
186 unsafe { sys::igPushStyleVar_Vec2(sys::ImGuiStyleVar_CellPadding as i32, vec) }
187 }
188 ScrollbarSize(v) => unsafe {
189 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_ScrollbarSize as i32, v)
190 },
191 ScrollbarRounding(v) => unsafe {
192 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_ScrollbarRounding as i32, v)
193 },
194 ScrollbarPadding(v) => unsafe {
195 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_ScrollbarPadding as i32, v)
196 },
197 GrabMinSize(v) => unsafe {
198 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_GrabMinSize as i32, v)
199 },
200 GrabRounding(v) => unsafe {
201 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_GrabRounding as i32, v)
202 },
203 ImageRounding(v) => unsafe {
204 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_ImageRounding as i32, v)
205 },
206 ImageBorderSize(v) => unsafe {
207 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_ImageBorderSize as i32, v)
208 },
209 TabRounding(v) => unsafe {
210 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_TabRounding as i32, v)
211 },
212 TabBorderSize(v) => unsafe {
213 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_TabBorderSize as i32, v)
214 },
215 TabMinWidthBase(v) => unsafe {
216 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_TabMinWidthBase as i32, v)
217 },
218 TabMinWidthShrink(v) => unsafe {
219 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_TabMinWidthShrink as i32, v)
220 },
221 TabBarBorderSize(v) => unsafe {
222 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_TabBarBorderSize as i32, v)
223 },
224 TabBarOverlineSize(v) => unsafe {
225 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_TabBarOverlineSize as i32, v)
226 },
227 TableAngledHeadersAngle(v) => unsafe {
228 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_TableAngledHeadersAngle as i32, v)
229 },
230 TableAngledHeadersTextAlign(v) => {
231 let p: [f32; 2] = v;
232 let vec = sys::ImVec2 { x: p[0], y: p[1] };
233 unsafe {
234 sys::igPushStyleVar_Vec2(sys::ImGuiStyleVar_TableAngledHeadersTextAlign as i32, vec)
235 }
236 }
237 TreeLinesSize(v) => unsafe {
238 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_TreeLinesSize as i32, v)
239 },
240 TreeLinesRounding(v) => unsafe {
241 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_TreeLinesRounding as i32, v)
242 },
243 MenuItemRounding(v) => unsafe {
244 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_MenuItemRounding as i32, v)
245 },
246 SelectableRounding(v) => unsafe {
247 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_SelectableRounding as i32, v)
248 },
249 DragDropTargetRounding(v) => unsafe {
250 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_DragDropTargetRounding as i32, v)
251 },
252 ButtonTextAlign(v) => {
253 let p: [f32; 2] = v;
254 let vec = sys::ImVec2 { x: p[0], y: p[1] };
255 unsafe { sys::igPushStyleVar_Vec2(sys::ImGuiStyleVar_ButtonTextAlign as i32, vec) }
256 }
257 SelectableTextAlign(v) => {
258 let p: [f32; 2] = v;
259 let vec = sys::ImVec2 { x: p[0], y: p[1] };
260 unsafe { sys::igPushStyleVar_Vec2(sys::ImGuiStyleVar_SelectableTextAlign as i32, vec) }
261 }
262 SeparatorSize(v) => unsafe {
263 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_SeparatorSize as i32, v)
264 },
265 SeparatorTextBorderSize(v) => unsafe {
266 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_SeparatorTextBorderSize as i32, v)
267 },
268 SeparatorTextAlign(v) => {
269 let p: [f32; 2] = v;
270 let vec = sys::ImVec2 { x: p[0], y: p[1] };
271 unsafe { sys::igPushStyleVar_Vec2(sys::ImGuiStyleVar_SeparatorTextAlign as i32, vec) }
272 }
273 SeparatorTextPadding(v) => {
274 let p: [f32; 2] = v;
275 let vec = sys::ImVec2 { x: p[0], y: p[1] };
276 unsafe { sys::igPushStyleVar_Vec2(sys::ImGuiStyleVar_SeparatorTextPadding as i32, vec) }
277 }
278 DockingSeparatorSize(v) => unsafe {
279 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_DockingSeparatorSize as i32, v)
280 },
281 }
282}
283
284#[cfg(test)]
285mod tests {
286 use super::*;
287
288 fn setup_context() -> crate::Context {
289 let mut ctx = crate::Context::create();
290 ctx.io_mut().set_display_size([128.0, 128.0]);
291 ctx.io_mut().set_delta_time(1.0 / 60.0);
292 let _ = ctx.font_atlas().build();
293 ctx
294 }
295
296 #[test]
297 fn style_var_component_scopes_are_typed_and_restore_values() {
298 let mut ctx = setup_context();
299 let ui = ctx.frame();
300 let original = ui.clone_style().window_padding();
301
302 {
303 let _x = ui.push_style_var_x(StyleVarVec2::WindowPadding, 17.0);
304 assert_eq!(ui.clone_style().window_padding(), [17.0, original[1]]);
305 }
306 assert_eq!(ui.clone_style().window_padding(), original);
307
308 {
309 let _y = ui.push_style_var_y(StyleVarVec2::WindowPadding, 23.0);
310 assert_eq!(ui.clone_style().window_padding(), [original[0], 23.0]);
311 }
312 assert_eq!(ui.clone_style().window_padding(), original);
313 }
314
315 #[test]
316 fn style_var_components_validate_values_before_ffi() {
317 let mut ctx = setup_context();
318 let ui = ctx.frame();
319
320 for value in [-1.0, f32::NAN, f32::INFINITY] {
321 assert!(
322 std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
323 let _token = ui.push_style_var_x(StyleVarVec2::WindowPadding, value);
324 }))
325 .is_err()
326 );
327 }
328 assert!(
329 std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
330 let _token = ui.push_style_var_y(StyleVarVec2::WindowTitleAlign, 1.1);
331 }))
332 .is_err()
333 );
334 }
335}