settings_ui: Keyboard navigation (#39652)
Closes #ISSUE Release Notes: - N/A *or* Added/Fixed/Improved ... --------- Co-authored-by: Mikayla <mikayla@zed.dev>
This commit is contained in:
@@ -402,6 +402,11 @@ impl ButtonCommon for Button {
|
||||
self.base = self.base.layer(elevation);
|
||||
self
|
||||
}
|
||||
|
||||
fn track_focus(mut self, focus_handle: &gpui::FocusHandle) -> Self {
|
||||
self.base = self.base.track_focus(focus_handle);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderOnce for Button {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use documented::Documented;
|
||||
use gpui::{
|
||||
AnyElement, AnyView, ClickEvent, CursorStyle, DefiniteLength, Hsla, MouseButton,
|
||||
AnyElement, AnyView, ClickEvent, CursorStyle, DefiniteLength, FocusHandle, Hsla, MouseButton,
|
||||
MouseClickEvent, MouseDownEvent, MouseUpEvent, Rems, StyleRefinement, relative,
|
||||
transparent_black,
|
||||
};
|
||||
@@ -41,6 +41,8 @@ pub trait ButtonCommon: Clickable + Disableable {
|
||||
fn tab_index(self, tab_index: impl Into<isize>) -> Self;
|
||||
|
||||
fn layer(self, elevation: ElevationIndex) -> Self;
|
||||
|
||||
fn track_focus(self, focus_handle: &FocusHandle) -> Self;
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)]
|
||||
@@ -405,6 +407,7 @@ pub struct ButtonLike {
|
||||
on_click: Option<Box<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>>,
|
||||
on_right_click: Option<Box<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>>,
|
||||
children: SmallVec<[AnyElement; 2]>,
|
||||
focus_handle: Option<FocusHandle>,
|
||||
}
|
||||
|
||||
impl ButtonLike {
|
||||
@@ -428,6 +431,7 @@ impl ButtonLike {
|
||||
on_right_click: None,
|
||||
layer: None,
|
||||
tab_index: None,
|
||||
focus_handle: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -549,6 +553,11 @@ impl ButtonCommon for ButtonLike {
|
||||
self.layer = Some(elevation);
|
||||
self
|
||||
}
|
||||
|
||||
fn track_focus(mut self, focus_handle: &gpui::FocusHandle) -> Self {
|
||||
self.focus_handle = Some(focus_handle.clone());
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl VisibleOnHover for ButtonLike {
|
||||
@@ -575,6 +584,9 @@ impl RenderOnce for ButtonLike {
|
||||
.h_flex()
|
||||
.id(self.id.clone())
|
||||
.when_some(self.tab_index, |this, tab_index| this.tab_index(tab_index))
|
||||
.when_some(self.focus_handle, |this, focus_handle| {
|
||||
this.track_focus(&focus_handle)
|
||||
})
|
||||
.font_ui(cx)
|
||||
.group("")
|
||||
.flex_none()
|
||||
|
||||
@@ -173,6 +173,11 @@ impl ButtonCommon for IconButton {
|
||||
self.base = self.base.layer(elevation);
|
||||
self
|
||||
}
|
||||
|
||||
fn track_focus(mut self, focus_handle: &gpui::FocusHandle) -> Self {
|
||||
self.base = self.base.track_focus(focus_handle);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl VisibleOnHover for IconButton {
|
||||
|
||||
@@ -132,6 +132,11 @@ impl ButtonCommon for ToggleButton {
|
||||
self.base = self.base.layer(elevation);
|
||||
self
|
||||
}
|
||||
|
||||
fn track_focus(mut self, focus_handle: &gpui::FocusHandle) -> Self {
|
||||
self.base = self.base.track_focus(focus_handle);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderOnce for ToggleButton {
|
||||
|
||||
@@ -29,6 +29,7 @@ pub struct DropdownMenu {
|
||||
handle: Option<PopoverMenuHandle<ContextMenu>>,
|
||||
attach: Option<Corner>,
|
||||
offset: Option<Point<Pixels>>,
|
||||
tab_index: Option<isize>,
|
||||
}
|
||||
|
||||
impl DropdownMenu {
|
||||
@@ -48,6 +49,7 @@ impl DropdownMenu {
|
||||
handle: None,
|
||||
attach: None,
|
||||
offset: None,
|
||||
tab_index: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,6 +69,7 @@ impl DropdownMenu {
|
||||
handle: None,
|
||||
attach: None,
|
||||
offset: None,
|
||||
tab_index: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,6 +104,11 @@ impl DropdownMenu {
|
||||
self.offset = Some(offset);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn tab_index(mut self, arg: isize) -> Self {
|
||||
self.tab_index = Some(arg);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Disableable for DropdownMenu {
|
||||
@@ -140,7 +148,8 @@ impl RenderOnce for DropdownMenu {
|
||||
.when(full_width, |this| this.full_width())
|
||||
.size(trigger_size)
|
||||
.disabled(self.disabled),
|
||||
};
|
||||
}
|
||||
.when_some(self.tab_index, |this, tab_index| this.tab_index(tab_index));
|
||||
|
||||
PopoverMenu::new((self.id.clone(), "popover"))
|
||||
.full_width(self.full_width)
|
||||
|
||||
@@ -20,6 +20,7 @@ pub struct TreeViewItem {
|
||||
on_hover: Option<Box<dyn Fn(&bool, &mut Window, &mut App) + 'static>>,
|
||||
on_toggle: Option<Arc<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>>,
|
||||
on_secondary_mouse_down: Option<Box<dyn Fn(&MouseDownEvent, &mut Window, &mut App) + 'static>>,
|
||||
tab_index: Option<isize>,
|
||||
}
|
||||
|
||||
impl TreeViewItem {
|
||||
@@ -39,6 +40,7 @@ impl TreeViewItem {
|
||||
on_hover: None,
|
||||
on_toggle: None,
|
||||
on_secondary_mouse_down: None,
|
||||
tab_index: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,6 +75,11 @@ impl TreeViewItem {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn tab_index(mut self, tab_index: isize) -> Self {
|
||||
self.tab_index = Some(tab_index);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn expanded(mut self, toggle: bool) -> Self {
|
||||
self.expanded = toggle;
|
||||
self
|
||||
@@ -142,6 +149,7 @@ impl RenderOnce for TreeViewItem {
|
||||
.cursor_pointer()
|
||||
.size_full()
|
||||
.relative()
|
||||
.when_some(self.tab_index, |this, index| this.tab_index(index))
|
||||
.map(|this| {
|
||||
let label = self.label;
|
||||
if self.root_item {
|
||||
@@ -151,16 +159,10 @@ impl RenderOnce for TreeViewItem {
|
||||
.gap_2p5()
|
||||
.rounded_sm()
|
||||
.border_1()
|
||||
.map(|this| {
|
||||
if self.focused && self.selected {
|
||||
this.border_color(focused_border).bg(selected_bg)
|
||||
} else if self.focused {
|
||||
this.border_color(focused_border)
|
||||
} else if self.selected {
|
||||
this.border_color(selected_border).bg(selected_bg)
|
||||
} else {
|
||||
this.border_color(transparent_border)
|
||||
}
|
||||
.focus(|s| s.border_color(focused_border))
|
||||
.border_color(transparent_border)
|
||||
.when(self.selected, |this| {
|
||||
this.border_color(selected_border).bg(selected_bg)
|
||||
})
|
||||
.hover(|s| s.bg(cx.theme().colors().element_hover))
|
||||
.child(
|
||||
@@ -181,21 +183,17 @@ impl RenderOnce for TreeViewItem {
|
||||
} else {
|
||||
this.child(indentation_line).child(
|
||||
h_flex()
|
||||
.id("nested_inner_tree_view_item")
|
||||
.w_full()
|
||||
.flex_grow()
|
||||
.px_1()
|
||||
.rounded_sm()
|
||||
.border_1()
|
||||
.map(|this| {
|
||||
if self.focused && self.selected {
|
||||
this.border_color(focused_border).bg(selected_bg)
|
||||
} else if self.focused {
|
||||
this.border_color(focused_border)
|
||||
} else if self.selected {
|
||||
this.border_color(selected_border).bg(selected_bg)
|
||||
} else {
|
||||
this.border_color(transparent_border)
|
||||
}
|
||||
.focusable()
|
||||
.in_focus(|s| s.border_color(focused_border))
|
||||
.border_color(transparent_border)
|
||||
.when(self.selected, |this| {
|
||||
this.border_color(selected_border).bg(selected_bg)
|
||||
})
|
||||
.hover(|s| s.bg(cx.theme().colors().element_hover))
|
||||
.child(
|
||||
@@ -209,11 +207,13 @@ impl RenderOnce for TreeViewItem {
|
||||
.when_some(
|
||||
self.on_click.filter(|_| !self.disabled),
|
||||
|this, on_click| {
|
||||
if self.root_item && self.on_toggle.is_some() {
|
||||
let on_toggle = self.on_toggle.clone().unwrap();
|
||||
|
||||
if self.root_item
|
||||
&& let Some(on_toggle) = self.on_toggle.clone()
|
||||
{
|
||||
this.on_click(move |event, window, cx| {
|
||||
on_click(event, window, cx);
|
||||
if !event.is_keyboard() {
|
||||
on_click(event, window, cx);
|
||||
}
|
||||
on_toggle(event, window, cx);
|
||||
})
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user