docking: screen-reader resize values follow the column width on either edge

On a dock at the right edge the column handle passed accessibility
values through the physical axis, so SetValue 300 gave width 180 and
Increment shrank the column. ResizeHandle::reversed applies
accessibility actions in value space; the pointer and arrow keys stay
physical.
This commit is contained in:
aiongg committed 2026-10-20 15:21:46 +00:00
1 parent c084db9c78
commit 0781c48870
3 files changed
+41 -4

No files matched your search

+24
View File
@@ -539,3 +539,27 @@ fn a_dock_wider_than_the_window_shrinks_to_fit_and_resizes() {
assert!(total < 800.0, "{total}");
assert!((d.hit(&Hit::Divider(Divider::Column(1))).unwrap().center().x - (divider.x - 30.0)).abs() < 1.0);
}
#[test]
fn screen_reader_values_follow_the_column_width_on_either_edge() {
use egui::accesskit::{Action as A, ActionData, ActionRequest, TreeId};
for (side, right_to_left) in [(Side::End, false), (Side::Start, true), (Side::Start, false)] {
let mut d = testing::DockDriver::new(docked(side, &[&[&[2]]]), TestContent::default()).with_style(move |s| s.right_to_left = right_to_left);
d.ctx.enable_accesskit();
d.settle();
let id = DockArea::<u32>::hit_id(d.id, &Hit::Divider(Divider::Column(2)));
let request = |action, data| Event::AccessKitActionRequest(ActionRequest { action, target_tree: TreeId::ROOT, target_node: id.accesskit_id(), data });
let case = format!("{side:?}, right to left {right_to_left}");
let out = d.frame(vec![request(A::SetValue, Some(ActionData::NumericValue(300.0)))]);
assert_eq!(out.actions, vec![Action::ResizeColumn { panel: 2, width: 300.0 }], "{case}");
let out = d.frame(vec![request(A::Increment, None)]);
assert_eq!(out.actions, vec![Action::ResizeColumn { panel: 2, width: 248.0 }], "{case}");
// Arrow keys stay physical: right moves the divider right.
d.ctx.memory_mut(|m| m.request_focus(id));
d.frame(vec![]);
let out = d.frame(vec![key(egui::Key::ArrowRight)]);
let wider = d.hit(&Hit::Divider(Divider::Column(2))).unwrap().center().x < 400.0;
let width = if wider { 248.0 } else { 232.0 };
assert_eq!(out.actions, vec![Action::ResizeColumn { panel: 2, width }], "{case}");
}
}
+1
View File
@@ -209,6 +209,7 @@ impl<P: Clone + Eq + Hash + Debug + Send + Sync + 'static> Renderer<'_, P> {
self.handle_style(),
)
.value(width, lo..=hi)
.reversed(inward < 0.0)
.show(ui);
self.register_interaction(ui.ctx(), response.response.id);
let next = (width + inward * response.delta).clamp(lo, hi);
+16 -4
View File
@@ -37,11 +37,12 @@ pub struct ResizeHandle<'a> {
hit_margin: f32,
step: f32,
value: Option<(f32, RangeInclusive<f32>)>,
reversed: bool,
}
impl<'a> ResizeHandle<'a> {
pub fn new(id: Id, axis: SplitAxis, rect: Rect, label: &'a str, style: ResizeHandleStyle) -> Self {
Self { id, axis, rect, label, style, hit_margin: 3.0, step: 8.0, value: None }
Self { id, axis, rect, label, style, hit_margin: 3.0, step: 8.0, value: None, reversed: false }
}
/// Expand the hit rectangle along the movement axis, in logical points. Default: 3.
@@ -63,6 +64,14 @@ impl<'a> ResizeHandle<'a> {
self
}
/// The value grows against the axis, as for a column docked on the right edge that widens
/// as its divider moves left. Accessibility actions then work on the value; the pointer
/// and arrow keys stay physical, and `delta` stays along the axis.
pub fn reversed(mut self, reversed: bool) -> Self {
self.reversed = reversed;
self
}
pub fn show(self, ui: &mut Ui) -> ResizeResponse {
let hit = self.rect.expand2(match self.axis {
SplitAxis::Horizontal => Vec2::new(self.hit_margin, 0.0),
@@ -116,27 +125,30 @@ impl<'a> ResizeHandle<'a> {
}
});
}
let mut change = 0.0;
ui.input_mut(|input| {
input.consume_accesskit_action_requests(response.id, |request| match request.action {
accesskit::Action::Increment => {
delta += self.step;
change += self.step;
true
}
accesskit::Action::Decrement => {
delta -= self.step;
change -= self.step;
true
}
accesskit::Action::SetValue => {
if let (Some((value, range)), Some(accesskit::ActionData::NumericValue(new_value))) = (&self.value, &request.data)
&& new_value.is_finite()
{
delta = (new_value.clamp(f64::from(*range.start()), f64::from(*range.end())) - f64::from(*value)) as f32;
change = (new_value.clamp(f64::from(*range.start()), f64::from(*range.end())) - f64::from(*value)) as f32;
delta = 0.0;
}
true
}
_ => false,
});
});
delta += if self.reversed { -change } else { change };
}
if !delta.is_finite() {
delta = 0.0;