1use glam::Vec2;
2use crate::{
3 color,
4 draw::{ImageHandle, RoundedCorners, UiDrawCommand, UiDrawCommandList},
5 rect::{Rect, Corners, FillColor},
6};
7use super::{Frame, point::FramePoint2d};
8
9#[derive(Clone, Copy)]
13pub struct RectFrame {
14 pub color: FillColor,
18
19 pub image: Option<ImageHandle>,
27
28 pub top_left: FramePoint2d,
30
31 pub bottom_right: FramePoint2d,
33
34 pub corner_radius: Corners<f32>,
36}
37
38impl From<FillColor> for RectFrame {
45 fn from(color: FillColor) -> Self {
46 Self::color(color)
47 }
48}
49
50impl From<ImageHandle> for RectFrame {
51 fn from(image: ImageHandle) -> Self {
52 Self::image(image)
53 }
54}
55
56impl RectFrame {
57 pub fn color(color: impl Into<FillColor>) -> Self {
59 Self {
60 color: color.into(),
61 ..Self::default()
62 }
63 }
64
65 pub fn image(image: ImageHandle) -> Self {
69 Self {
70 color: color::WHITE.into(),
71 image: Some(image),
72 ..Self::default()
73 }
74 }
75
76 pub fn color_image(color: impl Into<FillColor>, image: ImageHandle) -> Self {
78 Self {
79 color: color.into(),
80 image: Some(image),
81 ..Self::default()
82 }
83 }
84
85 pub fn with_corner_radius(self, radius: impl Into<Corners<f32>>) -> Self {
87 Self {
88 corner_radius: radius.into(),
89 ..self
90 }
91 }
92
93 pub fn with_inset(self, inset: f32) -> Self {
97 Self {
98 top_left: self.top_left + Vec2::splat(inset).into(),
99 bottom_right: self.bottom_right - Vec2::splat(inset).into(),
100 ..self
101 }
102 }
103}
104
105impl Default for RectFrame {
106 fn default() -> Self {
107 Self {
108 color: FillColor::transparent(),
109 image: None,
110 top_left: FramePoint2d::TOP_LEFT,
111 bottom_right: FramePoint2d::BOTTOM_RIGHT,
112 corner_radius: Corners::all(0.),
113 }
114 }
115}
116
117impl Frame for RectFrame {
118 fn draw(&self, draw: &mut UiDrawCommandList, rect: Rect) {
119 if self.color.is_transparent() {
120 return
121 }
122 let top_left = self.top_left.resolve(rect.size);
124 let bottom_right = self.bottom_right.resolve(rect.size);
125 draw.add(UiDrawCommand::Rectangle {
126 position: rect.position + top_left,
127 size: bottom_right - top_left,
128 color: self.color.corners(),
129 texture: self.image,
130 texture_uv: None,
131 rounded_corners: (self.corner_radius.max_f32() > 0.).then_some(
132 RoundedCorners::from_radius(self.corner_radius)
133 ),
134 });
135 }
136
137 fn covers_opaque(&self) -> bool {
138 self.top_left.x.relative <= 0. &&
139 self.top_left.x.absolute <= 0. &&
140 self.top_left.y.relative <= 0. &&
141 self.top_left.y.absolute <= 0. &&
142 self.bottom_right.x.relative >= 1. &&
143 self.bottom_right.x.absolute >= 0. &&
144 self.bottom_right.y.relative >= 1. &&
145 self.bottom_right.y.absolute >= 0. &&
146 self.color.is_opaque() &&
147 self.image.is_none() &&
148 self.corner_radius.max_f32() == 0.
149 }
150}