egui_scale/
lib.rs

1//! This crate provides a trait for scaling various types in the `egui` library.
2//! It includes implementations for primitive types, vectors, and various `egui` types.
3//! The `EguiScale` trait allows for scaling values by a given factor, which can be useful for
4//! creating responsive UIs that adapt to different screen sizes or user preferences.
5
6#![forbid(unsafe_code)]
7#![forbid(missing_docs)]
8#![deny(clippy::pedantic)]
9
10use egui::{
11    CornerRadius, FontId, Frame, Margin, Stroke, Style, Vec2, Visuals,
12    epaint::Shadow,
13    style::{Interaction, ScrollStyle, Spacing, TextCursorStyle, WidgetVisuals, Widgets},
14};
15
16/// A trait for scaling various types in the `egui` library.
17pub trait EguiScale {
18    /// Scales the value by the given factor.
19    fn scale(&mut self, scale: f32);
20
21    /// Scales the value by the given factor and return the modified value.
22    #[inline]
23    #[must_use]
24    fn scaled(mut self, scale: f32) -> Self
25    where
26        Self: Sized,
27    {
28        self.scale(scale);
29        self
30    }
31}
32
33impl EguiScale for f32 {
34    #[inline]
35    fn scale(&mut self, scale: f32) {
36        *self *= scale;
37    }
38}
39
40impl EguiScale for u8 {
41    #[inline]
42    fn scale(&mut self, scale: f32) {
43        #![allow(clippy::cast_possible_truncation)]
44        #![allow(clippy::cast_sign_loss)]
45
46        *self = (f32::from(*self) * scale) as u8;
47    }
48}
49
50impl EguiScale for i8 {
51    #[inline]
52    fn scale(&mut self, scale: f32) {
53        #![allow(clippy::cast_possible_truncation)]
54
55        *self = (f32::from(*self) * scale) as i8;
56    }
57}
58
59impl EguiScale for Vec2 {
60    #[inline]
61    fn scale(&mut self, scale: f32) {
62        *self *= scale;
63    }
64}
65
66impl EguiScale for CornerRadius {
67    #[inline]
68    fn scale(&mut self, scale: f32) {
69        self.nw.scale(scale);
70        self.ne.scale(scale);
71        self.se.scale(scale);
72        self.sw.scale(scale);
73    }
74}
75
76impl EguiScale for Margin {
77    #[inline]
78    fn scale(&mut self, scale: f32) {
79        self.left.scale(scale);
80        self.right.scale(scale);
81        self.top.scale(scale);
82        self.bottom.scale(scale);
83    }
84}
85
86impl<T: EguiScale> EguiScale for [T] {
87    #[inline]
88    fn scale(&mut self, scale: f32) {
89        for value in self.iter_mut() {
90            value.scale(scale);
91        }
92    }
93}
94
95impl EguiScale for Shadow {
96    #[inline]
97    fn scale(&mut self, scale: f32) {
98        self.offset.scale(scale);
99        self.blur.scale(scale);
100        self.spread.scale(scale);
101    }
102}
103
104impl EguiScale for Stroke {
105    #[inline]
106    fn scale(&mut self, scale: f32) {
107        self.width *= scale;
108        if self.width < 1.0 {
109            self.color.gamma_multiply(self.width);
110            self.width = 1.0;
111        }
112    }
113}
114
115impl EguiScale for WidgetVisuals {
116    #[inline]
117    fn scale(&mut self, scale: f32) {
118        self.bg_stroke.scale(scale);
119        self.corner_radius.scale(scale);
120        self.fg_stroke.scale(scale);
121        self.expansion.scale(scale);
122    }
123}
124
125impl EguiScale for Interaction {
126    #[inline]
127    fn scale(&mut self, scale: f32) {
128        self.resize_grab_radius_corner.scale(scale);
129        self.resize_grab_radius_side.scale(scale);
130    }
131}
132
133impl EguiScale for Widgets {
134    #[inline]
135    fn scale(&mut self, scale: f32) {
136        self.noninteractive.scale(scale);
137        self.inactive.scale(scale);
138        self.hovered.scale(scale);
139        self.active.scale(scale);
140        self.open.scale(scale);
141    }
142}
143
144impl EguiScale for TextCursorStyle {
145    #[inline]
146    fn scale(&mut self, scale: f32) {
147        self.stroke.scale(scale);
148    }
149}
150
151impl EguiScale for Visuals {
152    #[inline]
153    fn scale(&mut self, scale: f32) {
154        self.clip_rect_margin.scale(scale);
155        self.menu_corner_radius.scale(scale);
156        self.popup_shadow.scale(scale);
157        self.resize_corner_size.scale(scale);
158        self.selection.stroke.scale(scale);
159        self.text_cursor.scale(scale);
160        self.widgets.scale(scale);
161        self.window_corner_radius.scale(scale);
162        self.window_shadow.scale(scale);
163        self.window_stroke.scale(scale);
164    }
165}
166
167impl EguiScale for ScrollStyle {
168    #[inline]
169    fn scale(&mut self, scale: f32) {
170        self.bar_inner_margin.scale(scale);
171        self.bar_outer_margin.scale(scale);
172        self.bar_width.scale(scale);
173        self.floating_allocated_width.scale(scale);
174        self.floating_width.scale(scale);
175        self.handle_min_length.scale(scale);
176    }
177}
178
179impl EguiScale for Spacing {
180    #[inline]
181    fn scale(&mut self, scale: f32) {
182        self.button_padding.scale(scale);
183        self.combo_height.scale(scale);
184        self.combo_width.scale(scale);
185        self.icon_spacing.scale(scale);
186        self.icon_width.scale(scale);
187        self.icon_width_inner.scale(scale);
188        self.indent.scale(scale);
189        self.interact_size.scale(scale);
190        self.item_spacing.scale(scale);
191        self.menu_margin.scale(scale);
192        self.scroll.scale(scale);
193        self.slider_width.scale(scale);
194        self.text_edit_width.scale(scale);
195        self.tooltip_width.scale(scale);
196        self.window_margin.scale(scale);
197    }
198}
199
200impl EguiScale for FontId {
201    fn scale(&mut self, scale: f32) {
202        self.size.scale(scale);
203    }
204}
205
206impl EguiScale for Style {
207    #[inline]
208    fn scale(&mut self, scale: f32) {
209        if let Some(font_id) = &mut self.override_font_id {
210            font_id.scale(scale);
211        }
212        for font_id in self.text_styles.values_mut() {
213            font_id.scale(scale);
214        }
215        self.interaction.scale(scale);
216        self.spacing.scale(scale);
217        self.visuals.scale(scale);
218    }
219}
220
221impl<T> EguiScale for Option<T>
222where
223    T: EguiScale,
224{
225    #[inline]
226    fn scale(&mut self, scale: f32) {
227        if let Some(value) = self {
228            value.scale(scale);
229        }
230    }
231}
232
233impl EguiScale for Frame {
234    #[inline]
235    fn scale(&mut self, scale: f32) {
236        self.inner_margin.scale(scale);
237        self.outer_margin.scale(scale);
238        self.corner_radius.scale(scale);
239        self.shadow.scale(scale);
240        self.stroke.scale(scale);
241    }
242}