chore: Improve Scrollbar and Scrollable to support Axis and ScrollbarAxis. (#983)
This commit is contained in:
parent
c5fed17941
commit
1752d3e2b4
6 changed files with 72 additions and 62 deletions
|
|
@ -1,8 +1,8 @@
|
|||
use std::rc::Rc;
|
||||
|
||||
use gpui::{
|
||||
div, px, size, App, AppContext, Context, Entity, Focusable, InteractiveElement, IntoElement,
|
||||
ParentElement, Pixels, Render, ScrollHandle, SharedString, Size, Styled, Window,
|
||||
div, px, size, App, AppContext, Axis, Context, Entity, Focusable, InteractiveElement,
|
||||
IntoElement, ParentElement, Pixels, Render, ScrollHandle, SharedString, Size, Styled, Window,
|
||||
};
|
||||
use gpui_component::{
|
||||
button::{Button, ButtonGroup},
|
||||
|
|
@ -144,17 +144,17 @@ impl ScrollableStory {
|
|||
.child(
|
||||
Button::new("test-axis-both")
|
||||
.label("Both Scrollbar")
|
||||
.selected(self.axis == ScrollbarAxis::Both),
|
||||
.selected(self.axis.is_both()),
|
||||
)
|
||||
.child(
|
||||
Button::new("test-axis-vertical")
|
||||
.label("Vertical")
|
||||
.selected(self.axis == ScrollbarAxis::Vertical),
|
||||
.selected(self.axis.is_vertical()),
|
||||
)
|
||||
.child(
|
||||
Button::new("test-axis-horizontal")
|
||||
.label("Horizontal")
|
||||
.selected(self.axis == ScrollbarAxis::Horizontal),
|
||||
.selected(self.axis.is_horizontal()),
|
||||
)
|
||||
.on_click(cx.listener(|view, clicks: &Vec<usize>, _, cx| {
|
||||
if clicks.contains(&0) {
|
||||
|
|
@ -298,7 +298,7 @@ impl Render for ScrollableStory {
|
|||
.p_3()
|
||||
.w(self.test_width)
|
||||
.id("test-1")
|
||||
.scrollable(cx.entity().entity_id(), ScrollbarAxis::Vertical)
|
||||
.scrollable(cx.entity().entity_id(), Axis::Vertical)
|
||||
.gap_1()
|
||||
.child("Scrollable Example")
|
||||
.children(self.items.iter().take(500).map(|item| {
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ use std::{rc::Rc, time::Duration};
|
|||
|
||||
use gpui::{
|
||||
anchored, div, point, prelude::FluentBuilder as _, px, Animation, AnimationExt as _,
|
||||
AnyElement, App, ClickEvent, DefiniteLength, DismissEvent, Div, EventEmitter, FocusHandle,
|
||||
InteractiveElement as _, IntoElement, KeyBinding, MouseButton, ParentElement, Pixels,
|
||||
RenderOnce, Styled, Window,
|
||||
AnyElement, App, Axis, ClickEvent, DefiniteLength, DismissEvent, Div, EventEmitter,
|
||||
FocusHandle, InteractiveElement as _, IntoElement, KeyBinding, MouseButton, ParentElement,
|
||||
Pixels, RenderOnce, Styled, Window,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
|
|
@ -13,7 +13,6 @@ use crate::{
|
|||
h_flex,
|
||||
modal::overlay_color,
|
||||
root::ContextModal as _,
|
||||
scroll::ScrollbarAxis,
|
||||
title_bar::TITLE_BAR_HEIGHT,
|
||||
v_flex, ActiveTheme, IconName, Placement, Sizable, StyledExt as _,
|
||||
};
|
||||
|
|
@ -205,7 +204,7 @@ impl RenderOnce for Drawer {
|
|||
// Body
|
||||
div().flex_1().overflow_hidden().child(
|
||||
v_flex()
|
||||
.scrollable(window.current_view(), ScrollbarAxis::Vertical)
|
||||
.scrollable(window.current_view(), Axis::Vertical)
|
||||
.child(self.content),
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ use std::{rc::Rc, time::Duration};
|
|||
|
||||
use gpui::{
|
||||
anchored, div, hsla, point, prelude::FluentBuilder, px, relative, Animation, AnimationExt as _,
|
||||
AnyElement, App, Bounds, ClickEvent, Div, FocusHandle, Hsla, InteractiveElement, IntoElement,
|
||||
KeyBinding, MouseButton, ParentElement, Pixels, Point, RenderOnce, SharedString,
|
||||
AnyElement, App, Axis, Bounds, ClickEvent, Div, FocusHandle, Hsla, InteractiveElement,
|
||||
IntoElement, KeyBinding, MouseButton, ParentElement, Pixels, Point, RenderOnce, SharedString,
|
||||
StyleRefinement, Styled, Window,
|
||||
};
|
||||
use rust_i18n::t;
|
||||
|
|
@ -475,10 +475,7 @@ impl RenderOnce for Modal {
|
|||
v_flex()
|
||||
.pl(padding_left)
|
||||
.pr(padding_right)
|
||||
.scrollable(
|
||||
window.current_view(),
|
||||
crate::scroll::ScrollbarAxis::Vertical,
|
||||
)
|
||||
.scrollable(window.current_view(), Axis::Vertical)
|
||||
.child(self.content),
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@ use std::{cell::Cell, rc::Rc};
|
|||
|
||||
use super::{Scrollbar, ScrollbarAxis, ScrollbarState};
|
||||
use gpui::{
|
||||
canvas, div, relative, AnyElement, App, Div, Element, ElementId, EntityId, GlobalElementId,
|
||||
InteractiveElement, IntoElement, ParentElement, Pixels, Position, ScrollHandle, SharedString,
|
||||
Size, Stateful, StatefulInteractiveElement, Style, StyleRefinement, Styled, Window,
|
||||
canvas, div, relative, AnyElement, App, Bounds, Div, Element, ElementId, EntityId,
|
||||
GlobalElementId, InspectorElementId, InteractiveElement, Interactivity, IntoElement, LayoutId,
|
||||
ParentElement, Pixels, Position, ScrollHandle, SharedString, Size, Stateful,
|
||||
StatefulInteractiveElement, Style, StyleRefinement, Styled, Window,
|
||||
};
|
||||
|
||||
/// A scroll view is a container that allows the user to scroll through a large amount of content.
|
||||
|
|
@ -21,9 +22,9 @@ impl<E> Scrollable<E>
|
|||
where
|
||||
E: Element,
|
||||
{
|
||||
pub(crate) fn new(view_id: EntityId, element: E, axis: ScrollbarAxis) -> Self {
|
||||
pub(crate) fn new(view_id: EntityId, element: E, axis: impl Into<ScrollbarAxis>) -> Self {
|
||||
let id = ElementId::Name(SharedString::from(format!(
|
||||
"ScrollView:{}-{:?}",
|
||||
"scrollable-{}-{:?}",
|
||||
view_id,
|
||||
element.id(),
|
||||
)));
|
||||
|
|
@ -33,7 +34,7 @@ where
|
|||
_element: div().id("fake"),
|
||||
id,
|
||||
view_id,
|
||||
axis,
|
||||
axis: axis.into(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -51,8 +52,8 @@ where
|
|||
}
|
||||
|
||||
/// Set the axis of the scroll view.
|
||||
pub fn set_axis(&mut self, axis: ScrollbarAxis) {
|
||||
self.axis = axis;
|
||||
pub fn set_axis(&mut self, axis: impl Into<ScrollbarAxis>) {
|
||||
self.axis = axis.into();
|
||||
}
|
||||
|
||||
fn with_element_state<R>(
|
||||
|
|
@ -117,7 +118,7 @@ impl<E> InteractiveElement for Scrollable<E>
|
|||
where
|
||||
E: Element + InteractiveElement,
|
||||
{
|
||||
fn interactivity(&mut self) -> &mut gpui::Interactivity {
|
||||
fn interactivity(&mut self) -> &mut Interactivity {
|
||||
if let Some(element) = &mut self.element {
|
||||
element.interactivity()
|
||||
} else {
|
||||
|
|
@ -145,7 +146,7 @@ where
|
|||
type RequestLayoutState = AnyElement;
|
||||
type PrepaintState = ScrollViewState;
|
||||
|
||||
fn id(&self) -> Option<gpui::ElementId> {
|
||||
fn id(&self) -> Option<ElementId> {
|
||||
Some(self.id.clone())
|
||||
}
|
||||
|
||||
|
|
@ -155,11 +156,11 @@ where
|
|||
|
||||
fn request_layout(
|
||||
&mut self,
|
||||
id: Option<&gpui::GlobalElementId>,
|
||||
_: Option<&gpui::InspectorElementId>,
|
||||
id: Option<&GlobalElementId>,
|
||||
_: Option<&InspectorElementId>,
|
||||
window: &mut Window,
|
||||
cx: &mut App,
|
||||
) -> (gpui::LayoutId, Self::RequestLayoutState) {
|
||||
) -> (LayoutId, Self::RequestLayoutState) {
|
||||
let mut style = Style::default();
|
||||
style.flex_grow = 1.0;
|
||||
style.position = Position::Relative;
|
||||
|
|
@ -168,7 +169,6 @@ where
|
|||
|
||||
let axis = self.axis;
|
||||
let view_id = self.view_id;
|
||||
|
||||
let scroll_id = self.id.clone();
|
||||
let content = self.element.take().map(|c| c.into_any_element());
|
||||
|
||||
|
|
@ -208,8 +208,8 @@ where
|
|||
),
|
||||
)
|
||||
.into_any_element();
|
||||
let element_id = element.request_layout(window, cx);
|
||||
|
||||
let element_id = element.request_layout(window, cx);
|
||||
let layout_id = window.request_layout(style, vec![element_id], cx);
|
||||
|
||||
(layout_id, element)
|
||||
|
|
@ -218,8 +218,8 @@ where
|
|||
|
||||
fn prepaint(
|
||||
&mut self,
|
||||
_: Option<&gpui::GlobalElementId>,
|
||||
_: Option<&gpui::InspectorElementId>,
|
||||
_: Option<&GlobalElementId>,
|
||||
_: Option<&InspectorElementId>,
|
||||
_: gpui::Bounds<Pixels>,
|
||||
element: &mut Self::RequestLayoutState,
|
||||
window: &mut Window,
|
||||
|
|
@ -232,9 +232,9 @@ where
|
|||
|
||||
fn paint(
|
||||
&mut self,
|
||||
_: Option<&gpui::GlobalElementId>,
|
||||
_: Option<&gpui::InspectorElementId>,
|
||||
_: gpui::Bounds<Pixels>,
|
||||
_: Option<&GlobalElementId>,
|
||||
_: Option<&InspectorElementId>,
|
||||
_: Bounds<Pixels>,
|
||||
element: &mut Self::RequestLayoutState,
|
||||
_: &mut Self::PrepaintState,
|
||||
window: &mut Window,
|
||||
|
|
|
|||
|
|
@ -5,12 +5,12 @@ use std::{
|
|||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
use crate::ActiveTheme;
|
||||
use crate::{ActiveTheme, AxisExt};
|
||||
use gpui::{
|
||||
fill, point, px, relative, size, App, BorderStyle, Bounds, ContentMask, Corner, CursorStyle,
|
||||
Edges, Element, EntityId, Hitbox, Hsla, IntoElement, MouseDownEvent, MouseMoveEvent,
|
||||
MouseUpEvent, PaintQuad, Pixels, Point, Position, ScrollHandle, ScrollWheelEvent, Style,
|
||||
UniformListScrollHandle, Window,
|
||||
fill, point, px, relative, size, App, Axis, BorderStyle, Bounds, ContentMask, Corner,
|
||||
CursorStyle, Edges, Element, EntityId, Hitbox, Hsla, IntoElement, MouseDownEvent,
|
||||
MouseMoveEvent, MouseUpEvent, PaintQuad, Pixels, Point, Position, ScrollHandle,
|
||||
ScrollWheelEvent, Style, UniformListScrollHandle, Window,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
|
@ -85,9 +85,9 @@ pub struct ScrollbarState(Rc<Cell<ScrollbarStateInner>>);
|
|||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct ScrollbarStateInner {
|
||||
hovered_axis: Option<ScrollbarAxis>,
|
||||
hovered_on_thumb: Option<ScrollbarAxis>,
|
||||
dragged_axis: Option<ScrollbarAxis>,
|
||||
hovered_axis: Option<Axis>,
|
||||
hovered_on_thumb: Option<Axis>,
|
||||
dragged_axis: Option<Axis>,
|
||||
drag_pos: Point<Pixels>,
|
||||
last_scroll_offset: Point<Pixels>,
|
||||
last_scroll_time: Option<Instant>,
|
||||
|
|
@ -118,7 +118,7 @@ impl Deref for ScrollbarState {
|
|||
}
|
||||
|
||||
impl ScrollbarStateInner {
|
||||
fn with_drag_pos(&self, axis: ScrollbarAxis, pos: Point<Pixels>) -> Self {
|
||||
fn with_drag_pos(&self, axis: Axis, pos: Point<Pixels>) -> Self {
|
||||
let mut state = *self;
|
||||
if axis.is_vertical() {
|
||||
state.drag_pos.y = pos.y;
|
||||
|
|
@ -136,7 +136,7 @@ impl ScrollbarStateInner {
|
|||
state
|
||||
}
|
||||
|
||||
fn with_hovered(&self, axis: Option<ScrollbarAxis>) -> Self {
|
||||
fn with_hovered(&self, axis: Option<Axis>) -> Self {
|
||||
let mut state = *self;
|
||||
state.hovered_axis = axis;
|
||||
if axis.is_some() {
|
||||
|
|
@ -145,7 +145,7 @@ impl ScrollbarStateInner {
|
|||
state
|
||||
}
|
||||
|
||||
fn with_hovered_on_thumb(&self, axis: Option<ScrollbarAxis>) -> Self {
|
||||
fn with_hovered_on_thumb(&self, axis: Option<Axis>) -> Self {
|
||||
let mut state = *self;
|
||||
state.hovered_on_thumb = axis;
|
||||
if self.is_scrollbar_visible() {
|
||||
|
|
@ -201,14 +201,28 @@ pub enum ScrollbarAxis {
|
|||
Both,
|
||||
}
|
||||
|
||||
impl From<Axis> for ScrollbarAxis {
|
||||
fn from(axis: Axis) -> Self {
|
||||
match axis {
|
||||
Axis::Vertical => Self::Vertical,
|
||||
Axis::Horizontal => Self::Horizontal,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ScrollbarAxis {
|
||||
#[inline]
|
||||
fn is_vertical(&self) -> bool {
|
||||
/// Return true if the scrollbar axis is vertical.
|
||||
pub fn is_vertical(&self) -> bool {
|
||||
matches!(self, Self::Vertical)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_both(&self) -> bool {
|
||||
/// Return true if the scrollbar axis is horizontal.
|
||||
pub fn is_horizontal(&self) -> bool {
|
||||
matches!(self, Self::Horizontal)
|
||||
}
|
||||
|
||||
/// Return true if the scrollbar axis is both vertical and horizontal.
|
||||
pub fn is_both(&self) -> bool {
|
||||
matches!(self, Self::Both)
|
||||
}
|
||||
|
||||
|
|
@ -223,13 +237,13 @@ impl ScrollbarAxis {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn all(&self) -> Vec<ScrollbarAxis> {
|
||||
fn all(&self) -> Vec<Axis> {
|
||||
match self {
|
||||
Self::Vertical => vec![Self::Vertical],
|
||||
Self::Horizontal => vec![Self::Horizontal],
|
||||
Self::Vertical => vec![Axis::Vertical],
|
||||
Self::Horizontal => vec![Axis::Horizontal],
|
||||
// This should keep Horizontal first, Vertical is the primary axis
|
||||
// if Vertical not need display, then Horizontal will not keep right margin.
|
||||
Self::Both => vec![Self::Horizontal, Self::Vertical],
|
||||
Self::Both => vec![Axis::Horizontal, Axis::Vertical],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -252,14 +266,14 @@ impl Scrollbar {
|
|||
fn new(
|
||||
view_id: EntityId,
|
||||
state: ScrollbarState,
|
||||
axis: ScrollbarAxis,
|
||||
axis: impl Into<ScrollbarAxis>,
|
||||
scroll_handle: impl ScrollHandleOffsetable + 'static,
|
||||
scroll_size: gpui::Size<Pixels>,
|
||||
) -> Self {
|
||||
Self {
|
||||
view_id,
|
||||
state,
|
||||
axis,
|
||||
axis: axis.into(),
|
||||
scroll_size,
|
||||
scroll_handle: Rc::new(Box::new(scroll_handle)),
|
||||
max_fps: 120,
|
||||
|
|
@ -337,8 +351,8 @@ impl Scrollbar {
|
|||
}
|
||||
|
||||
/// Set scrollbar axis.
|
||||
pub fn axis(mut self, axis: ScrollbarAxis) -> Self {
|
||||
self.axis = axis;
|
||||
pub fn axis(mut self, axis: impl Into<ScrollbarAxis>) -> Self {
|
||||
self.axis = axis.into();
|
||||
self
|
||||
}
|
||||
|
||||
|
|
@ -416,7 +430,7 @@ pub struct PrepaintState {
|
|||
}
|
||||
|
||||
pub struct AxisPrepaintState {
|
||||
axis: ScrollbarAxis,
|
||||
axis: Axis,
|
||||
bar_hitbox: Hitbox,
|
||||
bounds: Bounds<Pixels>,
|
||||
radius: Pixels,
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ pub trait StyledExt: Styled + Sized {
|
|||
///
|
||||
/// Current this is only have a vertical scrollbar.
|
||||
#[inline]
|
||||
fn scrollable(self, view_id: EntityId, axis: ScrollbarAxis) -> Scrollable<Self>
|
||||
fn scrollable(self, view_id: EntityId, axis: impl Into<ScrollbarAxis>) -> Scrollable<Self>
|
||||
where
|
||||
Self: Element,
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue