1//! # panel
2use editor::{Editor, EditorElement, EditorStyle};
3use gpui::{actions, Entity, TextStyle};
4use settings::Settings;
5use theme::ThemeSettings;
6use ui::{prelude::*, Tab};
7
8actions!(panel, [NextPanelTab, PreviousPanelTab]);
9
10pub trait PanelHeader: workspace::Panel {
11 fn header_height(&self, cx: &mut App) -> Pixels {
12 Tab::container_height(cx)
13 }
14
15 fn panel_header_container(&self, _window: &mut Window, cx: &mut App) -> Div {
16 h_flex()
17 .h(self.header_height(cx))
18 .w_full()
19 .px_1()
20 .flex_none()
21 .border_b_1()
22 .border_color(cx.theme().colors().border)
23 }
24}
25
26/// Implement this trait to enable a panel to have tabs.
27pub trait PanelTabs: PanelHeader {
28 /// Returns the index of the currently selected tab.
29 fn selected_tab(&self, cx: &mut App) -> usize;
30 /// Selects the tab at the given index.
31 fn select_tab(&self, cx: &mut App, index: usize);
32 /// Moves to the next tab.
33 fn next_tab(&self, _: NextPanelTab, cx: &mut App) -> Self;
34 /// Moves to the previous tab.
35 fn previous_tab(&self, _: PreviousPanelTab, cx: &mut App) -> Self;
36}
37
38#[derive(IntoElement)]
39pub struct PanelTab {}
40
41impl RenderOnce for PanelTab {
42 fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
43 div()
44 }
45}
46
47pub fn panel_button(label: impl Into<SharedString>) -> ui::Button {
48 let label = label.into();
49 let id = ElementId::Name(label.clone().to_lowercase().replace(' ', "_").into());
50 ui::Button::new(id, label)
51 .label_size(ui::LabelSize::Small)
52 .icon_size(ui::IconSize::Small)
53 // TODO: Change this once we use on_surface_bg in button_like
54 .layer(ui::ElevationIndex::ModalSurface)
55 .size(ui::ButtonSize::Compact)
56}
57
58pub fn panel_filled_button(label: impl Into<SharedString>) -> ui::Button {
59 panel_button(label).style(ui::ButtonStyle::Filled)
60}
61
62pub fn panel_icon_button(id: impl Into<SharedString>, icon: IconName) -> ui::IconButton {
63 let id = ElementId::Name(id.into());
64 ui::IconButton::new(id, icon)
65 // TODO: Change this once we use on_surface_bg in button_like
66 .layer(ui::ElevationIndex::ModalSurface)
67 .size(ui::ButtonSize::Compact)
68}
69
70pub fn panel_filled_icon_button(id: impl Into<SharedString>, icon: IconName) -> ui::IconButton {
71 panel_icon_button(id, icon).style(ui::ButtonStyle::Filled)
72}
73
74pub fn panel_editor_container(_window: &mut Window, cx: &mut App) -> Div {
75 v_flex()
76 .size_full()
77 .gap(px(8.))
78 .p_2()
79 .bg(cx.theme().colors().editor_background)
80}
81
82pub fn panel_editor_style(monospace: bool, window: &Window, cx: &App) -> EditorStyle {
83 let settings = ThemeSettings::get_global(cx);
84
85 let font_size = TextSize::Small.rems(cx).to_pixels(window.rem_size());
86
87 let (font_family, font_fallbacks, font_features, font_weight, line_height) = if monospace {
88 (
89 settings.buffer_font.family.clone(),
90 settings.buffer_font.fallbacks.clone(),
91 settings.buffer_font.features.clone(),
92 settings.buffer_font.weight,
93 font_size * settings.buffer_line_height.value(),
94 )
95 } else {
96 (
97 settings.ui_font.family.clone(),
98 settings.ui_font.fallbacks.clone(),
99 settings.ui_font.features.clone(),
100 settings.ui_font.weight,
101 window.line_height(),
102 )
103 };
104
105 EditorStyle {
106 background: cx.theme().colors().editor_background,
107 local_player: cx.theme().players().local(),
108 text: TextStyle {
109 color: cx.theme().colors().text,
110 font_family,
111 font_fallbacks,
112 font_features,
113 font_size: TextSize::Small.rems(cx).into(),
114 font_weight,
115 line_height: line_height.into(),
116 ..Default::default()
117 },
118 ..Default::default()
119 }
120}
121
122pub fn panel_editor_element(
123 editor: &Entity<Editor>,
124 monospace: bool,
125 window: &mut Window,
126 cx: &mut App,
127) -> EditorElement {
128 EditorElement::new(editor, panel_editor_style(monospace, window, cx))
129}