Support calc `bevy::ui::Val`
- Dominant language
- Rust
- Stars
- 48.2k
- Forks
- 4.8k
- Avg merge
- 3d 22h
- Merged PRs (30d)
- 161
Description
## What problem does this solve or what need does it fill?
In css, we have `calc()` expression that can auto calculate and update when value is changed _(e.g. window resize event)_
## What solution would you like?
The define of `bevy::ui::Val`:
```rust
/// An enum that describes possible types of value in flexbox layout options
#[derive(Clone, PartialEq, Debug, Default, Serialize, Deserialize, Reflect)]
#[reflect_value(PartialEq, Serialize, Deserialize)]
pub enum Val {
/// No value defined
#[default]
Undefined,
/// Automatically determine this value
Auto,
/// Set this value in pixels
Px(f32),
/// Set this value in percent
Percent(f32),
/// A calc expression
Calc(CalcVal),
}
```
Define of `CalcVal`:
```rust
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize, Reflect)]
// Use `Box` to avoid infinity type size, so we cannot impl `Copy`
pub enum CalcVal {
/// a + b
Add(Box, Box),
/// a - b
Sub(Box, Box),
/// a * b
Mul(Box, f32),
/// a / b
Div(Box, f32),
/// -a
Neg(Box),
}
impl Add for Val {
type Output = Val;
fn add(self, rhs: f32) -> Self::Output {
match self {
Val::Undefined => Val::Undefined,
Val::Auto => Val::Auto,
Val::Px(value) => Val::Px(value + rhs),
Val::Percent(value) => Val::Percent(value + rhs),
Val::Calc(_) => panic!(),
}
}
}
impl Add for &Val {
type Output = Val;
fn add(self, rhs: Val) -> Self::Output {
if let Val::Undefined = rhs {
return Val::Undefined;
}
match self {
Val::Undefined => Val::Undefined,
Val::Auto => match rhs {
Val::Auto => Val::Auto,
_ => Val::Calc(CalcVal::Add(Box::new(self.clone()), Box::new(rhs))),
},
Val::Px(value) => match rhs {
Val::Px(rhs) => Val::Px(value + rhs),
_ => Val::Calc(CalcVal::Add(Box::new(self.clone()), Box::new(rhs))),
},
Val::Percent(value) => match rhs {
Val::Percent(rhs) => Val::Percent(value + rhs),
_ => Val::Calc(CalcVal::Add(Box::new(self.clone()), Box::new(rhs))),
},
Val::Calc(value) => match value {
_ => Val::Calc(CalcVal::Add(Box::new(Val::Calc(value.clone())), Box::new(rhs))),
}
}
}
}
impl AddAssign for Val {
fn add_assign(&mut self, rhs: f32) {
match self {
Val::Undefined | Val::Auto => {}
Val::Px(value) | Val::Percent(value) => *value += rhs,
_ => panic!(),
}
}
}
impl Sub for &Val {
type Output = Val;
fn sub(self, rhs: Val) -> Self::Output {
if let Val::Undefined = rhs {
return Val::Undefined;
}
match self {
Val::Undefined => Val::Undefined,
Val::Auto => match rhs {
Val::Auto => Val::Auto,
_ => Val::Calc(CalcVal::Sub(Box::new(self.clone()), Box::new(rhs))),
},
Val::Px(value) => match rhs {
Val::Px(rhs) => Val::Px(value - rhs),
_ => Val::Calc(CalcVal::Sub(Box::new(self.clone()), Box::new(rhs))),
},
Val::Percent(value) => match rhs {
Val::Percent(rhs) => Val::Percent(value - rhs),
_ => Val::Calc(CalcVal::Sub(Box::new(self.clone()), Box::new(rhs))),
},
Val::Calc(value) => match value {
_ => Val::Calc(CalcVal::Sub(Box::new(Val::Calc(value.clone())), Box::new(rhs))),
},
}
}
}
impl Mul for &Val {
type Output = Val;
fn mul(self, rhs: f32) -> Self::Output {
Val::Calc(CalcVal::Mul(Box::new(self.clone()), rhs))
}
}
impl Div for &Val {
type Output = Val;
fn div(self, rhs: f32) -> Self::Output {
Val::Calc(CalcVal::Div(Box::new(self.clone()), rhs))
}
}
impl Neg for &Val {
type Output = Val;
fn neg(self) -> Self::Output {
match self {
Val::Auto | Val::Undefined => self.clone(),
Val::Px(value) => Val::Px(-value),
Val::Percent(value) => Val::Percent(-value),
Val::Calc(value) => match value.clone() {
CalcVal::Sub(a, b) => Val::Calc(CalcVal::Sub(b.clone(), a.clone())),
CalcVal::Neg(a) => *a,
_ => Val::Calc(CalcVal::Neg(Box::new(self.clone()))),
}
}
}
}
```
## What alternative(s) have you considered?
Other solutions to solve and/or work around the problem presented.
## Additional context
Any other information you would like to add such as related previous work,
screenshots, benchmarks, etc.
Contributor guide
Assessment
This issue has not been assessed yet.