use std::rc::Rc;
use gpui_kit::component::button::Button;
use gpui_kit::component::menu::{DropdownMenu as _, PopupMenuItem};
use gpui_kit::component::{Icon, IconName, Sizable as _, h_flex};
use gpui_kit::{App, ElementId, IntoElement, ParentElement as _, RenderOnce, SharedString, Styled as _, Window, div, px};
type OnPick = Rc<dyn Fn(usize, &mut Window, &mut App)>;
const MENU_MAX_H: f32 = 360.;
#[derive(IntoElement)]
pub struct MenuSelect {
id: ElementId,
options: Vec<SharedString>,
selected: Option<usize>,
placeholder: SharedString,
on_pick: OnPick,
}
impl MenuSelect {
pub fn new(id: impl Into<ElementId>, options: Vec<SharedString>, selected: Option<usize>, on_pick: impl Fn(usize, &mut Window, &mut App) + 'static) -> Self {
Self { id: id.into(), options, selected, placeholder: "Choose…".into(), on_pick: Rc::new(on_pick) }
}
pub fn placeholder(mut self, text: impl Into<SharedString>) -> Self {
self.placeholder = text.into();
self
}
}
impl RenderOnce for MenuSelect {
fn render(self, _: &mut Window, _: &mut App) -> impl IntoElement {
let Self { id, options, selected, placeholder, on_pick } = self;
let current = selected.and_then(|i| options.get(i).cloned()).unwrap_or(placeholder);
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());
Button::new(id).outline().small().min_w_0().w_full().child(face).cursor_pointer().dropdown_menu(move |menu, _, _| {
let mut menu = menu.scrollable(true).max_h(px(MENU_MAX_H));
for (i, label) in options.iter().enumerate() {
let on_pick = on_pick.clone();
menu = menu.item(PopupMenuItem::new(label.clone()).checked(selected == Some(i)).on_click(move |_, window, cx| on_pick(i, window, cx)));
}
menu
})
}
}