1use gpui::{
2 AnyElement, IntoElement, ParentElement, Pixels, RenderOnce, Styled, px, transparent_black,
3};
4use smallvec::SmallVec;
5use theme::ActiveTheme;
6
7use crate::{h_flex, utils::CornerSolver};
8
9/// A ring is a stylistic focus indicator that draws a ring around
10/// an element with some space between the element and ring.
11#[derive(IntoElement)]
12pub struct Ring {
13 corner_radius: Pixels,
14 border_width: Pixels,
15 padding: Pixels,
16 focused: bool,
17 active: bool,
18 children: SmallVec<[AnyElement; 2]>,
19}
20
21impl Ring {
22 pub fn new(child_corner_radius: Pixels, focused: bool) -> Self {
23 let border_width = px(1.);
24 let padding = px(2.);
25 let corner_radius =
26 CornerSolver::parent_radius(child_corner_radius, border_width, padding, px(0.));
27 Self {
28 corner_radius,
29 border_width,
30 padding,
31 focused,
32 active: false,
33 children: SmallVec::new(),
34 }
35 }
36
37 pub fn active(mut self, active: bool) -> Self {
38 self.active = active;
39 self
40 }
41}
42
43impl RenderOnce for Ring {
44 fn render(self, _window: &mut gpui::Window, cx: &mut gpui::App) -> impl IntoElement {
45 let border_color = if self.focused && self.active {
46 cx.theme().colors().border_focused.opacity(0.48)
47 } else if self.focused {
48 cx.theme().colors().border_variant
49 } else {
50 transparent_black()
51 };
52
53 h_flex()
54 .border(self.border_width)
55 .border_color(border_color)
56 .rounded(self.corner_radius)
57 .p(self.padding)
58 .children(self.children)
59 }
60}
61
62impl ParentElement for Ring {
63 fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
64 self.children.extend(elements)
65 }
66}