use crate::geometry::Size;
#[derive(Copy, Clone, Debug, PartialEq, Default)]
#[cfg_attr(feature = "reflect", derive(bevy_reflect::Reflect))]
pub struct Insets {
pub left: f64,
pub right: f64,
pub top: f64,
pub bottom: f64,
}
impl Insets {
pub const ZERO: Self = Self {
left: 0.0,
right: 0.0,
top: 0.0,
bottom: 0.0,
};
pub fn all(v: f64) -> Self {
Self {
left: v,
right: v,
top: v,
bottom: v,
}
}
pub fn symmetric(h: f64, v: f64) -> Self {
Self {
left: h,
right: h,
top: v,
bottom: v,
}
}
pub fn from_sides(left: f64, right: f64, top: f64, bottom: f64) -> Self {
Self {
left,
right,
top,
bottom,
}
}
#[inline]
pub fn horizontal(&self) -> f64 {
self.left + self.right
}
#[inline]
pub fn vertical(&self) -> f64 {
self.top + self.bottom
}
#[inline]
pub fn scale(self, factor: f64) -> Self {
Self {
left: self.left * factor,
right: self.right * factor,
top: self.top * factor,
bottom: self.bottom * factor,
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "reflect", derive(bevy_reflect::Reflect))]
#[cfg_attr(feature = "reflect", reflect(opaque))]
pub struct HAnchor(u8);
impl HAnchor {
pub const ABSOLUTE: Self = HAnchor(0);
pub const LEFT: Self = HAnchor(1);
pub const CENTER: Self = HAnchor(2);
pub const RIGHT: Self = HAnchor(4);
pub const FIT: Self = HAnchor(8);
pub const STRETCH: Self = HAnchor(5); pub const MAX_FIT_OR_STRETCH: Self = HAnchor(13); pub const MIN_FIT_OR_STRETCH: Self = HAnchor(16);
#[inline]
pub fn contains(self, flags: Self) -> bool {
flags.0 != 0 && (self.0 & flags.0) == flags.0
}
#[inline]
pub fn is_stretch(self) -> bool {
self.contains(Self::LEFT) && self.contains(Self::RIGHT)
}
#[inline]
pub fn bits(self) -> u8 {
self.0
}
pub fn display_name(self) -> &'static str {
match self.0 {
b if b == Self::FIT.0 => "Fit",
b if b == Self::STRETCH.0 => "Stretch",
b if b == Self::LEFT.0 => "Left",
b if b == Self::CENTER.0 => "Center",
b if b == Self::RIGHT.0 => "Right",
b if b == Self::MAX_FIT_OR_STRETCH.0 => "MaxFitStr",
b if b == Self::MIN_FIT_OR_STRETCH.0 => "MinFitStr",
_ => "Abs",
}
}
}
impl Default for HAnchor {
fn default() -> Self {
Self::FIT
}
}
impl std::ops::BitOr for HAnchor {
type Output = Self;
fn bitor(self, rhs: Self) -> Self {
HAnchor(self.0 | rhs.0)
}
}
impl std::ops::BitAnd for HAnchor {
type Output = Self;
fn bitand(self, rhs: Self) -> Self {
HAnchor(self.0 & rhs.0)
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "reflect", derive(bevy_reflect::Reflect))]
#[cfg_attr(feature = "reflect", reflect(opaque))]
pub struct VAnchor(u8);
impl VAnchor {
pub const ABSOLUTE: Self = VAnchor(0);
pub const BOTTOM: Self = VAnchor(1);
pub const CENTER: Self = VAnchor(2);
pub const TOP: Self = VAnchor(4);
pub const FIT: Self = VAnchor(8);
pub const STRETCH: Self = VAnchor(5); pub const MAX_FIT_OR_STRETCH: Self = VAnchor(13); pub const MIN_FIT_OR_STRETCH: Self = VAnchor(16);
#[inline]
pub fn contains(self, flags: Self) -> bool {
flags.0 != 0 && (self.0 & flags.0) == flags.0
}
#[inline]
pub fn is_stretch(self) -> bool {
self.contains(Self::BOTTOM) && self.contains(Self::TOP)
}
#[inline]
pub fn bits(self) -> u8 {
self.0
}
pub fn display_name(self) -> &'static str {
match self.0 {
b if b == Self::FIT.0 => "Fit",
b if b == Self::STRETCH.0 => "Stretch",
b if b == Self::BOTTOM.0 => "Bottom",
b if b == Self::CENTER.0 => "Center",
b if b == Self::TOP.0 => "Top",
b if b == Self::MAX_FIT_OR_STRETCH.0 => "MaxFitStr",
b if b == Self::MIN_FIT_OR_STRETCH.0 => "MinFitStr",
_ => "Abs",
}
}
}
impl Default for VAnchor {
fn default() -> Self {
Self::FIT
}
}
impl std::ops::BitOr for VAnchor {
type Output = Self;
fn bitor(self, rhs: Self) -> Self {
VAnchor(self.0 | rhs.0)
}
}
impl std::ops::BitAnd for VAnchor {
type Output = Self;
fn bitand(self, rhs: Self) -> Self {
VAnchor(self.0 & rhs.0)
}
}
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "reflect", derive(bevy_reflect::Reflect))]
pub struct WidgetBase {
pub margin: Insets,
pub h_anchor: HAnchor,
pub v_anchor: VAnchor,
pub min_size: Size,
pub max_size: Size,
pub enforce_integer_bounds: bool,
}
impl WidgetBase {
pub fn new() -> Self {
Self {
margin: Insets::ZERO,
h_anchor: HAnchor::FIT,
v_anchor: VAnchor::FIT,
min_size: Size::ZERO,
max_size: Size::MAX,
enforce_integer_bounds: crate::pixel_bounds::default_enforce_integer_bounds(),
}
}
pub fn with_margin(mut self, m: Insets) -> Self {
self.margin = m;
self
}
pub fn with_h_anchor(mut self, h: HAnchor) -> Self {
self.h_anchor = h;
self
}
pub fn with_v_anchor(mut self, v: VAnchor) -> Self {
self.v_anchor = v;
self
}
pub fn with_min_size(mut self, s: Size) -> Self {
self.min_size = s;
self
}
pub fn with_max_size(mut self, s: Size) -> Self {
self.max_size = s;
self
}
#[inline]
pub fn clamp_size(&self, proposed: Size) -> Size {
Size::new(
proposed
.width
.clamp(self.min_size.width, self.max_size.width),
proposed
.height
.clamp(self.min_size.height, self.max_size.height),
)
}
pub fn scaled_margin(&self) -> Insets {
self.margin
}
}
impl Default for WidgetBase {
fn default() -> Self {
Self::new()
}
}
#[inline]
pub fn resolve_fit_or_stretch(fit_size: f64, stretch_size: f64, max_mode: bool) -> f64 {
if max_mode {
fit_size.max(stretch_size)
} else {
fit_size.min(stretch_size)
}
}