Fix keyboard navigation for numberedit

This commit is contained in:
Simon Gellis 2025-02-13 23:06:27 -05:00
parent c4f17bfc13
commit 92ccc482ae
1 changed files with 45 additions and 8 deletions

View File

@ -1,8 +1,9 @@
use std::ops::{Bound, RangeBounds}; use std::ops::{Bound, RangeBounds};
use egui::{ use egui::{
ecolor::HexColor, Align, Color32, CursorIcon, Frame, Layout, Margin, Rect, Response, RichText, ecolor::HexColor, Align, Color32, CursorIcon, Event, Frame, Key, Layout, Margin, Rect,
Rounding, Sense, Shape, Stroke, TextEdit, Ui, UiBuilder, Vec2, Widget, WidgetText, Response, RichText, Rounding, Sense, Shape, Stroke, TextEdit, Ui, UiBuilder, Vec2, Widget,
WidgetText,
}; };
pub trait UiExt { pub trait UiExt {
@ -117,10 +118,13 @@ impl<'a> NumberEdit<'a> {
impl Widget for NumberEdit<'_> { impl Widget for NumberEdit<'_> {
fn ui(self, ui: &mut Ui) -> Response { fn ui(self, ui: &mut Ui) -> Response {
let (last_value, mut str) = ui.memory(|m| { let (last_value, mut str, focus) = ui.memory(|m| {
m.data let (lv, s) = m
.data
.get_temp(ui.id()) .get_temp(ui.id())
.unwrap_or((*self.value, self.value.to_string())) .unwrap_or((*self.value, self.value.to_string()));
let focus = m.has_focus(ui.id());
(lv, s, focus)
}); });
let mut stale = false; let mut stale = false;
if *self.value != last_value { if *self.value != last_value {
@ -128,8 +132,34 @@ impl Widget for NumberEdit<'_> {
stale = true; stale = true;
} }
let valid = str.parse().is_ok_and(|v: usize| v == *self.value); let valid = str.parse().is_ok_and(|v: usize| v == *self.value);
let mut up_pressed = false;
let mut down_pressed = false;
if focus {
ui.input_mut(|i| {
i.events.retain(|e| match e {
Event::Key {
key: Key::ArrowUp,
pressed: true,
..
} => {
up_pressed = true;
false
}
Event::Key {
key: Key::ArrowDown,
pressed: true,
..
} => {
down_pressed = true;
false
}
_ => true,
})
});
}
let text = TextEdit::singleline(&mut str) let text = TextEdit::singleline(&mut str)
.horizontal_align(Align::Max) .horizontal_align(Align::Max)
.id(ui.id())
.margin(Margin { .margin(Margin {
left: 4.0, left: 4.0,
right: 20.0, right: 20.0,
@ -167,14 +197,14 @@ impl Widget for NumberEdit<'_> {
min: (arrow_left, arrow_top).into(), min: (arrow_left, arrow_top).into(),
max: (arrow_right, arrow_middle).into(), max: (arrow_right, arrow_middle).into(),
}; };
if draw_arrow(ui, top_arrow_rect, true).clicked_or_dragged() { if draw_arrow(ui, top_arrow_rect, true).clicked_or_dragged() || up_pressed {
delta = 1; delta = 1;
} }
let bottom_arrow_rect = Rect { let bottom_arrow_rect = Rect {
min: (arrow_left, arrow_middle).into(), min: (arrow_left, arrow_middle).into(),
max: (arrow_right, arrow_bottom).into(), max: (arrow_right, arrow_bottom).into(),
}; };
if draw_arrow(ui, bottom_arrow_rect, false).clicked_or_dragged() { if draw_arrow(ui, bottom_arrow_rect, false).clicked_or_dragged() || down_pressed {
delta = -1; delta = -1;
} }
@ -201,7 +231,14 @@ impl Widget for NumberEdit<'_> {
fn draw_arrow(ui: &mut Ui, rect: Rect, up: bool) -> Response { fn draw_arrow(ui: &mut Ui, rect: Rect, up: bool) -> Response {
let arrow_res = ui let arrow_res = ui
.allocate_rect(rect, Sense::click_and_drag()) .allocate_rect(
rect,
Sense {
click: true,
drag: true,
focusable: false,
},
)
.on_hover_cursor(CursorIcon::Default); .on_hover_cursor(CursorIcon::Default);
let visuals = ui.style().visuals.widgets.style(&arrow_res); let visuals = ui.style().visuals.widgets.style(&arrow_res);
let painter = ui.painter_at(arrow_res.rect); let painter = ui.painter_at(arrow_res.rect);