use std::ops::{Mul, MulAssign}; use bevy::reflect::Reflect; /// A struct for defining properties related to the edges of widgets /// /// This is useful for things like borders, padding, etc. #[derive(Debug, Default, Reflect, Copy, Clone, PartialEq, Eq)] pub struct Edge<T> where T: Copy + Default + PartialEq + Reflect, { /// The value of the top edge pub top: T, /// The value of the right edge pub right: T, /// The value of the bottom edge pub bottom: T, /// The value of the left edge pub left: T, } impl<T> Edge<T> where T: Copy + Default + PartialEq + Reflect, { /// Creates a new `Edge` with values individually specified for each edge /// /// # Arguments /// /// * `top`: The top edge value /// * `right`: The right edge value /// * `bottom`: The bottom edge value /// * `left`: The left edge value /// pub fn new(top: T, right: T, bottom: T, left: T) -> Self { Self { top, right, bottom, left, } } /// Creates a new `Edge` with matching vertical edges and matching horizontal edges /// /// # Arguments /// /// * `vertical`: The value of the vertical edges /// * `horizontal`: The value of the horizontal edges /// pub fn axis(vertical: T, horizontal: T) -> Self { Self { top: vertical, right: horizontal, bottom: vertical, left: horizontal, } } /// Creates a new `Edge` with all edges having the same value /// /// # Arguments /// /// * `value`: The value of all edges /// pub fn all(value: T) -> Self { Self { top: value, right: value, bottom: value, left: value, } } /// Converts this `Edge` into a tuple matching `(Top, Right, Bottom, Left)` pub fn into_tuple(self) -> (T, T, T, T) { (self.top, self.right, self.bottom, self.left) } } impl<T> From<Edge<T>> for (T, T, T, T) where T: Copy + Default + PartialEq + Reflect, { fn from(edge: Edge<T>) -> Self { edge.into_tuple() } } impl<T> From<T> for Edge<T> where T: Copy + Default + PartialEq + Reflect, { fn from(value: T) -> Self { Edge::all(value) } } impl<T> From<(T, T)> for Edge<T> where T: Copy + Default + PartialEq + Reflect, { fn from(value: (T, T)) -> Self { Edge::axis(value.0, value.1) } } impl<T> From<(T, T, T, T)> for Edge<T> where T: Copy + Default + PartialEq + Reflect, { fn from(value: (T, T, T, T)) -> Self { Edge::new(value.0, value.1, value.2, value.3) } } impl<T> Mul<T> for Edge<T> where T: Copy + Default + PartialEq + Mul<Output = T> + Reflect, { type Output = Self; fn mul(self, rhs: T) -> Self::Output { Self { top: self.top * rhs, right: self.right * rhs, bottom: self.bottom * rhs, left: self.left * rhs, } } } impl<T> Mul<Edge<T>> for Edge<T> where T: Copy + Default + PartialEq + Mul<Output = T> + Reflect, { type Output = Self; fn mul(self, rhs: Edge<T>) -> Self::Output { Self { top: rhs.top * self.top, right: rhs.right * self.right, bottom: rhs.bottom * self.bottom, left: rhs.left * self.left, } } } impl<T> MulAssign<T> for Edge<T> where T: Copy + Default + PartialEq + MulAssign + Reflect, { fn mul_assign(&mut self, rhs: T) { self.top *= rhs; self.right *= rhs; self.bottom *= rhs; self.left *= rhs; } } impl<T> MulAssign<Edge<T>> for Edge<T> where T: Copy + Default + PartialEq + MulAssign + Reflect, { fn mul_assign(&mut self, rhs: Edge<T>) { self.top *= rhs.top; self.right *= rhs.right; self.bottom *= rhs.bottom; self.left *= rhs.left; } } #[cfg(test)] mod tests { use super::Edge; #[test] fn tuples_should_convert_to_edge() { let expected = (1.0, 2.0, 3.0, 4.0); let edge: Edge<f32> = expected.into(); assert_eq!(expected, edge.into_tuple()); let expected = (1.0, 2.0, 1.0, 2.0); let edge: Edge<f32> = (expected.0, expected.1).into(); assert_eq!(expected, edge.into_tuple()); let expected = (1.0, 1.0, 1.0, 1.0); let edge: Edge<f32> = (expected.0).into(); assert_eq!(expected, edge.into_tuple()); let expected = (1.0, 1.0, 1.0, 1.0); let edge: Edge<f32> = expected.0.into(); assert_eq!(expected, edge.into_tuple()); } #[test] fn multiplication_should_work_on_edges() { let expected = (10.0, 20.0, 30.0, 40.0); let mut corner = Edge::new(1.0, 2.0, 3.0, 4.0); // Basic multiplication let multiplied = corner * 10.0; assert_eq!(expected, multiplied.into_tuple()); // Multiply and assign corner *= 10.0; assert_eq!(expected, corner.into_tuple()); } }