diff --git a/crates/settings_ui/src/keybindings.rs b/crates/settings_ui/src/keybindings.rs index 1e79417eb1326e63a2bab007578057e078677f26..fe32bd01787d60ed15612e116c859866c824b046 100644 --- a/crates/settings_ui/src/keybindings.rs +++ b/crates/settings_ui/src/keybindings.rs @@ -1,15 +1,16 @@ -use std::{cell::RefCell, fmt::Write as _, rc::Rc}; +use std::fmt::Write as _; use db::anyhow::anyhow; use gpui::{ - AnyElement, AppContext as _, Context, Entity, EventEmitter, FocusHandle, Focusable, FontWeight, - Global, IntoElement, Keymap, Length, ListHorizontalSizingBehavior, ListSizingBehavior, - ScrollHandle, Subscription, Task, UniformListScrollHandle, actions, div, uniform_list, + AnyElement, AppContext as _, Context, EventEmitter, FocusHandle, Focusable, FontWeight, Global, + IntoElement, Length, ListHorizontalSizingBehavior, ListSizingBehavior, Subscription, + UniformListScrollHandle, actions, div, px, uniform_list, }; +use editor::ShowScrollbar; use ui::{ - ActiveTheme as _, App, BorrowAppContext, Indicator, ParentElement as _, Render, SharedString, - Styled as _, Window, prelude::*, + ActiveTheme as _, App, BorrowAppContext, ParentElement as _, Render, Scrollbar, ScrollbarState, + SharedString, Styled as _, Window, prelude::*, }; use workspace::{Item, SerializableItem, Workspace, register_serializable_item}; @@ -54,6 +55,8 @@ struct KeymapEditor { _keymap_subscription: Subscription, processed_bindings: Vec, scroll_handle: UniformListScrollHandle, + vertical_scrollbar_state: ScrollbarState, + show_vertical_scrollbar: bool, } impl EventEmitter<()> for KeymapEditor {} @@ -66,16 +69,26 @@ impl Focusable for KeymapEditor { impl KeymapEditor { fn new(cx: &mut gpui::Context) -> Self { + let focus_handle = cx.focus_handle(); + let _keymap_subscription = cx.observe_global::(|this, cx| { let key_bindings = Self::process_bindings(cx); this.processed_bindings = key_bindings; + _ = this.update_scrollbar_visibility(cx); }); - Self { - focus_handle: cx.focus_handle(), + let scroll_handle = UniformListScrollHandle::new(); + let vertical_scrollbar_state = ScrollbarState::new(scroll_handle.clone()); + let mut this = Self { + focus_handle: focus_handle.clone(), _keymap_subscription, processed_bindings: vec![], - scroll_handle: UniformListScrollHandle::new(), - } + scroll_handle, + vertical_scrollbar_state, + show_vertical_scrollbar: false, + }; + + this.update_scrollbar_visibility(cx); + this } fn process_bindings(cx: &mut Context) -> Vec { @@ -105,6 +118,48 @@ impl KeymapEditor { } processed_bindings } + + fn update_scrollbar_visibility(&mut self, cx: &mut Context) { + use editor::EditorSettings; + use settings::Settings; + + let show_setting = EditorSettings::get_global(cx).scrollbar.show; + + self.show_vertical_scrollbar = match show_setting { + ShowScrollbar::Auto | ShowScrollbar::System | ShowScrollbar::Always => true, + ShowScrollbar::Never => false, + }; + + cx.notify(); + } + + fn render_vertical_scrollbar(&self, cx: &mut Context) -> impl IntoElement { + div() + .id("keymap-editor-vertical-scroll") + .occlude() + .flex_none() + .h_full() + .cursor_default() + .absolute() + .right_0() + .top_0() + .bottom_0() + .w(px(12.)) + .on_mouse_move(cx.listener(|_, _, _, cx| { + cx.notify(); + cx.stop_propagation() + })) + .on_hover(|_, _, cx| { + cx.stop_propagation(); + }) + .on_any_mouse_down(|_, _, cx| { + cx.stop_propagation(); + }) + .on_scroll_wheel(cx.listener(|_, _, _, cx| { + cx.notify(); + })) + .children(Scrollbar::vertical(self.vertical_scrollbar_state.clone())) + } } struct ProcessedKeybinding { @@ -126,6 +181,7 @@ impl Render for KeymapEditor { dbg!("rendering"); if self.processed_bindings.is_empty() { self.processed_bindings = Self::process_bindings(cx); + self.update_scrollbar_visibility(cx); } let table = Table::new(self.processed_bindings.len()); @@ -133,49 +189,67 @@ impl Render for KeymapEditor { let theme = cx.theme(); let headers = ["Command", "Keystrokes", "Context"].map(Into::into); - div().size_full().bg(theme.colors().background).child( - table - .render() - .h_full() - .child(table.render_header(headers, cx)) - .child( - uniform_list( - cx.entity(), - "keybindings", - table.row_count, - move |this, range, _, cx| { - return range - .map(|index| { - table.render_row( - index, - [ - string_cell( - this.processed_bindings[index].action.clone(), - ), - string_cell( - this.processed_bindings[index] - .keystroke_text - .clone(), - ), - string_cell( - this.processed_bindings[index].context.clone(), - ), - // TODO: Add a source field - // string_cell(keybinding.source().to_string()), - ], - cx, - ) - }) - .collect(); - }, - ) + div() + .size_full() + .bg(theme.colors().background) + .track_focus(&self.focus_handle) + .child( + div() + .relative() .size_full() - .flex_grow() - .track_scroll(self.scroll_handle.clone()) - .with_sizing_behavior(ListSizingBehavior::Auto) - .with_horizontal_sizing_behavior(ListHorizontalSizingBehavior::Unconstrained), - ), - ) + .child( + table + .render() + .h_full() + .child(table.render_header(headers, cx)) + .child( + uniform_list( + cx.entity(), + "keybindings", + table.row_count, + move |this, range, _, cx| { + return range + .map(|index| { + table.render_row( + index, + [ + string_cell( + this.processed_bindings[index] + .action + .clone(), + ), + string_cell( + this.processed_bindings[index] + .keystroke_text + .clone(), + ), + string_cell( + this.processed_bindings[index] + .context + .clone(), + ), + // TODO: Add a source field + // string_cell(keybinding.source().to_string()), + ], + cx, + ) + }) + .collect(); + }, + ) + .size_full() + .flex_grow() + .track_scroll(self.scroll_handle.clone()) + .with_sizing_behavior(ListSizingBehavior::Auto) + .with_horizontal_sizing_behavior( + ListHorizontalSizingBehavior::Unconstrained, + ), + ), + ) + .when(self.show_vertical_scrollbar, |this| { + this.child(self.render_vertical_scrollbar(cx)) + }), + ) } }