.
Some checks failed
Rust / build (ubuntu-latest, stable) (push) Failing after 5m17s

This commit is contained in:
2026-02-19 10:10:16 +07:00
parent 3e8efdd0ef
commit fad30a89f1
17 changed files with 226 additions and 149 deletions

View File

@@ -32,18 +32,12 @@ impl Display for Placement {
impl Placement {
#[inline]
pub fn is_horizontal(&self) -> bool {
match self {
Placement::Left | Placement::Right => true,
_ => false,
}
matches!(self, Placement::Left | Placement::Right)
}
#[inline]
pub fn is_vertical(&self) -> bool {
match self {
Placement::Top | Placement::Bottom => true,
_ => false,
}
matches!(self, Placement::Top | Placement::Bottom)
}
#[inline]
@@ -217,7 +211,9 @@ impl Side {
/// A trait to extend the [`Axis`] enum with utility methods.
pub trait AxisExt {
#[allow(clippy::wrong_self_convention)]
fn is_horizontal(self) -> bool;
#[allow(clippy::wrong_self_convention)]
fn is_vertical(self) -> bool;
}
@@ -236,6 +232,7 @@ impl AxisExt for Axis {
/// A trait for converting [`Pixels`] to `f32` and `f64`.
pub trait PixelsExt {
fn as_f32(&self) -> f32;
#[allow(clippy::wrong_self_convention)]
fn as_f64(self) -> f64;
}
impl PixelsExt for Pixels {

View File

@@ -152,6 +152,7 @@ where
}
/// Return true if either the list or the search input is focused.
#[allow(dead_code)]
pub(crate) fn is_focused(&self, window: &Window, cx: &App) -> bool {
self.focus_handle.is_focused(window) || self.query_input.focus_handle(cx).is_focused(window)
}
@@ -330,6 +331,7 @@ where
}
}
#[allow(dead_code)]
pub(crate) fn reset_on_cancel(mut self, reset: bool) -> Self {
self.reset_on_cancel = reset;
self

View File

@@ -33,8 +33,11 @@ pub struct ListItem {
secondary_selected: bool,
confirmed: bool,
check_icon: Option<Icon>,
#[allow(clippy::type_complexity)]
on_click: Option<Box<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>>,
#[allow(clippy::type_complexity)]
on_mouse_enter: Option<Box<dyn Fn(&MouseMoveEvent, &mut Window, &mut App) + 'static>>,
#[allow(clippy::type_complexity)]
suffix: Option<Box<dyn Fn(&mut Window, &mut App) -> AnyElement + 'static>>,
children: SmallVec<[AnyElement; 2]>,
}
@@ -157,8 +160,10 @@ impl RenderOnce for ListItem {
let corner_radii = self.style.corner_radii.clone();
let mut selected_style = StyleRefinement::default();
selected_style.corner_radii = corner_radii;
let _selected_style = StyleRefinement {
corner_radii,
..Default::default()
};
let is_selectable = !(self.disabled || self.mode.is_separator());

View File

@@ -1,5 +1,6 @@
pub(crate) mod cache;
mod delegate;
#[allow(clippy::module_inception)]
mod list;
mod list_item;
mod loading;

View File

@@ -18,6 +18,12 @@ impl ListSeparatorItem {
}
}
impl Default for ListSeparatorItem {
fn default() -> Self {
Self::new()
}
}
impl ParentElement for ListSeparatorItem {
fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
self.children.extend(elements);

View File

@@ -192,7 +192,7 @@ impl AppMenu {
) {
let is_selected = self.menu_bar.read(cx).selected_index == Some(self.ix);
_ = self.menu_bar.update(cx, |state, cx| {
self.menu_bar.update(cx, |state, cx| {
let new_ix = if is_selected { None } else { Some(self.ix) };
state.set_selected_index(new_ix, window, cx);
});
@@ -208,7 +208,7 @@ impl AppMenu {
return;
}
_ = self.menu_bar.update(cx, |state, cx| {
self.menu_bar.update(cx, |state, cx| {
state.set_selected_index(Some(self.ix), window, cx);
});
}

View File

@@ -37,6 +37,7 @@ impl<E: ParentElement + Styled> ContextMenuExt for E {}
pub struct ContextMenu<E: ParentElement + Styled + Sized> {
id: ElementId,
element: Option<E>,
#[allow(clippy::type_complexity)]
menu: Option<Rc<dyn Fn(PopupMenu, &mut Window, &mut Context<PopupMenu>) -> PopupMenu>>,
// This is not in use, just for style refinement forwarding.
_ignore_style: StyleRefinement,

View File

@@ -41,6 +41,7 @@ pub struct DropdownMenuPopover<T: Selectable + IntoElement + 'static> {
style: StyleRefinement,
anchor: Corner,
trigger: T,
#[allow(clippy::type_complexity)]
builder: Rc<dyn Fn(PopupMenu, &mut Window, &mut Context<PopupMenu>) -> PopupMenu>,
}

View File

@@ -16,7 +16,9 @@ pub(crate) struct MenuItemElement {
style: StyleRefinement,
disabled: bool,
selected: bool,
#[allow(clippy::type_complexity)]
on_click: Option<Box<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>>,
#[allow(clippy::type_complexity)]
on_hover: Option<Box<dyn Fn(&bool, &mut Window, &mut App) + 'static>>,
children: SmallVec<[AnyElement; 2]>,
}
@@ -104,12 +106,12 @@ impl RenderOnce for MenuItemElement {
})
.when(!self.disabled, |this| {
this.group_hover(self.group_name, |this| {
this.bg(cx.theme().element_background)
.text_color(cx.theme().element_foreground)
this.bg(cx.theme().secondary_background)
.text_color(cx.theme().secondary_foreground)
})
.when(self.selected, |this| {
this.bg(cx.theme().element_background)
.text_color(cx.theme().element_foreground)
this.bg(cx.theme().secondary_background)
.text_color(cx.theme().secondary_foreground)
})
.when_some(self.on_click, |this, on_click| {
this.on_mouse_down(MouseButton::Left, move |_, _, cx| {

View File

@@ -2,8 +2,8 @@ use std::rc::Rc;
use gpui::prelude::FluentBuilder;
use gpui::{
anchored, div, px, rems, Action, AnyElement, App, AppContext, Bounds, ClickEvent, Context,
Corner, DismissEvent, Edges, Entity, EventEmitter, FocusHandle, Focusable, Half,
anchored, div, px, rems, Action, AnyElement, App, AppContext, Axis, Bounds, ClickEvent,
Context, Corner, DismissEvent, Edges, Entity, EventEmitter, FocusHandle, Focusable, Half,
InteractiveElement, IntoElement, KeyBinding, MouseDownEvent, OwnedMenuItem, ParentElement,
Pixels, Point, Render, ScrollHandle, SharedString, StatefulInteractiveElement, Styled,
Subscription, WeakEntity, Window,
@@ -44,6 +44,7 @@ pub enum PopupMenuItem {
is_link: bool,
action: Option<Box<dyn Action>>,
// For link item
#[allow(clippy::type_complexity)]
handler: Option<Rc<dyn Fn(&ClickEvent, &mut Window, &mut App)>>,
},
/// A menu item with custom element render.
@@ -52,7 +53,9 @@ pub enum PopupMenuItem {
disabled: bool,
checked: bool,
action: Option<Box<dyn Action>>,
#[allow(clippy::type_complexity)]
render: Box<dyn Fn(&mut Window, &mut App) -> AnyElement + 'static>,
#[allow(clippy::type_complexity)]
handler: Option<Rc<dyn Fn(&ClickEvent, &mut Window, &mut App)>>,
},
/// A submenu item that opens another popup menu.
@@ -275,8 +278,11 @@ impl PopupMenuItem {
pub struct PopupMenu {
pub(crate) focus_handle: FocusHandle,
pub(crate) menu_items: Vec<PopupMenuItem>,
/// The focus handle of Entity to handle actions.
pub(crate) action_context: Option<FocusHandle>,
axis: Axis,
selected_index: Option<usize>,
min_width: Option<Pixels>,
max_width: Option<Pixels>,
@@ -290,7 +296,8 @@ pub struct PopupMenu {
scrollable: bool,
external_link_icon: bool,
scroll_handle: ScrollHandle,
// This will update on render
/// This will update on render
submenu_anchor: (Corner, Pixels),
_subscriptions: Vec<Subscription>,
@@ -304,6 +311,7 @@ impl PopupMenu {
parent_menu: None,
menu_items: Vec::new(),
selected_index: None,
axis: Axis::Vertical,
min_width: None,
max_width: None,
max_height: None,
@@ -354,6 +362,12 @@ impl PopupMenu {
self
}
/// Set the axis of children to horizontal.
pub fn horizontal(mut self) -> Self {
self.axis = Axis::Horizontal;
self
}
/// Set the menu to be scrollable to show vertical scrollbar.
///
/// NOTE: If this is true, the sub-menus will cannot be support.
@@ -643,6 +657,7 @@ impl PopupMenu {
}
/// Use small size, the menu item will have smaller height.
#[allow(dead_code)]
pub(crate) fn small(mut self) -> Self {
self.size = Size::Small;
self
@@ -734,41 +749,38 @@ impl PopupMenu {
}
fn confirm(&mut self, _: &Confirm, window: &mut Window, cx: &mut Context<Self>) {
match self.selected_index {
Some(index) => {
let item = self.menu_items.get(index);
match item {
Some(PopupMenuItem::Item {
handler, action, ..
}) => {
if let Some(handler) = handler {
handler(&ClickEvent::default(), window, cx);
} else if let Some(action) = action.as_ref() {
self.dispatch_confirm_action(action, window, cx);
}
if let Some(index) = self.selected_index {
let item = self.menu_items.get(index);
match item {
Some(PopupMenuItem::Item {
handler, action, ..
}) => {
if let Some(handler) = handler {
handler(&ClickEvent::default(), window, cx);
} else if let Some(action) = action.as_ref() {
self.dispatch_confirm_action(action.as_ref(), window, cx);
}
self.dismiss(&Cancel, window, cx)
}
Some(PopupMenuItem::ElementItem {
handler, action, ..
}) => {
if let Some(handler) = handler {
handler(&ClickEvent::default(), window, cx);
} else if let Some(action) = action.as_ref() {
self.dispatch_confirm_action(action, window, cx);
}
self.dismiss(&Cancel, window, cx)
}
_ => {}
self.dismiss(&Cancel, window, cx)
}
Some(PopupMenuItem::ElementItem {
handler, action, ..
}) => {
if let Some(handler) = handler {
handler(&ClickEvent::default(), window, cx);
} else if let Some(action) = action.as_ref() {
self.dispatch_confirm_action(action.as_ref(), window, cx);
}
self.dismiss(&Cancel, window, cx)
}
_ => {}
}
_ => {}
}
}
fn dispatch_confirm_action(
&self,
action: &Box<dyn Action>,
action: &dyn Action,
window: &mut Window,
cx: &mut Context<Self>,
) {
@@ -878,8 +890,7 @@ impl PopupMenu {
cx.notify();
return true;
}
return false;
false
}
fn _unselect_submenu(&mut self, _: &mut Window, cx: &mut Context<Self>) -> bool {
@@ -890,8 +901,7 @@ impl PopupMenu {
});
return true;
}
return false;
false
}
fn _focus_parent_menu(&mut self, window: &mut Window, cx: &mut Context<Self>) {
@@ -1248,7 +1258,9 @@ impl PopupMenu {
}
impl FluentBuilder for PopupMenu {}
impl EventEmitter<DismissEvent> for PopupMenu {}
impl Focusable for PopupMenu {
fn focus_handle(&self, _: &App) -> FocusHandle {
self.focus_handle.clone()
@@ -1302,13 +1314,17 @@ impl Render for PopupMenu {
.relative()
.occlude()
.child(
v_flex()
div()
.id("items")
.p_1()
.gap_y_0p5()
.min_w(rems(8.))
.when_some(self.min_width, |this, min_width| this.min_w(min_width))
.max_w(max_width)
.map(|this| match self.axis {
Axis::Horizontal => this.flex().flex_row().items_center(),
Axis::Vertical => this.flex().flex_col(),
})
.when(self.scrollable, |this| {
this.max_h(max_height)
.overflow_y_scroll()

View File

@@ -26,7 +26,9 @@ pub struct Popover {
default_open: bool,
open: Option<bool>,
tracked_focus_handle: Option<FocusHandle>,
#[allow(clippy::type_complexity)]
trigger: Option<Box<dyn FnOnce(bool, &Window, &App) -> AnyElement + 'static>>,
#[allow(clippy::type_complexity)]
content: Option<
Rc<
dyn Fn(&mut PopoverState, &mut Window, &mut Context<PopoverState>) -> AnyElement
@@ -40,6 +42,7 @@ pub struct Popover {
mouse_button: MouseButton,
appearance: bool,
overlay_closable: bool,
#[allow(clippy::type_complexity)]
on_open_change: Option<Rc<dyn Fn(&bool, &mut Window, &mut App)>>,
}
@@ -204,6 +207,7 @@ pub struct PopoverState {
pub(crate) tracked_focus_handle: Option<FocusHandle>,
trigger_bounds: Bounds<Pixels>,
open: bool,
#[allow(clippy::type_complexity)]
on_open_change: Option<Rc<dyn Fn(&bool, &mut Window, &mut App)>>,
_dismiss_subscription: Option<Subscription>,

View File

@@ -16,16 +16,16 @@ use theme::{ActiveTheme, ScrollbarMode};
use crate::AxisExt;
/// The width of the scrollbar (THUMB_ACTIVE_INSET * 2 + THUMB_ACTIVE_WIDTH)
const WIDTH: Pixels = px(4. * 2. + 8.);
const WIDTH: Pixels = px(1. * 2. + 8.);
const MIN_THUMB_SIZE: f32 = 48.;
const THUMB_WIDTH: Pixels = px(6.);
const THUMB_RADIUS: Pixels = px(6. / 2.);
const THUMB_INSET: Pixels = px(4.);
const THUMB_INSET: Pixels = px(1.);
const THUMB_ACTIVE_WIDTH: Pixels = px(8.);
const THUMB_ACTIVE_RADIUS: Pixels = px(8. / 2.);
const THUMB_ACTIVE_INSET: Pixels = px(4.);
const THUMB_ACTIVE_INSET: Pixels = px(1.);
const FADE_OUT_DURATION: f32 = 3.0;
const FADE_OUT_DELAY: f32 = 2.0;
@@ -167,10 +167,8 @@ impl ScrollbarStateInner {
fn with_hovered_on_thumb(&self, axis: Option<Axis>) -> Self {
let mut state = *self;
state.hovered_on_thumb = axis;
if self.is_scrollbar_visible() {
if axis.is_some() {
state.last_scroll_time = Some(std::time::Instant::now());
}
if self.is_scrollbar_visible() && axis.is_some() {
state.last_scroll_time = Some(std::time::Instant::now());
}
state
}
@@ -358,12 +356,14 @@ impl Scrollbar {
/// If you have very high CPU usage, consider reducing this value to improve performance.
///
/// Available values: 30..120
#[allow(dead_code)]
pub(crate) fn max_fps(mut self, max_fps: usize) -> Self {
self.max_fps = max_fps.clamp(30, 120);
self
}
// Get the width of the scrollbar.
#[allow(dead_code)]
pub(crate) const fn width() -> Pixels {
WIDTH
}
@@ -488,12 +488,16 @@ impl Element for Scrollbar {
window: &mut Window,
cx: &mut App,
) -> (LayoutId, Self::RequestLayoutState) {
let mut style = Style::default();
style.position = Position::Absolute;
style.flex_grow = 1.0;
style.flex_shrink = 1.0;
style.size.width = relative(1.).into();
style.size.height = relative(1.).into();
let style = Style {
position: Position::Absolute,
flex_grow: 1.0,
flex_shrink: 1.0,
size: Size {
width: relative(1.).into(),
height: relative(1.).into(),
},
..Default::default()
};
(window.request_layout(style, None, cx), ())
}
@@ -757,20 +761,11 @@ impl Element for Scrollbar {
bounds,
corner_radii: (0.).into(),
background: gpui::transparent_black().into(),
border_widths: if is_vertical {
Edges {
top: px(0.),
right: px(0.),
bottom: px(0.),
left: px(0.),
}
} else {
Edges {
top: px(0.),
right: px(0.),
bottom: px(0.),
left: px(0.),
}
border_widths: Edges {
top: px(0.),
right: px(0.),
bottom: px(0.),
left: px(0.),
},
border_color: state.border,
border_style: BorderStyle::default(),
@@ -786,14 +781,15 @@ impl Element for Scrollbar {
let scroll_handle = self.scroll_handle.clone();
move |event: &ScrollWheelEvent, phase, _, cx| {
if phase.bubble() && hitbox_bounds.contains(&event.position) {
if scroll_handle.offset() != state.get().last_scroll_offset {
state.set(state.get().with_last_scroll(
scroll_handle.offset(),
Some(Instant::now()),
));
cx.notify(view_id);
}
if phase.bubble()
&& hitbox_bounds.contains(&event.position)
&& scroll_handle.offset() != state.get().last_scroll_offset
{
state.set(state.get().with_last_scroll(
scroll_handle.offset(),
Some(Instant::now()),
));
cx.notify(view_id);
}
}
});
@@ -866,13 +862,9 @@ impl Element for Scrollbar {
if state.get().hovered_axis != Some(axis) {
notify = true;
}
} else {
if state.get().hovered_axis == Some(axis) {
if state.get().hovered_axis.is_some() {
state.set(state.get().with_hovered(None));
notify = true;
}
}
} else if state.get().hovered_axis == Some(axis) {
state.set(state.get().with_hovered(None));
notify = true;
}
// Update hovered state for scrollbar thumb
@@ -881,11 +873,9 @@ impl Element for Scrollbar {
state.set(state.get().with_hovered_on_thumb(Some(axis)));
notify = true;
}
} else {
if state.get().hovered_on_thumb == Some(axis) {
state.set(state.get().with_hovered_on_thumb(None));
notify = true;
}
} else if state.get().hovered_on_thumb == Some(axis) {
state.set(state.get().with_hovered_on_thumb(None));
notify = true;
}
// Move thumb position on dragging