theme: Add to support always show scrollbar mode and default to match with system style. (#621)
Close #573 - Fix theme settings to keeping when switch theme mode.
This commit is contained in:
parent
ec3d8e50ed
commit
437f1b2098
7 changed files with 188 additions and 72 deletions
35
crates/story/examples/scrollable.rs
Normal file
35
crates/story/examples/scrollable.rs
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
use gpui::*;
|
||||||
|
use story::{Assets, ScrollableStory};
|
||||||
|
|
||||||
|
pub struct Example {
|
||||||
|
story: Entity<ScrollableStory>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Example {
|
||||||
|
pub fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
|
||||||
|
let story = ScrollableStory::view(window, cx);
|
||||||
|
|
||||||
|
Self { story }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn view(window: &mut Window, cx: &mut App) -> Entity<Self> {
|
||||||
|
cx.new(|cx| Self::new(window, cx))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Render for Example {
|
||||||
|
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
|
||||||
|
div().p_4().size_full().child(self.story.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let app = Application::new().with_assets(Assets);
|
||||||
|
|
||||||
|
app.run(move |cx| {
|
||||||
|
story::init(cx);
|
||||||
|
cx.activate(true);
|
||||||
|
|
||||||
|
story::create_new_window("Scrollable Example", Example::view, cx);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -6,12 +6,12 @@ use gpui::{
|
||||||
ParentElement, Pixels, Render, ScrollHandle, SharedString, Size, Styled, Window,
|
ParentElement, Pixels, Render, ScrollHandle, SharedString, Size, Styled, Window,
|
||||||
};
|
};
|
||||||
use gpui_component::{
|
use gpui_component::{
|
||||||
button::Button,
|
button::{Button, ButtonGroup},
|
||||||
divider::Divider,
|
divider::Divider,
|
||||||
gray_100, gray_800, h_flex,
|
gray_100, gray_800, h_flex,
|
||||||
label::Label,
|
label::Label,
|
||||||
scroll::{Scrollbar, ScrollbarAxis, ScrollbarState},
|
scroll::{Scrollbar, ScrollbarAxis, ScrollbarState},
|
||||||
v_flex, v_virtual_list, ActiveTheme as _, StyledExt as _,
|
v_flex, v_virtual_list, ActiveTheme as _, Selectable, StyledExt as _,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct ScrollableStory {
|
pub struct ScrollableStory {
|
||||||
|
|
@ -23,6 +23,7 @@ pub struct ScrollableStory {
|
||||||
item_sizes: Rc<Vec<Size<Pixels>>>,
|
item_sizes: Rc<Vec<Size<Pixels>>>,
|
||||||
test_width: Pixels,
|
test_width: Pixels,
|
||||||
axis: ScrollbarAxis,
|
axis: ScrollbarAxis,
|
||||||
|
size_mode: usize,
|
||||||
message: SharedString,
|
message: SharedString,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -46,6 +47,7 @@ impl ScrollableStory {
|
||||||
item_sizes: Rc::new(item_sizes),
|
item_sizes: Rc::new(item_sizes),
|
||||||
test_width,
|
test_width,
|
||||||
axis: ScrollbarAxis::Both,
|
axis: ScrollbarAxis::Both,
|
||||||
|
size_mode: 0,
|
||||||
message: SharedString::default(),
|
message: SharedString::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -55,6 +57,7 @@ impl ScrollableStory {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn change_test_cases(&mut self, n: usize, cx: &mut Context<Self>) {
|
pub fn change_test_cases(&mut self, n: usize, cx: &mut Context<Self>) {
|
||||||
|
self.size_mode = n;
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
self.items = (0..5000).map(|i| format!("Item {}", i)).collect::<Vec<_>>();
|
self.items = (0..5000).map(|i| format!("Item {}", i)).collect::<Vec<_>>();
|
||||||
self.test_width = px(3000.);
|
self.test_width = px(3000.);
|
||||||
|
|
@ -98,46 +101,66 @@ impl ScrollableStory {
|
||||||
.child(
|
.child(
|
||||||
h_flex()
|
h_flex()
|
||||||
.gap_2()
|
.gap_2()
|
||||||
.child(Button::new("test-0").label("Size 0").on_click(cx.listener(
|
.child(
|
||||||
|view, _, _, cx| {
|
ButtonGroup::new("test-cases")
|
||||||
view.change_test_cases(0, cx);
|
.child(
|
||||||
},
|
Button::new("test-0")
|
||||||
)))
|
.label("Size 0")
|
||||||
.child(Button::new("test-1").label("Size 1").on_click(cx.listener(
|
.selected(self.size_mode == 0),
|
||||||
|view, _, _, cx| {
|
)
|
||||||
view.change_test_cases(1, cx);
|
.child(
|
||||||
},
|
Button::new("test-1")
|
||||||
)))
|
.label("Size 1")
|
||||||
.child(Button::new("test-2").label("Size 2").on_click(cx.listener(
|
.selected(self.size_mode == 1),
|
||||||
|view, _, _, cx| {
|
)
|
||||||
view.change_test_cases(2, cx);
|
.child(
|
||||||
},
|
Button::new("test-2")
|
||||||
)))
|
.label("Size 2")
|
||||||
.child(Button::new("test-3").label("Size 3").on_click(cx.listener(
|
.selected(self.size_mode == 2),
|
||||||
|view, _, _, cx| {
|
)
|
||||||
view.change_test_cases(3, cx);
|
.child(
|
||||||
},
|
Button::new("test-3")
|
||||||
)))
|
.label("Size 3")
|
||||||
|
.selected(self.size_mode == 3),
|
||||||
|
)
|
||||||
|
.on_click(cx.listener(|view, clicks: &Vec<usize>, _, cx| {
|
||||||
|
if clicks.contains(&0) {
|
||||||
|
view.change_test_cases(0, cx)
|
||||||
|
} else if clicks.contains(&1) {
|
||||||
|
view.change_test_cases(1, cx)
|
||||||
|
} else if clicks.contains(&2) {
|
||||||
|
view.change_test_cases(2, cx)
|
||||||
|
} else if clicks.contains(&3) {
|
||||||
|
view.change_test_cases(3, cx)
|
||||||
|
}
|
||||||
|
})),
|
||||||
|
)
|
||||||
.child(Divider::vertical().px_2())
|
.child(Divider::vertical().px_2())
|
||||||
.child(
|
.child(
|
||||||
Button::new("test-axis-both")
|
ButtonGroup::new("scrollbars")
|
||||||
.label("Both Scrollbar")
|
.child(
|
||||||
.on_click(cx.listener(|view, _, _, cx| {
|
Button::new("test-axis-both")
|
||||||
view.change_axis(ScrollbarAxis::Both, cx)
|
.label("Both Scrollbar")
|
||||||
})),
|
.selected(self.axis == ScrollbarAxis::Both),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
Button::new("test-axis-vertical")
|
Button::new("test-axis-vertical")
|
||||||
.label("Vertical")
|
.label("Vertical")
|
||||||
.on_click(cx.listener(|view, _, _, cx| {
|
.selected(self.axis == ScrollbarAxis::Vertical),
|
||||||
view.change_axis(ScrollbarAxis::Vertical, cx)
|
)
|
||||||
})),
|
.child(
|
||||||
)
|
Button::new("test-axis-horizontal")
|
||||||
.child(
|
.label("Horizontal")
|
||||||
Button::new("test-axis-horizontal")
|
.selected(self.axis == ScrollbarAxis::Horizontal),
|
||||||
.label("Horizontal")
|
)
|
||||||
.on_click(cx.listener(|view, _, _, cx| {
|
.on_click(cx.listener(|view, clicks: &Vec<usize>, _, cx| {
|
||||||
view.change_axis(ScrollbarAxis::Horizontal, cx)
|
if clicks.contains(&0) {
|
||||||
|
view.change_axis(ScrollbarAxis::Both, cx)
|
||||||
|
} else if clicks.contains(&1) {
|
||||||
|
view.change_axis(ScrollbarAxis::Vertical, cx)
|
||||||
|
} else if clicks.contains(&2) {
|
||||||
|
view.change_axis(ScrollbarAxis::Horizontal, cx)
|
||||||
|
}
|
||||||
})),
|
})),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
@ -179,8 +202,8 @@ impl Render for ScrollableStory {
|
||||||
.gap_4()
|
.gap_4()
|
||||||
.child(self.render_buttons(cx))
|
.child(self.render_buttons(cx))
|
||||||
.child(
|
.child(
|
||||||
div().w_full().child(
|
div().w_full().flex_1().child(
|
||||||
div().relative().w_full().h(px(350.)).child(
|
div().relative().size_full().child(
|
||||||
v_flex()
|
v_flex()
|
||||||
.id("test-0")
|
.id("test-0")
|
||||||
.relative()
|
.relative()
|
||||||
|
|
@ -265,8 +288,8 @@ impl Render for ScrollableStory {
|
||||||
.border_1()
|
.border_1()
|
||||||
.border_color(cx.theme().border)
|
.border_color(cx.theme().border)
|
||||||
.w_full()
|
.w_full()
|
||||||
.overflow_hidden()
|
|
||||||
.max_h(px(400.))
|
.max_h(px(400.))
|
||||||
|
.min_h(px(200.))
|
||||||
.child(
|
.child(
|
||||||
v_flex()
|
v_flex()
|
||||||
.p_3()
|
.p_3()
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,12 @@ impl AppTitleBar {
|
||||||
let locale_selector = cx.new(|cx| LocaleSelector::new(window, cx));
|
let locale_selector = cx.new(|cx| LocaleSelector::new(window, cx));
|
||||||
let font_size_selector = cx.new(|cx| FontSizeSelector::new(window, cx));
|
let font_size_selector = cx.new(|cx| FontSizeSelector::new(window, cx));
|
||||||
|
|
||||||
|
if cx.should_auto_hide_scrollbars() {
|
||||||
|
Theme::global_mut(cx).scrollbar_show = ScrollbarShow::Scrolling;
|
||||||
|
} else {
|
||||||
|
Theme::global_mut(cx).scrollbar_show = ScrollbarShow::Always;
|
||||||
|
}
|
||||||
|
|
||||||
let theme_color_picker = cx.new(|cx| {
|
let theme_color_picker = cx.new(|cx| {
|
||||||
let mut picker = ColorPicker::new("theme-color-picker", window, cx)
|
let mut picker = ColorPicker::new("theme-color-picker", window, cx)
|
||||||
.xsmall()
|
.xsmall()
|
||||||
|
|
@ -299,6 +305,11 @@ impl Render for FontSizeSelector {
|
||||||
scroll_show == ScrollbarShow::Hover,
|
scroll_show == ScrollbarShow::Hover,
|
||||||
Box::new(SelectScrollbarShow(ScrollbarShow::Hover)),
|
Box::new(SelectScrollbarShow(ScrollbarShow::Hover)),
|
||||||
)
|
)
|
||||||
|
.menu_with_check(
|
||||||
|
"Always show Scrollbar",
|
||||||
|
scroll_show == ScrollbarShow::Always,
|
||||||
|
Box::new(SelectScrollbarShow(ScrollbarShow::Always)),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
.anchor(Corner::TopRight),
|
.anchor(Corner::TopRight),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,26 @@ impl ButtonGroup {
|
||||||
/// Sets the on_click handler for the ButtonGroup.
|
/// Sets the on_click handler for the ButtonGroup.
|
||||||
///
|
///
|
||||||
/// The handler first argument is a vector of the selected button indices.
|
/// The handler first argument is a vector of the selected button indices.
|
||||||
|
///
|
||||||
|
/// The `&Vec<usize>` is the indices of the clicked (selected in `multiple` mode) buttons.
|
||||||
|
/// For example: `[0, 2, 3]` is means the first, third and fourth buttons are clicked.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// ButtonGroup::new("size-button")
|
||||||
|
/// .child(Button::new("large").label("Large").selected(self.size == Size::Large))
|
||||||
|
/// .child(Button::new("medium").label("Medium").selected(self.size == Size::Medium))
|
||||||
|
/// .child(Button::new("small").label("Small").selected(self.size == Size::Small))
|
||||||
|
/// .on_click(cx.listener(|view, clicks: &Vec<usize>, _, cx| {
|
||||||
|
/// if clicks.contains(&0) {
|
||||||
|
/// view.size = Size::Large;
|
||||||
|
/// } else if clicks.contains(&1) {
|
||||||
|
/// view.size = Size::Medium;
|
||||||
|
/// } else if clicks.contains(&2) {
|
||||||
|
/// view.size = Size::Small;
|
||||||
|
/// }
|
||||||
|
/// cx.notify();
|
||||||
|
/// }))
|
||||||
|
/// ```
|
||||||
pub fn on_click(
|
pub fn on_click(
|
||||||
mut self,
|
mut self,
|
||||||
handler: impl Fn(&Vec<usize>, &mut Window, &mut App) + 'static,
|
handler: impl Fn(&Vec<usize>, &mut Window, &mut App) + 'static,
|
||||||
|
|
|
||||||
|
|
@ -18,18 +18,24 @@ pub enum ScrollbarShow {
|
||||||
#[default]
|
#[default]
|
||||||
Scrolling,
|
Scrolling,
|
||||||
Hover,
|
Hover,
|
||||||
|
Always,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScrollbarShow {
|
impl ScrollbarShow {
|
||||||
fn is_hover(&self) -> bool {
|
fn is_hover(&self) -> bool {
|
||||||
matches!(self, Self::Hover)
|
matches!(self, Self::Hover)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_always(&self) -> bool {
|
||||||
|
matches!(self, Self::Always)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const BORDER_WIDTH: Pixels = px(0.);
|
const BORDER_WIDTH: Pixels = px(0.);
|
||||||
|
const WIDTH: Pixels = px(12.);
|
||||||
const MIN_THUMB_SIZE: f32 = 80.;
|
const MIN_THUMB_SIZE: f32 = 80.;
|
||||||
const THUMB_RADIUS: Pixels = Pixels(3.0);
|
const THUMB_RADIUS: Pixels = Pixels(4.0);
|
||||||
const THUMB_INSET: Pixels = Pixels(4.);
|
const THUMB_INSET: Pixels = Pixels(3.);
|
||||||
const FADE_OUT_DURATION: f32 = 3.0;
|
const FADE_OUT_DURATION: f32 = 3.0;
|
||||||
const FADE_OUT_DELAY: f32 = 2.0;
|
const FADE_OUT_DELAY: f32 = 2.0;
|
||||||
|
|
||||||
|
|
@ -153,6 +159,10 @@ impl ScrollbarState {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_scrollbar_visible(&self) -> bool {
|
fn is_scrollbar_visible(&self) -> bool {
|
||||||
|
if self.hovered_axis.is_some() || self.dragged_axis.is_some() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(last_time) = self.last_scroll_time {
|
if let Some(last_time) = self.last_scroll_time {
|
||||||
let elapsed = Instant::now().duration_since(last_time).as_secs_f32();
|
let elapsed = Instant::now().duration_since(last_time).as_secs_f32();
|
||||||
elapsed < FADE_OUT_DURATION
|
elapsed < FADE_OUT_DURATION
|
||||||
|
|
@ -195,9 +205,9 @@ impl ScrollbarAxis {
|
||||||
match self {
|
match self {
|
||||||
Self::Vertical => vec![Self::Vertical],
|
Self::Vertical => vec![Self::Vertical],
|
||||||
Self::Horizontal => vec![Self::Horizontal],
|
Self::Horizontal => vec![Self::Horizontal],
|
||||||
// This should keep vertical first, vertical is the primary axis
|
// This should keep Horizontal first, Vertical is the primary axis
|
||||||
// if vertical not need display, then horizontal will not keep right margin.
|
// if Vertical not need display, then Horizontal will not keep right margin.
|
||||||
Self::Both => vec![Self::Vertical, Self::Horizontal],
|
Self::Both => vec![Self::Horizontal, Self::Vertical],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -206,8 +216,6 @@ impl ScrollbarAxis {
|
||||||
pub struct Scrollbar {
|
pub struct Scrollbar {
|
||||||
view_id: EntityId,
|
view_id: EntityId,
|
||||||
axis: ScrollbarAxis,
|
axis: ScrollbarAxis,
|
||||||
/// When is vertical, this is the height of the scrollbar.
|
|
||||||
width: Pixels,
|
|
||||||
scroll_handle: Rc<Box<dyn ScrollHandleOffsetable>>,
|
scroll_handle: Rc<Box<dyn ScrollHandleOffsetable>>,
|
||||||
scroll_size: gpui::Size<Pixels>,
|
scroll_size: gpui::Size<Pixels>,
|
||||||
state: Rc<Cell<ScrollbarState>>,
|
state: Rc<Cell<ScrollbarState>>,
|
||||||
|
|
@ -231,7 +239,6 @@ impl Scrollbar {
|
||||||
state,
|
state,
|
||||||
axis,
|
axis,
|
||||||
scroll_size,
|
scroll_size,
|
||||||
width: px(12.),
|
|
||||||
scroll_handle: Rc::new(Box::new(scroll_handle)),
|
scroll_handle: Rc::new(Box::new(scroll_handle)),
|
||||||
max_fps: 120,
|
max_fps: 120,
|
||||||
}
|
}
|
||||||
|
|
@ -459,7 +466,7 @@ impl Element for Scrollbar {
|
||||||
|
|
||||||
// The horizontal scrollbar is set avoid overlapping with the vertical scrollbar, if the vertical scrollbar is visible.
|
// The horizontal scrollbar is set avoid overlapping with the vertical scrollbar, if the vertical scrollbar is visible.
|
||||||
let margin_end = if has_both && !is_vertical {
|
let margin_end = if has_both && !is_vertical {
|
||||||
self.width
|
WIDTH
|
||||||
} else {
|
} else {
|
||||||
px(0.)
|
px(0.)
|
||||||
};
|
};
|
||||||
|
|
@ -478,31 +485,29 @@ impl Element for Scrollbar {
|
||||||
|
|
||||||
let bounds = Bounds {
|
let bounds = Bounds {
|
||||||
origin: if is_vertical {
|
origin: if is_vertical {
|
||||||
point(
|
point(hitbox.origin.x + hitbox.size.width - WIDTH, hitbox.origin.y)
|
||||||
hitbox.origin.x + hitbox.size.width - self.width,
|
|
||||||
hitbox.origin.y,
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
point(
|
point(
|
||||||
hitbox.origin.x,
|
hitbox.origin.x,
|
||||||
hitbox.origin.y + hitbox.size.height - self.width,
|
hitbox.origin.y + hitbox.size.height - WIDTH,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
size: gpui::Size {
|
size: gpui::Size {
|
||||||
width: if is_vertical {
|
width: if is_vertical {
|
||||||
self.width
|
WIDTH
|
||||||
} else {
|
} else {
|
||||||
hitbox.size.width
|
hitbox.size.width
|
||||||
},
|
},
|
||||||
height: if is_vertical {
|
height: if is_vertical {
|
||||||
hitbox.size.height
|
hitbox.size.height
|
||||||
} else {
|
} else {
|
||||||
self.width
|
WIDTH
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let state = self.state.clone();
|
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_hover_to_show = cx.theme().scrollbar_show.is_hover();
|
||||||
let is_hovered_on_bar = state.get().hovered_axis == Some(axis);
|
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_hovered_on_thumb = state.get().hovered_on_thumb == Some(axis);
|
||||||
|
|
@ -510,7 +515,13 @@ impl Element for Scrollbar {
|
||||||
let (thumb_bg, bar_bg, bar_border, inset, radius) =
|
let (thumb_bg, bar_bg, bar_border, inset, radius) =
|
||||||
if state.get().dragged_axis == Some(axis) {
|
if state.get().dragged_axis == Some(axis) {
|
||||||
Self::style_for_active(cx)
|
Self::style_for_active(cx)
|
||||||
} else if is_hover_to_show && is_hovered_on_bar {
|
} else if is_hover_to_show && (is_hovered_on_bar || is_hovered_on_thumb) {
|
||||||
|
if is_hovered_on_thumb {
|
||||||
|
Self::style_for_hovered_thumb(cx)
|
||||||
|
} else {
|
||||||
|
Self::style_for_hovered_bar(cx)
|
||||||
|
}
|
||||||
|
} else if is_always_to_show {
|
||||||
if is_hovered_on_thumb {
|
if is_hovered_on_thumb {
|
||||||
Self::style_for_hovered_thumb(cx)
|
Self::style_for_hovered_thumb(cx)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -549,12 +560,12 @@ impl Element for Scrollbar {
|
||||||
let thumb_bounds = if is_vertical {
|
let thumb_bounds = if is_vertical {
|
||||||
Bounds::from_corners(
|
Bounds::from_corners(
|
||||||
point(bounds.origin.x, bounds.origin.y + thumb_start),
|
point(bounds.origin.x, bounds.origin.y + thumb_start),
|
||||||
point(bounds.origin.x + self.width, bounds.origin.y + thumb_end),
|
point(bounds.origin.x + WIDTH, bounds.origin.y + thumb_end),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Bounds::from_corners(
|
Bounds::from_corners(
|
||||||
point(bounds.origin.x + thumb_start, bounds.origin.y),
|
point(bounds.origin.x + thumb_start, bounds.origin.y),
|
||||||
point(bounds.origin.x + thumb_end, bounds.origin.y + self.width),
|
point(bounds.origin.x + thumb_end, bounds.origin.y + WIDTH),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
let thumb_fill_bounds = if is_vertical {
|
let thumb_fill_bounds = if is_vertical {
|
||||||
|
|
@ -564,7 +575,7 @@ impl Element for Scrollbar {
|
||||||
bounds.origin.y + thumb_start + inset,
|
bounds.origin.y + thumb_start + inset,
|
||||||
),
|
),
|
||||||
point(
|
point(
|
||||||
bounds.origin.x + self.width - inset,
|
bounds.origin.x + WIDTH - inset,
|
||||||
bounds.origin.y + thumb_end - inset,
|
bounds.origin.y + thumb_end - inset,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
@ -576,7 +587,7 @@ impl Element for Scrollbar {
|
||||||
),
|
),
|
||||||
point(
|
point(
|
||||||
bounds.origin.x + thumb_end - inset,
|
bounds.origin.x + thumb_end - inset,
|
||||||
bounds.origin.y + self.width - inset,
|
bounds.origin.y + WIDTH - inset,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1628,11 +1628,11 @@ where
|
||||||
.absolute()
|
.absolute()
|
||||||
.top_0()
|
.top_0()
|
||||||
.size_full()
|
.size_full()
|
||||||
.when(self.scrollbar_visible.right && rows_count > 0, |this| {
|
|
||||||
this.children(self.render_vertical_scrollbar(window, cx))
|
|
||||||
})
|
|
||||||
.when(self.scrollbar_visible.bottom, |this| {
|
.when(self.scrollbar_visible.bottom, |this| {
|
||||||
this.child(self.render_horizontal_scrollbar(window, cx))
|
this.child(self.render_horizontal_scrollbar(window, cx))
|
||||||
|
})
|
||||||
|
.when(self.scrollbar_visible.right && rows_count > 0, |this| {
|
||||||
|
this.children(self.render_vertical_scrollbar(window, cx))
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,8 @@ use gpui::{
|
||||||
use crate::{scroll::ScrollbarShow, Colorize as _};
|
use crate::{scroll::ScrollbarShow, Colorize as _};
|
||||||
|
|
||||||
pub fn init(cx: &mut App) {
|
pub fn init(cx: &mut App) {
|
||||||
Theme::sync_system_appearance(None, cx)
|
Theme::sync_system_appearance(None, cx);
|
||||||
|
Theme::sync_scrollbar_appearance(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ActiveTheme {
|
pub trait ActiveTheme {
|
||||||
|
|
@ -244,7 +245,7 @@ impl ThemeColor {
|
||||||
primary_hover: hsl(223.0, 5.9, 15.0),
|
primary_hover: hsl(223.0, 5.9, 15.0),
|
||||||
progress_bar: hsl(223.0, 5.9, 10.0),
|
progress_bar: hsl(223.0, 5.9, 10.0),
|
||||||
ring: hsl(240.0, 5.9, 65.0),
|
ring: hsl(240.0, 5.9, 65.0),
|
||||||
scrollbar: hsl(0., 0., 97.).opacity(0.75),
|
scrollbar: hsl(0., 0., 92.).opacity(0.75),
|
||||||
scrollbar_thumb: hsl(0., 0., 69.).opacity(0.9),
|
scrollbar_thumb: hsl(0., 0., 69.).opacity(0.9),
|
||||||
scrollbar_thumb_hover: hsl(0., 0., 59.),
|
scrollbar_thumb_hover: hsl(0., 0., 59.),
|
||||||
secondary: hsl(240.0, 5.9, 96.9),
|
secondary: hsl(240.0, 5.9, 96.9),
|
||||||
|
|
@ -487,16 +488,31 @@ impl Theme {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sync the Scrollbar showing behavior with the system
|
||||||
|
pub fn sync_scrollbar_appearance(cx: &mut App) {
|
||||||
|
if cx.should_auto_hide_scrollbars() {
|
||||||
|
cx.global_mut::<Theme>().scrollbar_show = ScrollbarShow::Scrolling;
|
||||||
|
} else {
|
||||||
|
cx.global_mut::<Theme>().scrollbar_show = ScrollbarShow::Always;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn change(mode: ThemeMode, window: Option<&mut Window>, cx: &mut App) {
|
pub fn change(mode: ThemeMode, window: Option<&mut Window>, cx: &mut App) {
|
||||||
let colors = match mode {
|
let colors = match mode {
|
||||||
ThemeMode::Light => ThemeColor::light(),
|
ThemeMode::Light => ThemeColor::light(),
|
||||||
ThemeMode::Dark => ThemeColor::dark(),
|
ThemeMode::Dark => ThemeColor::dark(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut theme = Theme::from(colors);
|
if !cx.has_global::<Theme>() {
|
||||||
theme.mode = mode;
|
let theme = Theme::from(colors);
|
||||||
|
cx.set_global(theme);
|
||||||
|
}
|
||||||
|
|
||||||
|
let theme = cx.global_mut::<Theme>();
|
||||||
|
|
||||||
|
theme.mode = mode;
|
||||||
|
theme.colors = colors;
|
||||||
|
|
||||||
cx.set_global(theme);
|
|
||||||
if let Some(window) = window {
|
if let Some(window) = window {
|
||||||
window.refresh();
|
window.refresh();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue