tab_stop.rs

  1use gpui::{
  2    App, Application, Bounds, Context, Div, ElementId, FocusHandle, KeyBinding, SharedString,
  3    Stateful, Window, WindowBounds, WindowOptions, actions, div, prelude::*, px, size,
  4};
  5
  6actions!(example, [Tab, TabPrev]);
  7
  8struct Example {
  9    focus_handle: FocusHandle,
 10    items: Vec<FocusHandle>,
 11    message: SharedString,
 12}
 13
 14impl Example {
 15    fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
 16        let items = vec![
 17            cx.focus_handle().tab_index(1).tab_stop(true),
 18            cx.focus_handle().tab_index(2).tab_stop(true),
 19            cx.focus_handle().tab_index(3).tab_stop(true),
 20            cx.focus_handle(),
 21            cx.focus_handle().tab_index(2).tab_stop(true),
 22        ];
 23
 24        let focus_handle = cx.focus_handle();
 25        window.focus(&focus_handle, cx);
 26
 27        Self {
 28            focus_handle,
 29            items,
 30            message: SharedString::from("Press `Tab`, `Shift-Tab` to switch focus."),
 31        }
 32    }
 33
 34    fn on_tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 35        window.focus_next(cx);
 36        self.message = SharedString::from("You have pressed `Tab`.");
 37    }
 38
 39    fn on_tab_prev(&mut self, _: &TabPrev, window: &mut Window, cx: &mut Context<Self>) {
 40        window.focus_prev(cx);
 41        self.message = SharedString::from("You have pressed `Shift-Tab`.");
 42    }
 43}
 44
 45impl Render for Example {
 46    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
 47        fn tab_stop_style<T: Styled>(this: T) -> T {
 48            this.border_3().border_color(gpui::blue())
 49        }
 50
 51        fn button(id: impl Into<ElementId>) -> Stateful<Div> {
 52            div()
 53                .id(id)
 54                .h_10()
 55                .flex_1()
 56                .flex()
 57                .justify_center()
 58                .items_center()
 59                .border_1()
 60                .border_color(gpui::black())
 61                .bg(gpui::black())
 62                .text_color(gpui::white())
 63                .focus(tab_stop_style)
 64                .shadow_sm()
 65        }
 66
 67        div()
 68            .id("app")
 69            .track_focus(&self.focus_handle)
 70            .on_action(cx.listener(Self::on_tab))
 71            .on_action(cx.listener(Self::on_tab_prev))
 72            .size_full()
 73            .flex()
 74            .flex_col()
 75            .p_4()
 76            .gap_3()
 77            .bg(gpui::white())
 78            .text_color(gpui::black())
 79            .child(self.message.clone())
 80            .children(
 81                self.items
 82                    .clone()
 83                    .into_iter()
 84                    .enumerate()
 85                    .map(|(ix, item_handle)| {
 86                        div()
 87                            .id(("item", ix))
 88                            .track_focus(&item_handle)
 89                            .h_10()
 90                            .w_full()
 91                            .flex()
 92                            .justify_center()
 93                            .items_center()
 94                            .border_1()
 95                            .border_color(gpui::black())
 96                            .when(
 97                                item_handle.tab_stop && item_handle.is_focused(window),
 98                                tab_stop_style,
 99                            )
100                            .map(|this| match item_handle.tab_stop {
101                                true => this
102                                    .hover(|this| this.bg(gpui::black().opacity(0.1)))
103                                    .child(format!("tab_index: {}", item_handle.tab_index)),
104                                false => this.opacity(0.4).child("tab_stop: false"),
105                            })
106                    }),
107            )
108            .child(
109                div()
110                    .flex()
111                    .flex_row()
112                    .gap_3()
113                    .items_center()
114                    .child(
115                        button("el1")
116                            .tab_index(4)
117                            .child("Button 1")
118                            .on_click(cx.listener(|this, _, _, cx| {
119                                this.message = "You have clicked Button 1.".into();
120                                cx.notify();
121                            })),
122                    )
123                    .child(
124                        button("el2")
125                            .tab_index(5)
126                            .child("Button 2")
127                            .on_click(cx.listener(|this, _, _, cx| {
128                                this.message = "You have clicked Button 2.".into();
129                                cx.notify();
130                            })),
131                    ),
132            )
133            .child(
134                div()
135                    .id("group-1")
136                    .tab_index(6)
137                    .tab_group()
138                    .tab_stop(false)
139                    .child(
140                        button("group-1-button-1")
141                            .tab_index(1)
142                            .child("Tab index [6, 1]"),
143                    )
144                    .child(
145                        button("group-1-button-2")
146                            .tab_index(2)
147                            .child("Tab index [6, 2]"),
148                    )
149                    .child(
150                        button("group-1-button-3")
151                            .tab_index(3)
152                            .child("Tab index [6, 3]"),
153                    ),
154            )
155            .child(
156                div()
157                    .id("group-2")
158                    .tab_index(7)
159                    .tab_group()
160                    .tab_stop(false)
161                    .child(
162                        button("group-2-button-1")
163                            .tab_index(1)
164                            .child("Tab index [7, 1]"),
165                    )
166                    .child(
167                        button("group-2-button-2")
168                            .tab_index(2)
169                            .child("Tab index [7, 2]"),
170                    )
171                    .child(
172                        button("group-2-button-3")
173                            .tab_index(3)
174                            .child("Tab index [7, 3]"),
175                    ),
176            )
177    }
178}
179
180fn main() {
181    Application::new().run(|cx: &mut App| {
182        cx.bind_keys([
183            KeyBinding::new("tab", Tab, None),
184            KeyBinding::new("shift-tab", TabPrev, None),
185        ]);
186
187        let bounds = Bounds::centered(None, size(px(800.), px(600.0)), cx);
188        cx.open_window(
189            WindowOptions {
190                window_bounds: Some(WindowBounds::Windowed(bounds)),
191                ..Default::default()
192            },
193            |window, cx| cx.new(|cx| Example::new(window, cx)),
194        )
195        .unwrap();
196
197        cx.activate(true);
198    });
199}