add transforms

This commit is contained in:
JMARyA 2025-01-20 05:05:04 +01:00
parent 11e1bd975f
commit ec10e5a89d
Signed by: jmarya
GPG key ID: 901B2ADDF27C2263
3 changed files with 390 additions and 0 deletions

View file

@ -46,6 +46,9 @@ pub mod prelude {
TextDecoration, TextHyphens, TextOverflow, TextTransform, TextWhitespace, TextWordBreak,
TextWrap, UnderlineOffset, VerticalTextAlignment,
};
pub use super::primitives::transform::{
RenderTransformCPU, RenderTransformGPU, Rotate, Scale, Skew, Transform, TransformOrigin,
};
pub use super::primitives::visibility::Visibility;
pub use super::primitives::width::{MaxWidth, MinWidth, Width};
pub use super::primitives::zindex::ZIndex;

View file

@ -21,6 +21,7 @@ pub mod shadow;
pub mod sized;
pub mod space;
pub mod text;
pub mod transform;
pub mod visibility;
pub mod width;
pub mod zindex;
@ -104,6 +105,7 @@ pub enum Side {
TopRight,
BottomRight,
BottomLeft,
Center,
}
impl Side {
@ -124,6 +126,7 @@ impl Side {
Self::TopRight => "tr",
Self::BottomRight => "br",
Self::BottomLeft => "bl",
Self::Center => "center",
}
}
}

View file

