add transforms
This commit is contained in:
parent
11e1bd975f
commit
ec10e5a89d
3 changed files with 390 additions and 0 deletions
|
@ -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;
|
||||
|
|
|
@ -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",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
384
src/ui/primitives/transform.rs
Normal file
384
src/ui/primitives/transform.rs
Normal 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())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue