Some fixes, impl for uniformlist

This commit is contained in:
MrSubidubi 2025-08-16 00:36:11 +02:00
parent a9dbfce8f9
commit 3da0c0aa60
2 changed files with 104 additions and 94 deletions

View file

@ -4553,7 +4553,6 @@ impl OutlinePanel {
};
v_flex()
.id("outline-panel-empty")
.flex_1()
.justify_center()
.size_full()
@ -4703,19 +4702,20 @@ impl OutlinePanel {
),
)
})
.custom_scrollbars(
Scrollbars::for_settings::<OutlinePanelSettings>()
.tracked_scroll_handle(self.scroll_handle.clone())
.with_track_along(ScrollAxes::Horizontal)
.tracked_entity(cx.entity()),
window,
cx,
)
};
v_flex()
.flex_shrink()
.size_full()
.child(list_contents.size_full().flex_shrink())
.custom_scrollbars(
Scrollbars::for_settings::<OutlinePanelSettings>()
.tracked_scroll_handle(self.scroll_handle.clone())
.with_track_along(ScrollAxes::Horizontal),
window,
cx,
)
}
.children(self.context_menu.as_ref().map(|(menu, position, _)| {
deferred(

View file

@ -4,8 +4,8 @@ use gpui::{
Along, App, AppContext as _, Axis as ScrollbarAxis, BorderStyle, Bounds, ContentMask, Context,
Corner, Corners, CursorStyle, Div, Edges, Element, ElementId, Entity, EntityId,
GlobalElementId, Hitbox, HitboxBehavior, Hsla, InteractiveElement, IntoElement, IsZero,
LayoutId, ListState, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement,
Pixels, Point, Position, Render, ScrollHandle, ScrollWheelEvent, Size, Stateful,
LayoutId, ListState, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Negate,
ParentElement, Pixels, Point, Position, Render, ScrollHandle, ScrollWheelEvent, Size, Stateful,
StatefulInteractiveElement, Style, Styled, Task, UniformList, UniformListDecoration,
UniformListScrollHandle, Window, prelude::FluentBuilder as _, px, quad, relative, size,
};
@ -217,24 +217,20 @@ where
{
let state = &scrollbar.read(cx).0;
if state.read(cx).disabled() {
div
} else {
div.when_some(state.read(cx).handle_to_track(), |this, handle| {
this.track_scroll(handle)
})
.when_some(
state
.read(cx)
.space_to_reserve_for(ScrollbarAxis::Horizontal),
|this, space| this.pb(space),
)
.when_some(
state.read(cx).space_to_reserve_for(ScrollbarAxis::Vertical),
|this, space| this.pr(space),
)
.child(state.clone())
}
div.when_some(state.read(cx).handle_to_track(), |this, handle| {
this.track_scroll(handle)
})
.when_some(
state
.read(cx)
.space_to_reserve_for(ScrollbarAxis::Horizontal),
|this, space| this.pb(space),
)
.when_some(
state.read(cx).space_to_reserve_for(ScrollbarAxis::Vertical),
|this, space| this.pr(space),
)
.child(state.clone())
}
impl<S: ScrollbarVisibilitySetting, T: ScrollableHandle> UniformListDecoration
@ -244,13 +240,14 @@ impl<S: ScrollbarVisibilitySetting, T: ScrollableHandle> UniformListDecoration
&self,
_visible_range: Range<usize>,
_bounds: Bounds<Pixels>,
_scroll_offset: Point<Pixels>,
scroll_offset: Point<Pixels>,
_item_height: Pixels,
_item_count: usize,
_window: &mut Window,
_cx: &mut App,
) -> gpui::AnyElement {
ScrollbarElement {
origin: scroll_offset.negate(),
state: self.0.clone(),
}
.into_any()
@ -558,7 +555,11 @@ impl<S: ScrollbarVisibilitySetting, T: ScrollableHandle> ScrollbarState<S, T> {
fn space_to_reserve_for(&self, axis: ScrollbarAxis) -> Option<Pixels> {
(self.show_state.is_disabled().not() && self.visibility.along(axis).needs_scroll_track())
.then(|| self.width.to_pixels() + 2 * SCROLLBAR_PADDING)
.then(|| self.space_to_reserve())
}
fn space_to_reserve(&self) -> Pixels {
self.width.to_pixels() + 2 * SCROLLBAR_PADDING
}
fn handle_to_track(&self) -> Option<&ScrollHandle> {
@ -692,11 +693,15 @@ impl<S: ScrollbarVisibilitySetting, T: ScrollableHandle> ScrollbarState<S, T> {
impl<S: ScrollbarVisibilitySetting, T: ScrollableHandle> Render for ScrollbarState<S, T> {
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
ScrollbarElement { state: cx.entity() }
ScrollbarElement {
state: cx.entity(),
origin: Default::default(),
}
}
}
struct ScrollbarElement<S: ScrollbarVisibilitySetting, T: ScrollableHandle> {
origin: Point<Pixels>,
state: Entity<ScrollbarState<S, T>>,
}
@ -912,86 +917,91 @@ impl<S: ScrollbarVisibilitySetting, T: ScrollableHandle> Element for ScrollbarEl
window: &mut Window,
cx: &mut App,
) -> Self::PrepaintState {
Some(ScrollbarPrepaintState {
parent_bounds: bounds,
thumbs: self
.state
.read(cx)
.thumb_ranges()
.map(|(axis, thumb_range, reserved_space)| {
let track_anchor = match axis {
ScrollbarAxis::Horizontal => Corner::BottomLeft,
ScrollbarAxis::Vertical => Corner::TopRight,
};
let scroll_track_bounds = Bounds::from_corner_and_size(
track_anchor,
bounds
.corner(track_anchor)
.apply_along(axis.invert(), |corner| corner - SCROLLBAR_PADDING),
bounds
.size
.apply_along(axis.invert(), |_| self.state.read(cx).width.to_pixels()),
);
self.state
.read(cx)
.disabled()
.not()
.then(|| ScrollbarPrepaintState {
parent_bounds: bounds,
thumbs: self
.state
.read(cx)
.thumb_ranges()
.map(|(axis, thumb_range, reserved_space)| {
let track_anchor = match axis {
ScrollbarAxis::Horizontal => Corner::BottomLeft,
ScrollbarAxis::Vertical => Corner::TopRight,
};
let Bounds { origin, size } = Bounds::from_corner_and_size(
track_anchor,
bounds
.corner(track_anchor)
.apply_along(axis.invert(), |corner| corner - SCROLLBAR_PADDING),
bounds.size.apply_along(axis.invert(), |_| {
self.state.read(cx).width.to_pixels()
}),
);
let scroll_track_bounds = Bounds::new(self.origin + origin, size);
let padded_bounds = scroll_track_bounds.extend(match axis {
ScrollbarAxis::Horizontal => Edges {
right: -SCROLLBAR_PADDING,
left: -SCROLLBAR_PADDING,
..Default::default()
},
ScrollbarAxis::Vertical => Edges {
top: -SCROLLBAR_PADDING,
bottom: -SCROLLBAR_PADDING,
..Default::default()
},
});
let thumb_offset = thumb_range.start * padded_bounds.size.along(axis);
let thumb_end = thumb_range.end * padded_bounds.size.along(axis);
let thumb_bounds = Bounds::new(
padded_bounds
.origin
.apply_along(axis, |origin| origin + thumb_offset),
padded_bounds
.size
.apply_along(axis, |_| thumb_end - thumb_offset),
);
ScrollbarLayout {
thumb_bounds,
track_bounds: padded_bounds,
axis,
cursor_hitbox: window.insert_hitbox(
if reserved_space.needs_scroll_track() {
padded_bounds
} else {
thumb_bounds
let padded_bounds = scroll_track_bounds.extend(match axis {
ScrollbarAxis::Horizontal => Edges {
right: -SCROLLBAR_PADDING,
left: -SCROLLBAR_PADDING,
..Default::default()
},
HitboxBehavior::BlockMouseExceptScroll,
),
reserved_space,
}
})
.collect(),
})
ScrollbarAxis::Vertical => Edges {
top: -SCROLLBAR_PADDING,
bottom: -SCROLLBAR_PADDING,
..Default::default()
},
});
let thumb_offset = thumb_range.start * padded_bounds.size.along(axis);
let thumb_end = thumb_range.end * padded_bounds.size.along(axis);
let thumb_bounds = Bounds::new(
padded_bounds
.origin
.apply_along(axis, |origin| origin + thumb_offset),
padded_bounds
.size
.apply_along(axis, |_| thumb_end - thumb_offset),
);
ScrollbarLayout {
thumb_bounds,
track_bounds: padded_bounds,
axis,
cursor_hitbox: window.insert_hitbox(
if reserved_space.needs_scroll_track() {
padded_bounds
} else {
thumb_bounds
},
HitboxBehavior::BlockMouseExceptScroll,
),
reserved_space,
}
})
.collect(),
})
}
fn paint(
&mut self,
_id: Option<&GlobalElementId>,
_inspector_id: Option<&gpui::InspectorElementId>,
bounds: Bounds<Pixels>,
Bounds { origin, size }: Bounds<Pixels>,
_request_layout: &mut Self::RequestLayoutState,
prepaint_state: &mut Self::PrepaintState,
window: &mut Window,
cx: &mut App,
) {
// Practically, we'll never hit the case of this being none
let Some(prepaint_state) = prepaint_state.take() else {
return;
};
let bounds = Bounds::new(self.origin + origin, size);
window.with_content_mask(Some(ContentMask { bounds }), |window| {
let colors = cx.theme().colors();