From 7b084199be8d81f5771a392e8f5836f33bfa0c89 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 10 Oct 2022 17:54:29 -0700 Subject: [PATCH] Auto-hide scrollbars --- crates/editor/src/editor.rs | 28 ++++++++ crates/editor/src/element.rs | 130 ++++++++++++++++++++--------------- 2 files changed, 101 insertions(+), 57 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 1abe65d482..3422e599f8 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -76,6 +76,7 @@ use util::{post_inc, ResultExt, TryFutureExt}; use workspace::{ItemNavHistory, Workspace}; const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500); +const SCROLLBAR_SHOW_INTERVAL: Duration = Duration::from_secs(1); const MAX_LINE_LEN: usize = 1024; const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10; const MAX_SELECTION_HISTORY_LEN: usize = 1024; @@ -427,6 +428,8 @@ pub struct Editor { focused: bool, show_local_cursors: bool, show_local_selections: bool, + show_scrollbars: bool, + hide_scrollbar_task: Option>, blink_epoch: usize, blinking_paused: bool, mode: EditorMode, @@ -1028,6 +1031,8 @@ impl Editor { focused: false, show_local_cursors: false, show_local_selections: true, + show_scrollbars: true, + hide_scrollbar_task: None, blink_epoch: 0, blinking_paused: false, mode, @@ -1059,6 +1064,7 @@ impl Editor { ], }; this.end_selection(cx); + this.make_scrollbar_visible(cx); let editor_created_event = EditorCreated(cx.handle()); cx.emit_global(editor_created_event); @@ -1179,6 +1185,7 @@ impl Editor { self.scroll_top_anchor = anchor; } + self.make_scrollbar_visible(cx); self.autoscroll_request.take(); hide_hover(self, cx); @@ -5932,6 +5939,27 @@ impl Editor { self.show_local_cursors && self.focused } + pub fn show_scrollbars(&self) -> bool { + self.show_scrollbars + } + + fn make_scrollbar_visible(&mut self, cx: &mut ViewContext) { + if !self.show_scrollbars { + self.show_scrollbars = true; + cx.notify(); + } + + self.hide_scrollbar_task = Some(cx.spawn_weak(|this, mut cx| async move { + Timer::after(SCROLLBAR_SHOW_INTERVAL).await; + if let Some(this) = this.upgrade(&cx) { + this.update(&mut cx, |this, cx| { + this.show_scrollbars = false; + cx.notify(); + }); + } + })); + } + fn on_buffer_changed(&mut self, _: ModelHandle, cx: &mut ViewContext) { cx.notify(); } diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 300edc02a6..66dbe50864 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -454,7 +454,6 @@ impl EditorElement { let bounds = gutter_bounds.union_rect(text_bounds); let scroll_top = layout.position_map.snapshot.scroll_position().y() * layout.position_map.line_height; - let editor = self.view(cx.app); cx.scene.push_quad(Quad { bounds: gutter_bounds, background: Some(self.style.gutter_background), @@ -468,7 +467,7 @@ impl EditorElement { corner_radius: 0., }); - if let EditorMode::Full = editor.mode { + if let EditorMode::Full = layout.mode { let mut active_rows = layout.active_rows.iter().peekable(); while let Some((start_row, contains_non_empty_selection)) = active_rows.next() { let mut end_row = *start_row; @@ -911,25 +910,24 @@ impl EditorElement { fn paint_scrollbar(&mut self, bounds: RectF, layout: &mut LayoutState, cx: &mut PaintContext) { enum ScrollbarMouseHandlers {} - let row_range = if let Some(row_range) = &layout.scrollbar_row_range { - row_range - } else { + if layout.mode != EditorMode::Full { return; - }; + } + let view = self.view.clone(); let style = &self.style.theme.scrollbar; let top = bounds.min_y(); let bottom = bounds.max_y(); + let right = bounds.max_x(); + let left = right - style.width; let height = bounds.height(); - + let row_range = &layout.scrollbar_row_range; let max_row = layout.max_row + ((row_range.end - row_range.start) as u32); let scrollbar_start = row_range.start as f32 / max_row as f32; let scrollbar_end = row_range.end as f32 / max_row as f32; - let thumb_top = top + scrollbar_start * height; let thumb_bottom = top + scrollbar_end * height; - let right = bounds.max_x(); - let left = right - style.width; + let track_bounds = RectF::from_points(vec2f(left, top), vec2f(right, bottom)); let thumb_bounds = RectF::from_points(vec2f(left, thumb_top), vec2f(right, thumb_bottom)); @@ -939,63 +937,75 @@ impl EditorElement { background: style.track.background_color, ..Default::default() }); - cx.scene.push_quad(Quad { - bounds: thumb_bounds, - border: style.thumb.border, - background: style.thumb.background_color, - corner_radius: style.thumb.corner_radius, - }); + if layout.show_scrollbars { + cx.scene.push_quad(Quad { + bounds: thumb_bounds, + border: style.thumb.border, + background: style.thumb.background_color, + corner_radius: style.thumb.corner_radius, + }); + } + cx.scene.push_cursor_region(CursorRegion { bounds: track_bounds, style: CursorStyle::Arrow, }); - - let view = self.view.clone(); cx.scene.push_mouse_region( - MouseRegion::new::( - self.view.id(), - self.view.id(), - track_bounds, - ) - .on_down(MouseButton::Left, { - let view = view.clone(); - let row_range_len = row_range.end - row_range.start; - move |e, cx| { - let y = e.position.y(); - if y < thumb_top || thumb_bottom < y { + MouseRegion::new::(view.id(), view.id(), track_bounds) + .on_move({ + let view = view.clone(); + move |_, cx| { if let Some(view) = view.upgrade(cx.deref_mut()) { view.update(cx.deref_mut(), |view, cx| { - let center_row = - ((y - top) * max_row as f32 / height).round() as u32; - let top_row = center_row.saturating_sub(row_range_len as u32 / 2); - let mut position = view.scroll_position(cx); - position.set_y(top_row as f32); - view.set_scroll_position(position, cx); + view.make_scrollbar_visible(cx); }); } } - } - }) - .on_drag(MouseButton::Left, { - let view = view.clone(); - move |e, cx| { - let y = e.prev_mouse_position.y(); - let new_y = e.position.y(); - if thumb_top < y && y < thumb_bottom { + }) + .on_down(MouseButton::Left, { + let view = view.clone(); + let row_range = row_range.clone(); + move |e, cx| { + let y = e.position.y(); if let Some(view) = view.upgrade(cx.deref_mut()) { view.update(cx.deref_mut(), |view, cx| { - let mut position = view.scroll_position(cx); - position - .set_y(position.y() + (new_y - y) * (max_row as f32) / height); - if position.y() < 0.0 { - position.set_y(0.); + if y < thumb_top || thumb_bottom < y { + let center_row = + ((y - top) * max_row as f32 / height).round() as u32; + let top_row = center_row.saturating_sub( + (row_range.end - row_range.start) as u32 / 2, + ); + let mut position = view.scroll_position(cx); + position.set_y(top_row as f32); + view.set_scroll_position(position, cx); + } else { + view.make_scrollbar_visible(cx); } - view.set_scroll_position(position, cx); }); } } - } - }), + }) + .on_drag(MouseButton::Left, { + let view = view.clone(); + move |e, cx| { + let y = e.prev_mouse_position.y(); + let new_y = e.position.y(); + if thumb_top < y && y < thumb_bottom { + if let Some(view) = view.upgrade(cx.deref_mut()) { + view.update(cx.deref_mut(), |view, cx| { + let mut position = view.scroll_position(cx); + position.set_y( + position.y() + (new_y - y) * (max_row as f32) / height, + ); + if position.y() < 0.0 { + position.set_y(0.); + } + view.set_scroll_position(position, cx); + }); + } + } + } + }), ); } @@ -1582,6 +1592,7 @@ impl Element for EditorElement { let mut active_rows = BTreeMap::new(); let mut highlighted_rows = None; let mut highlighted_ranges = Vec::new(); + let mut show_scrollbars = false; self.update_view(cx.app, |view, cx| { let display_map = view.display_map.update(cx, |map, cx| map.snapshot(cx)); @@ -1642,6 +1653,8 @@ impl Element for EditorElement { .collect(), )); } + + show_scrollbars = view.show_scrollbars(); }); let line_number_layouts = @@ -1652,11 +1665,8 @@ impl Element for EditorElement { .git_diff_hunks_in_range(start_row..end_row) .collect(); - let scrollbar_row_range = if snapshot.mode == EditorMode::Full { - Some(scroll_position.y()..(scroll_position.y() + visible_row_count as f32)) - } else { - None - }; + let scrollbar_row_range = + scroll_position.y()..(scroll_position.y() + visible_row_count as f32); let mut max_visible_line_width = 0.0; let line_layouts = self.layout_lines(start_row..end_row, &snapshot, cx); @@ -1720,6 +1730,7 @@ impl Element for EditorElement { let mut context_menu = None; let mut code_actions_indicator = None; let mut hover = None; + let mut mode = EditorMode::Full; cx.render(&self.view.upgrade(cx).unwrap(), |view, cx| { let newest_selection_head = view .selections @@ -1741,6 +1752,7 @@ impl Element for EditorElement { let visible_rows = start_row..start_row + line_layouts.len() as u32; hover = view.hover_state.render(&snapshot, &style, visible_rows, cx); + mode = view.mode; }); if let Some((_, context_menu)) = context_menu.as_mut() { @@ -1788,6 +1800,7 @@ impl Element for EditorElement { ( size, LayoutState { + mode, position_map: Arc::new(PositionMap { size, scroll_max, @@ -1801,6 +1814,7 @@ impl Element for EditorElement { gutter_padding, text_size, scrollbar_row_range, + show_scrollbars, max_row, gutter_margin, active_rows, @@ -1939,13 +1953,15 @@ pub struct LayoutState { gutter_padding: f32, gutter_margin: f32, text_size: Vector2F, + mode: EditorMode, active_rows: BTreeMap, highlighted_rows: Option>, line_number_layouts: Vec>, blocks: Vec, highlighted_ranges: Vec<(Range, Color)>, selections: Vec<(ReplicaId, Vec)>, - scrollbar_row_range: Option>, + scrollbar_row_range: Range, + show_scrollbars: bool, max_row: u32, context_menu: Option<(DisplayPoint, ElementBox)>, diff_hunks: Vec>,