focus_outline.rs

 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/// An outline 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 FocusOutline {
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 FocusOutline {
22    pub fn new(child_corner_radius: Pixels, focused: bool, offset: Pixels) -> Self {
23        let ring_width = px(1.);
24        let corner_radius =
25            CornerSolver::parent_radius(child_corner_radius, ring_width, offset, px(0.));
26        Self {
27            corner_radius,
28            border_width: ring_width,
29            padding: offset,
30            focused,
31            active: false,
32            children: SmallVec::new(),
33        }
34    }
35
36    pub fn active(mut self, active: bool) -> Self {
37        self.active = active;
38        self
39    }
40}
41
42impl RenderOnce for FocusOutline {
43    fn render(self, _window: &mut gpui::Window, cx: &mut gpui::App) -> impl IntoElement {
44        let border_color = if self.focused && self.active {
45            cx.theme().colors().border_focused.opacity(0.48)
46        } else if self.focused {
47            cx.theme().colors().border_variant
48        } else {
49            transparent_black()
50        };
51
52        h_flex()
53            .border(self.border_width)
54            .border_color(border_color)
55            .rounded(self.corner_radius)
56            .p(self.padding)
57            .children(self.children)
58    }
59}
60
61impl ParentElement for FocusOutline {
62    fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
63        self.children.extend(elements)
64    }
65}