diff --git a/crates/story/examples/tiles.rs b/crates/story/examples/tiles.rs index 38160d29..45ad95ff 100644 --- a/crates/story/examples/tiles.rs +++ b/crates/story/examples/tiles.rs @@ -7,6 +7,7 @@ use gpui_component::{ PanelState, PanelView, register_panel, }, input::{Input, InputState}, + scroll::ScrollbarShow, }; use serde::{Deserialize, Serialize}; use std::{sync::Arc, time::Duration}; @@ -239,6 +240,17 @@ impl StoryTiles { Ok(()) } + fn set_scrollbar_show(dock_area: &mut DockArea, cx: &mut App) { + match dock_area.items() { + DockItem::Tiles { view, .. } => { + view.update(cx, |this, cx| { + this.set_scrollbar_show(Some(ScrollbarShow::Always), cx); + }); + } + _ => {} + } + } + fn load_tiles( dock_area: Entity, window: &mut Window, @@ -273,7 +285,7 @@ impl StoryTiles { dock_area.update(cx, |dock_area, cx| { dock_area.load(state, window, cx).context("load layout")?; - + Self::set_scrollbar_show(dock_area, cx); Ok::<(), anyhow::Error>(()) }) } @@ -284,11 +296,12 @@ impl StoryTiles { cx: &mut Context, ) { let dock_item = Self::init_default_layout(&dock_area, window, cx); - _ = dock_area.update(cx, |view, cx| { - view.set_version(TILES_DOCK_AREA.version, window, cx); - view.set_center(dock_item, window, cx); + _ = dock_area.update(cx, |dock_area, cx| { + dock_area.set_version(TILES_DOCK_AREA.version, window, cx); + dock_area.set_center(dock_item, window, cx); - Self::save_tiles(&view.dump(cx)).unwrap(); + Self::set_scrollbar_show(dock_area, cx); + Self::save_tiles(&dock_area.dump(cx)).unwrap(); }); } diff --git a/crates/ui/src/dock/tiles.rs b/crates/ui/src/dock/tiles.rs index 124f7e7f..d015e52b 100644 --- a/crates/ui/src/dock/tiles.rs +++ b/crates/ui/src/dock/tiles.rs @@ -7,7 +7,7 @@ use std::{ use crate::{ h_flex, history::{History, HistoryItem}, - scroll::{Scrollbar, ScrollbarState}, + scroll::{Scrollbar, ScrollbarShow, ScrollbarState}, v_flex, ActiveTheme, Icon, IconName, }; @@ -15,10 +15,11 @@ use super::{ DockArea, Panel, PanelEvent, PanelInfo, PanelState, PanelView, StackPanel, TabPanel, TileMeta, }; use gpui::{ - actions, canvas, div, px, size, AnyElement, App, AppContext, Bounds, Context, DismissEvent, - DragMoveEvent, Empty, EntityId, EventEmitter, FocusHandle, Focusable, InteractiveElement, - IntoElement, MouseButton, MouseDownEvent, MouseUpEvent, ParentElement, Pixels, Point, Render, - ScrollHandle, Size, StatefulInteractiveElement, Styled, WeakEntity, Window, + actions, canvas, div, prelude::FluentBuilder, px, size, AnyElement, App, AppContext, Bounds, + Context, DismissEvent, DragMoveEvent, Empty, EntityId, EventEmitter, FocusHandle, Focusable, + InteractiveElement, IntoElement, MouseButton, MouseDownEvent, MouseUpEvent, ParentElement, + Pixels, Point, Render, ScrollHandle, Size, StatefulInteractiveElement, Styled, WeakEntity, + Window, }; actions!(tiles, [Undo, Redo]); @@ -140,6 +141,7 @@ pub struct Tiles { history: History, scroll_state: ScrollbarState, scroll_handle: ScrollHandle, + scrollbar_show: Option, } impl Panel for Tiles { @@ -189,6 +191,7 @@ impl Tiles { dragging_initial_mouse: Point::default(), dragging_initial_bounds: Bounds::default(), resizing_id: None, + scrollbar_show: None, resizing_drag_data: None, bounds: Bounds::default(), history: History::new().group_interval(std::time::Duration::from_millis(100)), @@ -197,6 +200,16 @@ impl Tiles { } } + /// Set the scrollbar show mode [`ScrollbarShow`], if not set use the `cx.theme().scrollbar_show`. + pub fn set_scrollbar_show( + &mut self, + scrollbar_show: Option, + cx: &mut Context, + ) { + self.scrollbar_show = scrollbar_show; + cx.notify(); + } + pub fn panels(&self) -> &[TileItem] { &self.panels } @@ -1058,7 +1071,10 @@ impl Render for Tiles { .bottom_0() .child( Scrollbar::both(&self.scroll_state, &self.scroll_handle) - .scroll_size(scroll_size), + .scroll_size(scroll_size) + .when_some(self.scrollbar_show, |this, scrollbar_show| { + this.scrollbar_show(scrollbar_show) + }), ), ) .size_full() diff --git a/crates/ui/src/scroll/scrollbar.rs b/crates/ui/src/scroll/scrollbar.rs index 54f495a7..a94bf29e 100644 --- a/crates/ui/src/scroll/scrollbar.rs +++ b/crates/ui/src/scroll/scrollbar.rs @@ -7,11 +7,11 @@ use std::{ use crate::{ActiveTheme, AxisExt}; use gpui::{ - fill, point, px, relative, size, App, Axis, BorderStyle, Bounds, ContentMask, Corner, - CursorStyle, Edges, Element, GlobalElementId, Hitbox, HitboxBehavior, Hsla, InspectorElementId, - IntoElement, IsZero, LayoutId, ListState, MouseDownEvent, MouseMoveEvent, MouseUpEvent, - PaintQuad, Pixels, Point, Position, ScrollHandle, ScrollWheelEvent, Size, Style, Timer, - UniformListScrollHandle, Window, + fill, point, px, relative, size, App, Axis, BorderStyle, Bounds, + ContentMask, Corner, CursorStyle, Edges, Element, GlobalElementId, Hitbox, HitboxBehavior, + Hsla, InspectorElementId, IntoElement, IsZero, LayoutId, ListState, MouseDownEvent, + MouseMoveEvent, MouseUpEvent, PaintQuad, Pixels, Point, Position, ScrollHandle, + ScrollWheelEvent, Size, Style, Timer, UniformListScrollHandle, Window, }; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -289,6 +289,7 @@ impl ScrollbarAxis { /// Scrollbar control for scroll-area or a uniform-list. pub struct Scrollbar { axis: ScrollbarAxis, + scrollbar_show: Option, scroll_handle: Rc>, state: ScrollbarState, scroll_size: Option>, @@ -308,6 +309,7 @@ impl Scrollbar { Self { state: state.clone(), axis: axis.into(), + scrollbar_show: None, scroll_handle: Rc::new(Box::new(scroll_handle.clone())), max_fps: 120, scroll_size: None, @@ -327,6 +329,12 @@ impl Scrollbar { Self::new(ScrollbarAxis::Both, state, scroll_handle) } + /// Set the scrollbar show mode [`ScrollbarShow`], if not set use the `cx.theme().scrollbar_show`. + pub fn scrollbar_show(mut self, scrollbar_show: ScrollbarShow) -> Self { + self.scrollbar_show = Some(scrollbar_show); + self + } + /// Create with horizontal scrollbar. pub fn horizontal( state: &ScrollbarState, @@ -408,8 +416,9 @@ impl Scrollbar { ) } - fn style_for_normal(cx: &App) -> (Hsla, Hsla, Hsla, Pixels, Pixels, Pixels) { - let (width, inset, radius) = match cx.theme().scrollbar_show { + fn style_for_normal(&self, cx: &App) -> (Hsla, Hsla, Hsla, Pixels, Pixels, Pixels) { + let scrollbar_show = self.scrollbar_show.unwrap_or(cx.theme().scrollbar_show); + let (width, inset, radius) = match scrollbar_show { ScrollbarShow::Scrolling => (THUMB_WIDTH, THUMB_INSET, THUMB_RADIUS), _ => (THUMB_ACTIVE_WIDTH, THUMB_ACTIVE_INSET, THUMB_ACTIVE_RADIUS), }; @@ -424,8 +433,9 @@ impl Scrollbar { ) } - fn style_for_idle(cx: &App) -> (Hsla, Hsla, Hsla, Pixels, Pixels, Pixels) { - let (width, inset, radius) = match cx.theme().scrollbar_show { + fn style_for_idle(&self, cx: &App) -> (Hsla, Hsla, Hsla, Pixels, Pixels, Pixels) { + let scrollbar_show = self.scrollbar_show.unwrap_or(cx.theme().scrollbar_show); + let (width, inset, radius) = match scrollbar_show { ScrollbarShow::Scrolling => (THUMB_WIDTH, THUMB_INSET, THUMB_RADIUS), _ => (THUMB_ACTIVE_WIDTH, THUMB_ACTIVE_INSET, THUMB_ACTIVE_RADIUS), }; @@ -577,9 +587,10 @@ impl Element for Scrollbar { }, }; + let scrollbar_show = self.scrollbar_show.unwrap_or(cx.theme().scrollbar_show); let state = self.state.clone(); - let is_always_to_show = cx.theme().scrollbar_show.is_always(); - let is_hover_to_show = cx.theme().scrollbar_show.is_hover(); + let is_always_to_show = scrollbar_show.is_always(); + let is_hover_to_show = scrollbar_show.is_hover(); let is_hovered_on_bar = state.get().hovered_axis == Some(axis); let is_hovered_on_thumb = state.get().hovered_on_thumb == Some(axis); let is_offset_changed = state.get().last_scroll_offset != self.scroll_handle.offset(); @@ -594,7 +605,7 @@ impl Element for Scrollbar { Self::style_for_hovered_bar(cx) } } else if is_offset_changed { - Self::style_for_normal(cx) + self.style_for_normal(cx) } else if is_always_to_show { if is_hovered_on_thumb { Self::style_for_hovered_thumb(cx) @@ -602,7 +613,7 @@ impl Element for Scrollbar { Self::style_for_hovered_bar(cx) } } else { - let mut idle_state = Self::style_for_idle(cx); + let mut idle_state = self.style_for_idle(cx); // Delay 2s to fade out the scrollbar thumb (in 1s) if let Some(last_time) = state.get().last_scroll_time { let elapsed = Instant::now().duration_since(last_time).as_secs_f32(); @@ -705,11 +716,11 @@ impl Element for Scrollbar { window: &mut Window, cx: &mut App, ) { + let scrollbar_show = self.scrollbar_show.unwrap_or(cx.theme().scrollbar_show); let view_id = window.current_view(); let hitbox_bounds = prepaint.hitbox.bounds; - let is_visible = - self.state.get().is_scrollbar_visible() || cx.theme().scrollbar_show.is_always(); - let is_hover_to_show = cx.theme().scrollbar_show.is_hover(); + let is_visible = self.state.get().is_scrollbar_visible() || scrollbar_show.is_always(); + let is_hover_to_show = scrollbar_show.is_hover(); // Update last_scroll_time when offset is changed. if self.scroll_handle.offset() != self.state.get().last_scroll_offset {