Skip to repository content

tenant.openagents/omega

No repository description is available.

OpenAgents Git authority 2026-07-28T03:35:19.140Z Public web read
NIP-34 coordinate30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omega
MaintainersHidden in public view
References2 branches · 1 tag
Read-only clonegit clone https://openagents.com/git/tenant.openagents/omega.git
Browse files

dropdown.rs

140 lines · 4.5 KB · rust
1use std::rc::Rc;
2
3use gpui::{App, ElementId, IntoElement, RenderOnce, SharedString};
4use heck::ToTitleCase as _;
5use ui::{
6    ButtonSize, ContextMenu, Disableable as _, DropdownMenu, DropdownStyle, FluentBuilder as _,
7    IconPosition, px,
8};
9
10#[derive(IntoElement)]
11pub struct EnumVariantDropdown<T>
12where
13    T: strum::VariantArray + strum::VariantNames + Copy + PartialEq + Send + Sync + 'static,
14{
15    id: ElementId,
16    current_value: T,
17    variants: &'static [T],
18    labels: &'static [&'static str],
19    should_do_title_case: bool,
20    tab_index: Option<isize>,
21    disabled: bool,
22    aria_label: Option<SharedString>,
23    aria_description: Option<SharedString>,
24    on_change: Rc<dyn Fn(T, &mut ui::Window, &mut App) + 'static>,
25}
26
27impl<T> EnumVariantDropdown<T>
28where
29    T: strum::VariantArray + strum::VariantNames + Copy + PartialEq + Send + Sync + 'static,
30{
31    pub fn new(
32        id: impl Into<ElementId>,
33        current_value: T,
34        variants: &'static [T],
35        labels: &'static [&'static str],
36        on_change: impl Fn(T, &mut ui::Window, &mut App) + 'static,
37    ) -> Self {
38        Self {
39            id: id.into(),
40            current_value,
41            variants,
42            labels,
43            should_do_title_case: true,
44            tab_index: None,
45            disabled: false,
46            aria_label: None,
47            aria_description: None,
48            on_change: Rc::new(on_change),
49        }
50    }
51
52    pub fn title_case(mut self, title_case: bool) -> Self {
53        self.should_do_title_case = title_case;
54        self
55    }
56
57    pub fn tab_index(mut self, tab_index: isize) -> Self {
58        self.tab_index = Some(tab_index);
59        self
60    }
61
62    pub fn disabled(mut self, disabled: bool) -> Self {
63        self.disabled = disabled;
64        self
65    }
66
67    /// Sets the label announced by assistive technology.
68    /// Defaults to the currently selected value's label.
69    pub fn aria_label(mut self, label: impl Into<SharedString>) -> Self {
70        self.aria_label = Some(label.into());
71        self
72    }
73
74    /// Sets the supplementary description announced by assistive technology
75    /// after the combobox's name, role, and value (e.g. a setting subtitle).
76    pub fn aria_description(mut self, description: impl Into<SharedString>) -> Self {
77        self.aria_description = Some(description.into());
78        self
79    }
80}
81
82impl<T> RenderOnce for EnumVariantDropdown<T>
83where
84    T: strum::VariantArray + strum::VariantNames + Copy + PartialEq + Send + Sync + 'static,
85{
86    fn render(self, window: &mut ui::Window, cx: &mut ui::App) -> impl gpui::IntoElement {
87        let current_value_label = self.labels[self
88            .variants
89            .iter()
90            .position(|v| *v == self.current_value)
91            .unwrap()];
92
93        let context_menu = window.use_keyed_state(current_value_label, cx, |window, cx| {
94            ContextMenu::new(window, cx, move |mut menu, _, _| {
95                for (&value, &label) in std::iter::zip(self.variants, self.labels) {
96                    let on_change = self.on_change.clone();
97                    let current_value = self.current_value;
98                    menu = menu.toggleable_entry(
99                        if self.should_do_title_case {
100                            label.to_title_case()
101                        } else {
102                            label.to_string()
103                        },
104                        value == current_value,
105                        IconPosition::End,
106                        None,
107                        move |window, cx| {
108                            on_change(value, window, cx);
109                        },
110                    );
111                }
112                menu
113            })
114        });
115
116        DropdownMenu::new(
117            self.id,
118            if self.should_do_title_case {
119                current_value_label.to_title_case()
120            } else {
121                current_value_label.to_string()
122            },
123            context_menu,
124        )
125        .when_some(self.aria_label, |this, label| this.aria_label(label))
126        .when_some(self.aria_description, |this, description| {
127            this.aria_description(description)
128        })
129        .disabled(self.disabled)
130        .when_some(self.tab_index, |elem, tab_index| elem.tab_index(tab_index))
131        .trigger_size(ButtonSize::Medium)
132        .style(DropdownStyle::Outlined)
133        .offset(gpui::Point {
134            x: px(0.0),
135            y: px(2.0),
136        })
137        .into_any_element()
138    }
139}
140
Served at tenant.openagents/omega Member data and write actions are omitted.