scrollbar: Use default cursor style when hovered on scrollbar. (#480)
- Move prepare code to `prepaint` stage. Close #474
This commit is contained in:
parent
22f60c7299
commit
26024ba2b5
2 changed files with 99 additions and 41 deletions
|
|
@ -41,8 +41,8 @@ pub use webview_story::WebViewStory;
|
||||||
|
|
||||||
use gpui::{
|
use gpui::{
|
||||||
actions, div, prelude::FluentBuilder as _, px, AnyElement, AnyView, AppContext, Div,
|
actions, div, prelude::FluentBuilder as _, px, AnyElement, AnyView, AppContext, Div,
|
||||||
Entity as _, EventEmitter, FocusableView, Hsla, InteractiveElement, IntoElement, ParentElement,
|
EventEmitter, FocusableView, Hsla, InteractiveElement, IntoElement, ParentElement, Render,
|
||||||
Render, SharedString, Styled as _, View, ViewContext, VisualContext, WindowContext,
|
SharedString, Styled as _, View, ViewContext, VisualContext, WindowContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
use ui::{
|
use ui::{
|
||||||
|
|
@ -53,9 +53,8 @@ use ui::{
|
||||||
label::Label,
|
label::Label,
|
||||||
notification::Notification,
|
notification::Notification,
|
||||||
popup_menu::PopupMenu,
|
popup_menu::PopupMenu,
|
||||||
scroll::ScrollbarAxis,
|
|
||||||
theme::ActiveTheme,
|
theme::ActiveTheme,
|
||||||
v_flex, ContextModal, IconName, StyledExt as _,
|
v_flex, ContextModal, IconName,
|
||||||
};
|
};
|
||||||
|
|
||||||
const PANEL_NAME: &str = "StoryContainer";
|
const PANEL_NAME: &str = "StoryContainer";
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@ 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, Edges, Element, EntityId, Hitbox, IntoElement,
|
fill, point, px, relative, Bounds, ContentMask, CursorStyle, Edges, Element, EntityId, Hitbox,
|
||||||
MouseDownEvent, MouseMoveEvent, MouseUpEvent, PaintQuad, Pixels, Point, Position, ScrollHandle,
|
Hsla, IntoElement, MouseDownEvent, MouseMoveEvent, MouseUpEvent, PaintQuad, Pixels, Point,
|
||||||
ScrollWheelEvent, Style, UniformListScrollHandle,
|
Position, ScrollHandle, ScrollWheelEvent, Style, UniformListScrollHandle,
|
||||||
};
|
};
|
||||||
|
|
||||||
const MIN_THUMB_SIZE: f32 = 80.;
|
const MIN_THUMB_SIZE: f32 = 80.;
|
||||||
|
|
@ -267,10 +267,31 @@ impl IntoElement for Scrollbar {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct PrepaintState {
|
||||||
|
hitbox: Hitbox,
|
||||||
|
states: Vec<AxisPrepaintState>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AxisPrepaintState {
|
||||||
|
axis: ScrollbarAxis,
|
||||||
|
bar_hitbox: Hitbox,
|
||||||
|
bounds: Bounds<Pixels>,
|
||||||
|
border_width: Pixels,
|
||||||
|
radius: Pixels,
|
||||||
|
bg: Hsla,
|
||||||
|
border: Hsla,
|
||||||
|
thumb_bounds: Bounds<Pixels>,
|
||||||
|
thumb_bg: Hsla,
|
||||||
|
scroll_size: Pixels,
|
||||||
|
container_size: Pixels,
|
||||||
|
thumb_size: Pixels,
|
||||||
|
margin_end: Pixels,
|
||||||
|
}
|
||||||
|
|
||||||
impl Element for Scrollbar {
|
impl Element for Scrollbar {
|
||||||
type RequestLayoutState = ();
|
type RequestLayoutState = ();
|
||||||
|
|
||||||
type PrepaintState = Hitbox;
|
type PrepaintState = PrepaintState;
|
||||||
|
|
||||||
fn id(&self) -> Option<gpui::ElementId> {
|
fn id(&self) -> Option<gpui::ElementId> {
|
||||||
None
|
None
|
||||||
|
|
@ -298,36 +319,27 @@ impl Element for Scrollbar {
|
||||||
_: &mut Self::RequestLayoutState,
|
_: &mut Self::RequestLayoutState,
|
||||||
cx: &mut gpui::WindowContext,
|
cx: &mut gpui::WindowContext,
|
||||||
) -> Self::PrepaintState {
|
) -> Self::PrepaintState {
|
||||||
cx.with_content_mask(Some(ContentMask { bounds }), |cx| {
|
let hitbox = cx.with_content_mask(Some(ContentMask { bounds }), |cx| {
|
||||||
cx.insert_hitbox(bounds, false)
|
cx.insert_hitbox(bounds, false)
|
||||||
})
|
});
|
||||||
}
|
|
||||||
|
let mut states = vec![];
|
||||||
|
|
||||||
fn paint(
|
|
||||||
&mut self,
|
|
||||||
_: Option<&gpui::GlobalElementId>,
|
|
||||||
_: Bounds<Pixels>,
|
|
||||||
_: &mut Self::RequestLayoutState,
|
|
||||||
hitbox: &mut Self::PrepaintState,
|
|
||||||
cx: &mut gpui::WindowContext,
|
|
||||||
) {
|
|
||||||
let hitbox_bounds = hitbox.bounds;
|
|
||||||
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() {
|
||||||
const NORMAL_OPACITY: f32 = 0.6;
|
|
||||||
|
|
||||||
let is_vertical = axis.is_vertical();
|
let is_vertical = axis.is_vertical();
|
||||||
let (scroll_area_size, container_size, scroll_position) = if is_vertical {
|
let (scroll_area_size, container_size, scroll_position) = if is_vertical {
|
||||||
(
|
(
|
||||||
self.scroll_size.height,
|
self.scroll_size.height,
|
||||||
hitbox_bounds.size.height,
|
hitbox.size.height,
|
||||||
self.scroll_handle.offset().y,
|
self.scroll_handle.offset().y,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
(
|
(
|
||||||
self.scroll_size.width,
|
self.scroll_size.width,
|
||||||
hitbox_bounds.size.width,
|
hitbox.size.width,
|
||||||
self.scroll_handle.offset().x,
|
self.scroll_handle.offset().x,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
@ -354,23 +366,23 @@ impl Element for Scrollbar {
|
||||||
let bounds = Bounds {
|
let bounds = Bounds {
|
||||||
origin: if is_vertical {
|
origin: if is_vertical {
|
||||||
point(
|
point(
|
||||||
hitbox_bounds.origin.x + hitbox_bounds.size.width - self.width,
|
hitbox.origin.x + hitbox.size.width - self.width,
|
||||||
hitbox_bounds.origin.y,
|
hitbox.origin.y,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
point(
|
point(
|
||||||
hitbox_bounds.origin.x,
|
hitbox.origin.x,
|
||||||
hitbox_bounds.origin.y + hitbox_bounds.size.height - self.width,
|
hitbox.origin.y + hitbox.size.height - self.width,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
size: gpui::Size {
|
size: gpui::Size {
|
||||||
width: if is_vertical {
|
width: if is_vertical {
|
||||||
self.width
|
self.width
|
||||||
} else {
|
} else {
|
||||||
hitbox_bounds.size.width
|
hitbox.size.width
|
||||||
},
|
},
|
||||||
height: if is_vertical {
|
height: if is_vertical {
|
||||||
hitbox_bounds.size.height
|
hitbox.size.height
|
||||||
} else {
|
} else {
|
||||||
self.width
|
self.width
|
||||||
},
|
},
|
||||||
|
|
@ -449,8 +461,55 @@ impl Element for Scrollbar {
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let bar_hitbox = cx.with_content_mask(Some(ContentMask { bounds }), |cx| {
|
||||||
|
cx.insert_hitbox(bounds, false)
|
||||||
|
});
|
||||||
|
|
||||||
|
states.push(AxisPrepaintState {
|
||||||
|
axis,
|
||||||
|
bar_hitbox,
|
||||||
|
bounds,
|
||||||
|
border_width,
|
||||||
|
radius,
|
||||||
|
bg: bar_bg,
|
||||||
|
border: bar_border,
|
||||||
|
thumb_bounds,
|
||||||
|
thumb_bg,
|
||||||
|
scroll_size: scroll_area_size,
|
||||||
|
container_size,
|
||||||
|
thumb_size: thumb_length,
|
||||||
|
margin_end,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
PrepaintState { hitbox, states }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn paint(
|
||||||
|
&mut self,
|
||||||
|
_: Option<&gpui::GlobalElementId>,
|
||||||
|
_: Bounds<Pixels>,
|
||||||
|
_: &mut Self::RequestLayoutState,
|
||||||
|
prepaint: &mut Self::PrepaintState,
|
||||||
|
cx: &mut gpui::WindowContext,
|
||||||
|
) {
|
||||||
|
let hitbox_bounds = prepaint.hitbox.bounds;
|
||||||
|
|
||||||
|
for state in prepaint.states.iter() {
|
||||||
|
let axis = state.axis;
|
||||||
|
let radius = state.radius;
|
||||||
|
let bounds = state.bounds;
|
||||||
|
let thumb_bounds = state.thumb_bounds;
|
||||||
|
let scroll_area_size = state.scroll_size;
|
||||||
|
let container_size = state.container_size;
|
||||||
|
let thumb_size = state.thumb_size;
|
||||||
|
let margin_end = state.margin_end;
|
||||||
|
let is_vertical = axis.is_vertical();
|
||||||
|
|
||||||
|
cx.set_cursor_style(CursorStyle::default(), &state.bar_hitbox);
|
||||||
|
|
||||||
cx.paint_layer(hitbox_bounds, |cx| {
|
cx.paint_layer(hitbox_bounds, |cx| {
|
||||||
cx.paint_quad(fill(bounds, bar_bg));
|
cx.paint_quad(fill(state.bounds, state.bg));
|
||||||
|
|
||||||
cx.paint_quad(PaintQuad {
|
cx.paint_quad(PaintQuad {
|
||||||
bounds,
|
bounds,
|
||||||
|
|
@ -461,20 +520,20 @@ impl Element for Scrollbar {
|
||||||
top: px(0.),
|
top: px(0.),
|
||||||
right: px(0.),
|
right: px(0.),
|
||||||
bottom: px(0.),
|
bottom: px(0.),
|
||||||
left: border_width,
|
left: state.border_width,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Edges {
|
Edges {
|
||||||
top: border_width,
|
top: state.border_width,
|
||||||
right: px(0.),
|
right: px(0.),
|
||||||
bottom: px(0.),
|
bottom: px(0.),
|
||||||
left: px(0.),
|
left: px(0.),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
border_color: bar_border,
|
border_color: state.border,
|
||||||
});
|
});
|
||||||
|
|
||||||
cx.paint_quad(fill(thumb_bounds, thumb_bg).corner_radii(radius));
|
cx.paint_quad(fill(thumb_bounds, state.thumb_bg).corner_radii(radius));
|
||||||
});
|
});
|
||||||
|
|
||||||
cx.on_mouse_event({
|
cx.on_mouse_event({
|
||||||
|
|
@ -519,11 +578,11 @@ impl Element for Scrollbar {
|
||||||
// Set the thumb bar center to the click position
|
// Set the thumb bar center to the click position
|
||||||
let offset = scroll_handle.offset();
|
let offset = scroll_handle.offset();
|
||||||
let percentage = if is_vertical {
|
let percentage = if is_vertical {
|
||||||
(event.position.y - thumb_length / 2. - bounds.origin.y)
|
(event.position.y - thumb_size / 2. - bounds.origin.y)
|
||||||
/ (bounds.size.height - thumb_length)
|
/ (bounds.size.height - thumb_size)
|
||||||
} else {
|
} else {
|
||||||
(event.position.x - thumb_length / 2. - bounds.origin.x)
|
(event.position.x - thumb_size / 2. - bounds.origin.x)
|
||||||
/ (bounds.size.width - thumb_length)
|
/ (bounds.size.width - thumb_size)
|
||||||
}
|
}
|
||||||
.min(1.);
|
.min(1.);
|
||||||
|
|
||||||
|
|
@ -587,10 +646,10 @@ impl Element for Scrollbar {
|
||||||
|
|
||||||
let percentage = (if is_vertical {
|
let percentage = (if is_vertical {
|
||||||
(event.position.y - drag_pos.y - bounds.origin.y)
|
(event.position.y - drag_pos.y - bounds.origin.y)
|
||||||
/ (bounds.size.height - thumb_length)
|
/ (bounds.size.height - thumb_size)
|
||||||
} else {
|
} else {
|
||||||
(event.position.x - drag_pos.x - bounds.origin.x)
|
(event.position.x - drag_pos.x - bounds.origin.x)
|
||||||
/ (bounds.size.width - thumb_length - margin_end)
|
/ (bounds.size.width - thumb_size - margin_end)
|
||||||
})
|
})
|
||||||
.clamp(0., 1.);
|
.clamp(0., 1.);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue