ui/components/icon/
icon_decoration.rs1use std::sync::Arc;
2
3use gpui::{Hsla, IntoElement, Point, svg};
4use strum::{EnumIter, EnumString, IntoStaticStr};
5
6use crate::prelude::*;
7
8const ICON_DECORATION_SIZE: Pixels = px(11.);
9
10#[derive(Debug, PartialEq, Eq, Copy, Clone, EnumIter, EnumString, IntoStaticStr)]
13#[strum(serialize_all = "snake_case")]
14pub enum KnockoutIconName {
15 XFg,
16 XBg,
17 DotFg,
18 DotBg,
19 TriangleFg,
20 TriangleBg,
21}
22
23impl KnockoutIconName {
24 pub fn path(&self) -> Arc<str> {
26 let file_stem: &'static str = self.into();
27 format!("icons/knockouts/{file_stem}.svg").into()
28 }
29}
30
31#[derive(Debug, PartialEq, Eq, Copy, Clone, EnumIter, EnumString)]
32pub enum IconDecorationKind {
33 X,
34 Dot,
35 Triangle,
36}
37
38impl IconDecorationKind {
39 fn fg(&self) -> KnockoutIconName {
40 match self {
41 Self::X => KnockoutIconName::XFg,
42 Self::Dot => KnockoutIconName::DotFg,
43 Self::Triangle => KnockoutIconName::TriangleFg,
44 }
45 }
46
47 fn bg(&self) -> KnockoutIconName {
48 match self {
49 Self::X => KnockoutIconName::XBg,
50 Self::Dot => KnockoutIconName::DotBg,
51 Self::Triangle => KnockoutIconName::TriangleBg,
52 }
53 }
54}
55
56#[derive(IntoElement)]
61pub struct IconDecoration {
62 kind: IconDecorationKind,
63 color: Hsla,
64 knockout_color: Hsla,
65 knockout_hover_color: Hsla,
66 size: Pixels,
67 position: Point<Pixels>,
68 group_name: Option<SharedString>,
69}
70
71impl IconDecoration {
72 pub fn new(kind: IconDecorationKind, knockout_color: Hsla, cx: &App) -> Self {
74 let color = cx.theme().colors().icon;
75 let position = Point::default();
76
77 Self {
78 kind,
79 color,
80 knockout_color,
81 knockout_hover_color: knockout_color,
82 size: ICON_DECORATION_SIZE,
83 position,
84 group_name: None,
85 }
86 }
87
88 pub fn kind(mut self, kind: IconDecorationKind) -> Self {
90 self.kind = kind;
91 self
92 }
93
94 pub fn color(mut self, color: Hsla) -> Self {
96 self.color = color;
97 self
98 }
99
100 pub fn knockout_color(mut self, color: Hsla) -> Self {
105 self.knockout_color = color;
106 self
107 }
108
109 pub fn knockout_hover_color(mut self, color: Hsla) -> Self {
111 self.knockout_hover_color = color;
112 self
113 }
114
115 pub fn position(mut self, position: Point<Pixels>) -> Self {
117 self.position = position;
118 self
119 }
120
121 pub fn size(mut self, size: Pixels) -> Self {
123 self.size = size;
124 self
125 }
126
127 pub fn group_name(mut self, name: Option<SharedString>) -> Self {
129 self.group_name = name;
130 self
131 }
132}
133
134impl RenderOnce for IconDecoration {
135 fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
136 let size = self.size;
137
138 let foreground = svg()
139 .absolute()
140 .bottom_0()
141 .right_0()
142 .size(size)
143 .path(self.kind.fg().path())
144 .text_color(self.color);
145
146 let background = svg()
147 .absolute()
148 .bottom_0()
149 .right_0()
150 .size(size)
151 .path(self.kind.bg().path())
152 .text_color(self.knockout_color)
153 .map(|this| match self.group_name {
154 Some(group_name) => this.group_hover(group_name, |style| {
155 style.text_color(self.knockout_hover_color)
156 }),
157 None => this.hover(|style| style.text_color(self.knockout_hover_color)),
158 });
159
160 div()
161 .size(size)
162 .flex_none()
163 .absolute()
164 .bottom(self.position.y)
165 .right(self.position.x)
166 .child(background)
167 .child(foreground)
168 }
169}