[tesselator] hide Path from view and improve thin rounded rectangles
This commit is contained in:
parent
96153a86e5
commit
62b1a2658f
7 changed files with 86 additions and 79 deletions
|
@ -2,7 +2,7 @@ use std::hash::Hash;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
layout::Direction,
|
layout::Direction,
|
||||||
paint::{LineStyle, PaintCmd, Path, TextStyle},
|
paint::{LineStyle, PaintCmd, TextStyle},
|
||||||
widgets::Label,
|
widgets::Label,
|
||||||
*,
|
*,
|
||||||
};
|
};
|
||||||
|
@ -112,7 +112,7 @@ pub fn paint_icon(ui: &mut Ui, openness: f32, response: &Response) {
|
||||||
|
|
||||||
// Draw a pointy triangle arrow:
|
// Draw a pointy triangle arrow:
|
||||||
let rect = Rect::from_center_size(rect.center(), vec2(rect.width(), rect.height()) * 0.75);
|
let rect = Rect::from_center_size(rect.center(), vec2(rect.width(), rect.height()) * 0.75);
|
||||||
let mut points = [rect.left_top(), rect.right_top(), rect.center_bottom()];
|
let mut points = vec![rect.left_top(), rect.right_top(), rect.center_bottom()];
|
||||||
let rotation = Vec2::angled(remap(openness, 0.0..=1.0, -TAU / 4.0..=0.0));
|
let rotation = Vec2::angled(remap(openness, 0.0..=1.0, -TAU / 4.0..=0.0));
|
||||||
for p in &mut points {
|
for p in &mut points {
|
||||||
let v = *p - rect.center();
|
let v = *p - rect.center();
|
||||||
|
@ -121,7 +121,7 @@ pub fn paint_icon(ui: &mut Ui, openness: f32, response: &Response) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.painter().add(PaintCmd::Path {
|
ui.painter().add(PaintCmd::Path {
|
||||||
path: Path::from_point_loop(&points),
|
points,
|
||||||
closed: true,
|
closed: true,
|
||||||
fill: Default::default(),
|
fill: Default::default(),
|
||||||
outline: LineStyle::new(stroke_width, stroke_color),
|
outline: LineStyle::new(stroke_width, stroke_color),
|
||||||
|
|
|
@ -531,39 +531,47 @@ fn paint_frame_interaction(
|
||||||
interaction: WindowInteraction,
|
interaction: WindowInteraction,
|
||||||
visuals: style::WidgetVisuals,
|
visuals: style::WidgetVisuals,
|
||||||
) {
|
) {
|
||||||
|
use paint::tessellator::path::add_circle_quadrant;
|
||||||
|
|
||||||
let cr = ui.style().visuals.window_corner_radius;
|
let cr = ui.style().visuals.window_corner_radius;
|
||||||
let Rect { min, max } = rect;
|
let Rect { min, max } = rect;
|
||||||
|
|
||||||
let mut path = Path::default();
|
let mut points = Vec::new();
|
||||||
|
|
||||||
if interaction.right && !interaction.bottom && !interaction.top {
|
if interaction.right && !interaction.bottom && !interaction.top {
|
||||||
path.add_line_segment([pos2(max.x, min.y + cr), pos2(max.x, max.y - cr)]);
|
points.push(pos2(max.x, min.y + cr));
|
||||||
|
points.push(pos2(max.x, max.y - cr));
|
||||||
}
|
}
|
||||||
if interaction.right && interaction.bottom {
|
if interaction.right && interaction.bottom {
|
||||||
path.add_line_segment([pos2(max.x, min.y + cr), pos2(max.x, max.y - cr)]);
|
points.push(pos2(max.x, min.y + cr));
|
||||||
path.add_circle_quadrant(pos2(max.x - cr, max.y - cr), cr, 0.0);
|
points.push(pos2(max.x, max.y - cr));
|
||||||
|
add_circle_quadrant(&mut points, pos2(max.x - cr, max.y - cr), cr, 0.0);
|
||||||
}
|
}
|
||||||
if interaction.bottom {
|
if interaction.bottom {
|
||||||
path.add_line_segment([pos2(max.x - cr, max.y), pos2(min.x + cr, max.y)]);
|
points.push(pos2(max.x - cr, max.y));
|
||||||
|
points.push(pos2(min.x + cr, max.y));
|
||||||
}
|
}
|
||||||
if interaction.left && interaction.bottom {
|
if interaction.left && interaction.bottom {
|
||||||
path.add_circle_quadrant(pos2(min.x + cr, max.y - cr), cr, 1.0);
|
add_circle_quadrant(&mut points, pos2(min.x + cr, max.y - cr), cr, 1.0);
|
||||||
}
|
}
|
||||||
if interaction.left {
|
if interaction.left {
|
||||||
path.add_line_segment([pos2(min.x, max.y - cr), pos2(min.x, min.y + cr)]);
|
points.push(pos2(min.x, max.y - cr));
|
||||||
|
points.push(pos2(min.x, min.y + cr));
|
||||||
}
|
}
|
||||||
if interaction.left && interaction.top {
|
if interaction.left && interaction.top {
|
||||||
path.add_circle_quadrant(pos2(min.x + cr, min.y + cr), cr, 2.0);
|
add_circle_quadrant(&mut points, pos2(min.x + cr, min.y + cr), cr, 2.0);
|
||||||
}
|
}
|
||||||
if interaction.top {
|
if interaction.top {
|
||||||
path.add_line_segment([pos2(min.x + cr, min.y), pos2(max.x - cr, min.y)]);
|
points.push(pos2(min.x + cr, min.y));
|
||||||
|
points.push(pos2(max.x - cr, min.y));
|
||||||
}
|
}
|
||||||
if interaction.right && interaction.top {
|
if interaction.right && interaction.top {
|
||||||
path.add_circle_quadrant(pos2(max.x - cr, min.y + cr), cr, 3.0);
|
add_circle_quadrant(&mut points, pos2(max.x - cr, min.y + cr), cr, 3.0);
|
||||||
path.add_line_segment([pos2(max.x, min.y + cr), pos2(max.x, max.y - cr)]);
|
points.push(pos2(max.x, min.y + cr));
|
||||||
|
points.push(pos2(max.x, max.y - cr));
|
||||||
}
|
}
|
||||||
ui.painter().add(PaintCmd::Path {
|
ui.painter().add(PaintCmd::Path {
|
||||||
path,
|
points,
|
||||||
closed: false,
|
closed: false,
|
||||||
fill: Default::default(),
|
fill: Default::default(),
|
||||||
outline: visuals.bg_outline,
|
outline: visuals.bg_outline,
|
||||||
|
|
|
@ -653,7 +653,7 @@ impl Painting {
|
||||||
if line.len() >= 2 {
|
if line.len() >= 2 {
|
||||||
let points: Vec<Pos2> = line.iter().map(|p| rect.min + *p).collect();
|
let points: Vec<Pos2> = line.iter().map(|p| rect.min + *p).collect();
|
||||||
painter.add(PaintCmd::Path {
|
painter.add(PaintCmd::Path {
|
||||||
path: Path::from_open_points(&points),
|
points,
|
||||||
closed: false,
|
closed: false,
|
||||||
outline: LineStyle::new(self.line_width, LIGHT_GRAY),
|
outline: LineStyle::new(self.line_width, LIGHT_GRAY),
|
||||||
fill: Default::default(),
|
fill: Default::default(),
|
||||||
|
|
|
@ -13,6 +13,6 @@ pub use {
|
||||||
color::{Rgba, Srgba},
|
color::{Rgba, Srgba},
|
||||||
command::{LineStyle, PaintCmd},
|
command::{LineStyle, PaintCmd},
|
||||||
fonts::{FontDefinitions, Fonts, TextStyle},
|
fonts::{FontDefinitions, Fonts, TextStyle},
|
||||||
tessellator::{PaintJobs, PaintOptions, Path, Triangles, Vertex},
|
tessellator::{PaintJobs, PaintOptions, Triangles, Vertex},
|
||||||
texture_atlas::Texture,
|
texture_atlas::Texture,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use {
|
use {
|
||||||
super::{font::Galley, fonts::TextStyle, Path, Srgba, Triangles},
|
super::{font::Galley, fonts::TextStyle, Srgba, Triangles},
|
||||||
crate::math::{Pos2, Rect},
|
crate::math::{Pos2, Rect},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -19,7 +19,9 @@ pub enum PaintCmd {
|
||||||
style: LineStyle,
|
style: LineStyle,
|
||||||
},
|
},
|
||||||
Path {
|
Path {
|
||||||
path: Path,
|
points: Vec<Pos2>,
|
||||||
|
/// If true, connect the first and last of the points together.
|
||||||
|
/// This is required if `fill != TRANSPARENT`.
|
||||||
closed: bool,
|
closed: bool,
|
||||||
fill: Srgba,
|
fill: Srgba,
|
||||||
outline: LineStyle,
|
outline: LineStyle,
|
||||||
|
|
|
@ -184,34 +184,15 @@ pub struct PathPoint {
|
||||||
|
|
||||||
/// A connected line (without thickness or gaps) which can be tessellated
|
/// A connected line (without thickness or gaps) which can be tessellated
|
||||||
/// to either to an outline (with thickness) or a filled convex area.
|
/// to either to an outline (with thickness) or a filled convex area.
|
||||||
|
/// Used as a scratch-pad during tesselation.
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct Path(Vec<PathPoint>);
|
struct Path(Vec<PathPoint>);
|
||||||
|
|
||||||
impl Path {
|
impl Path {
|
||||||
pub fn from_point_loop(points: &[Pos2]) -> Self {
|
|
||||||
let mut path = Self::default();
|
|
||||||
path.add_line_loop(points);
|
|
||||||
path
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_open_points(points: &[Pos2]) -> Self {
|
|
||||||
let mut path = Self::default();
|
|
||||||
path.add_open_points(points);
|
|
||||||
path
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
self.0.clear();
|
self.0.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
|
||||||
self.0.is_empty()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
|
||||||
self.0.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reserve(&mut self, additional: usize) {
|
pub fn reserve(&mut self, additional: usize) {
|
||||||
self.0.reserve(additional)
|
self.0.reserve(additional)
|
||||||
}
|
}
|
||||||
|
@ -247,14 +228,15 @@ impl Path {
|
||||||
// Common case optimization:
|
// Common case optimization:
|
||||||
self.add_line_segment([points[0], points[1]]);
|
self.add_line_segment([points[0], points[1]]);
|
||||||
} else {
|
} else {
|
||||||
|
// TODO: optimize
|
||||||
self.reserve(n);
|
self.reserve(n);
|
||||||
self.add_point(points[0], (points[1] - points[0]).normalized().rot90());
|
self.add_point(points[0], (points[1] - points[0]).normalized().rot90());
|
||||||
for i in 1..n - 1 {
|
for i in 1..n - 1 {
|
||||||
let n0 = (points[i] - points[i - 1]).normalized().rot90(); // TODO: don't calculate each normal twice!
|
let n0 = (points[i] - points[i - 1]).normalized().rot90();
|
||||||
let n1 = (points[i + 1] - points[i]).normalized().rot90(); // TODO: don't calculate each normal twice!
|
let n1 = (points[i + 1] - points[i]).normalized().rot90();
|
||||||
let v = (n0 + n1) / 2.0;
|
let v = (n0 + n1) / 2.0;
|
||||||
let normal = v / v.length_sq();
|
let normal = v / v.length_sq(); // TODO: handle VERY sharp turns better
|
||||||
self.add_point(points[i], normal); // TODO: handle VERY sharp turns better
|
self.add_point(points[i], normal);
|
||||||
}
|
}
|
||||||
self.add_point(
|
self.add_point(
|
||||||
points[n - 1],
|
points[n - 1],
|
||||||
|
@ -273,22 +255,20 @@ impl Path {
|
||||||
let n0 = (points[i] - points[(i + n - 1) % n]).normalized().rot90();
|
let n0 = (points[i] - points[(i + n - 1) % n]).normalized().rot90();
|
||||||
let n1 = (points[(i + 1) % n] - points[i]).normalized().rot90();
|
let n1 = (points[(i + 1) % n] - points[i]).normalized().rot90();
|
||||||
let v = (n0 + n1) / 2.0;
|
let v = (n0 + n1) / 2.0;
|
||||||
let normal = v / v.length_sq();
|
let normal = v / v.length_sq(); // TODO: handle VERY sharp turns better
|
||||||
self.add_point(points[i], normal); // TODO: handle VERY sharp turns better
|
self.add_point(points[i], normal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add_rectangle(&mut self, rect: Rect) {
|
pub(crate) mod path {
|
||||||
let min = rect.min;
|
//! Helpers for constructing paths
|
||||||
let max = rect.max;
|
use super::*;
|
||||||
self.reserve(4);
|
|
||||||
self.add_point(pos2(min.x, min.y), vec2(-1.0, -1.0));
|
/// overwrites existing points
|
||||||
self.add_point(pos2(max.x, min.y), vec2(1.0, -1.0));
|
pub fn rounded_rectangle(path: &mut Vec<Pos2>, rect: Rect, corner_radius: f32) {
|
||||||
self.add_point(pos2(max.x, max.y), vec2(1.0, 1.0));
|
path.clear();
|
||||||
self.add_point(pos2(min.x, max.y), vec2(-1.0, 1.0));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_rounded_rectangle(&mut self, rect: Rect, corner_radius: f32) {
|
|
||||||
let min = rect.min;
|
let min = rect.min;
|
||||||
let max = rect.max;
|
let max = rect.max;
|
||||||
|
|
||||||
|
@ -297,12 +277,18 @@ impl Path {
|
||||||
.min(rect.height() * 0.5);
|
.min(rect.height() * 0.5);
|
||||||
|
|
||||||
if cr <= 0.0 {
|
if cr <= 0.0 {
|
||||||
self.add_rectangle(rect);
|
let min = rect.min;
|
||||||
|
let max = rect.max;
|
||||||
|
path.reserve(4);
|
||||||
|
path.push(pos2(min.x, min.y));
|
||||||
|
path.push(pos2(max.x, min.y));
|
||||||
|
path.push(pos2(max.x, max.y));
|
||||||
|
path.push(pos2(min.x, max.y));
|
||||||
} else {
|
} else {
|
||||||
self.add_circle_quadrant(pos2(max.x - cr, max.y - cr), cr, 0.0);
|
add_circle_quadrant(path, pos2(max.x - cr, max.y - cr), cr, 0.0);
|
||||||
self.add_circle_quadrant(pos2(min.x + cr, max.y - cr), cr, 1.0);
|
add_circle_quadrant(path, pos2(min.x + cr, max.y - cr), cr, 1.0);
|
||||||
self.add_circle_quadrant(pos2(min.x + cr, min.y + cr), cr, 2.0);
|
add_circle_quadrant(path, pos2(min.x + cr, min.y + cr), cr, 2.0);
|
||||||
self.add_circle_quadrant(pos2(max.x - cr, min.y + cr), cr, 3.0);
|
add_circle_quadrant(path, pos2(max.x - cr, min.y + cr), cr, 3.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,21 +310,20 @@ impl Path {
|
||||||
// * angle 3 * TAU / 4 = top
|
// * angle 3 * TAU / 4 = top
|
||||||
// - quadrant 3: right top
|
// - quadrant 3: right top
|
||||||
// * angle 4 * TAU / 4 = right
|
// * angle 4 * TAU / 4 = right
|
||||||
pub fn add_circle_quadrant(&mut self, center: Pos2, radius: f32, quadrant: f32) {
|
pub fn add_circle_quadrant(path: &mut Vec<Pos2>, center: Pos2, radius: f32, quadrant: f32) {
|
||||||
// TODO: optimize with precalculated vertices for some radii ranges
|
// TODO: optimize with precalculated vertices for some radii ranges
|
||||||
|
|
||||||
let n = (radius * 0.75).round() as i32; // TODO: tweak a bit more
|
let n = (radius * 0.75).round() as i32; // TODO: tweak a bit more
|
||||||
let n = clamp(n, 2..=32);
|
let n = clamp(n, 2..=32);
|
||||||
self.reserve(n as usize + 1);
|
|
||||||
const RIGHT_ANGLE: f32 = TAU / 4.0;
|
const RIGHT_ANGLE: f32 = TAU / 4.0;
|
||||||
|
path.reserve(n as usize + 1);
|
||||||
for i in 0..=n {
|
for i in 0..=n {
|
||||||
let angle = remap(
|
let angle = remap(
|
||||||
i as f32,
|
i as f32,
|
||||||
0.0..=n as f32,
|
0.0..=n as f32,
|
||||||
quadrant * RIGHT_ANGLE..=(quadrant + 1.0) * RIGHT_ANGLE,
|
quadrant * RIGHT_ANGLE..=(quadrant + 1.0) * RIGHT_ANGLE,
|
||||||
);
|
);
|
||||||
let normal = vec2(angle.cos(), angle.sin());
|
path.push(center + radius * Vec2::angled(angle));
|
||||||
self.add_point(center + radius * normal, normal);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -374,12 +359,7 @@ impl Default for PaintOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tesselate the given convex area into a polygon.
|
/// Tesselate the given convex area into a polygon.
|
||||||
pub fn fill_closed_path(
|
fn fill_closed_path(path: &[PathPoint], color: Srgba, options: PaintOptions, out: &mut Triangles) {
|
||||||
path: &[PathPoint],
|
|
||||||
color: Srgba,
|
|
||||||
options: PaintOptions,
|
|
||||||
out: &mut Triangles,
|
|
||||||
) {
|
|
||||||
if color == color::TRANSPARENT {
|
if color == color::TRANSPARENT {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -420,7 +400,7 @@ pub fn fill_closed_path(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tesselate the given path as an outline with thickness.
|
/// Tesselate the given path as an outline with thickness.
|
||||||
pub fn paint_path_outline(
|
fn paint_path_outline(
|
||||||
path: &[PathPoint],
|
path: &[PathPoint],
|
||||||
path_type: PathType,
|
path_type: PathType,
|
||||||
style: LineStyle,
|
style: LineStyle,
|
||||||
|
@ -584,11 +564,12 @@ fn mul_color(color: Srgba, factor: f32) -> Srgba {
|
||||||
/// * `out`: where the triangles are put
|
/// * `out`: where the triangles are put
|
||||||
/// * `scratchpad_path`: if you plan to run `tessellate_paint_command`
|
/// * `scratchpad_path`: if you plan to run `tessellate_paint_command`
|
||||||
/// many times, pass it a reference to the same `Path` to avoid excessive allocations.
|
/// many times, pass it a reference to the same `Path` to avoid excessive allocations.
|
||||||
pub fn tessellate_paint_command(
|
fn tessellate_paint_command(
|
||||||
command: PaintCmd,
|
command: PaintCmd,
|
||||||
options: PaintOptions,
|
options: PaintOptions,
|
||||||
fonts: &Fonts,
|
fonts: &Fonts,
|
||||||
out: &mut Triangles,
|
out: &mut Triangles,
|
||||||
|
scratchpad_points: &mut Vec<Pos2>,
|
||||||
scratchpad_path: &mut Path,
|
scratchpad_path: &mut Path,
|
||||||
) {
|
) {
|
||||||
let path = scratchpad_path;
|
let path = scratchpad_path;
|
||||||
|
@ -616,12 +597,18 @@ pub fn tessellate_paint_command(
|
||||||
paint_path_outline(&path.0, Open, style, options, out);
|
paint_path_outline(&path.0, Open, style, options, out);
|
||||||
}
|
}
|
||||||
PaintCmd::Path {
|
PaintCmd::Path {
|
||||||
path,
|
points,
|
||||||
closed,
|
closed,
|
||||||
fill,
|
fill,
|
||||||
outline,
|
outline,
|
||||||
} => {
|
} => {
|
||||||
if path.len() >= 2 {
|
if points.len() >= 2 {
|
||||||
|
if closed {
|
||||||
|
path.add_line_loop(&points);
|
||||||
|
} else {
|
||||||
|
path.add_open_points(&points);
|
||||||
|
}
|
||||||
|
|
||||||
if fill != TRANSPARENT {
|
if fill != TRANSPARENT {
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
closed,
|
closed,
|
||||||
|
@ -645,7 +632,8 @@ pub fn tessellate_paint_command(
|
||||||
rect.min = rect.min.max(pos2(-1e7, -1e7));
|
rect.min = rect.min.max(pos2(-1e7, -1e7));
|
||||||
rect.max = rect.max.min(pos2(1e7, 1e7));
|
rect.max = rect.max.min(pos2(1e7, 1e7));
|
||||||
|
|
||||||
path.add_rounded_rectangle(rect, corner_radius);
|
path::rounded_rectangle(scratchpad_points, rect, corner_radius);
|
||||||
|
path.add_line_loop(scratchpad_points);
|
||||||
fill_closed_path(&path.0, fill, options, out);
|
fill_closed_path(&path.0, fill, options, out);
|
||||||
paint_path_outline(&path.0, Closed, outline, options, out);
|
paint_path_outline(&path.0, Closed, outline, options, out);
|
||||||
}
|
}
|
||||||
|
@ -710,6 +698,7 @@ pub fn tessellate_paint_commands(
|
||||||
options: PaintOptions,
|
options: PaintOptions,
|
||||||
fonts: &Fonts,
|
fonts: &Fonts,
|
||||||
) -> Vec<(Rect, Triangles)> {
|
) -> Vec<(Rect, Triangles)> {
|
||||||
|
let mut scratchpad_points = Vec::new();
|
||||||
let mut scratchpad_path = Path::default();
|
let mut scratchpad_path = Path::default();
|
||||||
|
|
||||||
let mut jobs = PaintJobs::default();
|
let mut jobs = PaintJobs::default();
|
||||||
|
@ -721,7 +710,14 @@ pub fn tessellate_paint_commands(
|
||||||
}
|
}
|
||||||
|
|
||||||
let out = &mut jobs.last_mut().unwrap().1;
|
let out = &mut jobs.last_mut().unwrap().1;
|
||||||
tessellate_paint_command(cmd, options, fonts, out, &mut scratchpad_path);
|
tessellate_paint_command(
|
||||||
|
cmd,
|
||||||
|
options,
|
||||||
|
fonts,
|
||||||
|
out,
|
||||||
|
&mut scratchpad_points,
|
||||||
|
&mut scratchpad_path,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if options.debug_paint_clip_rects {
|
if options.debug_paint_clip_rects {
|
||||||
|
@ -736,6 +732,7 @@ pub fn tessellate_paint_commands(
|
||||||
options,
|
options,
|
||||||
fonts,
|
fonts,
|
||||||
triangles,
|
triangles,
|
||||||
|
&mut scratchpad_points,
|
||||||
&mut scratchpad_path,
|
&mut scratchpad_path,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -366,11 +366,11 @@ impl<'a> Widget for Checkbox<'a> {
|
||||||
|
|
||||||
if *checked {
|
if *checked {
|
||||||
ui.painter().add(PaintCmd::Path {
|
ui.painter().add(PaintCmd::Path {
|
||||||
path: Path::from_open_points(&[
|
points: vec![
|
||||||
pos2(small_icon_rect.left(), small_icon_rect.center().y),
|
pos2(small_icon_rect.left(), small_icon_rect.center().y),
|
||||||
pos2(small_icon_rect.center().x, small_icon_rect.bottom()),
|
pos2(small_icon_rect.center().x, small_icon_rect.bottom()),
|
||||||
pos2(small_icon_rect.right(), small_icon_rect.top()),
|
pos2(small_icon_rect.right(), small_icon_rect.top()),
|
||||||
]),
|
],
|
||||||
closed: false,
|
closed: false,
|
||||||
outline: LineStyle::new(ui.style().visuals.line_width, stroke_color),
|
outline: LineStyle::new(ui.style().visuals.line_width, stroke_color),
|
||||||
fill: Default::default(),
|
fill: Default::default(),
|
||||||
|
|
Loading…
Reference in a new issue