1use editor::{Editor, EditorElement, EditorStyle};
2use gpui::{Action, Entity, FocusHandle, Hsla, IntoElement, TextStyle};
3use settings::Settings;
4use theme::ThemeSettings;
5use ui::{IconButton, IconButtonShape};
6use ui::{Tooltip, prelude::*};
7
8pub(super) enum ActionButtonState {
9 Disabled,
10 Toggled,
11}
12
13pub(super) fn render_action_button(
14 id_prefix: &'static str,
15 icon: ui::IconName,
16 button_state: Option<ActionButtonState>,
17 tooltip: &'static str,
18 action: &'static dyn Action,
19 focus_handle: FocusHandle,
20) -> impl IntoElement {
21 IconButton::new(
22 SharedString::from(format!("{id_prefix}-{}", action.name())),
23 icon,
24 )
25 .shape(IconButtonShape::Square)
26 .on_click({
27 let focus_handle = focus_handle.clone();
28 move |_, window, cx| {
29 if !focus_handle.is_focused(window) {
30 window.focus(&focus_handle, cx);
31 }
32 window.dispatch_action(action.boxed_clone(), cx);
33 }
34 })
35 .tooltip(move |_window, cx| Tooltip::for_action_in(tooltip, action, &focus_handle, cx))
36 .when_some(button_state, |this, state| match state {
37 ActionButtonState::Toggled => this.toggle_state(true),
38 ActionButtonState::Disabled => this.disabled(true),
39 })
40}
41
42pub(crate) fn input_base_styles(border_color: Hsla, map: impl FnOnce(Div) -> Div) -> Div {
43 h_flex()
44 .map(map)
45 .min_w_32()
46 .h_8()
47 .pl_2()
48 .pr_1()
49 .border_1()
50 .border_color(border_color)
51 .rounded_md()
52}
53pub(crate) fn filter_search_results_input(
54 border_color: Hsla,
55 map: impl FnOnce(Div) -> Div,
56 cx: &App,
57) -> Div {
58 input_base_styles(border_color, map).pl_0().child(
59 h_flex()
60 .mr_2()
61 .px_2()
62 .h_full()
63 .border_r_1()
64 .border_color(cx.theme().colors().border)
65 .bg(cx.theme().colors().text_accent.opacity(0.05))
66 .child(Label::new("Find in Results").color(Color::Muted)),
67 )
68}
69
70pub(crate) fn render_text_input(
71 editor: &Entity<Editor>,
72 color_override: Option<Color>,
73 app: &App,
74) -> impl IntoElement {
75 let (color, use_syntax) = if editor.read(app).read_only(app) {
76 (app.theme().colors().text_disabled, false)
77 } else {
78 match color_override {
79 Some(color_override) => (color_override.color(app), false),
80 None => (app.theme().colors().text, true),
81 }
82 };
83
84 let settings = ThemeSettings::get_global(app);
85 let text_style = TextStyle {
86 color,
87 font_family: settings.buffer_font.family.clone(),
88 font_features: settings.buffer_font.features.clone(),
89 font_fallbacks: settings.buffer_font.fallbacks.clone(),
90 font_size: rems(0.875).into(),
91 font_weight: settings.buffer_font.weight,
92 line_height: relative(1.3),
93 ..TextStyle::default()
94 };
95
96 let mut editor_style = EditorStyle {
97 background: app.theme().colors().toolbar_background,
98 local_player: app.theme().players().local(),
99 text: text_style,
100 ..EditorStyle::default()
101 };
102 if use_syntax {
103 editor_style.syntax = app.theme().syntax().clone();
104 }
105
106 EditorElement::new(editor, editor_style)
107}
108
109/// This element makes all search inputs align as if they were in the same column
110pub(crate) fn alignment_element() -> Div {
111 div().size_5().flex_none().ml_0p5()
112}