use crate::{
Borderable,
Color,
Colorable,
Point,
Rect,
Scalar,
Sizeable,
};
use crate::draw::shape::triangle::Triangle;
use crate::position::Dimensions;
use crate::widget;
#[derive(Copy, Clone, Debug, WidgetCommon_)]
pub struct BorderedRectangle {
#[carbide(common_builder)]
pub common: widget::CommonBuilder,
pub style: Style,
}
widget_ids! {
struct Ids {
border,
rectangle,
}
}
#[derive(Copy, Clone, Debug, Default, PartialEq, WidgetStyle_)]
pub struct Style {
#[carbide(default = "theme.shape_color")]
pub color: Option<Color>,
#[carbide(default = "theme.border_width")]
pub border: Option<Scalar>,
#[carbide(default = "theme.border_color")]
pub border_color: Option<Color>,
}
pub struct State {
ids: Ids,
}
impl BorderedRectangle {
pub fn new(_dim: Dimensions) -> Self {
BorderedRectangle {
common: widget::CommonBuilder::default(),
style: Style::default(),
} }
builder_method!(pub with_style { style = Style });
}
impl Colorable for BorderedRectangle {
builder_method!(color { style.color = Some(Color) });
}
impl Borderable for BorderedRectangle {
builder_methods!{
border { style.border = Some(Scalar) }
border_color { style.border_color = Some(Color) }
}
}
pub fn border_triangles(rect: Rect, border: Scalar) -> Option<[Triangle<Point>; 8]> {
if border <= 0.0 {
return None;
}
let (l, r, b, t) = rect.l_r_b_t();
let l_pad = l + border;
let r_pad = r - border;
let b_pad = b + border;
let t_pad = t - border;
let r1 = [[l, t], [r_pad, t], [r_pad, t_pad], [l, t_pad]];
let r2 = [[r_pad, t], [r, t], [r, b_pad], [r_pad, b_pad]];
let r3 = [[l_pad, b_pad], [r, b_pad], [r, b], [l_pad, b]];
let r4 = [[l, t_pad], [l_pad, t_pad], [l_pad, b], [l, b]];
let (r1a, r1b) = widget::triangles::from_quad(r1);
let (r2a, r2b) = widget::triangles::from_quad(r2);
let (r3a, r3b) = widget::triangles::from_quad(r3);
let (r4a, r4b) = widget::triangles::from_quad(r4);
Some([r1a, r1b, r2a, r2b, r3a, r3b, r4a, r4b])
}
pub fn rounded_border_triangles(
rect: Rect,
thickness: Scalar,
radius: Scalar,
corner_resolution: usize,
) -> RoundedBorderTriangles {
RoundedBorderTriangles::new(rect, thickness, radius, corner_resolution)
}
#[derive(Clone)]
pub struct RoundedBorderTriangles {
outer: widget::old::rounded_rectangle::Points,
inner: widget::old::rounded_rectangle::Points,
outer_end: Option<Point>,
inner_end: Option<Point>,
last_points: [Point; 2],
is_next_outer: bool,
}
impl RoundedBorderTriangles {
pub fn new(
rect: Rect,
mut thickness: Scalar,
radius: Scalar,
corner_resolution: usize,
) -> Self {
thickness = {
let (w, h) = rect.w_h();
thickness.min(w * 0.5).min(h * 0.5)
};
let inner_rect = rect.pad(thickness);
let mut outer = widget::old::rounded_rectangle::points(rect, radius, corner_resolution);
let mut inner = widget::old::rounded_rectangle::points(inner_rect, radius, corner_resolution);
let last_outer = outer.next().unwrap();
let last_inner = inner.next().unwrap();
let outer_end = Some(last_outer);
let inner_end = Some(last_inner);
let last_points = [last_outer, last_inner];
let is_next_outer = true;
RoundedBorderTriangles { outer, inner, is_next_outer, last_points, outer_end, inner_end }
}
}
impl Iterator for RoundedBorderTriangles {
type Item = Triangle<Point>;
fn next(&mut self) -> Option<Self::Item> {
let next_point = match self.is_next_outer {
true => self.outer.next().or_else(|| self.outer_end.take()),
false => self.inner.next().or_else(|| self.inner_end.take()),
};
next_point.map(|c| {
self.is_next_outer = !self.is_next_outer;
let a = self.last_points[0];
let b = self.last_points[1];
self.last_points[0] = b;
self.last_points[1] = c;
Triangle([a, b, c])
})
}
}