kitchen_ui/widgets/
menu_select.rs1use std::rc::Rc;
4
5use gpui_kit::component::button::Button;
6use gpui_kit::component::menu::{DropdownMenu as _, PopupMenuItem};
7use gpui_kit::component::{Icon, IconName, Sizable as _, h_flex};
8use gpui_kit::{App, ElementId, IntoElement, ParentElement as _, RenderOnce, SharedString, Styled as _, Window, div, px};
9
10type OnPick = Rc<dyn Fn(usize, &mut Window, &mut App)>;
11
12const MENU_MAX_H: f32 = 360.;
14
15#[derive(IntoElement)]
19pub struct MenuSelect {
20 id: ElementId,
21 options: Vec<SharedString>,
22 selected: Option<usize>,
23 placeholder: SharedString,
24 on_pick: OnPick,
25}
26
27impl MenuSelect {
28 pub fn new(id: impl Into<ElementId>, options: Vec<SharedString>, selected: Option<usize>, on_pick: impl Fn(usize, &mut Window, &mut App) + 'static) -> Self {
30 Self { id: id.into(), options, selected, placeholder: "Choose…".into(), on_pick: Rc::new(on_pick) }
31 }
32
33 pub fn placeholder(mut self, text: impl Into<SharedString>) -> Self {
35 self.placeholder = text.into();
36 self
37 }
38}
39
40impl RenderOnce for MenuSelect {
41 fn render(self, _: &mut Window, _: &mut App) -> impl IntoElement {
42 let Self { id, options, selected, placeholder, on_pick } = self;
43 let current = selected.and_then(|i| options.get(i).cloned()).unwrap_or(placeholder);
44 let face = h_flex().w_full().min_w_0().gap_1().child(div().flex_1().min_w_0().truncate().text_left().child(current)).child(Icon::new(IconName::ChevronDown).xsmall());
45 Button::new(id).outline().small().min_w_0().w_full().child(face).cursor_pointer().dropdown_menu(move |menu, _, _| {
46 let mut menu = menu.scrollable(true).max_h(px(MENU_MAX_H));
47 for (i, label) in options.iter().enumerate() {
48 let on_pick = on_pick.clone();
49 menu = menu.item(PopupMenuItem::new(label.clone()).checked(selected == Some(i)).on_click(move |_, window, cx| on_pick(i, window, cx)));
50 }
51 menu
52 })
53 }
54}