first pass at show scrollbar

Ben Kunkle created

Change summary

crates/settings_ui/src/keybindings.rs | 178 ++++++++++++++++++++--------
1 file changed, 126 insertions(+), 52 deletions(-)

Detailed changes

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<ProcessedKeybinding>,
     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>) -> Self {
+        let focus_handle = cx.focus_handle();
+
         let _keymap_subscription = cx.observe_global::<KeymapEventChannel>(|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<Self>) -> Vec<ProcessedKeybinding> {
@@ -105,6 +118,48 @@ impl KeymapEditor {
         }
         processed_bindings
     }
+
+    fn update_scrollbar_visibility(&mut self, cx: &mut Context<Self>) {
+        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<Self>) -> 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))
+                    }),
+            )
     }
 }