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")]
65 pub fn push_style_var(&self, style_var: StyleVar) -> StyleStackToken<'_> {
66 validate_style_var("Ui::push_style_var()", style_var);
67 let is_alpha = matches!(style_var, StyleVar::Alpha(_));
68 self.run_with_bound_context(|| unsafe { push_style_var(style_var) });
69 StyleStackToken::new_for(self, is_alpha)
70 }
71
72 #[doc(alias = "PushStyleVarX")]
74 pub fn push_style_var_x(&self, style_var: StyleVarVec2, value: f32) -> StyleStackToken<'_> {
75 validate_style_var_component("Ui::push_style_var_x()", style_var, value);
76 self.run_with_bound_context(|| unsafe { sys::igPushStyleVarX(style_var.raw(), value) });
77 StyleStackToken::new(self)
78 }
79
80 #[doc(alias = "PushStyleVarY")]
82 pub fn push_style_var_y(&self, style_var: StyleVarVec2, value: f32) -> StyleStackToken<'_> {
83 validate_style_var_component("Ui::push_style_var_y()", style_var, value);
84 self.run_with_bound_context(|| unsafe { sys::igPushStyleVarY(style_var.raw(), value) });
85 StyleStackToken::new(self)
86 }
87}
88
89create_token!(
90 #[doc(alias = "PopStyleColor")]
93 pub struct ColorStackToken<'ui>;
94
95 pop crate::scope::NativeScopePop::PopStyleColor;
96
97 drop { unsafe { sys::igPopStyleColor(1) } }
99);
100
101impl ColorStackToken<'_> {
102 pub fn pop(self) {
108 self.end()
109 }
110}
111
112create_token!(
113 #[doc(alias = "PopStyleVar")]
116 pub struct StyleStackToken<'ui>;
117
118 pop crate::scope::NativeScopePop::PopStyleVar { is_alpha: false };
119
120 drop { unsafe { sys::igPopStyleVar(1) } }
122);
123
124impl<'ui> StyleStackToken<'ui> {
125 fn new_for(ui: &'ui Ui, is_alpha: bool) -> Self {
126 Self {
127 scope: ui.begin_native_scope(
128 crate::scope::NativeScopePop::PopStyleVar { is_alpha },
129 "StyleStackToken",
130 ),
131 _phantom: std::marker::PhantomData,
132 }
133 }
134
135 pub fn pop(self) {
141 self.end()
142 }
143}
144
145unsafe fn push_style_var(style_var: StyleVar) {
147 use StyleVar::*;
148 match style_var {
149 Alpha(v) => unsafe { sys::igPushStyleVar_Float(sys::ImGuiStyleVar_Alpha as i32, v) },
150 DisabledAlpha(v) => unsafe {
151 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_DisabledAlpha as i32, v)
152 },
153 WindowPadding(v) => {
154 let p: [f32; 2] = v;
155 let vec = sys::ImVec2 { x: p[0], y: p[1] };
156 unsafe { sys::igPushStyleVar_Vec2(sys::ImGuiStyleVar_WindowPadding as i32, vec) }
157 }
158 WindowRounding(v) => unsafe {
159 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_WindowRounding as i32, v)
160 },
161 WindowBorderSize(v) => unsafe {
162 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_WindowBorderSize as i32, v)
163 },
164 WindowMinSize(v) => {
165 let p: [f32; 2] = v;
166 let vec = sys::ImVec2 { x: p[0], y: p[1] };
167 unsafe { sys::igPushStyleVar_Vec2(sys::ImGuiStyleVar_WindowMinSize as i32, vec) }
168 }
169 WindowTitleAlign(v) => {
170 let p: [f32; 2] = v;
171 let vec = sys::ImVec2 { x: p[0], y: p[1] };
172 unsafe { sys::igPushStyleVar_Vec2(sys::ImGuiStyleVar_WindowTitleAlign as i32, vec) }
173 }
174 ChildRounding(v) => unsafe {
175 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_ChildRounding as i32, v)
176 },
177 ChildBorderSize(v) => unsafe {
178 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_ChildBorderSize as i32, v)
179 },
180 PopupRounding(v) => unsafe {
181 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_PopupRounding as i32, v)
182 },
183 PopupBorderSize(v) => unsafe {
184 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_PopupBorderSize as i32, v)
185 },
186 FramePadding(v) => {
187 let p: [f32; 2] = v;
188 let vec = sys::ImVec2 { x: p[0], y: p[1] };
189 unsafe { sys::igPushStyleVar_Vec2(sys::ImGuiStyleVar_FramePadding as i32, vec) }
190 }
191 FrameRounding(v) => unsafe {
192 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_FrameRounding as i32, v)
193 },
194 FrameBorderSize(v) => unsafe {
195 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_FrameBorderSize as i32, v)
196 },
197 ItemSpacing(v) => {
198 let p: [f32; 2] = v;
199 let vec = sys::ImVec2 { x: p[0], y: p[1] };
200 unsafe { sys::igPushStyleVar_Vec2(sys::ImGuiStyleVar_ItemSpacing as i32, vec) }
201 }
202 ItemInnerSpacing(v) => {
203 let p: [f32; 2] = v;
204 let vec = sys::ImVec2 { x: p[0], y: p[1] };
205 unsafe { sys::igPushStyleVar_Vec2(sys::ImGuiStyleVar_ItemInnerSpacing as i32, vec) }
206 }
207 IndentSpacing(v) => unsafe {
208 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_IndentSpacing as i32, v)
209 },
210 CellPadding(v) => {
211 let p: [f32; 2] = v;
212 let vec = sys::ImVec2 { x: p[0], y: p[1] };
213 unsafe { sys::igPushStyleVar_Vec2(sys::ImGuiStyleVar_CellPadding as i32, vec) }
214 }
215 ScrollbarSize(v) => unsafe {
216 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_ScrollbarSize as i32, v)
217 },
218 ScrollbarRounding(v) => unsafe {
219 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_ScrollbarRounding as i32, v)
220 },
221 ScrollbarPadding(v) => unsafe {
222 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_ScrollbarPadding as i32, v)
223 },
224 GrabMinSize(v) => unsafe {
225 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_GrabMinSize as i32, v)
226 },
227 GrabRounding(v) => unsafe {
228 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_GrabRounding as i32, v)
229 },
230 ImageRounding(v) => unsafe {
231 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_ImageRounding as i32, v)
232 },
233 ImageBorderSize(v) => unsafe {
234 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_ImageBorderSize as i32, v)
235 },
236 TabRounding(v) => unsafe {
237 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_TabRounding as i32, v)
238 },
239 TabBorderSize(v) => unsafe {
240 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_TabBorderSize as i32, v)
241 },
242 TabMinWidthBase(v) => unsafe {
243 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_TabMinWidthBase as i32, v)
244 },
245 TabMinWidthShrink(v) => unsafe {
246 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_TabMinWidthShrink as i32, v)
247 },
248 TabBarBorderSize(v) => unsafe {
249 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_TabBarBorderSize as i32, v)
250 },
251 TabBarOverlineSize(v) => unsafe {
252 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_TabBarOverlineSize as i32, v)
253 },
254 TableAngledHeadersAngle(v) => unsafe {
255 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_TableAngledHeadersAngle as i32, v)
256 },
257 TableAngledHeadersTextAlign(v) => {
258 let p: [f32; 2] = v;
259 let vec = sys::ImVec2 { x: p[0], y: p[1] };
260 unsafe {
261 sys::igPushStyleVar_Vec2(sys::ImGuiStyleVar_TableAngledHeadersTextAlign as i32, vec)
262 }
263 }
264 TreeLinesSize(v) => unsafe {
265 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_TreeLinesSize as i32, v)
266 },
267 TreeLinesRounding(v) => unsafe {
268 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_TreeLinesRounding as i32, v)
269 },
270 MenuItemRounding(v) => unsafe {
271 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_MenuItemRounding as i32, v)
272 },
273 SelectableRounding(v) => unsafe {
274 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_SelectableRounding as i32, v)
275 },
276 DragDropTargetRounding(v) => unsafe {
277 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_DragDropTargetRounding as i32, v)
278 },
279 ButtonTextAlign(v) => {
280 let p: [f32; 2] = v;
281 let vec = sys::ImVec2 { x: p[0], y: p[1] };
282 unsafe { sys::igPushStyleVar_Vec2(sys::ImGuiStyleVar_ButtonTextAlign as i32, vec) }
283 }
284 SelectableTextAlign(v) => {
285 let p: [f32; 2] = v;
286 let vec = sys::ImVec2 { x: p[0], y: p[1] };
287 unsafe { sys::igPushStyleVar_Vec2(sys::ImGuiStyleVar_SelectableTextAlign as i32, vec) }
288 }
289 SeparatorSize(v) => unsafe {
290 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_SeparatorSize as i32, v)
291 },
292 SeparatorTextBorderSize(v) => unsafe {
293 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_SeparatorTextBorderSize as i32, v)
294 },
295 SeparatorTextAlign(v) => {
296 let p: [f32; 2] = v;
297 let vec = sys::ImVec2 { x: p[0], y: p[1] };
298 unsafe { sys::igPushStyleVar_Vec2(sys::ImGuiStyleVar_SeparatorTextAlign as i32, vec) }
299 }
300 SeparatorTextPadding(v) => {
301 let p: [f32; 2] = v;
302 let vec = sys::ImVec2 { x: p[0], y: p[1] };
303 unsafe { sys::igPushStyleVar_Vec2(sys::ImGuiStyleVar_SeparatorTextPadding as i32, vec) }
304 }
305 DockingSeparatorSize(v) => unsafe {
306 sys::igPushStyleVar_Float(sys::ImGuiStyleVar_DockingSeparatorSize as i32, v)
307 },
308 }
309}
310
311#[cfg(test)]
312mod tests {
313 use super::*;
314
315 fn setup_context() -> crate::Context {
316 let mut ctx = crate::Context::create();
317 ctx.io_mut().set_display_size([128.0, 128.0]);
318 ctx.io_mut().set_delta_time(1.0 / 60.0);
319 ctx.font_atlas()
320 .try_claim_legacy_renderer()
321 .expect("legacy renderer font atlas should be available")
322 .build();
323 ctx
324 }
325
326 #[test]
327 fn style_var_component_scopes_are_typed_and_restore_values() {
328 let mut ctx = setup_context();
329 let ui = ctx.frame();
330 let original = ui.clone_style().window_padding();
331
332 {
333 let _x = ui.push_style_var_x(StyleVarVec2::WindowPadding, 17.0);
334 assert_eq!(ui.clone_style().window_padding(), [17.0, original[1]]);
335 }
336 assert_eq!(ui.clone_style().window_padding(), original);
337
338 {
339 let _y = ui.push_style_var_y(StyleVarVec2::WindowPadding, 23.0);
340 assert_eq!(ui.clone_style().window_padding(), [original[0], 23.0]);
341 }
342 assert_eq!(ui.clone_style().window_padding(), original);
343 }
344
345 #[test]
346 fn style_var_components_validate_values_before_ffi() {
347 let mut ctx = setup_context();
348 let ui = ctx.frame();
349
350 for value in [-1.0, f32::NAN, f32::INFINITY] {
351 assert!(
352 std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
353 let _token = ui.push_style_var_x(StyleVarVec2::WindowPadding, value);
354 }))
355 .is_err()
356 );
357 }
358 assert!(
359 std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
360 let _token = ui.push_style_var_y(StyleVarVec2::WindowTitleAlign, 1.1);
361 }))
362 .is_err()
363 );
364 }
365}