tab: Use on_click instead of action for TabBar dropdown menu. (#1454)

Close #1453
This commit is contained in:
Jason Lee 2025-10-29 09:04:14 +08:00 committed by GitHub
parent 55db53a46d
commit 4eb1ed2cfd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 48 additions and 31 deletions

View file

@ -168,6 +168,30 @@ impl PopupMenuItem {
self self
} }
/// Set checked state for the menu item by adding or removing check icon.
///
/// If true, will set the icon to check icon, otherwise remove the icon.
pub fn checked(mut self, checked: bool) -> Self {
match &mut self {
PopupMenuItem::Item { icon: i, .. } => {
if checked {
*i = Some(IconName::Check.into());
} else {
*i = None;
}
}
PopupMenuItem::ElementItem { icon: i, .. } => {
if checked {
*i = Some(IconName::Check.into());
} else {
*i = None;
}
}
_ => {}
}
self
}
/// Add a click handler for the menu item. /// Add a click handler for the menu item.
/// ///
/// Only works for [`PopupMenuItem::Item`] and [`PopupMenuItem::ElementItem`]. /// Only works for [`PopupMenuItem::Item`] and [`PopupMenuItem::ElementItem`].

View file

@ -1,22 +1,15 @@
use std::sync::Arc;
use crate::button::{Button, ButtonVariants as _};
use crate::menu::DropdownMenu as _;
use crate::{h_flex, ActiveTheme, IconName, Selectable, Sizable, Size, StyledExt};
use gpui::prelude::FluentBuilder as _;
use gpui::{ use gpui::{
div, Action, AnyElement, App, Corner, Div, Edges, ElementId, IntoElement, ParentElement, div, prelude::FluentBuilder as _, px, AnyElement, App, Corner, Div, Edges, ElementId,
Pixels, RenderOnce, ScrollHandle, Stateful, StatefulInteractiveElement as _, StyleRefinement, InteractiveElement, IntoElement, ParentElement, Pixels, RenderOnce, ScrollHandle, Stateful,
Styled, Window, StatefulInteractiveElement as _, StyleRefinement, Styled, Window,
}; };
use gpui::{px, InteractiveElement};
use smallvec::SmallVec; use smallvec::SmallVec;
use std::rc::Rc;
use super::{Tab, TabVariant}; use super::{Tab, TabVariant};
use crate::button::{Button, ButtonVariants as _};
#[derive(Action, Debug, Clone, Copy, PartialEq, Eq)] use crate::menu::{DropdownMenu as _, PopupMenuItem};
#[action(namespace = tab_bar, no_json)] use crate::{h_flex, ActiveTheme, IconName, Selectable, Sizable, Size, StyledExt};
pub struct SelectTab(usize);
#[derive(IntoElement)] #[derive(IntoElement)]
pub struct TabBar { pub struct TabBar {
@ -31,7 +24,7 @@ pub struct TabBar {
variant: TabVariant, variant: TabVariant,
size: Size, size: Size,
menu: bool, menu: bool,
on_click: Option<Arc<dyn Fn(&usize, &mut Window, &mut App) + 'static>>, on_click: Option<Rc<dyn Fn(&usize, &mut Window, &mut App) + 'static>>,
/// Special for internal TabPanel to remove the top border. /// Special for internal TabPanel to remove the top border.
tab_item_top_offset: Pixels, tab_item_top_offset: Pixels,
} }
@ -138,8 +131,11 @@ impl TabBar {
/// Set the on_click callback of the TabBar, the first parameter is the index of the clicked tab. /// Set the on_click callback of the TabBar, the first parameter is the index of the clicked tab.
/// ///
/// When this is set, the children's on_click will be ignored. /// When this is set, the children's on_click will be ignored.
pub fn on_click(mut self, on_click: impl Fn(&usize, &mut Window, &mut App) + 'static) -> Self { pub fn on_click<F>(mut self, on_click: F) -> Self
self.on_click = Some(Arc::new(on_click)); where
F: Fn(&usize, &mut Window, &mut App) + 'static,
{
self.on_click = Some(Rc::new(on_click));
self self
} }
@ -212,17 +208,10 @@ impl RenderOnce for TabBar {
let mut item_labels = Vec::new(); let mut item_labels = Vec::new();
let selected_index = self.selected_index; let selected_index = self.selected_index;
let on_click = self.on_click.clone();
self.base self.base
.group("tab-bar") .group("tab-bar")
.on_action({
let on_click = self.on_click.clone();
move |action: &SelectTab, window: &mut Window, cx: &mut App| {
if let Some(on_click) = on_click.clone() {
on_click(&action.0, window, cx);
}
}
})
.relative() .relative()
.flex() .flex()
.items_center() .items_center()
@ -286,12 +275,16 @@ impl RenderOnce for TabBar {
.dropdown_menu(move |mut this, _, _| { .dropdown_menu(move |mut this, _, _| {
this = this.scrollable(); this = this.scrollable();
for (ix, (label, disabled)) in item_labels.iter().enumerate() { for (ix, (label, disabled)) in item_labels.iter().enumerate() {
this = this.menu_with_check_and_disabled( this = this.item(
label.clone().unwrap_or_default(), PopupMenuItem::new(label.clone().unwrap_or_default())
selected_index == Some(ix), .checked(selected_index == Some(ix))
Box::new(SelectTab(ix)), .disabled(*disabled)
*disabled, .when_some(on_click.clone(), |this, on_click| {
); this.on_click(move |_, window, cx| {
on_click(&ix, window, cx)
})
}),
)
} }
this this