@ -0,0 +1,384 @@
use crate::ui::UIWidget;
use maud::{Markup, Render, html};
use super::{
Side,
flex::Either,
space::{Fraction, ScreenValue},
};
#[allow(non_snake_case)]
pub fn Scale<T: UIWidget + 'static>(size: f64, inner: T) -> ScaleWidget {
ScaleWidget(Box::new(inner), size, 0)
}
pub struct ScaleWidget(Box<dyn UIWidget>, f64, u8);
impl ScaleWidget {
pub fn x(mut self) -> Self {
self.2 = 1;
self
}
pub fn y(mut self) -> Self {
self.2 = 2;
self
}
}
impl Render for ScaleWidget {
fn render(&self) -> Markup {
self.render_with_class("")
}
}
impl UIWidget for ScaleWidget {
fn can_inherit(&self) -> bool {
true
}
fn base_class(&self) -> Vec<String> {
match self.2 {
1 => vec![format!("scale-x-[{:.2}]", self.1)],
2 => vec![format!("scale-y-[{:.2}]", self.1)],
_ => vec![format!("scale-[{:.2}]", self.1)],
}
}
fn extended_class(&self) -> Vec<String> {
let mut c = self.base_class();
c.extend_from_slice(&self.0.extended_class());
c
}
fn render_with_class(&self, class: &str) -> Markup {
if self.0.as_ref().can_inherit() {
self.0
.as_ref()
.render_with_class(&format!("{} {class}", self.base_class().join(" ")))
} else {
html! {
div class=(format!("{} {class}", self.base_class().join(" "))) {
(self.0.as_ref())
}
}
}
}
}
#[allow(non_snake_case)]
pub fn Rotate<T: UIWidget + 'static>(deg: u32, inner: T) -> RotateWidget {
RotateWidget(Box::new(inner), deg)
}
pub struct RotateWidget(Box<dyn UIWidget>, u32);
impl Render for RotateWidget {
fn render(&self) -> Markup {
self.render_with_class("")
}
}
impl UIWidget for RotateWidget {
fn can_inherit(&self) -> bool {
true
}
fn base_class(&self) -> Vec<String> {
vec![format!("rotate-[{:.2}deg]", self.1)]
}
fn extended_class(&self) -> Vec<String> {
let mut c = self.base_class();
c.extend_from_slice(&self.0.extended_class());
c
}
fn render_with_class(&self, class: &str) -> Markup {
if self.0.as_ref().can_inherit() {
self.0
.as_ref()
.render_with_class(&format!("{} {class}", self.base_class().join(" ")))
} else {
html! {
div class=(format!("{} {class}", self.base_class().join(" "))) {
(self.0.as_ref())
}
}
}
}
}
#[allow(non_snake_case)]
pub fn RenderTransformCPU<T: UIWidget + 'static>(inner: T) -> HardwareAccelerationWidget {
HardwareAccelerationWidget(Box::new(inner), 0)
}
#[allow(non_snake_case)]
pub fn RenderTransformGPU<T: UIWidget + 'static>(inner: T) -> HardwareAccelerationWidget {
HardwareAccelerationWidget(Box::new(inner), 1)
}
pub struct HardwareAccelerationWidget(Box<dyn UIWidget>, u8);
impl Render for HardwareAccelerationWidget {
fn render(&self) -> Markup {
self.render_with_class("")
}
}
impl UIWidget for HardwareAccelerationWidget {
fn can_inherit(&self) -> bool {
true
}
fn base_class(&self) -> Vec<String> {
match self.1 {
1 => vec!["transform-gpu".to_string()],
_ => vec!["transform-cpu".to_string()],
}
}
fn extended_class(&self) -> Vec<String> {
let mut c = self.base_class();
c.extend_from_slice(&self.0.extended_class());
c
}
fn render_with_class(&self, class: &str) -> Markup {
if self.0.as_ref().can_inherit() {
self.0
.as_ref()
.render_with_class(&format!("{} {class}", self.base_class().join(" ")))
} else {
html! {
div class=(format!("{} {class}", self.base_class().join(" "))) {
(self.0.as_ref())
}
}
}
}
}
#[allow(non_snake_case)]
pub fn Transform<
T: UIWidget + 'static,
X: Into<Either<ScreenValue, Fraction>>,
Y: Into<Either<ScreenValue, Fraction>>,
>(
x: Option<X>,
y: Option<Y>,
inner: T,
) -> TransformWidget {
TransformWidget {
inner: Box::new(inner),
x: x.map(|x| x.into()),
y: y.map(|y| y.into()),
}
}
pub struct TransformWidget {
inner: Box<dyn UIWidget>,
x: Option<Either<ScreenValue, Fraction>>,
y: Option<Either<ScreenValue, Fraction>>,
}
impl Render for TransformWidget {
fn render(&self) -> Markup {
self.render_with_class("")
}
}
impl UIWidget for TransformWidget {
fn can_inherit(&self) -> bool {
true
}
fn base_class(&self) -> Vec<String> {
let mut ret = Vec::new();
if let Some(x) = &self.x {
ret.push(format!(
"translate-x-{}",
x.map(|x| x.to_value().to_string(), |x| x.to_value().to_string())
));
}
if let Some(y) = &self.y {
ret.push(format!(
"translate-y-{}",
y.map(|y| y.to_value().to_string(), |y| y.to_value().to_string())
));
}
ret
}
fn extended_class(&self) -> Vec<String> {
let mut c = self.base_class();
c.extend_from_slice(&self.inner.extended_class());
c
}
fn render_with_class(&self, class: &str) -> Markup {
if self.inner.as_ref().can_inherit() {
self.inner
.as_ref()
.render_with_class(&format!("{} {class}", self.base_class().join(" ")))
} else {
html! {
div class=(format!("{} {class}", self.base_class().join(" "))) {
(self.inner.as_ref())
}
}
}
}
}
pub enum SkewValue {
_0,
_1,
_2,
_3,
_6,
_12,
}
impl SkewValue {
pub const fn to_value(&self) -> &str {
match self {
SkewValue::_0 => "0",
SkewValue::_1 => "1",
SkewValue::_2 => "2",
SkewValue::_3 => "3",
SkewValue::_6 => "6",
SkewValue::_12 => "12",
}
}
}
#[allow(non_snake_case)]
pub fn Skew<T: UIWidget + 'static>(
x: Option<SkewValue>,
y: Option<SkewValue>,
inner: T,
) -> SkewWidget {
SkewWidget {
inner: Box::new(inner),
x,
y,
}
}
pub struct SkewWidget {
inner: Box<dyn UIWidget>,
x: Option<SkewValue>,
y: Option<SkewValue>,
}
impl Render for SkewWidget {
fn render(&self) -> Markup {
self.render_with_class("")
}
}
impl UIWidget for SkewWidget {
fn can_inherit(&self) -> bool {
true
}
fn base_class(&self) -> Vec<String> {
let mut ret = Vec::new();
if let Some(x) = &self.x {
ret.push(format!("skew-x-{}", x.to_value()));
}
if let Some(y) = &self.y {
ret.push(format!("skew-y-{}", y.to_value()));
}
ret
}
fn extended_class(&self) -> Vec<String> {
let mut c = self.base_class();
c.extend_from_slice(&self.inner.extended_class());
c
}
fn render_with_class(&self, class: &str) -> Markup {
if self.inner.as_ref().can_inherit() {
self.inner
.as_ref()
.render_with_class(&format!("{} {class}", self.base_class().join(" ")))
} else {
html! {
div class=(format!("{} {class}", self.base_class().join(" "))) {
(self.inner.as_ref())
}
}
}
}
}
#[allow(non_snake_case)]
pub fn TransformOrigin<T: UIWidget + 'static>(origin: Side, inner: T) -> TransformOriginWidget {
TransformOriginWidget(Box::new(inner), origin)
}
pub struct TransformOriginWidget(Box<dyn UIWidget>, Side);
impl Render for TransformOriginWidget {
fn render(&self) -> Markup {
self.render_with_class("")
}
}
impl UIWidget for TransformOriginWidget {
fn can_inherit(&self) -> bool {
true
}
fn base_class(&self) -> Vec<String> {
let side = match self.1 {
Side::Start => "top",
Side::End => "bottom",
Side::Top => "top",
Side::Right => "right",
Side::Bottom => "bottom",
Side::Left => "left",
Side::StartStart => "top-left",
Side::StartEnd => "top-right",
Side::EndEnd => "bottom-right",
Side::EndStart => "bottom-left",
Side::TopLeft => "top-left",
Side::TopRight => "top-right",
Side::BottomRight => "bottom-right",
Side::BottomLeft => "bottom-left",
Side::Center => "center",
};
vec![format!("origin-{side}")]
}
fn extended_class(&self) -> Vec<String> {
let mut c = self.base_class();
c.extend_from_slice(&self.0.extended_class());
c
}
fn render_with_class(&self, class: &str) -> Markup {
if self.0.as_ref().can_inherit() {
self.0
.as_ref()
.render_with_class(&format!("{} {class}", self.base_class().join(" ")))
} else {
html! {
div class=(format!("{} {class}", self.base_class().join(" "))) {
(self.0.as_ref())
}
}
}
}
}