Skip to content

LT-22688: Arrow keys move between writing systems - #1181

Merged
aror92 merged 7 commits into
mainfrom
avalonia-tab-navigation
Oct 14, 2026
Merged

aror92 merged 7 commits into
mainfrom
avalonia-tab-navigation

Conversation

@aror92

@aror92 aror92 commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Fix Avalonia tab traversal in multistring fields. Rather than having a tab stop at every writing system of a multistring field and at every paragraph of a structured-text field in Avalonia, use one tab stop per field and move between writing systems with the arrow keys (matching WinForms behavior).

Fix highlighting in reference vector fields. Once focused on, a reference vector field would remain highlighted until another reference vector field was selected. The highlight is painted now only while the field or one of its menus is in focus.


Update Avalonia behavior to use arrow keys instead of tab stops to move between WSs:
DetailValueStopGroup (new), used by FwMultiWsTextField and FwStructuredTextField: only the first enterable editor is a Tab stop. Up and Down move to the next or previous writing system (or paragraph) from the last or first visual line. Left and Right do the same at the text edges, and an empty value moves at once. Shift+Tab from a later editor leaves the field. Tab entry puts the caret at the start of existing text instead of selecting all of it.

FwMultiWsTextField's navKeyDown handles every Left/Right press itself, so it now asks the group first; relying on handler order left the edge crossing unreachable in editable rows.

Fix ReferenceVectorField highlighting:
FwReferenceVectorField: the current item stayed highlighted after focus moved on, until another vector row selected an item. The highlight is now painted only while focus is inside the field, a menu gesture is in progress, or one of the item's own menus is open. The item still stays current for menus.

DetailMenuRequest: BeginMenuGesture and EndMenuGesture now reach the row's selection source even without a text editor, so a read-only item stays highlighted while its right-click menu is open.

Add tests:
DataTreeTabNavigationIntegrationTests.cs: replaced the test that expected Tab to visit every writing system, and added tests for Up/Down, Left/Right, Shift+Tab, structured-text paragraphs and caret placement. DetailMenuTests.cs: added the highlight tests.


This change is Reviewable

Tab stopped at every writing system of a multistring field and
at every paragraph of a structured-text field in Avalonia.
The WinForms DataTree has one tab stop per field and moves between
writing systems with the arrow keys.

* Update Avalonia behavior to use arrow keys instead of tab stops
to move between WSs.

DetailValueStopGroup (new), used by FwMultiWsTextField and
FwStructuredTextField: only the first enterable editor is a Tab
stop. Up and Down move to the next or previous writing system
(or paragraph) from the last or first visual line. Left and
Right do the same at the text edges, and an empty value moves
at once. Shift+Tab from a later editor leaves the field. Tab
entry puts the caret at the start of existing text instead of
selecting all of it.

FwMultiWsTextField's navKeyDown handles every Left/Right press
itself, so it now asks the group first; relying on handler
order left the edge crossing unreachable in editable rows.

* Fix ReferenceVectorField highlighting.

FwReferenceVectorField: the current item stayed highlighted
after focus moved on, until another vector row selected an
item. The highlight is now painted only while focus is inside
the field, a menu gesture is in progress, or one of the item's
own menus is open. The item still stays current for menus.

DetailMenuRequest: BeginMenuGesture and EndMenuGesture now
reach the row's selection source even without a text editor,
so a read-only item stays highlighted while its right-click
menu is open.

* Add tests.

DataTreeTabNavigationIntegrationTests.cs: replaced the test
that expected Tab to visit every writing system, and added
tests for Up/Down, Left/Right, Shift+Tab, structured-text
paragraphs and caret placement. DetailMenuTests.cs: added the
highlight tests.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

NUnit Tests

    1 files      1 suites   13m 45s ⏱️
6 656 tests 6 571 ✅ 85 💤 0 ❌
6 665 runs  6 580 ✅ 85 💤 0 ❌

Results for commit 1e0d9b3.

♻️ This comment has been updated with latest results.

@codecov-commenter

codecov-commenter commented Oct 13, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.98131% with 30 lines in your changes missing coverage. Please review.
✅ Project coverage is 39.62%. Comparing base (2b981ed) to head (1e0d9b3).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...c/Common/FwAvalonia/Detail/DetailValueStopGroup.cs 80.14% 7 Missing and 21 partials ⚠️
Src/Common/FwAvalonia/Detail/DetailModel.cs 77.77% 0 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff            @@
##           main    #1181       +/-   ##
=========================================
+ Coverage      0   39.62%   +39.62%     
=========================================
  Files         0     1541     +1541     
  Lines         0   354887   +354887     
  Branches      0    41175    +41175     
