1use skia_safe::{BlendMode, Color, Point, TileMode};
4
5#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
7pub enum LayoutOptions {
8 #[default]
9 Start,
10 Center,
11 End,
12 Fill,
13}
14
15#[derive(Clone, Copy, PartialEq, Debug, Default)]
16pub struct Thickness {
17 pub left: f32,
18 pub top: f32,
19 pub right: f32,
20 pub bottom: f32,
21}
22
23impl Thickness {
24 pub const ZERO: Thickness = Thickness { left: 0.0, top: 0.0, right: 0.0, bottom: 0.0 };
25
26 pub const fn new(left: f32, top: f32, right: f32, bottom: f32) -> Self {
27 Self { left, top, right, bottom }
28 }
29 pub const fn uniform(all: f32) -> Self {
30 Self::new(all, all, all, all)
31 }
32 pub fn horizontal(&self) -> f32 {
33 self.left + self.right
34 }
35 pub fn vertical(&self) -> f32 {
36 self.top + self.bottom
37 }
38 pub fn max(self, other: Thickness) -> Thickness {
40 let (a, b) = (self, other);
41 Thickness::new(a.left.max(b.left), a.top.max(b.top), a.right.max(b.right), a.bottom.max(b.bottom))
42 }
43}
44
45#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
48pub enum RenderingModeType {
49 Default,
52 #[default]
54 Accelerated,
55}
56
57#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
60pub enum GesturesMode {
61 #[default]
64 Enabled,
65 Lock,
68}
69
70#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
72pub enum GpuBackend {
73 #[default]
76 Auto,
77 OpenGl,
79 Vulkan,
81}
82
83#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
85#[allow(clippy::upper_case_acronyms)]
86pub enum CacheType {
87 #[default]
88 None,
89 Operations,
91 OperationsFull,
95 Image,
98 GPU,
100 ImageDoubleBuffered,
103 ImageComposite,
106 ImageCompositeGPU,
108}
109
110impl CacheType {
111 pub(crate) fn resolved(self) -> Self {
113 match self {
114 CacheType::GPU => CacheType::Image,
115 CacheType::ImageCompositeGPU => CacheType::ImageComposite,
116 other => other,
117 }
118 }
119}
120
121#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
123pub enum LockTouch {
124 #[default]
125 Disabled,
126 Enabled,
127 PassNone,
128 PassTap,
129 PassTapAndLongPress,
130}
131
132#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
134pub struct Dirty(pub(crate) u8);
135
136impl Dirty {
137 pub const NONE: Dirty = Dirty(0);
138 pub const MEASURE: Dirty = Dirty(1);
140 pub const DRAW: Dirty = Dirty(2);
142 pub const REPAINT: Dirty = Dirty(4);
144 pub const APPLY: Dirty = Dirty(8);
146 pub const MEASURE_APPLY: Dirty = Dirty(1 | 8);
147 pub const DRAW_APPLY: Dirty = Dirty(2 | 8);
148
149 pub fn contains(self, other: Dirty) -> bool {
150 self.0 & other.0 == other.0 && other.0 != 0
151 }
152 pub fn is_empty(self) -> bool {
153 self.0 == 0
154 }
155}
156
157impl std::ops::BitOrAssign for Dirty {
158 fn bitor_assign(&mut self, rhs: Dirty) {
159 self.0 |= rhs.0
160 }
161}
162
163pub trait IntoProp<T> {
165 fn into_prop(self) -> T;
166}
167
168impl<T> IntoProp<T> for T {
169 fn into_prop(self) -> T {
170 self
171 }
172}
173impl IntoProp<f32> for i32 {
174 fn into_prop(self) -> f32 {
175 self as f32
176 }
177}
178impl IntoProp<f32> for f64 {
179 fn into_prop(self) -> f32 {
180 self as f32
181 }
182}
183impl IntoProp<String> for &str {
184 fn into_prop(self) -> String {
185 self.to_owned()
186 }
187}
188impl IntoProp<Option<Color>> for Color {
189 fn into_prop(self) -> Option<Color> {
190 Some(self)
191 }
192}
193impl IntoProp<Option<char>> for char {
194 fn into_prop(self) -> Option<char> {
195 Some(self)
196 }
197}
198impl IntoProp<Option<bool>> for bool {
199 fn into_prop(self) -> Option<bool> {
200 Some(self)
201 }
202}
203impl IntoProp<Thickness> for f32 {
204 fn into_prop(self) -> Thickness {
205 Thickness::uniform(self)
206 }
207}
208impl IntoProp<Thickness> for i32 {
209 fn into_prop(self) -> Thickness {
210 Thickness::uniform(self as f32)
211 }
212}
213impl IntoProp<Thickness> for (f32, f32) {
214 fn into_prop(self) -> Thickness {
216 Thickness::new(self.0, self.1, self.0, self.1)
217 }
218}
219impl IntoProp<Thickness> for (i32, i32) {
220 fn into_prop(self) -> Thickness {
221 (self.0 as f32, self.1 as f32).into_prop()
222 }
223}
224impl IntoProp<Thickness> for (f32, f32, f32, f32) {
225 fn into_prop(self) -> Thickness {
227 Thickness::new(self.0, self.1, self.2, self.3)
228 }
229}
230impl IntoProp<Thickness> for (i32, i32, i32, i32) {
231 fn into_prop(self) -> Thickness {
232 Thickness::new(self.0 as f32, self.1 as f32, self.2 as f32, self.3 as f32)
233 }
234}
235
236#[derive(Clone, Copy, PartialEq, Debug, Default)]
240pub struct CornerRadius {
241 pub top_left: f32,
242 pub top_right: f32,
243 pub bottom_left: f32,
244 pub bottom_right: f32,
245}
246
247impl CornerRadius {
248 pub const fn new(top_left: f32, top_right: f32, bottom_left: f32, bottom_right: f32) -> Self {
249 Self { top_left, top_right, bottom_left, bottom_right }
250 }
251 pub const fn uniform(all: f32) -> Self {
252 Self::new(all, all, all, all)
253 }
254 pub fn is_zero(&self) -> bool {
255 *self == Self::default()
256 }
257}
258
259impl IntoProp<CornerRadius> for f32 {
260 fn into_prop(self) -> CornerRadius {
261 CornerRadius::uniform(self)
262 }
263}
264impl IntoProp<CornerRadius> for i32 {
265 fn into_prop(self) -> CornerRadius {
266 CornerRadius::uniform(self as f32)
267 }
268}
269impl IntoProp<CornerRadius> for (f32, f32, f32, f32) {
270 fn into_prop(self) -> CornerRadius {
272 CornerRadius::new(self.0, self.1, self.2, self.3)
273 }
274}
275impl IntoProp<CornerRadius> for (i32, i32, i32, i32) {
276 fn into_prop(self) -> CornerRadius {
277 CornerRadius::new(self.0 as f32, self.1 as f32, self.2 as f32, self.3 as f32)
278 }
279}
280
281impl IntoProp<Vec<Point>> for Vec<(f32, f32)> {
283 fn into_prop(self) -> Vec<Point> {
284 self.into_iter().map(Point::from).collect()
285 }
286}
287
288#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
289pub enum GradientType {
290 None,
291 #[default]
292 Linear,
293 Circular,
295 Oval,
297 Sweep,
299 Conical,
301}
302
303#[derive(Clone, PartialEq, Debug)]
305pub struct SkiaGradient {
306 pub gradient_type: GradientType,
307 pub colors: Vec<Color>,
308 pub color_positions: Vec<f32>,
310 pub start_x_ratio: f32,
312 pub start_y_ratio: f32,
313 pub end_x_ratio: f32,
314 pub end_y_ratio: f32,
315 pub tile_mode: TileMode,
316 pub light: f32,
318 pub opacity: f32,
320 pub blend_mode: BlendMode,
321}
322
323impl Default for SkiaGradient {
324 fn default() -> Self {
325 Self {
326 gradient_type: GradientType::Linear,
327 colors: Vec::new(),
328 color_positions: Vec::new(),
329 start_x_ratio: 0.0,
330 start_y_ratio: 0.0,
331 end_x_ratio: 0.0,
332 end_y_ratio: 1.0,
333 tile_mode: TileMode::Clamp,
334 light: 1.0,
335 opacity: 1.0,
336 blend_mode: BlendMode::SrcOver,
337 }
338 }
339}
340
341impl SkiaGradient {
342 pub fn new(gradient_type: GradientType, colors: impl Into<Vec<Color>>) -> Self {
344 Self { gradient_type, colors: colors.into(), ..Self::default() }
345 }
346
347 pub fn angle(mut self, degrees: f32) -> Self {
351 let mut direction = degrees - 90.0;
352 if direction < 0.0 {
353 direction += 360.0;
354 }
355 let angle = direction.min(360.0) % 360.0;
356 let ratio = |v: f32| if v <= f32::EPSILON { 0.0 } else { v };
358 let (start, end) = ((180.0 - angle).to_radians(), (360.0 - angle).to_radians());
359 (self.start_x_ratio, self.start_y_ratio) = (ratio(start.cos()), ratio(start.sin()));
360 (self.end_x_ratio, self.end_y_ratio) = (ratio(end.cos()), ratio(end.sin()));
361 self
362 }
363}
364
365macro_rules! fluent {
367 ($ty:ident { $($name:ident: $field:ty),* $(,)? }) => {
368 impl $ty {
369 $(pub fn $name(mut self, v: impl IntoProp<$field>) -> Self {
370 self.$name = v.into_prop();
371 self
372 })*
373 }
374 };
375}
376
377fluent!(SkiaGradient {
378 gradient_type: GradientType,
379 colors: Vec<Color>,
380 color_positions: Vec<f32>,
381 start_x_ratio: f32,
382 start_y_ratio: f32,
383 end_x_ratio: f32,
384 end_y_ratio: f32,
385 tile_mode: TileMode,
386 light: f32,
387 opacity: f32,
388 blend_mode: BlendMode,
389});
390
391impl IntoProp<Option<Box<SkiaGradient>>> for SkiaGradient {
392 fn into_prop(self) -> Option<Box<SkiaGradient>> {
393 Some(Box::new(self))
394 }
395}
396
397#[derive(Clone, Copy, PartialEq, Debug)]
399pub struct SkiaShadow {
400 pub x: f32,
401 pub y: f32,
402 pub blur: f32,
404 pub opacity: f32,
406 pub color: Color,
407 pub shadow_only: bool,
409}
410
411impl Default for SkiaShadow {
412 fn default() -> Self {
413 Self { x: 2.0, y: 2.0, blur: 5.0, opacity: 0.5, color: Color::TRANSPARENT, shadow_only: false }
414 }
415}
416
417impl SkiaShadow {
418 pub fn new(color: Color) -> Self {
421 Self { color, ..Self::default() }
422 }
423}
424
425fluent!(SkiaShadow { x: f32, y: f32, blur: f32, opacity: f32, color: Color, shadow_only: bool });
426
427impl IntoProp<Vec<SkiaShadow>> for SkiaShadow {
428 fn into_prop(self) -> Vec<SkiaShadow> {
429 vec![self]
430 }
431}