use skia_safe::{BlendMode, Color, Point, TileMode};
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
pub enum LayoutOptions {
#[default]
Start,
Center,
End,
Fill,
}
#[derive(Clone, Copy, PartialEq, Debug, Default)]
pub struct Thickness {
pub left: f32,
pub top: f32,
pub right: f32,
pub bottom: f32,
}
impl Thickness {
pub const ZERO: Thickness = Thickness { left: 0.0, top: 0.0, right: 0.0, bottom: 0.0 };
pub const fn new(left: f32, top: f32, right: f32, bottom: f32) -> Self {
Self { left, top, right, bottom }
}
pub const fn uniform(all: f32) -> Self {
Self::new(all, all, all, all)
}
pub fn horizontal(&self) -> f32 {
self.left + self.right
}
pub fn vertical(&self) -> f32 {
self.top + self.bottom
}
pub fn max(self, other: Thickness) -> Thickness {
let (a, b) = (self, other);
Thickness::new(a.left.max(b.left), a.top.max(b.top), a.right.max(b.right), a.bottom.max(b.bottom))
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
pub enum RenderingModeType {
Default,
#[default]
Accelerated,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
pub enum GesturesMode {
#[default]
Enabled,
Lock,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
pub enum GpuBackend {
#[default]
Auto,
OpenGl,
Vulkan,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
#[allow(clippy::upper_case_acronyms)]
pub enum CacheType {
#[default]
None,
Operations,
OperationsFull,
Image,
GPU,
ImageDoubleBuffered,
ImageComposite,
ImageCompositeGPU,
}
impl CacheType {
pub(crate) fn resolved(self) -> Self {
match self {
CacheType::GPU => CacheType::Image,
CacheType::ImageCompositeGPU => CacheType::ImageComposite,
other => other,
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
pub enum LockTouch {
#[default]
Disabled,
Enabled,
PassNone,
PassTap,
PassTapAndLongPress,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
pub struct Dirty(pub(crate) u8);
impl Dirty {
pub const NONE: Dirty = Dirty(0);
pub const MEASURE: Dirty = Dirty(1);
pub const DRAW: Dirty = Dirty(2);
pub const REPAINT: Dirty = Dirty(4);
pub const APPLY: Dirty = Dirty(8);
pub const MEASURE_APPLY: Dirty = Dirty(1 | 8);
pub const DRAW_APPLY: Dirty = Dirty(2 | 8);
pub fn contains(self, other: Dirty) -> bool {
self.0 & other.0 == other.0 && other.0 != 0
}
pub fn is_empty(self) -> bool {
self.0 == 0
}
}
impl std::ops::BitOrAssign for Dirty {
fn bitor_assign(&mut self, rhs: Dirty) {
self.0 |= rhs.0
}
}
pub trait IntoProp<T> {
fn into_prop(self) -> T;
}
impl<T> IntoProp<T> for T {
fn into_prop(self) -> T {
self
}
}
impl IntoProp<f32> for i32 {
fn into_prop(self) -> f32 {
self as f32
}
}
impl IntoProp<f32> for f64 {
fn into_prop(self) -> f32 {
self as f32
}
}
impl IntoProp<String> for &str {
fn into_prop(self) -> String {
self.to_owned()
}
}
impl IntoProp<Option<Color>> for Color {
fn into_prop(self) -> Option<Color> {
Some(self)
}
}
impl IntoProp<Option<char>> for char {
fn into_prop(self) -> Option<char> {
Some(self)
}
}
impl IntoProp<Option<bool>> for bool {
fn into_prop(self) -> Option<bool> {
Some(self)
}
}
impl IntoProp<Thickness> for f32 {
fn into_prop(self) -> Thickness {
Thickness::uniform(self)
}
}
impl IntoProp<Thickness> for i32 {
fn into_prop(self) -> Thickness {
Thickness::uniform(self as f32)
}
}
impl IntoProp<Thickness> for (f32, f32) {
fn into_prop(self) -> Thickness {
Thickness::new(self.0, self.1, self.0, self.1)
}
}
impl IntoProp<Thickness> for (i32, i32) {
fn into_prop(self) -> Thickness {
(self.0 as f32, self.1 as f32).into_prop()
}
}
impl IntoProp<Thickness> for (f32, f32, f32, f32) {
fn into_prop(self) -> Thickness {
Thickness::new(self.0, self.1, self.2, self.3)
}
}
impl IntoProp<Thickness> for (i32, i32, i32, i32) {
fn into_prop(self) -> Thickness {
Thickness::new(self.0 as f32, self.1 as f32, self.2 as f32, self.3 as f32)
}
}
#[derive(Clone, Copy, PartialEq, Debug, Default)]
pub struct CornerRadius {
pub top_left: f32,
pub top_right: f32,
pub bottom_left: f32,
pub bottom_right: f32,
}
impl CornerRadius {
pub const fn new(top_left: f32, top_right: f32, bottom_left: f32, bottom_right: f32) -> Self {
Self { top_left, top_right, bottom_left, bottom_right }
}
pub const fn uniform(all: f32) -> Self {
Self::new(all, all, all, all)
}
pub fn is_zero(&self) -> bool {
*self == Self::default()
}
}
impl IntoProp<CornerRadius> for f32 {
fn into_prop(self) -> CornerRadius {
CornerRadius::uniform(self)
}
}
impl IntoProp<CornerRadius> for i32 {
fn into_prop(self) -> CornerRadius {
CornerRadius::uniform(self as f32)
}
}
impl IntoProp<CornerRadius> for (f32, f32, f32, f32) {
fn into_prop(self) -> CornerRadius {
CornerRadius::new(self.0, self.1, self.2, self.3)
}
}
impl IntoProp<CornerRadius> for (i32, i32, i32, i32) {
fn into_prop(self) -> CornerRadius {
CornerRadius::new(self.0 as f32, self.1 as f32, self.2 as f32, self.3 as f32)
}
}
impl IntoProp<Vec<Point>> for Vec<(f32, f32)> {
fn into_prop(self) -> Vec<Point> {
self.into_iter().map(Point::from).collect()
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
pub enum GradientType {
None,
#[default]
Linear,
Circular,
Oval,
Sweep,
Conical,
}
#[derive(Clone, PartialEq, Debug)]
pub struct SkiaGradient {
pub gradient_type: GradientType,
pub colors: Vec<Color>,
pub color_positions: Vec<f32>,
pub start_x_ratio: f32,
pub start_y_ratio: f32,
pub end_x_ratio: f32,
pub end_y_ratio: f32,
pub tile_mode: TileMode,
pub light: f32,
pub opacity: f32,
pub blend_mode: BlendMode,
}
impl Default for SkiaGradient {
fn default() -> Self {
Self {
gradient_type: GradientType::Linear,
colors: Vec::new(),
color_positions: Vec::new(),
start_x_ratio: 0.0,
start_y_ratio: 0.0,
end_x_ratio: 0.0,
end_y_ratio: 1.0,
tile_mode: TileMode::Clamp,
light: 1.0,
opacity: 1.0,
blend_mode: BlendMode::SrcOver,
}
}
}
impl SkiaGradient {
pub fn new(gradient_type: GradientType, colors: impl Into<Vec<Color>>) -> Self {
Self { gradient_type, colors: colors.into(), ..Self::default() }
}
pub fn angle(mut self, degrees: f32) -> Self {
let mut direction = degrees - 90.0;
if direction < 0.0 {
direction += 360.0;
}
let angle = direction.min(360.0) % 360.0;
let ratio = |v: f32| if v <= f32::EPSILON { 0.0 } else { v };
let (start, end) = ((180.0 - angle).to_radians(), (360.0 - angle).to_radians());
(self.start_x_ratio, self.start_y_ratio) = (ratio(start.cos()), ratio(start.sin()));
(self.end_x_ratio, self.end_y_ratio) = (ratio(end.cos()), ratio(end.sin()));
self
}
}
macro_rules! fluent {
($ty:ident { $($name:ident: $field:ty),* $(,)? }) => {
impl $ty {
$(pub fn $name(mut self, v: impl IntoProp<$field>) -> Self {
self.$name = v.into_prop();
self
})*
}
};
}
fluent!(SkiaGradient {
gradient_type: GradientType,
colors: Vec<Color>,
color_positions: Vec<f32>,
start_x_ratio: f32,
start_y_ratio: f32,
end_x_ratio: f32,
end_y_ratio: f32,
tile_mode: TileMode,
light: f32,
opacity: f32,
blend_mode: BlendMode,
});
impl IntoProp<Option<Box<SkiaGradient>>> for SkiaGradient {
fn into_prop(self) -> Option<Box<SkiaGradient>> {
Some(Box::new(self))
}
}
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct SkiaShadow {
pub x: f32,
pub y: f32,
pub blur: f32,
pub opacity: f32,
pub color: Color,
pub shadow_only: bool,
}
impl Default for SkiaShadow {
fn default() -> Self {
Self { x: 2.0, y: 2.0, blur: 5.0, opacity: 0.5, color: Color::TRANSPARENT, shadow_only: false }
}
}
impl SkiaShadow {
pub fn new(color: Color) -> Self {
Self { color, ..Self::default() }
}
}
fluent!(SkiaShadow { x: f32, y: f32, blur: f32, opacity: f32, color: Color, shadow_only: bool });
impl IntoProp<Vec<SkiaShadow>> for SkiaShadow {
fn into_prop(self) -> Vec<SkiaShadow> {
vec![self]
}
}