mirror of
https://github.com/emilk/egui.git
synced 2026-08-29 04:40:03 -04:00
Hand out an AccessKit focus request at the start of the pass
AccessKit asks for focus by node id, and `Focus::interested_in_focus` only picks the request up once the widget itself runs. Everything that reads the focus before the widget — styling it, for one — therefore saw the old focus, so a text edit was styled unfocused in the very pass it got focused, and lost its focus ring for a frame. A widget in `focus_widgets_cache` has asked for focus in an earlier pass, so it is one we can hand focus to in `begin_pass`, the same way a `request_focus` from the last pass is handed out. Memory then holds the focus before any widget runs, and `Ui::widget_style` needs to know nothing about focus at all. `interested_in_focus` keeps the same grant as a fallback, for the first pass a widget is focusable in, and the two share `take_focus_from_accesskit`. The four `text_edit_*` snapshots gain a caret along with the ring, because the field is now focused for real in that pass rather than a pass later. Also drops `fallback_gap` from `TextEdit`, which has no `gap` of its own to defer to, and moves the `DragValue` `HasClasses` impl above its test module.
This commit is contained in:
@@ -618,6 +618,27 @@ impl Focus {
|
|||||||
self.id_requested_by_accesskit = Some(*target_node);
|
self.id_requested_by_accesskit = Some(*target_node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// `interested_in_focus` only picks the request up once the widget runs, which is too late
|
||||||
|
// for anything that reads the focus before it — styling the widget, for one. A widget in
|
||||||
|
// the cache asked for focus in an earlier pass, so it is one we can hand focus to now.
|
||||||
|
let accesskit_focus = self.id_requested_by_accesskit.and_then(|node_id| {
|
||||||
|
self.focus_widgets_cache
|
||||||
|
.keys()
|
||||||
|
.find(|id| id.accesskit_id() == node_id)
|
||||||
|
.copied()
|
||||||
|
});
|
||||||
|
if let Some(id) = accesskit_focus {
|
||||||
|
self.take_focus_from_accesskit(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Give a widget the focus that AccessKit asked for.
|
||||||
|
fn take_focus_from_accesskit(&mut self, id: Id) {
|
||||||
|
self.focused_widget = Some(FocusWidget::new(id));
|
||||||
|
self.id_requested_by_accesskit = None;
|
||||||
|
self.give_to_next = false;
|
||||||
|
self.reset_focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn end_pass(&mut self, used_ids: &IdMap<Rect>) {
|
pub(crate) fn end_pass(&mut self, used_ids: &IdMap<Rect>) {
|
||||||
@@ -645,11 +666,10 @@ impl Focus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn interested_in_focus(&mut self, id: Id) {
|
fn interested_in_focus(&mut self, id: Id) {
|
||||||
|
// `begin_pass` hands out the request as soon as it can, but it can only recognize a widget
|
||||||
|
// that has been here before. This catches the first pass a widget is focusable in.
|
||||||
if self.id_requested_by_accesskit == Some(id.accesskit_id()) {
|
if self.id_requested_by_accesskit == Some(id.accesskit_id()) {
|
||||||
self.focused_widget = Some(FocusWidget::new(id));
|
self.take_focus_from_accesskit(id);
|
||||||
self.id_requested_by_accesskit = None;
|
|
||||||
self.give_to_next = false;
|
|
||||||
self.reset_focus();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The rect is updated at the end of the frame.
|
// The rect is updated at the end of the frame.
|
||||||
|
|||||||
@@ -603,7 +603,7 @@ impl Widget for DragValue<'_> {
|
|||||||
.clip_text(false)
|
.clip_text(false)
|
||||||
.horizontal_align(ui.layout().horizontal_align())
|
.horizontal_align(ui.layout().horizontal_align())
|
||||||
.vertical_align(ui.layout().vertical_align())
|
.vertical_align(ui.layout().vertical_align())
|
||||||
.min_size(min_size.unwrap_or(ui.spacing().interact_size))
|
.min_size(min_size.unwrap_or_else(|| ui.spacing().interact_size))
|
||||||
.id(id)
|
.id(id)
|
||||||
.desired_width(
|
.desired_width(
|
||||||
ui.spacing().interact_size.x - 2.0 * ui.spacing().button_padding.x,
|
ui.spacing().interact_size.x - 2.0 * ui.spacing().button_padding.x,
|
||||||
@@ -654,7 +654,7 @@ impl Widget for DragValue<'_> {
|
|||||||
.wrap_mode(TextWrapMode::Extend)
|
.wrap_mode(TextWrapMode::Extend)
|
||||||
.sense(Sense::click_and_drag())
|
.sense(Sense::click_and_drag())
|
||||||
.gap(0.0)
|
.gap(0.0)
|
||||||
.min_size(min_size.unwrap_or(ui.spacing().interact_size)); // TODO(emilk): find some more generic solution to `min_size`
|
.min_size(min_size.unwrap_or_else(|| ui.spacing().interact_size)); // TODO(emilk): find some more generic solution to `min_size`
|
||||||
|
|
||||||
let cursor_icon = if value <= *range.start() {
|
let cursor_icon = if value <= *range.start() {
|
||||||
CursorIcon::ResizeEast
|
CursorIcon::ResizeEast
|
||||||
@@ -822,6 +822,16 @@ fn select_all_text(ui: &Ui, widget_id: Id, response_id: Id, value_text: &str) {
|
|||||||
state.store(ui.ctx(), response_id);
|
state.store(ui.ctx(), response_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl HasClasses for DragValue<'_> {
|
||||||
|
fn classes(&self) -> &Classes {
|
||||||
|
&self.classes
|
||||||
|
}
|
||||||
|
|
||||||
|
fn classes_mut(&mut self) -> &mut Classes {
|
||||||
|
&mut self.classes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::clamp_value_to_range;
|
use super::clamp_value_to_range;
|
||||||
@@ -881,13 +891,3 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HasClasses for DragValue<'_> {
|
|
||||||
fn classes(&self) -> &Classes {
|
|
||||||
&self.classes
|
|
||||||
}
|
|
||||||
|
|
||||||
fn classes_mut(&mut self) -> &mut Classes {
|
|
||||||
&mut self.classes
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -745,7 +745,7 @@ impl TextEdit<'_> {
|
|||||||
|
|
||||||
let allocated = AtomLayout::new(atoms)
|
let allocated = AtomLayout::new(atoms)
|
||||||
.id(id)
|
.id(id)
|
||||||
.fallback_gap(gap)
|
.gap(gap)
|
||||||
.min_size(Vec2::new(allocate_width, min_height.at_least(min_size.y)))
|
.min_size(Vec2::new(allocate_width, min_height.at_least(min_size.y)))
|
||||||
.max_width(allocate_width)
|
.max_width(allocate_width)
|
||||||
.sense(sense)
|
.sense(sense)
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:570216d6ffa3cc278705582d95b96200bc3ef1608b8f2983a6ed3f8b2ee7276c
|
oid sha256:806f3f69228e62d9d0838fb27a02f46cae29efffee54d8182ecbfd2c12f405ba
|
||||||
size 2280
|
size 2413
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:b66afca19d0a0a6fac4737816443fbd481635897807689dbd75321360ffa079d
|
oid sha256:2ae71de200dfb36f64e1ce95c2ad78ef3c1e88e792ada5b5fa1d8fa8c938d8fd
|
||||||
size 13803
|
size 13806
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:20afbde3e1edc7a599936f83188fb1a2c35d2d1344ce7ad8e115b937266481fc
|
oid sha256:10459c5ac931ee55d814e7e4122167f1d4050fff39c409cef995c91d6deaef55
|
||||||
size 2547
|
size 2563
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:4b0af10fca47b33752aed2549528dba6b6e8c4818f2fc2b9de60451afdd30a2b
|
oid sha256:123f7d1a86d644d2e830a2c8b73e8c509ce33fd5d3ead28d3eccf6180a2fcfc5
|
||||||
size 1690
|
size 1790
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:76be7b08da637ecbf898efd8322615d5e2f1cb1757665e5486db86ccb7fb3438
|
oid sha256:f916e217bd4beb3637acb5394a7da876f9ec684860c9ca922f8bfa3ded6a2684
|
||||||
size 9462
|
size 9462
|
||||||
|
|||||||
Reference in New Issue
Block a user