scrollbar: Improve scrollbar behaviour. (#481)
- Only show scroll when recent scrolled. - Keep showing scrollbar when is visible and hovered on. - Delay 3s to fade out. - If not visible, do not handle mouse down event. - Add `cx.theme().scrollbar_show` option to control scrollbar show `[Hover, Scrolling]`, default: `Scrolling`. Close #472 
This commit is contained in:
parent
26024ba2b5
commit
2836540260
4 changed files with 198 additions and 83 deletions
|
|
@ -14,6 +14,7 @@ use ui::{
|
||||||
dock::{DockArea, DockAreaState, DockEvent, DockItem, DockPlacement},
|
dock::{DockArea, DockAreaState, DockEvent, DockItem, DockPlacement},
|
||||||
h_flex,
|
h_flex,
|
||||||
popup_menu::PopupMenuExt,
|
popup_menu::PopupMenuExt,
|
||||||
|
scroll::ScrollbarShow,
|
||||||
theme::{ActiveTheme, Theme},
|
theme::{ActiveTheme, Theme},
|
||||||
ContextModal, IconName, Root, Sizable, TitleBar,
|
ContextModal, IconName, Root, Sizable, TitleBar,
|
||||||
};
|
};
|
||||||
|
|
@ -25,6 +26,9 @@ const MAIN_DOCK_AREA: DockAreaTab = DockAreaTab {
|
||||||
version: 5,
|
version: 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq, Deserialize)]
|
||||||
|
struct SelectScrollbarShow(ScrollbarShow);
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Deserialize)]
|
#[derive(Clone, PartialEq, Eq, Deserialize)]
|
||||||
struct SelectLocale(SharedString);
|
struct SelectLocale(SharedString);
|
||||||
|
|
||||||
|
|
@ -34,7 +38,10 @@ struct SelectFont(usize);
|
||||||
#[derive(Clone, PartialEq, Eq, Deserialize)]
|
#[derive(Clone, PartialEq, Eq, Deserialize)]
|
||||||
struct AddPanel(DockPlacement);
|
struct AddPanel(DockPlacement);
|
||||||
|
|
||||||
impl_actions!(story, [SelectLocale, SelectFont, AddPanel]);
|
impl_actions!(
|
||||||
|
story,
|
||||||
|
[SelectLocale, SelectFont, AddPanel, SelectScrollbarShow]
|
||||||
|
);
|
||||||
|
|
||||||
actions!(workspace, [Open, CloseWindow]);
|
actions!(workspace, [Open, CloseWindow]);
|
||||||
|
|
||||||
|
|
@ -573,30 +580,52 @@ impl FontSizeSelector {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_select(&mut self, font_size: &SelectFont, cx: &mut ViewContext<Self>) {
|
fn on_select_font(&mut self, font_size: &SelectFont, cx: &mut ViewContext<Self>) {
|
||||||
Theme::global_mut(cx).font_size = font_size.0 as f32;
|
Theme::global_mut(cx).font_size = font_size.0 as f32;
|
||||||
cx.refresh();
|
cx.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn on_select_scrollbar_show(&mut self, show: &SelectScrollbarShow, cx: &mut ViewContext<Self>) {
|
||||||
|
Theme::global_mut(cx).scrollbar_show = show.0;
|
||||||
|
cx.refresh();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Render for FontSizeSelector {
|
impl Render for FontSizeSelector {
|
||||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||||
let focus_handle = self.focus_handle.clone();
|
let focus_handle = self.focus_handle.clone();
|
||||||
let font_size = cx.theme().font_size as i32;
|
let font_size = cx.theme().font_size as i32;
|
||||||
|
let scroll_show = cx.theme().scrollbar_show;
|
||||||
|
|
||||||
div()
|
div()
|
||||||
.id("font-size-selector")
|
.id("font-size-selector")
|
||||||
.track_focus(&focus_handle)
|
.track_focus(&focus_handle)
|
||||||
.on_action(cx.listener(Self::on_select))
|
.on_action(cx.listener(Self::on_select_font))
|
||||||
|
.on_action(cx.listener(Self::on_select_scrollbar_show))
|
||||||
.child(
|
.child(
|
||||||
Button::new("btn")
|
Button::new("btn")
|
||||||
.small()
|
.small()
|
||||||
.ghost()
|
.ghost()
|
||||||
.icon(IconName::ALargeSmall)
|
.icon(IconName::Settings2)
|
||||||
.popup_menu(move |this, _| {
|
.popup_menu(move |this, _| {
|
||||||
this.menu_with_check("Large", font_size == 18, Box::new(SelectFont(18)))
|
this.menu_with_check(
|
||||||
.menu_with_check("Default", font_size == 16, Box::new(SelectFont(16)))
|
"Font Large",
|
||||||
.menu_with_check("Small", font_size == 14, Box::new(SelectFont(14)))
|
font_size == 18,
|
||||||
|
Box::new(SelectFont(18)),
|
||||||
|
)
|
||||||
|
.menu_with_check("Font Default", font_size == 16, Box::new(SelectFont(16)))
|
||||||
|
.menu_with_check("Font Small", font_size == 14, Box::new(SelectFont(14)))
|
||||||
|
.separator()
|
||||||
|
.menu_with_check(
|
||||||
|
"Scrolling to show Scrollbar",
|
||||||
|
scroll_show == ScrollbarShow::Scrolling,
|
||||||
|
Box::new(SelectScrollbarShow(ScrollbarShow::Scrolling)),
|
||||||
|
)
|
||||||
|
.menu_with_check(
|
||||||
|
"Hover to show Scrollbar",
|
||||||
|
scroll_show == ScrollbarShow::Hover,
|
||||||
|
Box::new(SelectScrollbarShow(ScrollbarShow::Hover)),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
.anchor(AnchorCorner::TopRight),
|
.anchor(AnchorCorner::TopRight),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1249,7 +1249,7 @@ impl Render for TextInput {
|
||||||
.absolute()
|
.absolute()
|
||||||
.top_0()
|
.top_0()
|
||||||
.left_0()
|
.left_0()
|
||||||
.right_0()
|
.right(px(1.))
|
||||||
.bottom_0()
|
.bottom_0()
|
||||||
.child(
|
.child(
|
||||||
Scrollbar::vertical(
|
Scrollbar::vertical(
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,32 @@ use std::{cell::Cell, rc::Rc, time::Instant};
|
||||||
|
|
||||||
use crate::theme::ActiveTheme;
|
use crate::theme::ActiveTheme;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
fill, point, px, relative, Bounds, ContentMask, CursorStyle, Edges, Element, EntityId, Hitbox,
|
fill, point, px, relative, AppContext, Bounds, ContentMask, CursorStyle, Edges, Element,
|
||||||
Hsla, IntoElement, MouseDownEvent, MouseMoveEvent, MouseUpEvent, PaintQuad, Pixels, Point,
|
EntityId, Hitbox, Hsla, IntoElement, MouseDownEvent, MouseMoveEvent, MouseUpEvent, PaintQuad,
|
||||||
Position, ScrollHandle, ScrollWheelEvent, Style, UniformListScrollHandle,
|
Pixels, Point, Position, ScrollHandle, ScrollWheelEvent, Style, UniformListScrollHandle,
|
||||||
};
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
/// Scrollbar show mode.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash, Default)]
|
||||||
|
pub enum ScrollbarShow {
|
||||||
|
#[default]
|
||||||
|
Scrolling,
|
||||||
|
Hover,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ScrollbarShow {
|
||||||
|
fn is_hover(&self) -> bool {
|
||||||
|
matches!(self, Self::Hover)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const MIN_THUMB_SIZE: f32 = 80.;
|
const MIN_THUMB_SIZE: f32 = 80.;
|
||||||
const THUMB_RADIUS: Pixels = Pixels(3.0);
|
const THUMB_RADIUS: Pixels = Pixels(3.0);
|
||||||
const THUMB_INSET: Pixels = Pixels(4.);
|
const THUMB_INSET: Pixels = Pixels(4.);
|
||||||
|
const FADE_OUT_DURATION: f32 = 3.0;
|
||||||
|
const FADE_OUT_DELAY: f32 = 2.0;
|
||||||
|
const NORMAL_OPACITY: f32 = 0.6;
|
||||||
|
|
||||||
pub trait ScrollHandleOffsetable {
|
pub trait ScrollHandleOffsetable {
|
||||||
fn offset(&self) -> Point<Pixels>;
|
fn offset(&self) -> Point<Pixels>;
|
||||||
|
|
@ -92,6 +110,9 @@ impl ScrollbarState {
|
||||||
fn with_hovered(&self, axis: Option<ScrollbarAxis>) -> Self {
|
fn with_hovered(&self, axis: Option<ScrollbarAxis>) -> Self {
|
||||||
let mut state = *self;
|
let mut state = *self;
|
||||||
state.hovered_axis = axis;
|
state.hovered_axis = axis;
|
||||||
|
if self.is_scrollbar_visible() {
|
||||||
|
state.last_scroll_time = Some(Instant::now());
|
||||||
|
}
|
||||||
state
|
state
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -111,6 +132,21 @@ impl ScrollbarState {
|
||||||
state.last_scroll_time = last_scroll_time;
|
state.last_scroll_time = last_scroll_time;
|
||||||
state
|
state
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn with_last_scroll_time(&self, t: Option<Instant>) -> Self {
|
||||||
|
let mut state = *self;
|
||||||
|
state.last_scroll_time = t;
|
||||||
|
state
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_scrollbar_visible(&self) -> bool {
|
||||||
|
if let Some(last_time) = self.last_scroll_time {
|
||||||
|
let elapsed = Instant::now().duration_since(last_time).as_secs_f32();
|
||||||
|
elapsed < FADE_OUT_DURATION
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
|
@ -257,6 +293,52 @@ impl Scrollbar {
|
||||||
self.axis = axis;
|
self.axis = axis;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn style_for_default(cx: &AppContext) -> (Hsla, Hsla, Hsla, Pixels, Pixels) {
|
||||||
|
(
|
||||||
|
cx.theme().scrollbar_thumb,
|
||||||
|
cx.theme().scrollbar,
|
||||||
|
cx.theme().border,
|
||||||
|
THUMB_INSET - px(1.),
|
||||||
|
THUMB_RADIUS,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn style_for_hovered_thumb(cx: &AppContext) -> (Hsla, Hsla, Hsla, Pixels, Pixels) {
|
||||||
|
(
|
||||||
|
cx.theme().scrollbar_thumb,
|
||||||
|
cx.theme().scrollbar,
|
||||||
|
cx.theme().border,
|
||||||
|
THUMB_INSET - px(1.),
|
||||||
|
THUMB_RADIUS,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn style_for_hovered_bar(cx: &AppContext) -> (Hsla, Hsla, Hsla, Pixels, Pixels) {
|
||||||
|
let (inset, radius) = if cx.theme().scrollbar_show.is_hover() {
|
||||||
|
(THUMB_INSET, THUMB_RADIUS - px(1.))
|
||||||
|
} else {
|
||||||
|
(THUMB_INSET - px(1.), THUMB_RADIUS)
|
||||||
|
};
|
||||||
|
|
||||||
|
(
|
||||||
|
cx.theme().scrollbar_thumb.opacity(NORMAL_OPACITY),
|
||||||
|
gpui::transparent_black(),
|
||||||
|
gpui::transparent_black(),
|
||||||
|
inset,
|
||||||
|
radius,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn style_for_idle(_: &AppContext) -> (Hsla, Hsla, Hsla, Pixels, Pixels) {
|
||||||
|
(
|
||||||
|
gpui::transparent_black(),
|
||||||
|
gpui::transparent_black(),
|
||||||
|
gpui::transparent_black(),
|
||||||
|
THUMB_INSET,
|
||||||
|
THUMB_RADIUS - px(1.),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoElement for Scrollbar {
|
impl IntoElement for Scrollbar {
|
||||||
|
|
@ -326,7 +408,6 @@ impl Element for Scrollbar {
|
||||||
let mut states = vec![];
|
let mut states = vec![];
|
||||||
|
|
||||||
let mut has_both = self.axis.is_both();
|
let mut has_both = self.axis.is_both();
|
||||||
const NORMAL_OPACITY: f32 = 0.6;
|
|
||||||
|
|
||||||
for axis in self.axis.all().into_iter() {
|
for axis in self.axis.all().into_iter() {
|
||||||
let is_vertical = axis.is_vertical();
|
let is_vertical = axis.is_vertical();
|
||||||
|
|
@ -390,49 +471,45 @@ impl Element for Scrollbar {
|
||||||
};
|
};
|
||||||
|
|
||||||
let state = self.state.clone();
|
let state = self.state.clone();
|
||||||
|
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_thumb = state.get().hovered_on_thumb == Some(axis);
|
||||||
|
|
||||||
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_default(cx)
|
||||||
cx.theme().scrollbar_thumb,
|
} else if is_hover_to_show && is_hovered_on_bar {
|
||||||
cx.theme().scrollbar,
|
if is_hovered_on_thumb {
|
||||||
cx.theme().border,
|
Self::style_for_hovered_thumb(cx)
|
||||||
THUMB_INSET - px(1.),
|
|
||||||
THUMB_RADIUS,
|
|
||||||
)
|
|
||||||
} else if state.get().hovered_axis == Some(axis) {
|
|
||||||
if state.get().hovered_on_thumb == Some(axis) {
|
|
||||||
(
|
|
||||||
cx.theme().scrollbar_thumb,
|
|
||||||
cx.theme().scrollbar,
|
|
||||||
cx.theme().border,
|
|
||||||
THUMB_INSET - px(1.),
|
|
||||||
THUMB_RADIUS,
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
(
|
Self::style_for_hovered_bar(cx)
|
||||||
cx.theme().scrollbar_thumb.opacity(NORMAL_OPACITY),
|
|
||||||
gpui::transparent_black(),
|
|
||||||
gpui::transparent_black(),
|
|
||||||
THUMB_INSET,
|
|
||||||
THUMB_RADIUS,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let mut idle_state = (
|
let mut idle_state = Self::style_for_idle(cx);
|
||||||
gpui::transparent_black(),
|
// Delay 2s to fade out the scrollbar thumb (in 1s)
|
||||||
gpui::transparent_black(),
|
|
||||||
gpui::transparent_black(),
|
|
||||||
THUMB_INSET,
|
|
||||||
THUMB_RADIUS - px(1.),
|
|
||||||
);
|
|
||||||
if let Some(last_time) = state.get().last_scroll_time {
|
if let Some(last_time) = state.get().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();
|
||||||
if elapsed < 1.0 {
|
if elapsed < FADE_OUT_DURATION {
|
||||||
let y_value = NORMAL_OPACITY - elapsed.powi(10); // y = 1 - x^10
|
if is_hovered_on_bar {
|
||||||
idle_state.0 = cx.theme().scrollbar_thumb.opacity(y_value);
|
state.set(state.get().with_last_scroll_time(Some(Instant::now())));
|
||||||
cx.request_animation_frame();
|
idle_state = if is_hovered_on_thumb {
|
||||||
|
Self::style_for_hovered_thumb(cx)
|
||||||
|
} else {
|
||||||
|
Self::style_for_hovered_bar(cx)
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
let y_value = if elapsed < FADE_OUT_DELAY {
|
||||||
|
NORMAL_OPACITY
|
||||||
|
} else {
|
||||||
|
// y = 1 - (x - 2)^10
|
||||||
|
NORMAL_OPACITY - (elapsed - FADE_OUT_DELAY).powi(10)
|
||||||
|
};
|
||||||
|
idle_state.0 = cx.theme().scrollbar_thumb.opacity(y_value);
|
||||||
|
cx.request_animation_frame();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
idle_state
|
idle_state
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -494,6 +571,8 @@ impl Element for Scrollbar {
|
||||||
cx: &mut gpui::WindowContext,
|
cx: &mut gpui::WindowContext,
|
||||||
) {
|
) {
|
||||||
let hitbox_bounds = prepaint.hitbox.bounds;
|
let hitbox_bounds = prepaint.hitbox.bounds;
|
||||||
|
let is_visible = self.state.get().is_scrollbar_visible();
|
||||||
|
let is_hover_to_show = cx.theme().scrollbar_show.is_hover();
|
||||||
|
|
||||||
for state in prepaint.states.iter() {
|
for state in prepaint.states.iter() {
|
||||||
let axis = state.axis;
|
let axis = state.axis;
|
||||||
|
|
@ -557,52 +636,54 @@ impl Element for Scrollbar {
|
||||||
|
|
||||||
let safe_range = (-scroll_area_size + container_size)..px(0.);
|
let safe_range = (-scroll_area_size + container_size)..px(0.);
|
||||||
|
|
||||||
cx.on_mouse_event({
|
if is_hover_to_show || is_visible {
|
||||||
let state = self.state.clone();
|
cx.on_mouse_event({
|
||||||
let view_id = self.view_id;
|
let state = self.state.clone();
|
||||||
let scroll_handle = self.scroll_handle.clone();
|
let view_id = self.view_id;
|
||||||
|
let scroll_handle = self.scroll_handle.clone();
|
||||||
|
|
||||||
move |event: &MouseDownEvent, phase, cx| {
|
move |event: &MouseDownEvent, phase, cx| {
|
||||||
if phase.bubble() && bounds.contains(&event.position) {
|
if phase.bubble() && bounds.contains(&event.position) {
|
||||||
cx.stop_propagation();
|
cx.stop_propagation();
|
||||||
|
|
||||||
if thumb_bounds.contains(&event.position) {
|
if thumb_bounds.contains(&event.position) {
|
||||||
// click on the thumb bar, set the drag position
|
// click on the thumb bar, set the drag position
|
||||||
let pos = event.position - thumb_bounds.origin;
|
let pos = event.position - thumb_bounds.origin;
|
||||||
|
|
||||||
state.set(state.get().with_drag_pos(axis, pos));
|
state.set(state.get().with_drag_pos(axis, pos));
|
||||||
|
|
||||||
cx.notify(Some(view_id));
|
cx.notify(Some(view_id));
|
||||||
} else {
|
|
||||||
// click on the scrollbar, jump to the position
|
|
||||||
// Set the thumb bar center to the click position
|
|
||||||
let offset = scroll_handle.offset();
|
|
||||||
let percentage = if is_vertical {
|
|
||||||
(event.position.y - thumb_size / 2. - bounds.origin.y)
|
|
||||||
/ (bounds.size.height - thumb_size)
|
|
||||||
} else {
|
} else {
|
||||||
(event.position.x - thumb_size / 2. - bounds.origin.x)
|
// click on the scrollbar, jump to the position
|
||||||
/ (bounds.size.width - thumb_size)
|
// Set the thumb bar center to the click position
|
||||||
}
|
let offset = scroll_handle.offset();
|
||||||
.min(1.);
|
let percentage = if is_vertical {
|
||||||
|
(event.position.y - thumb_size / 2. - bounds.origin.y)
|
||||||
|
/ (bounds.size.height - thumb_size)
|
||||||
|
} else {
|
||||||
|
(event.position.x - thumb_size / 2. - bounds.origin.x)
|
||||||
|
/ (bounds.size.width - thumb_size)
|
||||||
|
}
|
||||||
|
.min(1.);
|
||||||
|
|
||||||
if is_vertical {
|
if is_vertical {
|
||||||
scroll_handle.set_offset(point(
|
scroll_handle.set_offset(point(
|
||||||
offset.x,
|
offset.x,
|
||||||
(-scroll_area_size * percentage)
|
(-scroll_area_size * percentage)
|
||||||
.clamp(safe_range.start, safe_range.end),
|
.clamp(safe_range.start, safe_range.end),
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
scroll_handle.set_offset(point(
|
scroll_handle.set_offset(point(
|
||||||
(-scroll_area_size * percentage)
|
(-scroll_area_size * percentage)
|
||||||
.clamp(safe_range.start, safe_range.end),
|
.clamp(safe_range.start, safe_range.end),
|
||||||
offset.y,
|
offset.y,
|
||||||
));
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
cx.on_mouse_event({
|
cx.on_mouse_event({
|
||||||
let scroll_handle = self.scroll_handle.clone();
|
let scroll_handle = self.scroll_handle.clone();
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ use gpui::{
|
||||||
ViewContext, WindowAppearance, WindowContext,
|
ViewContext, WindowAppearance, WindowContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::scroll::ScrollbarShow;
|
||||||
|
|
||||||
pub fn init(cx: &mut AppContext) {
|
pub fn init(cx: &mut AppContext) {
|
||||||
Theme::sync_system_appearance(cx)
|
Theme::sync_system_appearance(cx)
|
||||||
}
|
}
|
||||||
|
|
@ -373,6 +375,8 @@ pub struct Theme {
|
||||||
pub radius: f32,
|
pub radius: f32,
|
||||||
pub shadow: bool,
|
pub shadow: bool,
|
||||||
pub transparent: Hsla,
|
pub transparent: Hsla,
|
||||||
|
/// Show the scrollbar mode, default: Scrolling
|
||||||
|
pub scrollbar_show: ScrollbarShow,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for Theme {
|
impl Deref for Theme {
|
||||||
|
|
@ -518,6 +522,7 @@ impl From<ThemeColor> for Theme {
|
||||||
},
|
},
|
||||||
radius: 4.0,
|
radius: 4.0,
|
||||||
shadow: true,
|
shadow: true,
|
||||||
|
scrollbar_show: ScrollbarShow::default(),
|
||||||
colors,
|
colors,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue