1use khora_sdk::editor_ui::{FontFamilyHint, Icon, Interaction, TextAlign, UiBuilder, UiTheme};
20use super::paint::{paint_icon, paint_text_size, with_alpha};
25
26pub fn paint_kbd_chip(
29 ui: &mut dyn UiBuilder,
30 origin: [f32; 2],
31 label: &str,
32 theme: &UiTheme,
33) -> f32 {
34 let measured = ui.measure_text(label, 10.5, FontFamilyHint::Monospace)[0];
35 let w = measured.max(14.0) + 10.0;
36 let h = 16.0;
37 ui.paint_rect_filled(origin, [w, h], theme.surface_active, 3.0);
38 ui.paint_rect_stroke(origin, [w, h], theme.border, 3.0, 1.0);
39 ui.paint_line(
41 [origin[0] + 1.0, origin[1] + h - 0.5],
42 [origin[0] + w - 1.0, origin[1] + h - 0.5],
43 with_alpha(theme.border, 0.5),
44 1.0,
45 );
46 ui.paint_text_styled(
47 [origin[0] + w * 0.5, origin[1] + 2.0],
48 label,
49 10.5,
50 theme.text_dim,
51 FontFamilyHint::Monospace,
52 TextAlign::Center,
53 );
54 origin[0] + w
55}
56
57pub fn paint_status_dot(ui: &mut dyn UiBuilder, center: [f32; 2], color: [f32; 4]) {
59 ui.paint_circle_filled(center, 3.5, color);
60 ui.paint_circle_filled(center, 5.5, with_alpha(color, 0.18));
61}
62
63pub fn paint_search_pill(
67 ui: &mut dyn UiBuilder,
68 origin: [f32; 2],
69 width: f32,
70 height: f32,
71 placeholder: &str,
72 theme: &UiTheme,
73) -> (Interaction, f32) {
74 ui.paint_rect_filled(origin, [width, height], theme.surface_elevated, 6.0);
75 ui.paint_rect_stroke(
76 origin,
77 [width, height],
78 with_alpha(theme.separator, 0.6),
79 6.0,
80 1.0,
81 );
82
83 let cy = origin[1] + height * 0.5;
84 paint_icon(
85 ui,
86 [origin[0] + 10.0, cy - 6.5],
87 Icon::Search,
88 13.0,
89 theme.text_dim,
90 );
91
92 paint_text_size(
93 ui,
94 [
95 origin[0] + 30.0,
96 origin[1] + (height - theme.font_size_body) * 0.5,
97 ],
98 placeholder,
99 theme.font_size_body - 0.5,
100 theme.text_muted,
101 );
102
103 let chip_y = origin[1] + (height - 16.0) * 0.5;
105 let mut x = origin[0] + width - 12.0;
106 for ch in ["K", "⌘"] {
107 let measured = ui.measure_text(ch, 10.5, FontFamilyHint::Monospace)[0];
108 let w = measured.max(14.0) + 10.0;
109 x -= w + 2.0;
110 paint_kbd_chip(ui, [x, chip_y], ch, theme);
111 }
112
113 let interaction = ui.interact_rect("titlebar-search", [origin[0], origin[1], width, height]);
114 (interaction, origin[0] + width)
115}
116
117pub fn panel_tab(
119 ui: &mut dyn UiBuilder,
120 id_salt: &str,
121 origin: [f32; 2],
122 label: &str,
123 badge: Option<&str>,
124 active: bool,
125 theme: &UiTheme,
126) -> (bool, f32) {
127 let label_w = ui.measure_text(
128 label,
129 theme.font_size_body - 1.0,
130 FontFamilyHint::Proportional,
131 )[0];
132 let badge_w = badge
133 .map(|b| ui.measure_text(b, 9.5, FontFamilyHint::Monospace)[0] + 10.0)
134 .unwrap_or(0.0);
135 let pad_x = 10.0;
136 let w = pad_x * 2.0 + label_w + if badge.is_some() { badge_w + 6.0 } else { 0.0 };
137 let h = 22.0;
138
139 let bg = if active {
140 theme.surface_active
141 } else {
142 theme.surface
143 };
144 if active {
145 ui.paint_rect_filled(origin, [w, h], bg, 4.0);
146 }
147
148 let text_color = if active { theme.text } else { theme.text_dim };
149 paint_text_size(
150 ui,
151 [
152 origin[0] + pad_x,
153 origin[1] + (h - theme.font_size_body) * 0.5,
154 ],
155 label,
156 theme.font_size_body - 1.0,
157 text_color,
158 );
159
160 if let Some(badge) = badge {
161 let badge_x = origin[0] + pad_x + label_w + 6.0;
162 let badge_y = origin[1] + 4.0;
163 ui.paint_rect_filled(
164 [badge_x, badge_y],
165 [badge_w - 4.0, 14.0],
166 if active {
167 with_alpha(theme.primary, 0.20)
168 } else {
169 theme.surface_elevated
170 },
171 999.0,
172 );
173 let badge_text_color = if active {
174 theme.primary
175 } else {
176 theme.text_dim
177 };
178 ui.paint_text_styled(
179 [badge_x + (badge_w - 4.0) * 0.5, badge_y + 1.0],
180 badge,
181 9.5,
182 badge_text_color,
183 FontFamilyHint::Monospace,
184 TextAlign::Center,
185 );
186 }
187
188 let interaction = ui.interact_rect(id_salt, [origin[0], origin[1], w, h]);
189 (interaction.clicked, w)
190}
191
192pub fn paint_panel_header(
196 ui: &mut dyn UiBuilder,
197 panel_rect: [f32; 4],
198 height: f32,
199 theme: &UiTheme,
200) {
201 let [x, y, w, _] = panel_rect;
202 super::paint::paint_vertical_gradient(
203 ui,
204 [x, y, w, height],
205 theme.surface_elevated,
206 theme.surface,
207 4,
208 );
209 ui.paint_line(
210 [x, y + height],
211 [x + w, y + height],
212 with_alpha(theme.separator, 0.55),
213 1.0,
214 );
215}