bevyengine / bevyengine/bevy

Support calc `bevy::ui::Val`

Open
#5,893 4 comments 2 reactions 0 assignees View on GitHub
A-UI C-Usability
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.