Skip to main content

dear_imgui_rs/
colors.rs

1//! Color utilities
2//!
3//! Lightweight RGBA color type and helpers for converting to/from Dear ImGui
4//! packed colors. Useful for configuring styles and draw-list primitives.
5//!
6//! Quick example:
7//! ```no_run
8//! # use dear_imgui_rs::*;
9//! let white = Color::rgb(1.0, 1.0, 1.0);
10//! let abgr = white.to_imgui_u32();
11//! # let mut ctx = Context::create();
12//! # let ui = ctx.frame();
13//! ui.text(format!("0x{:08x}", abgr));
14//! ```
15//!
16use std::fmt;
17
18use crate::sys;
19
20/// RGBA color with 32-bit floating point components
21#[repr(C)]
22#[derive(Copy, Clone, Debug, PartialEq)]
23pub struct Color {
24    pub r: f32,
25    pub g: f32,
26    pub b: f32,
27    pub a: f32,
28}
29
30impl Color {
31    pub const fn new(r: f32, g: f32, b: f32, a: f32) -> Self {
32        Self { r, g, b, a }
33    }
34    pub const fn rgb(r: f32, g: f32, b: f32) -> Self {
35        Self::new(r, g, b, 1.0)
36    }
37    pub fn from_rgba_bytes(r: u8, g: u8, b: u8, a: u8) -> Self {
38        Self::new(
39            r as f32 / 255.0,
40            g as f32 / 255.0,
41            b as f32 / 255.0,
42            a as f32 / 255.0,
43        )
44    }
45    pub fn from_rgb_bytes(r: u8, g: u8, b: u8) -> Self {
46        Self::from_rgba_bytes(r, g, b, 255)
47    }
48    /// Construct from an ImGui-packed color (ImU32 ABGR order).
49    ///
50    /// ImGui packs colors with IM_COL32(R,G,B,A) into `(A<<24)|(B<<16)|(G<<8)|R`.
51    /// This converts that ABGR-packed u32 into an RGBA float Color.
52    pub fn from_imgui_u32(abgr: u32) -> Self {
53        unsafe {
54            let v = sys::igColorConvertU32ToFloat4(abgr);
55            Self::new(v.x, v.y, v.z, v.w)
56        }
57    }
58
59    /// Construct from an opaque 24-bit RGB value (0xRRGGBB).
60    pub fn from_rgb_u32(rgb: u32) -> Self {
61        Self::from_rgba_bytes(
62            ((rgb >> 16) & 0xFF) as u8,
63            ((rgb >> 8) & 0xFF) as u8,
64            (rgb & 0xFF) as u8,
65            255,
66        )
67    }
68
69    /// Pack to ImGui ImU32 ABGR order `(A<<24)|(B<<16)|(G<<8)|R`.
70    pub fn to_imgui_u32(self) -> u32 {
71        unsafe {
72            sys::igColorConvertFloat4ToU32(sys::ImVec4_c {
73                x: self.r,
74                y: self.g,
75                z: self.b,
76                w: self.a,
77            })
78        }
79    }
80    pub fn to_array(self) -> [f32; 4] {
81        [self.r, self.g, self.b, self.a]
82    }
83    pub fn from_array(arr: [f32; 4]) -> Self {
84        Self::new(arr[0], arr[1], arr[2], arr[3])
85    }
86    pub fn with_alpha(mut self, alpha: f32) -> Self {
87        self.a = alpha;
88        self
89    }
90    pub fn lerp(self, other: Self, t: f32) -> Self {
91        let t = t.clamp(0.0, 1.0);
92        Self::new(
93            self.r + (other.r - self.r) * t,
94            self.g + (other.g - self.g) * t,
95            self.b + (other.b - self.b) * t,
96            self.a + (other.a - self.a) * t,
97        )
98    }
99
100    /// Convert RGB to HSV using Dear ImGui semantics (h in [0, 1]).
101    ///
102    /// Note: this differs from [`Color::to_hsv`], which returns hue in degrees.
103    #[doc(alias = "ColorConvertRGBtoHSV")]
104    pub fn to_hsv01(self) -> (f32, f32, f32) {
105        let mut h = 0.0;
106        let mut s = 0.0;
107        let mut v = 0.0;
108        unsafe {
109            sys::igColorConvertRGBtoHSV(self.r, self.g, self.b, &mut h, &mut s, &mut v);
110        }
111        (h, s, v)
112    }
113
114    /// Convert HSV to RGB using Dear ImGui semantics (h in [0, 1]).
115    ///
116    /// Note: this differs from [`Color::from_hsv`], which expects hue in degrees.
117    #[doc(alias = "ColorConvertHSVtoRGB")]
118    pub fn from_hsv01(h: f32, s: f32, v: f32) -> Self {
119        let mut r = 0.0;
120        let mut g = 0.0;
121        let mut b = 0.0;
122        unsafe {
123            sys::igColorConvertHSVtoRGB(h, s, v, &mut r, &mut g, &mut b);
124        }
125        Self::rgb(r, g, b)
126    }
127
128    pub fn to_hsv(self) -> (f32, f32, f32) {
129        let max = self.r.max(self.g).max(self.b);
130        let min = self.r.min(self.g).min(self.b);
131        let delta = max - min;
132        let h = if delta == 0.0 {
133            0.0
134        } else if max == self.r {
135            60.0 * (((self.g - self.b) / delta) % 6.0)
136        } else if max == self.g {
137            60.0 * (((self.b - self.r) / delta) + 2.0)
138        } else {
139            60.0 * (((self.r - self.g) / delta) + 4.0)
140        };
141        let s = if max == 0.0 { 0.0 } else { delta / max };
142        let v = max;
143        (h, s, v)
144    }
145    pub fn from_hsv(h: f32, s: f32, v: f32) -> Self {
146        let h = h % 360.0;
147        let c = v * s;
148        let x = c * (1.0 - ((h / 60.0) % 2.0 - 1.0).abs());
149        let m = v - c;
150        let (r, g, b) = if h < 60.0 {
151            (c, x, 0.0)
152        } else if h < 120.0 {
153            (x, c, 0.0)
154        } else if h < 180.0 {
155            (0.0, c, x)
156        } else if h < 240.0 {
157            (0.0, x, c)
158        } else if h < 300.0 {
159            (x, 0.0, c)
160        } else {
161            (c, 0.0, x)
162        };
163        Self::new(r + m, g + m, b + m, 1.0)
164    }
165}
166
167impl Default for Color {
168    fn default() -> Self {
169        Self::new(1.0, 1.0, 1.0, 1.0)
170    }
171}
172impl From<[f32; 4]> for Color {
173    fn from(arr: [f32; 4]) -> Self {
174        Self::from_array(arr)
175    }
176}
177impl From<Color> for [f32; 4] {
178    fn from(color: Color) -> Self {
179        color.to_array()
180    }
181}
182impl From<(f32, f32, f32, f32)> for Color {
183    fn from((r, g, b, a): (f32, f32, f32, f32)) -> Self {
184        Self::new(r, g, b, a)
185    }
186}
187impl From<Color> for (f32, f32, f32, f32) {
188    fn from(color: Color) -> Self {
189        (color.r, color.g, color.b, color.a)
190    }
191}
192
193impl fmt::Display for Color {
194    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
195        write!(
196            f,
197            "rgba({:.3}, {:.3}, {:.3}, {:.3})",
198            self.r, self.g, self.b, self.a
199        )
200    }
201}
202
203/// Common color constants
204impl Color {
205    pub const TRANSPARENT: Color = Color::new(0.0, 0.0, 0.0, 0.0);
206    pub const BLACK: Color = Color::new(0.0, 0.0, 0.0, 1.0);
207    pub const WHITE: Color = Color::new(1.0, 1.0, 1.0, 1.0);
208    pub const RED: Color = Color::new(1.0, 0.0, 0.0, 1.0);
209    pub const GREEN: Color = Color::new(0.0, 1.0, 0.0, 1.0);
210    pub const BLUE: Color = Color::new(0.0, 0.0, 1.0, 1.0);
211    pub const YELLOW: Color = Color::new(1.0, 1.0, 0.0, 1.0);
212    pub const CYAN: Color = Color::new(0.0, 1.0, 1.0, 1.0);
213    pub const MAGENTA: Color = Color::new(1.0, 0.0, 1.0, 1.0);
214}