dear_imgui_rs/
style.rs

1//! Styling and colors
2//!
3//! High-level access to Dear ImGui style parameters and color table. Use this
4//! module to read or tweak padding, rounding, sizes and retrieve or modify
5//! named colors via [`StyleColor`].
6//!
7//! Example:
8//! ```no_run
9//! # use dear_imgui_rs::*;
10//! # let mut ctx = Context::create();
11//! // Adjust style before building a frame
12//! {
13//!     let style = ctx.style_mut();
14//!     style.set_window_rounding(6.0);
15//!     style.set_color(StyleColor::WindowBg, [0.10, 0.10, 0.12, 1.0]);
16//! }
17//! // Optionally show the style editor for the current style
18//! # let ui = ctx.frame();
19//! ui.show_default_style_editor();
20//! ```
21//!
22//! Quick example (temporary style color):
23//! ```no_run
24//! # use dear_imgui_rs::*;
25//! # let mut ctx = Context::create();
26//! # let ui = ctx.frame();
27//! let c = ui.push_style_color(StyleColor::Text, [0.2, 1.0, 0.2, 1.0]);
28//! ui.text("green text");
29//! c.pop();
30//! ```
31//!
32#![allow(
33    clippy::cast_possible_truncation,
34    clippy::cast_sign_loss,
35    clippy::as_conversions
36)]
37use crate::Context;
38use crate::internal::RawWrapper;
39use crate::sys;
40use crate::utils::HoveredFlags;
41use crate::widget::TreeNodeFlags;
42use crate::widget::{TableFlags, TableRowFlags};
43use crate::window::WindowFlags;
44#[cfg(feature = "serde")]
45use serde::{Deserialize, Serialize};
46use std::cell::UnsafeCell;
47
48/// User interface style/colors
49///
50/// Note: This is a transparent wrapper over `sys::ImGuiStyle` (v1.92+ layout).
51/// Do not assume field layout here; use accessors or `raw()/raw_mut()` if needed.
52#[repr(transparent)]
53#[derive(Debug)]
54pub struct Style(pub(crate) UnsafeCell<sys::ImGuiStyle>);
55
56// Ensure the wrapper stays layout-compatible with the sys bindings.
57const _: [(); std::mem::size_of::<sys::ImGuiStyle>()] = [(); std::mem::size_of::<Style>()];
58const _: [(); std::mem::align_of::<sys::ImGuiStyle>()] = [(); std::mem::align_of::<Style>()];
59
60impl Style {
61    #[inline]
62    fn inner(&self) -> &sys::ImGuiStyle {
63        // Safety: `Style` is a view into ImGui-owned style data. Dear ImGui can update style state
64        // (e.g. via push/pop stacks or user code) while Rust holds `&Style`, so we store it behind
65        // `UnsafeCell` to make that interior mutability explicit.
66        unsafe { &*self.0.get() }
67    }
68
69    #[inline]
70    fn inner_mut(&mut self) -> &mut sys::ImGuiStyle {
71        // Safety: caller has `&mut Style`, so this is a unique Rust borrow for this wrapper.
72        unsafe { &mut *self.0.get() }
73    }
74
75    /// Get a color by style color identifier
76    pub fn color(&self, color: StyleColor) -> [f32; 4] {
77        let c = self.inner().Colors[color as usize];
78        [c.x, c.y, c.z, c.w]
79    }
80
81    /// Set a color by style color identifier
82    pub fn set_color(&mut self, color: StyleColor, value: [f32; 4]) {
83        self.inner_mut().Colors[color as usize] = sys::ImVec4 {
84            x: value[0],
85            y: value[1],
86            z: value[2],
87            w: value[3],
88        };
89    }
90
91    /// Get main font scale (formerly io.FontGlobalScale)
92    pub fn font_scale_main(&self) -> f32 {
93        self.inner().FontScaleMain
94    }
95
96    /// Set main font scale (formerly io.FontGlobalScale)
97    pub fn set_font_scale_main(&mut self, scale: f32) {
98        self.inner_mut().FontScaleMain = scale;
99    }
100
101    /// Get DPI font scale (auto-overwritten if ConfigDpiScaleFonts=true)
102    pub fn font_scale_dpi(&self) -> f32 {
103        self.inner().FontScaleDpi
104    }
105
106    /// Set DPI font scale
107    pub fn set_font_scale_dpi(&mut self, scale: f32) {
108        self.inner_mut().FontScaleDpi = scale;
109    }
110
111    /// Base size used by style for font sizing
112    pub fn font_size_base(&self) -> f32 {
113        self.inner().FontSizeBase
114    }
115
116    pub fn set_font_size_base(&mut self, sz: f32) {
117        self.inner_mut().FontSizeBase = sz;
118    }
119
120    // Common style accessors (typed, convenient)
121
122    pub fn alpha(&self) -> f32 {
123        self.inner().Alpha
124    }
125    pub fn set_alpha(&mut self, v: f32) {
126        self.inner_mut().Alpha = v;
127    }
128
129    pub fn disabled_alpha(&self) -> f32 {
130        self.inner().DisabledAlpha
131    }
132    pub fn set_disabled_alpha(&mut self, v: f32) {
133        self.inner_mut().DisabledAlpha = v;
134    }
135
136    pub fn window_padding(&self) -> [f32; 2] {
137        [self.inner().WindowPadding.x, self.inner().WindowPadding.y]
138    }
139    pub fn set_window_padding(&mut self, v: [f32; 2]) {
140        self.inner_mut().WindowPadding = sys::ImVec2 { x: v[0], y: v[1] };
141    }
142
143    pub fn window_rounding(&self) -> f32 {
144        self.inner().WindowRounding
145    }
146    pub fn set_window_rounding(&mut self, v: f32) {
147        self.inner_mut().WindowRounding = v;
148    }
149
150    pub fn window_border_size(&self) -> f32 {
151        self.inner().WindowBorderSize
152    }
153    pub fn set_window_border_size(&mut self, v: f32) {
154        self.inner_mut().WindowBorderSize = v;
155    }
156
157    pub fn window_min_size(&self) -> [f32; 2] {
158        [self.inner().WindowMinSize.x, self.inner().WindowMinSize.y]
159    }
160    pub fn set_window_min_size(&mut self, v: [f32; 2]) {
161        self.inner_mut().WindowMinSize = sys::ImVec2 { x: v[0], y: v[1] };
162    }
163
164    pub fn window_title_align(&self) -> [f32; 2] {
165        [
166            self.inner().WindowTitleAlign.x,
167            self.inner().WindowTitleAlign.y,
168        ]
169    }
170    pub fn set_window_title_align(&mut self, v: [f32; 2]) {
171        self.inner_mut().WindowTitleAlign = sys::ImVec2 { x: v[0], y: v[1] };
172    }
173
174    pub fn window_menu_button_position(&self) -> Direction {
175        Direction::from(self.inner().WindowMenuButtonPosition)
176    }
177    pub fn set_window_menu_button_position(&mut self, d: Direction) {
178        self.inner_mut().WindowMenuButtonPosition = d.into();
179    }
180
181    pub fn child_rounding(&self) -> f32 {
182        self.inner().ChildRounding
183    }
184    pub fn set_child_rounding(&mut self, v: f32) {
185        self.inner_mut().ChildRounding = v;
186    }
187
188    pub fn child_border_size(&self) -> f32 {
189        self.inner().ChildBorderSize
190    }
191    pub fn set_child_border_size(&mut self, v: f32) {
192        self.inner_mut().ChildBorderSize = v;
193    }
194
195    pub fn popup_rounding(&self) -> f32 {
196        self.inner().PopupRounding
197    }
198    pub fn set_popup_rounding(&mut self, v: f32) {
199        self.inner_mut().PopupRounding = v;
200    }
201
202    pub fn popup_border_size(&self) -> f32 {
203        self.inner().PopupBorderSize
204    }
205    pub fn set_popup_border_size(&mut self, v: f32) {
206        self.inner_mut().PopupBorderSize = v;
207    }
208
209    pub fn frame_padding(&self) -> [f32; 2] {
210        [self.inner().FramePadding.x, self.inner().FramePadding.y]
211    }
212    pub fn set_frame_padding(&mut self, v: [f32; 2]) {
213        self.inner_mut().FramePadding = sys::ImVec2 { x: v[0], y: v[1] };
214    }
215
216    pub fn frame_rounding(&self) -> f32 {
217        self.inner().FrameRounding
218    }
219    pub fn set_frame_rounding(&mut self, v: f32) {
220        self.inner_mut().FrameRounding = v;
221    }
222
223    pub fn frame_border_size(&self) -> f32 {
224        self.inner().FrameBorderSize
225    }
226    pub fn set_frame_border_size(&mut self, v: f32) {
227        self.inner_mut().FrameBorderSize = v;
228    }
229
230    pub fn item_spacing(&self) -> [f32; 2] {
231        [self.inner().ItemSpacing.x, self.inner().ItemSpacing.y]
232    }
233    pub fn set_item_spacing(&mut self, v: [f32; 2]) {
234        self.inner_mut().ItemSpacing = sys::ImVec2 { x: v[0], y: v[1] };
235    }
236
237    pub fn item_inner_spacing(&self) -> [f32; 2] {
238        [
239            self.inner().ItemInnerSpacing.x,
240            self.inner().ItemInnerSpacing.y,
241        ]
242    }
243    pub fn set_item_inner_spacing(&mut self, v: [f32; 2]) {
244        self.inner_mut().ItemInnerSpacing = sys::ImVec2 { x: v[0], y: v[1] };
245    }
246
247    pub fn cell_padding(&self) -> [f32; 2] {
248        [self.inner().CellPadding.x, self.inner().CellPadding.y]
249    }
250    pub fn set_cell_padding(&mut self, v: [f32; 2]) {
251        self.inner_mut().CellPadding = sys::ImVec2 { x: v[0], y: v[1] };
252    }
253
254    pub fn touch_extra_padding(&self) -> [f32; 2] {
255        [
256            self.inner().TouchExtraPadding.x,
257            self.inner().TouchExtraPadding.y,
258        ]
259    }
260    pub fn set_touch_extra_padding(&mut self, v: [f32; 2]) {
261        self.inner_mut().TouchExtraPadding = sys::ImVec2 { x: v[0], y: v[1] };
262    }
263
264    pub fn indent_spacing(&self) -> f32 {
265        self.inner().IndentSpacing
266    }
267    pub fn set_indent_spacing(&mut self, v: f32) {
268        self.inner_mut().IndentSpacing = v;
269    }
270
271    pub fn columns_min_spacing(&self) -> f32 {
272        self.inner().ColumnsMinSpacing
273    }
274    pub fn set_columns_min_spacing(&mut self, v: f32) {
275        self.inner_mut().ColumnsMinSpacing = v;
276    }
277
278    pub fn scrollbar_size(&self) -> f32 {
279        self.inner().ScrollbarSize
280    }
281    pub fn set_scrollbar_size(&mut self, v: f32) {
282        self.inner_mut().ScrollbarSize = v;
283    }
284
285    pub fn scrollbar_rounding(&self) -> f32 {
286        self.inner().ScrollbarRounding
287    }
288    pub fn set_scrollbar_rounding(&mut self, v: f32) {
289        self.inner_mut().ScrollbarRounding = v;
290    }
291
292    pub fn grab_min_size(&self) -> f32 {
293        self.inner().GrabMinSize
294    }
295    pub fn set_grab_min_size(&mut self, v: f32) {
296        self.inner_mut().GrabMinSize = v;
297    }
298
299    pub fn grab_rounding(&self) -> f32 {
300        self.inner().GrabRounding
301    }
302    pub fn set_grab_rounding(&mut self, v: f32) {
303        self.inner_mut().GrabRounding = v;
304    }
305
306    pub fn log_slider_deadzone(&self) -> f32 {
307        self.inner().LogSliderDeadzone
308    }
309    pub fn set_log_slider_deadzone(&mut self, v: f32) {
310        self.inner_mut().LogSliderDeadzone = v;
311    }
312
313    pub fn tab_rounding(&self) -> f32 {
314        self.inner().TabRounding
315    }
316    pub fn set_tab_rounding(&mut self, v: f32) {
317        self.inner_mut().TabRounding = v;
318    }
319
320    pub fn tab_border_size(&self) -> f32 {
321        self.inner().TabBorderSize
322    }
323    pub fn set_tab_border_size(&mut self, v: f32) {
324        self.inner_mut().TabBorderSize = v;
325    }
326
327    pub fn color_button_position(&self) -> Direction {
328        Direction::from(self.inner().ColorButtonPosition)
329    }
330    pub fn set_color_button_position(&mut self, d: Direction) {
331        self.inner_mut().ColorButtonPosition = d.into();
332    }
333
334    pub fn button_text_align(&self) -> [f32; 2] {
335        [
336            self.inner().ButtonTextAlign.x,
337            self.inner().ButtonTextAlign.y,
338        ]
339    }
340    pub fn set_button_text_align(&mut self, v: [f32; 2]) {
341        self.inner_mut().ButtonTextAlign = sys::ImVec2 { x: v[0], y: v[1] };
342    }
343
344    pub fn selectable_text_align(&self) -> [f32; 2] {
345        [
346            self.inner().SelectableTextAlign.x,
347            self.inner().SelectableTextAlign.y,
348        ]
349    }
350    pub fn set_selectable_text_align(&mut self, v: [f32; 2]) {
351        self.inner_mut().SelectableTextAlign = sys::ImVec2 { x: v[0], y: v[1] };
352    }
353
354    pub fn display_window_padding(&self) -> [f32; 2] {
355        [
356            self.inner().DisplayWindowPadding.x,
357            self.inner().DisplayWindowPadding.y,
358        ]
359    }
360    pub fn set_display_window_padding(&mut self, v: [f32; 2]) {
361        self.inner_mut().DisplayWindowPadding = sys::ImVec2 { x: v[0], y: v[1] };
362    }
363
364    pub fn display_safe_area_padding(&self) -> [f32; 2] {
365        [
366            self.inner().DisplaySafeAreaPadding.x,
367            self.inner().DisplaySafeAreaPadding.y,
368        ]
369    }
370    pub fn set_display_safe_area_padding(&mut self, v: [f32; 2]) {
371        self.inner_mut().DisplaySafeAreaPadding = sys::ImVec2 { x: v[0], y: v[1] };
372    }
373
374    pub fn mouse_cursor_scale(&self) -> f32 {
375        self.inner().MouseCursorScale
376    }
377    pub fn set_mouse_cursor_scale(&mut self, v: f32) {
378        self.inner_mut().MouseCursorScale = v;
379    }
380
381    pub fn anti_aliased_lines(&self) -> bool {
382        self.inner().AntiAliasedLines
383    }
384    pub fn set_anti_aliased_lines(&mut self, v: bool) {
385        self.inner_mut().AntiAliasedLines = v;
386    }
387
388    pub fn anti_aliased_lines_use_tex(&self) -> bool {
389        self.inner().AntiAliasedLinesUseTex
390    }
391    pub fn set_anti_aliased_lines_use_tex(&mut self, v: bool) {
392        self.inner_mut().AntiAliasedLinesUseTex = v;
393    }
394
395    pub fn anti_aliased_fill(&self) -> bool {
396        self.inner().AntiAliasedFill
397    }
398    pub fn set_anti_aliased_fill(&mut self, v: bool) {
399        self.inner_mut().AntiAliasedFill = v;
400    }
401
402    pub fn curve_tessellation_tol(&self) -> f32 {
403        self.inner().CurveTessellationTol
404    }
405    pub fn set_curve_tessellation_tol(&mut self, v: f32) {
406        self.inner_mut().CurveTessellationTol = v;
407    }
408
409    pub fn circle_tessellation_max_error(&self) -> f32 {
410        self.inner().CircleTessellationMaxError
411    }
412    pub fn set_circle_tessellation_max_error(&mut self, v: f32) {
413        self.inner_mut().CircleTessellationMaxError = v;
414    }
415
416    // Newly exposed 1.92+ or less-common fields
417
418    pub fn window_border_hover_padding(&self) -> f32 {
419        self.inner().WindowBorderHoverPadding
420    }
421    pub fn set_window_border_hover_padding(&mut self, v: f32) {
422        self.inner_mut().WindowBorderHoverPadding = v;
423    }
424
425    pub fn scrollbar_padding(&self) -> f32 {
426        self.inner().ScrollbarPadding
427    }
428    pub fn set_scrollbar_padding(&mut self, v: f32) {
429        self.inner_mut().ScrollbarPadding = v;
430    }
431
432    pub fn image_border_size(&self) -> f32 {
433        self.inner().ImageBorderSize
434    }
435    pub fn set_image_border_size(&mut self, v: f32) {
436        self.inner_mut().ImageBorderSize = v;
437    }
438
439    pub fn tab_min_width_base(&self) -> f32 {
440        self.inner().TabMinWidthBase
441    }
442    pub fn set_tab_min_width_base(&mut self, v: f32) {
443        self.inner_mut().TabMinWidthBase = v;
444    }
445
446    pub fn tab_min_width_shrink(&self) -> f32 {
447        self.inner().TabMinWidthShrink
448    }
449    pub fn set_tab_min_width_shrink(&mut self, v: f32) {
450        self.inner_mut().TabMinWidthShrink = v;
451    }
452
453    pub fn tab_close_button_min_width_selected(&self) -> f32 {
454        self.inner().TabCloseButtonMinWidthSelected
455    }
456    pub fn set_tab_close_button_min_width_selected(&mut self, v: f32) {
457        self.inner_mut().TabCloseButtonMinWidthSelected = v;
458    }
459
460    pub fn tab_close_button_min_width_unselected(&self) -> f32 {
461        self.inner().TabCloseButtonMinWidthUnselected
462    }
463    pub fn set_tab_close_button_min_width_unselected(&mut self, v: f32) {
464        self.inner_mut().TabCloseButtonMinWidthUnselected = v;
465    }
466
467    pub fn tab_bar_border_size(&self) -> f32 {
468        self.inner().TabBarBorderSize
469    }
470    pub fn set_tab_bar_border_size(&mut self, v: f32) {
471        self.inner_mut().TabBarBorderSize = v;
472    }
473
474    pub fn tab_bar_overline_size(&self) -> f32 {
475        self.inner().TabBarOverlineSize
476    }
477    pub fn set_tab_bar_overline_size(&mut self, v: f32) {
478        self.inner_mut().TabBarOverlineSize = v;
479    }
480
481    pub fn table_angled_headers_angle(&self) -> f32 {
482        self.inner().TableAngledHeadersAngle
483    }
484    pub fn set_table_angled_headers_angle(&mut self, v: f32) {
485        self.inner_mut().TableAngledHeadersAngle = v;
486    }
487
488    pub fn table_angled_headers_text_align(&self) -> [f32; 2] {
489        [
490            self.inner().TableAngledHeadersTextAlign.x,
491            self.inner().TableAngledHeadersTextAlign.y,
492        ]
493    }
494    pub fn set_table_angled_headers_text_align(&mut self, v: [f32; 2]) {
495        self.inner_mut().TableAngledHeadersTextAlign = sys::ImVec2 { x: v[0], y: v[1] };
496    }
497
498    pub fn tree_lines_flags(&self) -> TreeNodeFlags {
499        TreeNodeFlags::from_bits_truncate(self.inner().TreeLinesFlags as i32)
500    }
501    pub fn set_tree_lines_flags(&mut self, flags: TreeNodeFlags) {
502        self.inner_mut().TreeLinesFlags = flags.bits() as sys::ImGuiTreeNodeFlags;
503    }
504
505    pub fn tree_lines_size(&self) -> f32 {
506        self.inner().TreeLinesSize
507    }
508    pub fn set_tree_lines_size(&mut self, v: f32) {
509        self.inner_mut().TreeLinesSize = v;
510    }
511
512    pub fn tree_lines_rounding(&self) -> f32 {
513        self.inner().TreeLinesRounding
514    }
515    pub fn set_tree_lines_rounding(&mut self, v: f32) {
516        self.inner_mut().TreeLinesRounding = v;
517    }
518
519    pub fn separator_text_border_size(&self) -> f32 {
520        self.inner().SeparatorTextBorderSize
521    }
522    pub fn set_separator_text_border_size(&mut self, v: f32) {
523        self.inner_mut().SeparatorTextBorderSize = v;
524    }
525
526    pub fn separator_text_align(&self) -> [f32; 2] {
527        [
528            self.inner().SeparatorTextAlign.x,
529            self.inner().SeparatorTextAlign.y,
530        ]
531    }
532    pub fn set_separator_text_align(&mut self, v: [f32; 2]) {
533        self.inner_mut().SeparatorTextAlign = sys::ImVec2 { x: v[0], y: v[1] };
534    }
535
536    pub fn separator_text_padding(&self) -> [f32; 2] {
537        [
538            self.inner().SeparatorTextPadding.x,
539            self.inner().SeparatorTextPadding.y,
540        ]
541    }
542    pub fn set_separator_text_padding(&mut self, v: [f32; 2]) {
543        self.inner_mut().SeparatorTextPadding = sys::ImVec2 { x: v[0], y: v[1] };
544    }
545
546    pub fn docking_node_has_close_button(&self) -> bool {
547        self.inner().DockingNodeHasCloseButton
548    }
549    pub fn set_docking_node_has_close_button(&mut self, v: bool) {
550        self.inner_mut().DockingNodeHasCloseButton = v;
551    }
552
553    pub fn docking_separator_size(&self) -> f32 {
554        self.inner().DockingSeparatorSize
555    }
556    pub fn set_docking_separator_size(&mut self, v: f32) {
557        self.inner_mut().DockingSeparatorSize = v;
558    }
559
560    pub fn hover_stationary_delay(&self) -> f32 {
561        self.inner().HoverStationaryDelay
562    }
563    pub fn set_hover_stationary_delay(&mut self, v: f32) {
564        self.inner_mut().HoverStationaryDelay = v;
565    }
566
567    pub fn hover_delay_short(&self) -> f32 {
568        self.inner().HoverDelayShort
569    }
570    pub fn set_hover_delay_short(&mut self, v: f32) {
571        self.inner_mut().HoverDelayShort = v;
572    }
573
574    pub fn hover_delay_normal(&self) -> f32 {
575        self.inner().HoverDelayNormal
576    }
577    pub fn set_hover_delay_normal(&mut self, v: f32) {
578        self.inner_mut().HoverDelayNormal = v;
579    }
580
581    pub fn hover_flags_for_tooltip_mouse(&self) -> HoveredFlags {
582        HoveredFlags::from_bits_truncate(self.inner().HoverFlagsForTooltipMouse as i32)
583    }
584    pub fn set_hover_flags_for_tooltip_mouse(&mut self, flags: HoveredFlags) {
585        self.inner_mut().HoverFlagsForTooltipMouse = flags.bits() as sys::ImGuiHoveredFlags;
586    }
587
588    pub fn hover_flags_for_tooltip_nav(&self) -> HoveredFlags {
589        HoveredFlags::from_bits_truncate(self.inner().HoverFlagsForTooltipNav as i32)
590    }
591    pub fn set_hover_flags_for_tooltip_nav(&mut self, flags: HoveredFlags) {
592        self.inner_mut().HoverFlagsForTooltipNav = flags.bits() as sys::ImGuiHoveredFlags;
593    }
594}
595
596// HoveredFlags are defined in utils.rs and re-exported at crate root.
597
598/// A cardinal direction
599#[repr(i32)]
600#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
601pub enum Direction {
602    None = sys::ImGuiDir_None as i32,
603    Left = sys::ImGuiDir_Left as i32,
604    Right = sys::ImGuiDir_Right as i32,
605    Up = sys::ImGuiDir_Up as i32,
606    Down = sys::ImGuiDir_Down as i32,
607}
608
609impl From<sys::ImGuiDir> for Direction {
610    fn from(d: sys::ImGuiDir) -> Self {
611        match d as i32 {
612            x if x == sys::ImGuiDir_Left as i32 => Direction::Left,
613            x if x == sys::ImGuiDir_Right as i32 => Direction::Right,
614            x if x == sys::ImGuiDir_Up as i32 => Direction::Up,
615            x if x == sys::ImGuiDir_Down as i32 => Direction::Down,
616            _ => Direction::None,
617        }
618    }
619}
620
621impl From<Direction> for sys::ImGuiDir {
622    fn from(d: Direction) -> Self {
623        match d {
624            Direction::None => sys::ImGuiDir_None,
625            Direction::Left => sys::ImGuiDir_Left,
626            Direction::Right => sys::ImGuiDir_Right,
627            Direction::Up => sys::ImGuiDir_Up,
628            Direction::Down => sys::ImGuiDir_Down,
629        }
630    }
631}
632
633/// Style color identifier
634#[repr(i32)]
635#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
636#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
637pub enum StyleColor {
638    Text = sys::ImGuiCol_Text as i32,
639    TextDisabled = sys::ImGuiCol_TextDisabled as i32,
640    WindowBg = sys::ImGuiCol_WindowBg as i32,
641    ChildBg = sys::ImGuiCol_ChildBg as i32,
642    PopupBg = sys::ImGuiCol_PopupBg as i32,
643    Border = sys::ImGuiCol_Border as i32,
644    BorderShadow = sys::ImGuiCol_BorderShadow as i32,
645    FrameBg = sys::ImGuiCol_FrameBg as i32,
646    FrameBgHovered = sys::ImGuiCol_FrameBgHovered as i32,
647    FrameBgActive = sys::ImGuiCol_FrameBgActive as i32,
648    TitleBg = sys::ImGuiCol_TitleBg as i32,
649    TitleBgActive = sys::ImGuiCol_TitleBgActive as i32,
650    TitleBgCollapsed = sys::ImGuiCol_TitleBgCollapsed as i32,
651    MenuBarBg = sys::ImGuiCol_MenuBarBg as i32,
652    ScrollbarBg = sys::ImGuiCol_ScrollbarBg as i32,
653    ScrollbarGrab = sys::ImGuiCol_ScrollbarGrab as i32,
654    ScrollbarGrabHovered = sys::ImGuiCol_ScrollbarGrabHovered as i32,
655    ScrollbarGrabActive = sys::ImGuiCol_ScrollbarGrabActive as i32,
656    CheckMark = sys::ImGuiCol_CheckMark as i32,
657    SliderGrab = sys::ImGuiCol_SliderGrab as i32,
658    SliderGrabActive = sys::ImGuiCol_SliderGrabActive as i32,
659    Button = sys::ImGuiCol_Button as i32,
660    ButtonHovered = sys::ImGuiCol_ButtonHovered as i32,
661    ButtonActive = sys::ImGuiCol_ButtonActive as i32,
662    Header = sys::ImGuiCol_Header as i32,
663    HeaderHovered = sys::ImGuiCol_HeaderHovered as i32,
664    HeaderActive = sys::ImGuiCol_HeaderActive as i32,
665    Separator = sys::ImGuiCol_Separator as i32,
666    SeparatorHovered = sys::ImGuiCol_SeparatorHovered as i32,
667    SeparatorActive = sys::ImGuiCol_SeparatorActive as i32,
668    ResizeGrip = sys::ImGuiCol_ResizeGrip as i32,
669    ResizeGripHovered = sys::ImGuiCol_ResizeGripHovered as i32,
670    ResizeGripActive = sys::ImGuiCol_ResizeGripActive as i32,
671    Tab = sys::ImGuiCol_Tab as i32,
672    TabHovered = sys::ImGuiCol_TabHovered as i32,
673    // Newly added tab colors in docking branch
674    TabSelected = sys::ImGuiCol_TabSelected as i32,
675    TabSelectedOverline = sys::ImGuiCol_TabSelectedOverline as i32,
676    TabDimmed = sys::ImGuiCol_TabDimmed as i32,
677    TabDimmedSelected = sys::ImGuiCol_TabDimmedSelected as i32,
678    TabDimmedSelectedOverline = sys::ImGuiCol_TabDimmedSelectedOverline as i32,
679    DockingPreview = sys::ImGuiCol_DockingPreview as i32,
680    DockingEmptyBg = sys::ImGuiCol_DockingEmptyBg as i32,
681    PlotLines = sys::ImGuiCol_PlotLines as i32,
682    PlotLinesHovered = sys::ImGuiCol_PlotLinesHovered as i32,
683    PlotHistogram = sys::ImGuiCol_PlotHistogram as i32,
684    PlotHistogramHovered = sys::ImGuiCol_PlotHistogramHovered as i32,
685    TableHeaderBg = sys::ImGuiCol_TableHeaderBg as i32,
686    TableBorderStrong = sys::ImGuiCol_TableBorderStrong as i32,
687    TableBorderLight = sys::ImGuiCol_TableBorderLight as i32,
688    TableRowBg = sys::ImGuiCol_TableRowBg as i32,
689    TableRowBgAlt = sys::ImGuiCol_TableRowBgAlt as i32,
690    TextSelectedBg = sys::ImGuiCol_TextSelectedBg as i32,
691    TextLink = sys::ImGuiCol_TextLink as i32,
692    TreeLines = sys::ImGuiCol_TreeLines as i32,
693    InputTextCursor = sys::ImGuiCol_InputTextCursor as i32,
694    DragDropTarget = sys::ImGuiCol_DragDropTarget as i32,
695    DragDropTargetBg = sys::ImGuiCol_DragDropTargetBg as i32,
696    UnsavedMarker = sys::ImGuiCol_UnsavedMarker as i32,
697    NavCursor = sys::ImGuiCol_NavCursor as i32,
698    NavWindowingHighlight = sys::ImGuiCol_NavWindowingHighlight as i32,
699    NavWindowingDimBg = sys::ImGuiCol_NavWindowingDimBg as i32,
700    ModalWindowDimBg = sys::ImGuiCol_ModalWindowDimBg as i32,
701}
702
703impl StyleColor {
704    pub const COUNT: usize = sys::ImGuiCol_COUNT as usize;
705}
706
707impl Clone for Style {
708    fn clone(&self) -> Self {
709        Self(UnsafeCell::new(*self.inner()))
710    }
711}
712
713impl PartialEq for Style {
714    fn eq(&self, other: &Self) -> bool {
715        *self.inner() == *other.inner()
716    }
717}
718
719impl RawWrapper for Style {
720    type Raw = sys::ImGuiStyle;
721
722    unsafe fn raw(&self) -> &Self::Raw {
723        self.inner()
724    }
725
726    unsafe fn raw_mut(&mut self) -> &mut Self::Raw {
727        self.inner_mut()
728    }
729}
730
731/// A temporary change in user interface style
732#[derive(Copy, Clone, Debug, PartialEq)]
733#[non_exhaustive]
734pub enum StyleVar {
735    /// Global alpha applies to everything
736    Alpha(f32),
737    /// Additional alpha multiplier applied to disabled elements
738    DisabledAlpha(f32),
739    /// Padding within a window
740    WindowPadding([f32; 2]),
741    /// Rounding radius of window corners
742    WindowRounding(f32),
743    /// Thickness of border around windows
744    WindowBorderSize(f32),
745    /// Minimum window size
746    WindowMinSize([f32; 2]),
747    /// Alignment for title bar text
748    WindowTitleAlign([f32; 2]),
749    /// Rounding radius of child window corners
750    ChildRounding(f32),
751    /// Thickness of border around child windows
752    ChildBorderSize(f32),
753    /// Rounding radius of popup window corners
754    PopupRounding(f32),
755    /// Thickness of border around popup/tooltip windows
756    PopupBorderSize(f32),
757    /// Padding within a framed rectangle (used by most widgets)
758    FramePadding([f32; 2]),
759    /// Rounding radius of frame corners (used by most widgets)
760    FrameRounding(f32),
761    /// Thickness of border around frames
762    FrameBorderSize(f32),
763    /// Horizontal and vertical spacing between widgets/lines
764    ItemSpacing([f32; 2]),
765    /// Horizontal and vertical spacing between within elements of a composed widget
766    ItemInnerSpacing([f32; 2]),
767    /// Horizontal indentation when e.g. entering a tree node
768    IndentSpacing(f32),
769    /// Padding within a table cell
770    CellPadding([f32; 2]),
771    /// Width of the vertical scrollbar, height of the horizontal scrollbar
772    ScrollbarSize(f32),
773    /// Rounding radius of scrollbar corners
774    ScrollbarRounding(f32),
775    /// Minimum width/height of a grab box for slider/scrollbar
776    GrabMinSize(f32),
777    /// Rounding radius of grabs corners
778    GrabRounding(f32),
779    /// Rounding radius of upper corners of tabs
780    TabRounding(f32),
781    /// Alignment of button text when button is larger than text
782    ButtonTextAlign([f32; 2]),
783    /// Alignment of selectable text when selectable is larger than text
784    SelectableTextAlign([f32; 2]),
785}
786
787/// Which base preset to start from when applying a [`Theme`].
788///
789/// This controls which built-in Dear ImGui color set is used as a starting
790/// point before applying any overrides.
791#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
792#[derive(Copy, Clone, Debug, PartialEq, Eq)]
793pub enum ThemePreset {
794    /// Do not touch existing style colors; only apply explicit overrides.
795    None,
796    /// Use Dear ImGui's built-in dark preset.
797    Dark,
798    /// Use Dear ImGui's built-in light preset.
799    Light,
800    /// Use Dear ImGui's classic preset.
801    Classic,
802}
803
804impl Default for ThemePreset {
805    fn default() -> Self {
806        ThemePreset::None
807    }
808}
809
810/// A single color override for a given [`StyleColor`] entry.
811#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
812#[derive(Clone, Debug, PartialEq)]
813pub struct ColorOverride {
814    /// Target style color to override.
815    pub id: StyleColor,
816    /// New RGBA color (0.0-1.0 range) to apply.
817    pub rgba: [f32; 4],
818}
819
820/// High-level style tweaks that can be applied on top of a preset.
821///
822/// This does not expose the full `ImGuiStyle` surface, only the most commonly
823/// themed fields. All fields are optional; `None` means "leave unchanged".
824#[derive(Clone, Debug)]
825#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
826#[cfg_attr(feature = "serde", serde(default))]
827pub struct StyleTweaks {
828    pub window_rounding: Option<f32>,
829    pub frame_rounding: Option<f32>,
830    pub tab_rounding: Option<f32>,
831
832    pub window_padding: Option<[f32; 2]>,
833    pub frame_padding: Option<[f32; 2]>,
834    pub cell_padding: Option<[f32; 2]>,
835    pub item_spacing: Option<[f32; 2]>,
836    pub item_inner_spacing: Option<[f32; 2]>,
837
838    pub scrollbar_size: Option<f32>,
839    pub grab_min_size: Option<f32>,
840
841    pub indent_spacing: Option<f32>,
842    pub scrollbar_rounding: Option<f32>,
843    pub grab_rounding: Option<f32>,
844    pub window_border_size: Option<f32>,
845    pub child_border_size: Option<f32>,
846    pub popup_border_size: Option<f32>,
847    pub frame_border_size: Option<f32>,
848    pub tab_border_size: Option<f32>,
849    pub child_rounding: Option<f32>,
850    pub popup_rounding: Option<f32>,
851
852    pub anti_aliased_lines: Option<bool>,
853    pub anti_aliased_fill: Option<bool>,
854}
855
856impl Default for StyleTweaks {
857    fn default() -> Self {
858        Self {
859            window_rounding: None,
860            frame_rounding: None,
861            tab_rounding: None,
862            window_padding: None,
863            frame_padding: None,
864            cell_padding: None,
865            item_spacing: None,
866            item_inner_spacing: None,
867            scrollbar_size: None,
868            grab_min_size: None,
869            indent_spacing: None,
870            scrollbar_rounding: None,
871            grab_rounding: None,
872            window_border_size: None,
873            child_border_size: None,
874            popup_border_size: None,
875            frame_border_size: None,
876            tab_border_size: None,
877            child_rounding: None,
878            popup_rounding: None,
879            anti_aliased_lines: None,
880            anti_aliased_fill: None,
881        }
882    }
883}
884
885impl StyleTweaks {
886    /// Apply these tweaks to the given style.
887    pub fn apply(&self, style: &mut Style) {
888        if let Some(v) = self.window_rounding {
889            style.set_window_rounding(v);
890        }
891        if let Some(v) = self.frame_rounding {
892            style.set_frame_rounding(v);
893        }
894        if let Some(v) = self.tab_rounding {
895            style.set_tab_rounding(v);
896        }
897
898        if let Some(v) = self.window_padding {
899            style.set_window_padding(v);
900        }
901        if let Some(v) = self.frame_padding {
902            style.set_frame_padding(v);
903        }
904        if let Some(v) = self.cell_padding {
905            style.set_cell_padding(v);
906        }
907        if let Some(v) = self.item_spacing {
908            style.set_item_spacing(v);
909        }
910        if let Some(v) = self.item_inner_spacing {
911            style.set_item_inner_spacing(v);
912        }
913
914        if let Some(v) = self.scrollbar_size {
915            style.set_scrollbar_size(v);
916        }
917        if let Some(v) = self.grab_min_size {
918            style.set_grab_min_size(v);
919        }
920
921        if let Some(v) = self.indent_spacing {
922            style.set_indent_spacing(v);
923        }
924        if let Some(v) = self.scrollbar_rounding {
925            style.set_scrollbar_rounding(v);
926        }
927        if let Some(v) = self.grab_rounding {
928            style.set_grab_rounding(v);
929        }
930        if let Some(v) = self.window_border_size {
931            style.set_window_border_size(v);
932        }
933        if let Some(v) = self.child_border_size {
934            style.set_child_border_size(v);
935        }
936        if let Some(v) = self.popup_border_size {
937            style.set_popup_border_size(v);
938        }
939        if let Some(v) = self.frame_border_size {
940            style.set_frame_border_size(v);
941        }
942        if let Some(v) = self.tab_border_size {
943            style.set_tab_border_size(v);
944        }
945        if let Some(v) = self.child_rounding {
946            style.set_child_rounding(v);
947        }
948        if let Some(v) = self.popup_rounding {
949            style.set_popup_rounding(v);
950        }
951
952        if let Some(v) = self.anti_aliased_lines {
953            style.set_anti_aliased_lines(v);
954        }
955        if let Some(v) = self.anti_aliased_fill {
956            style.set_anti_aliased_fill(v);
957        }
958    }
959}
960
961/// Window-related theme defaults (flags/behavior).
962#[derive(Clone, Debug, Default)]
963#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
964pub struct WindowTheme {
965    /// Default flags for top-level windows.
966    pub default_window_flags: Option<WindowFlags>,
967    /// Default flags for popups/modals.
968    pub popup_window_flags: Option<WindowFlags>,
969}
970
971/// Table-related theme defaults (flags/behavior).
972#[derive(Clone, Debug, Default)]
973#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
974pub struct TableTheme {
975    /// Default flags for tables created via `Ui::table` / `Ui::begin_table`.
976    pub default_table_flags: Option<TableFlags>,
977    /// Default row flags for data tables.
978    pub default_row_flags: Option<TableRowFlags>,
979}
980
981/// High-level theme configuration for Dear ImGui.
982///
983/// A theme is applied in three stages:
984/// 1) Choose a base preset (`Dark`/`Light`/`Classic` or `None`).
985/// 2) Apply any explicit color overrides.
986/// 3) Apply a small set of style tweaks.
987///
988/// Window/table defaults are provided as data and can be used by higher-level
989/// helpers when building windows and tables.
990#[derive(Clone, Debug, Default)]
991#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
992pub struct Theme {
993    /// Base preset to start from, before applying overrides.
994    #[cfg_attr(feature = "serde", serde(default))]
995    pub preset: ThemePreset,
996
997    /// Color overrides on top of the preset.
998    #[cfg_attr(feature = "serde", serde(default))]
999    pub colors: Vec<ColorOverride>,
1000
1001    /// Optional style tweaks on top of the preset.
1002    #[cfg_attr(feature = "serde", serde(default))]
1003    pub style: StyleTweaks,
1004
1005    /// Window-related defaults (flags/behavior).
1006    #[cfg_attr(feature = "serde", serde(default))]
1007    pub windows: WindowTheme,
1008
1009    /// Table-related defaults (flags/behavior).
1010    #[cfg_attr(feature = "serde", serde(default))]
1011    pub tables: TableTheme,
1012}
1013
1014impl Theme {
1015    /// Apply this theme to a given style.
1016    ///
1017    /// This does not touch fonts or IO; it only updates `ImGuiStyle`.
1018    pub fn apply_to_style(&self, style: &mut Style) {
1019        // 1) Base preset
1020        match self.preset {
1021            ThemePreset::None => {}
1022            ThemePreset::Dark => unsafe {
1023                sys::igStyleColorsDark(style.raw_mut());
1024            },
1025            ThemePreset::Light => unsafe {
1026                sys::igStyleColorsLight(style.raw_mut());
1027            },
1028            ThemePreset::Classic => unsafe {
1029                sys::igStyleColorsClassic(style.raw_mut());
1030            },
1031        }
1032
1033        // 2) Color overrides
1034        for c in &self.colors {
1035            style.set_color(c.id, c.rgba);
1036        }
1037
1038        // 3) Common style tweaks
1039        self.style.apply(style);
1040    }
1041
1042    /// Apply this theme to the given context (current style).
1043    pub fn apply_to_context(&self, ctx: &mut Context) {
1044        let style = ctx.style_mut();
1045        self.apply_to_style(style);
1046    }
1047}