Skip to main content

cosmic/surface/
corner_radius.rs

1use iced::Rectangle;
2use iced_runtime::platform_specific::wayland::CornerRadius;
3
4#[must_use]
5pub fn rounded_rect_strips(rect: Rectangle<f32>, radius: CornerRadius) -> Vec<Rectangle<f32>> {
6    let mut out = Vec::new();
7
8    let w = rect.width.max(0.0);
9    let h = rect.height.max(0.0);
10
11    if w <= 0.0 || h <= 0.0 {
12        return out;
13    }
14
15    let tl = radius.top_left as i32;
16    let tr = radius.top_right as i32;
17    let bl = radius.bottom_left as i32;
18    let br = radius.bottom_right as i32;
19
20    let max_top = tl.max(tr);
21    let max_bottom = bl.max(br);
22
23    let center_y = rect.y + max_top as f32;
24    let center_h = (h as i32 - max_top - max_bottom).max(0) as f32;
25
26    if center_h > 0.0 {
27        out.push(Rectangle {
28            x: rect.x,
29            y: center_y,
30            width: w,
31            height: center_h,
32        });
33    }
34
35    for y in 0..max_top {
36        let left = if y < tl { circle_inset(tl, y) } else { 0 };
37
38        let right = if y < tr { circle_inset(tr, y) } else { 0 };
39
40        let strip_x = rect.x + left as f32;
41        let strip_w = (w as i32 - left - right).max(0) as f32;
42
43        if strip_w > 0.0 {
44            out.push(Rectangle {
45                x: strip_x,
46                y: rect.y + y as f32,
47                width: strip_w,
48                height: if h > 1. { 2. } else { 1. },
49            });
50        }
51    }
52
53    for y in 0..max_bottom {
54        let cy = max_bottom - 1 - y;
55        let left = if cy < bl { circle_inset(bl, cy) } else { 0 };
56
57        let right = if cy < br { circle_inset(br, cy) } else { 0 };
58
59        let strip_x = rect.x + left as f32;
60        let strip_w = (w as i32 - left - right).max(0) as f32;
61
62        if strip_w > 0.0 {
63            out.push(Rectangle {
64                x: strip_x,
65                y: rect.y + h - max_bottom as f32 + y as f32 - if h > 1. { 1. } else { 0. },
66                width: strip_w,
67                height: if h > 1. { 2. } else { 1. },
68            });
69        }
70    }
71
72    out
73}
74
75fn circle_inset(radius: i32, y: i32) -> i32 {
76    if radius <= 0 {
77        return 0;
78    }
79
80    let fy = y as f32 + 0.5;
81    let r = radius as f32;
82
83    let x = r - (r * r - (r - fy) * (r - fy)).sqrt();
84
85    x.floor() as i32
86}