@@ -506,6 +506,7 @@ pub struct SettingsWindow {
|
||||
title_bar: Option<Entity<PlatformTitleBar>>,
|
||||
original_window: Option<WindowHandle<Workspace>>,
|
||||
files: Vec<(SettingsUiFile, FocusHandle)>,
|
||||
drop_down_file: Option<usize>,
|
||||
worktree_root_dirs: HashMap<WorktreeId, String>,
|
||||
current_file: SettingsUiFile,
|
||||
pages: Vec<SettingsPage>,
|
||||
@@ -971,6 +972,7 @@ impl SettingsWindow {
|
||||
original_window,
|
||||
worktree_root_dirs: HashMap::default(),
|
||||
files: vec![],
|
||||
drop_down_file: None,
|
||||
current_file: current_file,
|
||||
pages: vec![],
|
||||
navbar_entries: vec![],
|
||||
@@ -1440,7 +1442,7 @@ impl SettingsWindow {
|
||||
.iter()
|
||||
.any(|(file, _)| file == &self.current_file);
|
||||
if !current_file_still_exists {
|
||||
self.change_file(0, window, cx);
|
||||
self.change_file(0, window, false, cx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1460,12 +1462,22 @@ impl SettingsWindow {
|
||||
self.open_navbar_entry_page(first_navbar_entry_index);
|
||||
}
|
||||
|
||||
fn change_file(&mut self, ix: usize, window: &mut Window, cx: &mut Context<SettingsWindow>) {
|
||||
fn change_file(
|
||||
&mut self,
|
||||
ix: usize,
|
||||
window: &mut Window,
|
||||
drop_down_file: bool,
|
||||
cx: &mut Context<SettingsWindow>,
|
||||
) {
|
||||
if ix >= self.files.len() {
|
||||
self.current_file = SettingsUiFile::User;
|
||||
self.build_ui(window, cx);
|
||||
return;
|
||||
}
|
||||
if drop_down_file {
|
||||
self.drop_down_file = Some(ix);
|
||||
}
|
||||
|
||||
if self.files[ix].0 == self.current_file {
|
||||
return;
|
||||
}
|
||||
@@ -1485,9 +1497,30 @@ impl SettingsWindow {
|
||||
|
||||
fn render_files_header(
|
||||
&self,
|
||||
_window: &mut Window,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<SettingsWindow>,
|
||||
) -> impl IntoElement {
|
||||
const OVERFLOW_LIMIT: usize = 1;
|
||||
|
||||
let file_button =
|
||||
|ix, file: &SettingsUiFile, focus_handle, cx: &mut Context<SettingsWindow>| {
|
||||
Button::new(
|
||||
ix,
|
||||
self.display_name(&file)
|
||||
.expect("Files should always have a name"),
|
||||
)
|
||||
.toggle_state(file == &self.current_file)
|
||||
.selected_style(ButtonStyle::Tinted(ui::TintColor::Accent))
|
||||
.track_focus(focus_handle)
|
||||
.on_click(cx.listener({
|
||||
let focus_handle = focus_handle.clone();
|
||||
move |this, _: &gpui::ClickEvent, window, cx| {
|
||||
this.change_file(ix, window, false, cx);
|
||||
focus_handle.focus(window);
|
||||
}
|
||||
}))
|
||||
};
|
||||
let this = cx.entity();
|
||||
h_flex()
|
||||
.w_full()
|
||||
.pb_4()
|
||||
@@ -1499,31 +1532,73 @@ impl SettingsWindow {
|
||||
.child(
|
||||
h_flex()
|
||||
.id("file_buttons_container")
|
||||
.w_64() // Temporary fix until long-term solution is a fixed set of buttons representing a file location (User, Project, and Remote)
|
||||
.gap_1()
|
||||
.overflow_x_scroll()
|
||||
.children(
|
||||
self.files
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(ix, (file, focus_handle))| {
|
||||
Button::new(
|
||||
ix,
|
||||
self.display_name(&file)
|
||||
.expect("Files should always have a name"),
|
||||
self.files.iter().enumerate().take(OVERFLOW_LIMIT).map(
|
||||
|(ix, (file, focus_handle))| file_button(ix, file, focus_handle, cx),
|
||||
),
|
||||
)
|
||||
.when(self.files.len() > OVERFLOW_LIMIT, |div| {
|
||||
div.children(
|
||||
self.files
|
||||
.iter()
|
||||
.enumerate()
|
||||
.skip(OVERFLOW_LIMIT)
|
||||
.find(|(_, (file, _))| file == &self.current_file)
|
||||
.map(|(ix, (file, focus_handle))| {
|
||||
file_button(ix, file, focus_handle, cx)
|
||||
})
|
||||
.or_else(|| {
|
||||
let ix = self.drop_down_file.unwrap_or(OVERFLOW_LIMIT);
|
||||
self.files.get(ix).map(|(file, focus_handle)| {
|
||||
file_button(ix, file, focus_handle, cx)
|
||||
})
|
||||
}),
|
||||
)
|
||||
.when(
|
||||
self.files.len() > OVERFLOW_LIMIT + 1,
|
||||
|div| {
|
||||
div.child(
|
||||
DropdownMenu::new(
|
||||
"more-files",
|
||||
format!("+{}", self.files.len() - (OVERFLOW_LIMIT + 1)),
|
||||
ContextMenu::build(window, cx, move |mut menu, _, _| {
|
||||
for (ix, (file, focus_handle)) in self
|
||||
.files
|
||||
.iter()
|
||||
.enumerate()
|
||||
.skip(OVERFLOW_LIMIT + 1)
|
||||
{
|
||||
menu = menu.entry(
|
||||
self.display_name(file)
|
||||
.expect("Files should always have a name"),
|
||||
None,
|
||||
{
|
||||
let this = this.clone();
|
||||
let focus_handle = focus_handle.clone();
|
||||
move |window, cx| {
|
||||
this.update(cx, |this, cx| {
|
||||
this.change_file(
|
||||
ix, window, true, cx,
|
||||
);
|
||||
});
|
||||
focus_handle.focus(window);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
menu
|
||||
}),
|
||||
)
|
||||
.style(DropdownStyle::Ghost)
|
||||
.tab_index(0)
|
||||
.no_chevron(),
|
||||
)
|
||||
.toggle_state(file == &self.current_file)
|
||||
.selected_style(ButtonStyle::Tinted(ui::TintColor::Accent))
|
||||
.track_focus(focus_handle)
|
||||
.on_click(cx.listener({
|
||||
let focus_handle = focus_handle.clone();
|
||||
move |this, _: &gpui::ClickEvent, window, cx| {
|
||||
this.change_file(ix, window, cx);
|
||||
focus_handle.focus(window);
|
||||
}
|
||||
}))
|
||||
}),
|
||||
),
|
||||
},
|
||||
)
|
||||
}),
|
||||
)
|
||||
.child(
|
||||
Button::new("edit-in-json", "Edit in settings.json")
|
||||
@@ -2675,6 +2750,7 @@ mod test {
|
||||
worktree_root_dirs: HashMap::default(),
|
||||
files: Vec::default(),
|
||||
current_file: crate::SettingsUiFile::User,
|
||||
drop_down_file: None,
|
||||
pages,
|
||||
search_bar: cx.new(|cx| Editor::single_line(window, cx)),
|
||||
navbar_entry: selected_idx.expect("Must have a selected navbar entry"),
|
||||
|
||||
@@ -30,6 +30,7 @@ pub struct DropdownMenu {
|
||||
attach: Option<Corner>,
|
||||
offset: Option<Point<Pixels>>,
|
||||
tab_index: Option<isize>,
|
||||
chevron: bool,
|
||||
}
|
||||
|
||||
impl DropdownMenu {
|
||||
@@ -50,6 +51,7 @@ impl DropdownMenu {
|
||||
attach: None,
|
||||
offset: None,
|
||||
tab_index: None,
|
||||
chevron: true,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +72,7 @@ impl DropdownMenu {
|
||||
attach: None,
|
||||
offset: None,
|
||||
tab_index: None,
|
||||
chevron: true,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,6 +112,11 @@ impl DropdownMenu {
|
||||
self.tab_index = Some(arg);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn no_chevron(mut self) -> Self {
|
||||
self.chevron = false;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Disableable for DropdownMenu {
|
||||
@@ -132,19 +140,23 @@ impl RenderOnce for DropdownMenu {
|
||||
let button = match self.label {
|
||||
LabelKind::Text(text) => Button::new(self.id.clone(), text)
|
||||
.style(button_style)
|
||||
.icon(IconName::ChevronUpDown)
|
||||
.icon_position(IconPosition::End)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.icon_color(Color::Muted)
|
||||
.when(self.chevron, |this| {
|
||||
this.icon(IconName::ChevronUpDown)
|
||||
.icon_position(IconPosition::End)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.icon_color(Color::Muted)
|
||||
})
|
||||
.when(full_width, |this| this.full_width())
|
||||
.size(trigger_size)
|
||||
.disabled(self.disabled),
|
||||
LabelKind::Element(_element) => Button::new(self.id.clone(), "")
|
||||
.style(button_style)
|
||||
.icon(IconName::ChevronUpDown)
|
||||
.icon_position(IconPosition::End)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.icon_color(Color::Muted)
|
||||
.when(self.chevron, |this| {
|
||||
this.icon(IconName::ChevronUpDown)
|
||||
.icon_position(IconPosition::End)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.icon_color(Color::Muted)
|
||||
})
|
||||
.when(full_width, |this| this.full_width())
|
||||
.size(trigger_size)
|
||||
.disabled(self.disabled),
|
||||
|
||||
Reference in New Issue
Block a user