=========================================
+ Hits          0   140616   +140616     
- Misses        0   184880   +184880     
- Partials      0    29391    +29391     
Files with missing lines Coverage Δ
Src/Common/FwAvalonia/Detail/FwFieldControls.cs 87.56% <100.00%> (ø)
.../Common/FwAvalonia/Detail/FwStructuredTextField.cs 79.86% <100.00%> (ø)
Src/Common/FwAvalonia/Detail/DetailModel.cs 78.84% <77.77%> (ø)
...c/Common/FwAvalonia/Detail/DetailValueStopGroup.cs 80.14% <80.14%> (ø)

... and 1537 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Include the new focus-tracking handler in the handler count for the
ReferenceVector_ReadOnly_WiresOnlyTheItemSelectHandlers test.
@github-actions

github-actions Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

Comment hygiene (advisory)

No comment-style violations in the lines this branch adds since origin/main.

aror92 and others added 2 commits October 13, 2026 12:14
A structured-text paragraph computed its right-to-left direction
only for the read-along per-run-font display, and only when the
paragraph needed one. The editor was always left-to-right, so an
RTL paragraph flipped direction when it took focus, and the arrow
keys crossed to the next paragraph at the wrong edge.

FwStructuredTextField.cs: added IsFirstRunRightToLeft, which
reads the first run's writing-system font, and used it to set
the paragraph TextBox's FlowDirection when it is created.
CreateValueContentWithFontSwap now reads the direction back from
the box, so the display and the editor cannot disagree.

DetailValueStopGroup already reads the box's FlowDirection to
decide which arrow advances, so it needed no change.

DataTreeTabNavigationIntegrationTests.cs: added tests that an
RTL paragraph, with and without a per-run-font display, takes
its direction and crosses on Left at its logical end and on
Right at its logical start, but not on the opposite keys.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A structured-text paragraph set its editor's FlowDirection once,
when the editor was created. Editing away an RTL first run left
the paragraph right-to-left, so the arrow keys crossed to the
neighboring paragraph at the wrong edge.

FwStructuredTextField.cs: replaced IsFirstRunRightToLeft with
FirstRunRightToLeft, which returns null when the first run is
missing, untagged, or has no font. After each successful
TrySetParagraphText, WireParagraphTextEditing sets FlowDirection
from the new first run when the result is not null. Otherwise the
direction is kept, so emptying an RTL paragraph and retyping does
not flip it mid-edit.

DataTreeTabNavigationIntegrationTests.cs: added tests that
editing away an RTL first run flips the paragraph to the new
first run's direction, that emptying an RTL paragraph keeps it
RTL, and that replacing text in an RTL first run keeps it RTL.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@aror92
aror92 marked this pull request as ready for review October 14, 2026 13:12
@thejambi

Copy link
Copy Markdown
Contributor

Src/Common/FwAvalonia/Detail/DetailValueStopGroup.cs line 208 at r1 (raw file):

		// True when the caret sits on the first (or last) visual line of a wrapped editor, so the
		// arrow has nowhere left to go inside it. An editor with no laid-out text is one line.
		private static bool IsOnEdgeLine(TextBox box, bool first)

Suggestion: add a test for Up/Down in text that wraps

IsOnEdgeLine and CaretNearX are the most layout-sensitive parts of this change. They decide whether Up/Down stays inside a wrapped value or moves to the next writing system, and where the caret lands when it moves. All the Up/Down tests use short single-line values, so neither branch runs; that's where most of this file's partially covered lines in Codecov come from.

One test would cover both. Use a narrow window and a value long enough to wrap to three lines, then check:

  1. With the caret on line 1, Down keeps focus in the same box and moves the caret down a line.
  2. With the caret on line 3, Down moves focus to the next writing system, and the caret lands near the same horizontal position.
  3. Optionally, the mirror case: with the caret on line 1 of a later writing system, Up moves to the previous one.

Not blocking. The single-line behavior is well covered, and this would protect the wrapped case against layout changes.

@thejambi thejambi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

:lgtm:

@thejambi reviewed 7 files and all commit messages, and made 1 comment.
Reviewable status: all files reviewed, 1 unresolved discussion (waiting on aror92).

aror92 and others added 3 commits October 14, 2026 10:23
Every Up/Down test used short single-line values, so the two
layout-dependent branches of DetailValueStopGroup never ran:
IsOnEdgeLine, which decides whether the arrow stays inside a
wrapped value or moves to the next writing system, and
CaretNearX, which picks where the caret lands.

DataTreeTabNavigationIntegrationTests.cs: added
UpAndDownInWrappedText_MoveWithinTheValueBeforeLeavingIt. In a
narrow window with two long values, it checks that Down from the
first line stays in the box and moves to the second line, that
Down from the last line moves to the next writing system's first
line near the same horizontal position, and that Up from there
returns to the previous value's last line.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

@thejambi thejambi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@thejambi reviewed 3 files and all commit messages.
Reviewable status: all files reviewed, 1 unresolved discussion (waiting on aror92).

@aror92
aror92 merged commit e8487e6 into main Oct 14, 2026
8 of 9 checks passed
@aror92
aror92 deleted the avalonia-tab-navigation branch October 14, 2026 14:47
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.

3 participants