Skip to content

Fix accessible focus in virtualized lists - #13425

Open
0xrariux wants to merge 5 commits into
slint-ui:masterfrom
0xrariux:fix-virtualized-accessible-delegate-focus
Open

0xrariux wants to merge 5 commits into
slint-ui:masterfrom
0xrariux:fix-virtualized-accessible-delegate-focus

Conversation

@0xrariux

Copy link
Copy Markdown

Fixes #12645.

accessible-delegate-focus was resolved as an ordinal among the currently materialized accessible children. For a virtualized ListView, those children start at the visible model index instead of zero, so focus was lost or delegated to the wrong item after scrolling.

This change resolves the delegate against accessible-item-index when descendants expose logical indices. If the requested indexed item is not materialized, focus stays on the parent instead of moving to an unrelated child. Components without indexed descendants retain the existing positional behavior.

The shared resolver is used by both AccessKit/Winit and Qt. The regression test covers a scrolled virtualized list, a target outside the materialized window, and the compatibility path for unindexed children.

Tested with:

  • cargo fmt --check
  • cargo test -p slint-interpreter --features internal,internal-highlight
  • cargo test -p i-slint-backend-winit --lib
  • cargo check -p i-slint-backend-qt
  • cargo clippy -p i-slint-core --lib -- -D warnings

Resolve accessible-delegate-focus against accessible-item-index when
descendants expose logical indices. This keeps focus aligned with
materialized ListView rows after scrolling while preserving positional
delegation for existing unindexed components.

Add a regression test for a virtualized list, an unmaterialized target,
and the positional compatibility path.

Fixes slint-ui#12645

ChangeLog: Fixed accessibility focus delegation for virtualized lists after scrolling past the first items

@ogoffart ogoffart left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These comments are from claude.


The fix does not reach the Qt style. ListItem in
internal/compiler/widgets/qt/std-widgets-impl.slint:11 sets only
accessible-role and accessible-label, with no accessible-item-index. The
other four styles all set it (fluent/components.slint:53,
material:111, cupertino:65, cosmic:109), and even qt/tabwidget.slint:12
sets it for tabs.

So with the native style — the style you get with the Qt backend, which is the
backend whose delegateFocus this PR rewrites — a StandardListView still has
no indexed descendants, keeps the positional path, and focus after scrolling
stays wrong.

The missing property predates this PR, so it is not a regression here. But it
would be good to either add accessible-item-index: root.index; in the same
change, or say in the commit message that Qt-style lists are a follow-up.

Comment thread internal/backends/qt/qt_accessible.rs Outdated
Comment thread internal/backends/qt/qt_accessible.rs Outdated
Comment thread internal/core/accessibility.rs
Comment thread internal/interpreter/tests.rs Outdated
Expose logical indices on Qt list items so native-style virtualized lists
use the indexed focus delegate lookup.

Refresh cached accessibility children before mapping the live delegate
position. Remember the last focus target by QObject identity to avoid
announcing the same row again when scrolling only changes materialization.

Keep the strict fallback for indexed trees: a positional match for a
missing logical row would focus a different row. Document that contract
and assert the resolved item's index in the regression test.
Comment thread internal/interpreter/tests.rs Outdated
The focus delegate resolver belongs to the runtime, so exercise it with a
.slint fixture compiled by the test drivers instead of an interpreter
unit test. Keep the Rust assertions for the scrolled list, missing logical
index, and positional compatibility path.
The shared test calls accessible_descendents, whose existing name is flagged by cspell. Match the local spelling exception in the defining runtime module.
Comment thread internal/backends/qt/qt_accessible.rs
Keep the Qt focus delegation tracker dependent only on the delegate-focus property. Resolve the logical index when delegation runs, outside the tracker, to avoid rebuilding the accessibility subtree during scrolling.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

accessible-delegate-focus resolves against materialised children, losing AX focus past a virtualised ListView's visible window

3 participants