From 8b57dd6f7fca7f3832d92eeafee581b7062f3e2d Mon Sep 17 00:00:00 2001 From: Jason Naylor Date: Fri, 16 Oct 2026 08:36:00 -0700 Subject: [PATCH 1/3] LT-22687: Add a UX guide and decision register under Docs/ux Docs/ux/README.md states how the FieldWorks UI should look and behave, in sections for universal rules, dialogs, browse views, detail views and interlinear text. Most rules keep long-standing WinForms behavior; the three that depart from it are marked as needing team consensus. A register tracks the adopted, provisional and temporary decisions. winforms-theme-baseline.md lists the WinForms colors and sizes beside the Avalonia tokens that replaced them, so divergence can be measured. Also points the ADR index and the Avalonia migration skills at the guide. Co-Authored-By: Claude Opus 5.5 --- .claude/skills/convert-dialog/SKILL.md | 4 +- .claude/skills/dialog-update/SKILL.md | 4 +- .../skills/fieldworks-avalonia-ui/SKILL.md | 4 + .../SKILL.md | 5 + Docs/architecture/adr/README.md | 4 +- Docs/ux/README.md | 569 ++++++++++++++++++ Docs/ux/winforms-theme-baseline.md | 74 +++ 7 files changed, 661 insertions(+), 3 deletions(-) create mode 100644 Docs/ux/README.md create mode 100644 Docs/ux/winforms-theme-baseline.md diff --git a/.claude/skills/convert-dialog/SKILL.md b/.claude/skills/convert-dialog/SKILL.md index 98deb77fe3..43227dd4af 100644 --- a/.claude/skills/convert-dialog/SKILL.md +++ b/.claude/skills/convert-dialog/SKILL.md @@ -210,7 +210,9 @@ create-integration-test skill consumes this file verbatim. in the migration skill). 3. From the analysis document's layout section, propose an Avalonia layout that AT MINIMUM replicates the WinForms capability; exceed it where the - effort is low. + effort is low. Check it against the Universal and Dialogs rules in + `Docs/ux/README.md` (buttons, window behavior, help, input checking, + choosers); the guide's rule wins over a WinForms habit it replaces. 4. For items with no exemplar: catalog the item's purpose and capabilities, then look for an adequate replacement in Avalonia packages -- both those already imported and others not yet used (an un-imported package is a diff --git a/.claude/skills/dialog-update/SKILL.md b/.claude/skills/dialog-update/SKILL.md index 9dd9bfbc46..1274b9d750 100644 --- a/.claude/skills/dialog-update/SKILL.md +++ b/.claude/skills/dialog-update/SKILL.md @@ -19,7 +19,9 @@ believe a divergence is warranted, stop and ask; do not encode it and move on. Approved divergences must be recorded (see *Divergence register* below) with a one-line reason and the approver — otherwise the next person reads it as a bug -and "fixes" it, thrashing the code. +and "fixes" it, thrashing the code. A difference that applies to dialogs in +general (button order, help, input checking) is a UX guide rule in +`Docs/ux/README.md`, not a per-dialog divergence. ## The dialog pairs (start here) diff --git a/.claude/skills/fieldworks-avalonia-ui/SKILL.md b/.claude/skills/fieldworks-avalonia-ui/SKILL.md index be0bbc9a3a..860c514263 100644 --- a/.claude/skills/fieldworks-avalonia-ui/SKILL.md +++ b/.claude/skills/fieldworks-avalonia-ui/SKILL.md @@ -19,6 +19,10 @@ description: "Build, review, or fix Avalonia UI code in FieldWorks: XAML, MVVM, ## Start From the Established Patterns +The user-visible rules (labels, menus, keyboard, theme values, dialog buttons, +browse and detail behavior) are in the UX guide, `Docs/ux/README.md`; follow +it, and record any new view-wide UX decision in its register. + Do not design controls or seams from scratch. The migration hub skill (`fieldworks-winforms-to-avalonia-migration`) documents the decided architecture; its diff --git a/.claude/skills/fieldworks-winforms-to-avalonia-migration/SKILL.md b/.claude/skills/fieldworks-winforms-to-avalonia-migration/SKILL.md index 1e2aae1252..9f17c5d51b 100644 --- a/.claude/skills/fieldworks-winforms-to-avalonia-migration/SKILL.md +++ b/.claude/skills/fieldworks-winforms-to-avalonia-migration/SKILL.md @@ -24,6 +24,11 @@ A region is not "migrated" until it passes the symbol audit, parity gates, and has zero runtime dependency on native Views/DataTree infrastructure — otherwise you have only wrapped the old system. +How converted UI should look and behave is set by the UX guide, +`Docs/ux/README.md`; this skill covers how to build it. A decision that applies +across views goes in the guide's decision register; a difference in one +converted screen goes in that conversion's Jira issue. + ## Established Architecture — Reuse, Don't Reinvent Past migrations already decided the paradigms below. Before writing any new diff --git a/Docs/architecture/adr/README.md b/Docs/architecture/adr/README.md index 9fd119285e..88c4753c81 100644 --- a/Docs/architecture/adr/README.md +++ b/Docs/architecture/adr/README.md @@ -19,9 +19,11 @@ Not to be confused with: work, indexed for reading before planning in a covered area. - `openspec/` — proposed changes with their specs and task lists, which are archived once implemented. +- `Docs/ux/` — the living UX guide: how the user interface should look and + behave, with its own register of provisional and temporary UX decisions. An ADR records *why a constraint exists*. If what you are writing will need -editing the next time the code changes, it belongs in one of the other three. +editing the next time the code changes, it belongs in one of the others. | ADR | Decision | | --- | --- | diff --git a/Docs/ux/README.md b/Docs/ux/README.md new file mode 100644 index 0000000000..fd7937cbbf --- /dev/null +++ b/Docs/ux/README.md @@ -0,0 +1,569 @@ +# FieldWorks UX guide + +This guide states how the FieldWorks user interface should look and behave. It +covers new and changed Avalonia UI now, and it is written as the guide for all +FieldWorks UI, since every screen is moving to Avalonia. It is authoritative +for view-wide UX decisions: where code and this guide disagree, either the code +is a bug or the guide needs a recorded change. + +The rules state intent. Measurements (colors, sizes, spacing) live in theme +tokens, not here; [winforms-theme-baseline.md](winforms-theme-baseline.md) +records the WinForms values they started from, so divergence can be measured. +Skills and other agent instructions keep the mechanics of following a rule and +link to the rule here. + +Many rules come from long-standing WinForms behavior that users already rely +on. A rule that deliberately departs from WinForms carries a **Needs team +consensus** note until the team agrees to it. + +Differences in a single converted screen, such as a field that works +differently in one dialog, are recorded in that conversion's Jira issue, not +here. This guide holds decisions that apply across views; its +[decision register](#decision-register) lists decisions that are provisional +or temporary. + +Sections: [Universal](#universal) | [Dialogs](#dialogs) | +[Browse views](#browse-views) | [Detail views](#detail-views) | +[Interlinear text](#interlinear-text) | [Decision register](#decision-register) +| [Appendix: terms and code](#appendix-terms-and-where-they-live-in-code) + +## Universal + +### Stealth to wealth + +**Stealth to wealth.** FieldWorks reveals capability as a user's data and skill +grow. A new user with an empty project should see a small, calm interface. +Fields, columns, commands and options appear when the data needs them or when +the user asks for them. + +- Prefer hiding until relevant over disabling. Show what applies to the current + tool and record. *(The exception is a fixed set of controls such as dialog + tabs: there, show what doesn't apply as disabled, so the layout doesn't + shift.)* +- Everything hidden must be reachable by a visible, discoverable route (Show + Hidden Fields, the column chooser, Configure…). Never rely on hover alone or + on a secret shortcut. +- Data the user has entered is never hidden by default. A field that holds data + shows. +- Allow quick, rough work now and refinement later. Don't force a user to + complete an analysis before moving on. + +### Writing system drives input and direction + +**The writing system drives input and direction.** Wherever the user edits data +text, the active keyboard (and input method) follows the writing system at the +cursor. When focus moves from data text to an interface control such as a dialog +or toolbar box, the user's default keyboard returns. Text direction and +alignment come from the writing system: right-to-left data reads and aligns +right-to-left in every view, mixed-direction text displays in the correct order, +and sequences the user reads in order (such as morphemes) follow the writing +system's direction. Interface text (menus, labels, buttons) follows the +interface language's direction, not the data's. + +### Command labels + +**Commands say what they do.** A command label starts with a verb (Insert, +Delete, Move, Show, Configure…) and names its object ("Insert Sense", "Delete +Example"). A label ends in "…" when the command needs more input before it acts +(opens a dialog or asks for confirmation); a command that acts immediately has +no "…". Dialog titles never end in "…". Commands that move the user to another +tool use one form: "Show in {tool}". The "…" is part of the localized string, +never appended in code. Every top-level menu has an access key, and menu +commands should have one too; in a long menu where keys would collide, give them +first to the most frequently used commands. + +### Menu structure + +**Menus keep their shape.** Users rely on muscle memory, so the new UI keeps the +WinForms menu order: the main menu (File, Send/Receive, Edit, View, Data, +Insert, Format, Tools, Window, Help) and every existing context menu keep their +items in the same order and grouping, especially in high-use places such as the +detail-view row menus and the browse-view menus. Areas add commands to the +existing menus, never new top-level menus. A new context menu follows the +WinForms pattern: text editing first (Cut, Copy, Paste) where it applies, then +navigation ("Show in…"), then commands that act on the item, with structural and +destructive commands (Move, Delete) last, and separators between groups. A set +of related commands appears the same way, flat or as a submenu, wherever it +occurs. + +### Keyboard shortcuts + +**Shortcuts are kept, not reinvented.** The new UI keeps every WinForms shortcut +with its meaning in that area; users' hands know them. A new shortcut must not +reuse a key that already has a meaning in the same area, and a modifier keeps +one meaning across a family of commands (in interlinear, Shift means "move +without approving"). Every shortcut is shown next to its command in the menu. +Developer and support tools (such as Inspect entry or the nightly update +channel) may stay behind a key combination, because they aren't user features; a +user feature always has a visible command. + +### Status bar + +**Tell the user when the view isn't showing everything.** Whenever a filter, a +non-default sort, or another mode changes what the user sees, the status bar +says so, and each kind of state keeps its own distinct indicator. These +indicators disappear when the view returns to its default, so their presence +always means something. The status bar shows the current record's position +("3/120") or "No Records". If the user asks to go to something the current +filter hides, ask before turning the filter off; never silently fail to show it. + +### Empty and missing values + +**Empty looks empty; missing looks missing.** A field with no value shows a +muted hint saying what goes there (for example "Type to add Gloss"), never +placeholder characters that could be mistaken for data. Where the user needs to +see that an expected value is missing (an unanalyzed word's gloss, an empty +chart cell), use one missing-value marker everywhere ("***"), drawn so it can't +be mistaken for typed text. Hint text and markers are never saved as data, and +they disappear as soon as the user types. + +### Clickable items + +**Clickable things look and feel clickable, the same way everywhere.** Anything +that navigates or runs a command when clicked gets one shared, recognizable +"clickable" treatment, used consistently across the product. A link style is one +way to do it; whatever the treatment is, it comes from the theme, and every +clickable item uses it. The pointer confirms what a click will do (for example, +a hand over clickable items and a text pointer over editable text). A disabled +command looks disabled rather than vanishing. A view that the user is working +against from elsewhere (a preview, a find target) keeps its selection visible +when it loses focus; other views hide it. + +### Data text font + +**Data text is drawn as the user configured it.** Text the user entered or that +belongs to their project (entries, glosses, list items, example sentences) is +drawn in its writing system's font and the project's styles, wherever it +appears: detail views, browse cells, choosers, dialogs, menus listing data. Only +interface text (labels, buttons, menus, captions) uses the interface font. Never +draw data text in the interface font to make a screen look uniform; for scripts +that need a specific font, the wrong font can mean missing or broken characters. + +### Theme values + +**Every color, size and spacing comes from the theme.** Screens use named theme +values (tokens) for color, spacing, sizing and type, never one-off numbers. When +something needs a look the theme doesn't have, add a named token for its purpose +(for example "approved guess background"), not a raw value at the point of use. +The same purpose always uses the same token, so one meaning has one look +everywhere, and a theme change reaches every screen. + +### Localizable text + +**Every word the user reads can be translated.** All interface text, including +labels, tooltips, messages, accessible names and the "…" on commands, comes from +localizable resources, never from strings written in code. Messages are whole +sentences with placeholders ("Delete {0}?"), not fragments joined in code, +because word order differs between languages. Layouts leave room for longer +translations. Technical detail about errors and exceptions is not covered by +this rule: it may appear untranslated in the error report dialogs and in logs +meant for the development team. + +### Keyboard and assistive access + +**Everything works without a mouse and can be read by assistive tools.** Every +control the user can act on can be reached and operated from the keyboard, in a +sensible Tab order that follows the visual reading order, and the focused item +is always visibly marked. Every such control has an accessible name in the +interface language (usually its visible label) and a stable automation id that +does not change with language or layout, so screen readers and automated tests +can find it. Icon-only buttons always have a tooltip that matches their +accessible name. + +### Views remember their state + +**Views come back the way the user left them.** When a user switches away from a +tool and returns, or reopens the project, each view shows what it showed before: +the same record or item selected and scrolled into view, the same choices of +what to show and how (columns, sort, filter, expanded sections, the line choices +in an interlinear text, the last kind of bulk change used). Tools that work on +the same records share the current record, so switching tools during a task +keeps the user's place; how each tool shows those records belongs to that tool. +These settings are kept per project and per user. Anything remembered can be +returned to its default from where it was set (Show All in a filter, the default +sort, the default columns). + +## Dialogs + +### Dialog buttons + +**Dialog buttons sit in one place and behave one way.** Buttons that close the +dialog form one group at the bottom right, in this order: the confirming button, +named for its action where that's clearer than OK (Delete, Merge, Create); any +alternative ways to confirm (Create and Edit); Cancel; Apply, if the dialog has +it; then Help when a help topic exists. Buttons that act without closing the +dialog (Browse, Restore Defaults, Select All, More) do not join that group: +place them next to the content they affect, or at the bottom left. Enter +activates the confirming button and Esc cancels. A dialog that only shows +information, or applies changes immediately, offers Close instead of OK and +Cancel, and Esc closes it. Buttons share one standard size from the theme. + +### Dialog windows + +**Dialogs are compact, owned windows.** A dialog belongs to the window that +opened it: it opens centered on that window, stays in front of it, has no +minimize or maximize button, and doesn't appear separately in the taskbar. It +shows the FieldWorks icon. Layout is compact, matching the density users know +from FieldWorks rather than roomy default spacing. A dialog whose content can +grow (lists, trees, previews, long text) is resizable, has a sensible minimum +size, and remembers its size and position, always reopening fully on screen; a +dialog with fixed content is not resizable. + +### Checking input + +> **Needs team consensus.** Intentional departure from WinForms; modernization. + +**Show problems where they are, and never lose the user's input.** When +something the user entered can't be accepted, say so next to that field, in +plain words that say how to fix it, and keep the dialog open with everything the +user typed intact. Check a field when the user leaves it or presses the +confirming button, not on every keystroke. Disable the confirming button only +when the reason is obvious from what's on screen (for example, nothing is +selected yet in a chooser); otherwise leave it enabled and explain the problem +when it is pressed. Use a separate message box only to confirm a consequential +action (such as deleting) or for a problem that isn't about any one field. + +### Help + +**Help is one keystroke away and goes to the right page.** A dialog with a help +topic shows a Help button, and F1 opens the same topic. Help opens the page for +this dialog (or the field, from a detail-view row), never a generic start page. +A dialog with no help topic shows no Help button rather than a disabled one. The +title-bar "?" button is not used. + +### Advanced options + +> **Needs team consensus.** Replaces five WinForms patterns with one. + +**Advanced options use one pattern.** A dialog that has options most users don't +need opens showing only the common ones, with a single "More options" expander +that reveals the rest in place. The expander looks and behaves the same in every +dialog, and the dialog remembers whether the user left it open. If any advanced +option is already set to something other than its default, the advanced section +opens automatically, so a user never has a hidden setting affecting their work. +Wizards mark optional steps as optional and let the user finish without them. + +### Choosers + +**Choosers work the same everywhere.** Choosing from a list (a category, a +semantic domain, a variant type) always uses the same chooser: a searchable list +or tree, with the current value visible, OK enabled once something is chosen, +and its size and position remembered. A chooser that picks from a user-editable +list offers a link to edit that list, always worded "Edit the {list name} list". +In a field that holds several items, the chooser adds items; items already in +the field are shown but can't be picked again, and items are removed from the +field itself, not from the chooser. + +## Browse views + +### Browse view criteria + +**Browse view criteria.** A browse view is a table of records, one per row, +chosen when seeing many records side by side helps the user. Choose the layout +by the task: + +- **Hierarchical records with little to compare** (lists, categories): no browse + view; the records appear as a tree in the sidebar beside the detail view. +- **Pick a record, then edit it:** a narrow browse view beside the detail view, + showing only the few columns needed to find the record. Full editing happens + in the detail view. +- **Compare or survey many records across many fields:** a full-width browse + view. Simple text fields can be corrected in place in their cells, so the user + can fix what they spot without leaving the table; anything more involved is + edited in the detail view. The full-width browse tool and its editing tool + share one list of records, so the current record, sort and filter carry across + when the user switches. +- **Enter many records quickly:** a browse view whose cells are the entry form + (Collect Words). +- **Change many records at once:** a full-width Bulk Edit tool. Its cells are + read-only; changes go through the checkbox column and the bulk edit bar, so a + whole-list change is always deliberate. +- **Read a flowing document or a text:** a document view, not a browse view. + +In-place editing in a cell uses the same editor, validation and undo as that +field in the detail view. + +### Columns + +**Columns start few and grow on request.** A browse view opens with a small +default set of columns: just enough to recognize and find the record, and for a +narrow browse view beside a detail view, fewer still. All other columns stay +available through the column chooser: frequently wanted columns appear directly +in its quick menu, and the rest are behind "More Column Choices…". The user's +choice of columns, their order and their widths are remembered for each tool in +each project. A column that shows text in one writing system displays that +writing system's data. When the user switches it to a different writing system, +the header says which one, using its abbreviation. Every header is a localized +label, and a shorter localized form may be used where the full label doesn't +fit. + +### Sorting + +**Sorting is done from the column headers.** Clicking a column header sorts by +that column, and clicking it again reverses the order. Shift+click adds the +column as a further sort key, and each sorted header shows its direction and its +rank. Sort options that only make sense for language data, such as sorting from +the end of the word or by length, sit in the header's context menu. Text columns +sort by their writing system's collation, not by the order of the character +codes. The sort is remembered with the list of records, so it survives restarts +and is shared by every tool that uses that list. + +### Filter bar + +**Lists of records can be filtered from the columns.** A browse view that shows +a tool's main list of records has a filter bar under the headers, with one +filter cell per column; lists inside choosers and dialogs don't, since they have +their own search box. Every filter cell offers the same menu in the same order: +Show All, then Blanks and Non-blanks, then options that suit the column's kind +of data (for example a list chooser for a list field, or a range for a number), +then "Filter for…" to type a pattern. Typed patterns are matched in the column's +writing system. Filters in several columns combine: a record shows only if it +passes all of them. Like the sort, the filter is remembered with the list of +records. + +### Bulk Edit + +**Bulk changes are previewed, deliberate and undoable.** Changes to many records +at once happen only in a Bulk Edit tool, never as a side effect of an ordinary +browse or detail view. The user first narrows the records by filtering and +checking rows, then chooses the change; a change applies only to the checked +rows that pass the current filter. Kinds of change that don't apply to the +chosen field are shown as unavailable rather than hidden. Every change except +delete can be previewed in the table before it's applied; the preview is clearly +marked as not yet saved and can be cleared. The command that applies the change +names what it will do. Deleting records asks for confirmation and says how many +records will be deleted. A whole bulk change, including a delete, is one undo +step; if some change can't be undone, the confirmation says so before anything +happens. + +### Checkboxes + +**Checkboxes.** Where the user checks rows to choose what an action affects, +rows start checked when the action normally applies to the whole list, and +unchecked when the user is picking a few items out of many. + +### Current record and keyboard + +**The current record is always visible and easy to move.** The browse view marks +the current record's row so it stands out at a glance, using a marker that +doesn't hide the text being edited in an editable list. Whenever the current +record changes, by any route, its row is scrolled into view. In a list used to +pick records, the arrow keys move to the previous or next record while focus +stays in the list, so the user can step through records and watch the detail +view change; Home, End, Page Up and Page Down move to the first record, the last +record or a page at a time. The record navigation commands (First, Previous, +Next, Last) are always available from the menu and keep their WinForms +shortcuts. + +## Detail views + +### What a detail view is + +**What a detail view is.** A detail view edits one record: the record currently +selected in the tool's list of records, whether that list is shown as a browse +view beside it, a tree in the sidebar, or not at all. It is the full editing +form for that record, laid out as rows: each row has a label on the left and the +field's value on the right, and related rows are grouped under section headers +(Senses, Allomorphs, Etymology). Owned records, such as the senses of an entry +or the examples of a sense, appear nested inside it rather than in a separate +window. Selecting a different record in the list replaces the detail view's +contents; there is no Save step. Every change is kept as the user makes it, and +it can be undone. + +### Field visibility by area + +**Initial field visibility is predetermined by area: show what will matter, and +let the user choose.** Each area decides which fields its detail views show at +first, aiming to show the fields a user needs to make a usable record there, +plus every field that already holds data. Fields that only some users need +appear when they hold data, or when the user turns on Show Hidden Fields for +that tool. Show Hidden Fields is off by default, is found in the same place in +every tool, and is remembered per tool. A field is never hidden in a way the +user can't undo: anything hidden can be shown again, either with Show Hidden +Fields or by changing that field's visibility. When a tool is converted, its +fields keep their WinForms visibility; how much an area hides is that area's +decision, not something to make uniform. + +### Field control + +**Users have field-by-field control of visibility and location.** Every row in a +detail view offers the same field commands in the same place at the end of its +context menu: set the field's visibility (always visible, hidden unless it has +data, or normally hidden), move the field up or down among its neighbors, and +Help when a topic exists. These choices apply to that field in that tool +everywhere it appears, not just to the current record, and are remembered. The +wording of the visibility choices is the same everywhere, so the user learns it +once. A user who has rearranged or hidden fields can return a tool's form to its +defaults. + +### Sections and expansion + +**Sections organize the form and can be folded away.** Groups of related rows +sit under a section header that stands out from ordinary rows, with clear space +above it, so the user can scan the form by section. A section or nested record +that can be expanded shows whether it is expanded, starts expanded, and can be +collapsed or expanded by mouse or keyboard. Collapsing something applies to that +record only, and the record remembers it. The current row's section header is +where that section's commands appear. + +### Labels + +**Labels line up, stay readable, and can be narrowed.** All rows in a detail +view share one label column, and nested rows indent their labels to show the +nesting. The user can drag the column narrower or wider for all rows at once, +and the width is remembered per tool. When the column gets too narrow for full +labels, each label switches to a short localized abbreviation, and its tooltip +always gives the full label. Field labels use Title Case ("Lexeme Form", +"Grammatical Info."). + +### Fields in several writing systems + +**Each writing system gets its own line.** A field that holds text in several +writing systems shows one line per writing system, each starting with that +writing system's abbreviation, so the user always knows which language they're +typing in. Each line follows its writing system's direction and font. By default +the field shows the project's active writing systems that apply to it; a writing +system that already holds data in the field always shows, and at least one +always shows. From the field's menu the user can show all of them for now, or +choose which ones the field shows from then on. Where a field mixes vernacular +and analysis writing systems, vernacular comes first. + +### Saving and undo + +> **Needs team consensus.** Last sentence: field-level problem display replaces +> WinForms message boxes. + +**Edits save themselves, one undoable step per field.** There is no Save button +in a detail view. A change to a field is committed when the user leaves that +field, moves to another record or tool, or runs a command, and becomes its own +undo step, named for the field ("Undo change Gloss"), so Undo reverses exactly +one field at a time. While the user is typing in a field, Undo works within the +text first. If a value can't be accepted, the problem is shown at that field in +plain words, the user's typing is kept, and focus stays there until it's fixed +or the change is undone, as in *Checking input* for dialogs. + +### Tab and focus + +**Tab moves through the fields in order, and focus lands where the user +expects.** Tab and Shift+Tab move from field to field in the order they appear, +including into nested records, and through each writing system's line in a +multilingual field. A field that holds several items (references, environments) +is one Tab stop: Tab lands on its first item, the arrow keys move between items +(following the row's direction), Home and End jump to the ends, and items that +can be reordered move with Ctrl+arrow. The field's add and configure buttons are +their own stops after the items. Expand and collapse markers, labels and the +row's menu button aren't Tab stops. At the first and last field, Tab carries on +into the rest of the window as it does elsewhere. Opening a record puts the +cursor in its first editable field. After a command that changes the form +(inserting a sense, for example), the cursor goes to the new item's first field; +after any other refresh it stays in the field the user was in. + +### Current row + +**The user can always see where they are, without the form shouting.** The field +being edited is clearly marked by its edit box's focus treatment, and the +current item in a field that holds several items is marked as selected. Rows are +not filled or highlighted as a whole; the form stays calm so the data reads +easily. When the current field is inside a collapsed section, the section's +header shows that it contains it. The current row's section shows its commands, +as in *Sections and expansion*. + +## Interlinear text + +### Analysis trust colors + +**Colors tell the user how much to trust an analysis.** In every view of +interlinear text, an analysis is shaded to show where it came from: one color +for a guess based on the user's earlier approvals, another for a machine guess, +another where several approved analyses could apply, and no shading once the +user has approved it. The same meaning has the same color on every interlinear +surface (text, the word being analyzed, choices, concordance), and these colors +aren't used for anything else, such as selection or highlighting elsewhere in +the product. Shading is never the only signal: the analysis's state can also be +read from its tooltip or by assistive tools. + +### Analysis commits + +**Analysis work is never lost, and approving is always a choice.** Whatever the +user types while analyzing a word is kept when they move to another word, by any +route. Approving an analysis, which turns a guess into the user's own analysis, +is a separate, deliberate action. Every command that moves to another word comes +in a pair: the plain form approves and moves; the same keys with Shift move +without approving. Each commit is one undo step. While analyzing a word, Tab +moves between its lines, and the same key opens the list of choices on every +line. + +### The word being analyzed + +**It's always clear which word is being analyzed.** The word the user is working +on is set apart from the surrounding text, so it's clear at a glance which word +the user's typing and choices apply to. Within it, it's clear which lines the +user can type in and which only display information. Every line that offers a +list of choices shows that it does, in the same way. Where several approved +analyses could apply, the user can see how many. + +### Interlinear lines + +**Each interlinear task starts with the lines it needs, and the user can change +them.** A new user glossing a text sees only a few lines (the word, its gloss, +its category, a free translation); morpheme-by-morpheme analysis lines appear by +default only where that work is done. The user can show, hide and add lines, and +choose which writing systems each line shows; those choices are remembered +separately for each task. However the user makes these changes, the result +always keeps this shape: + +- At least one line always shows, and a view where the user analyzes words + always shows the word itself in the default vernacular writing system. +- Lines keep a fixed order by kind: word lines first, then the morpheme lines + together as one block, then the lines about the whole sentence (free + translation, literal translation, notes). Only the writing-system lines of the + same field can be reordered among themselves, and they stay together. +- The same line can't appear twice in the same writing system. + +Each line's label says which line it is and, where it matters, which writing +system it shows. + +## Decision register + +Each entry has one status: + +- **Adopted**: decided; change it only by adding a new entry that supersedes it. +- **Provisional**: in use, but expected to be revisited; it names the trigger + for revisiting. +- **Temporary**: a known gap or compromise; it names the condition that ends + it. + +A superseded entry stays in the table, marked as superseded and pointing to the +entry that replaces it. + +| Decision | Status | Revisit trigger / end condition | Decided | +| --- | --- | --- | --- | +| Empty or appendable sequences in detail views show a "Type to add {item}" row as an extra in-place way to add; insert commands stay in the menus and section commands. | Adopted | — | 2026-08-11, LT-22687 | +| Sections that offer commands show them on the section header at all times (see *Sections and expansion*). | Adopted | — | 2026-08-11, LT-22687 | +| Section commands appear as one "Field options" link per section that opens a menu (WinForms shows one link per command), and that link is a Tab stop. | Provisional | LT-22693 | 2026-08-11, LT-22687 | +| Edit boxes in detail views have a visible border. | Provisional | Users push back on the look | 2026-08-11, LT-22687 | +| Tab stops at the first and last detail-view row instead of carrying on into the rest of the window. | Temporary | The whole window is Avalonia (LT-22688) | 2026-09-22, commit 23965cd67 | + +## Appendix: terms and where they live in code + +The guide uses terms from the user's point of view. This table connects them to +code, for developers and AI agents. + +| Guide term | WinForms code | Avalonia code | +|---|---|---| +| list of records (shared by tools) | `RecordClerk` / `RecordList` (xWorks) | same `RecordClerk`, used by the Avalonia `RecordEditView` host | +| browse view | `BrowseViewer`, `XmlBrowseViewBase` | — | +| detail view | `DataTree` (DetailControls), `RecordEditView` | `DataTree` (FwAvalonia/Detail), `DetailComposer`, `DetailModel`, `RecordEditView.Avalonia` | +| row / field (detail view) | `Slice` | detail row (`DetailComposer` output) | +| section, section header | heavy `SummarySlice`, `header="true"` parts | section header row | +| section commands | `hotlinks=` on a part, `SummaryCommandControl` | `CreateHotlinkStrip` ("Field options") | +| field visibility | part `visibility` (`always` / `ifdata` / `never`) and layout overrides | same layouts, read by `DetailComposer` | +| "Type to add ..." row | `GhostStringSlice` | ghost row | +| filter bar | `FilterBar` | — | +| bulk edit bar | `BulkEditBar` | — | +| the word being analyzed | focus box: `SandboxBase`, `FocusBoxController` | — | +| interlinear lines | `InterlinLineChoices` | — | +| theme values | system colors and literals | design tokens (ADR 0001/0002) | + +A "—" means the area isn't converted yet; the converting change fills in the +cell. diff --git a/Docs/ux/winforms-theme-baseline.md b/Docs/ux/winforms-theme-baseline.md new file mode 100644 index 0000000000..67b433a843 --- /dev/null +++ b/Docs/ux/winforms-theme-baseline.md @@ -0,0 +1,74 @@ +# WinForms theme baseline + +The measured or coded look of the WinForms interface, set beside the Avalonia +theme token that now carries each value. The [UX guide](README.md) states what +each element must achieve; this table records where its look started, so +divergence from WinForms can be measured instead of argued from memory. + +How to read and keep it: + +- **WinForms value** is what the WinForms code draws, cited by file and line + (paths under `Src/`). "Measured" means the value was read from a rendered + baseline rather than from a constant. +- **Avalonia token** names the key in `Src/Common/FwAvaloniaTheme/Tokens/`. A + "—" means that area isn't converted yet; the converting change fills it in. +- **Match / differs**: a *differs* row must cite a + [decision register](README.md#decision-register) entry or a guide rule that + calls for the change. A difference with neither is a bug. *Check* marks a row + whose comparison still needs confirming. +- Add a row when a conversion introduces a token for an element that WinForms + already drew. + +## Detail views + +| Element | WinForms value | Source | Avalonia token | Match / differs | +| --- | --- | --- | --- | --- | +| Label column width | 150 px | `Common/Controls/DetailControls/DataTree.cs:113` | `DataTree.LabelColumnWidth` (150) | Match | +| Label / value splitter width | 5 px | `Common/Controls/DetailControls/Slice.cs:854` | `DataTree.SplitterWidth` (5) | Match | +| Width at which labels switch to abbreviations | 60 px | `Common/Controls/DetailControls/Slice.cs:53` | `DataTree.WsAbbrevWidth` (60) | Check: the token uses this value for the writing-system abbreviation column, a different element | +| Field label color | `SystemColors.ControlDarkDark` (#696969) | `Common/Controls/DetailControls/Slice.cs:1466` | `FwLabelBrush` (#696969) | Match | +| Field label font | Sans serif, 10 pt | `Common/Controls/DetailControls/Slice.cs:80` | `FwSurfaceFontSize` (11) | Check: Avalonia font sizes are in device-independent pixels, so 11 is about 8.25 pt, not 10 pt | +| Writing-system abbreviation color | #404040 (measured) | `Common/Controls/DetailControls/DetailControlsTests/DataTreeRenderTests.DataTreeRender_multiws.verified.png` | `FwWsAbbrevBrush` (#404040) | Match | +| Rule between rows | 1 px, `Color.LightGray` | `Common/Controls/DetailControls/DataTree.cs:1999` | `FwSliceRuleBrush` (LightGray), `DataTree.SliceRuleHeight` (1) | Match | +| Rule above a section header | 3 px, `Color.LightGray` (1 + `HeavyweightRuleThickness` 2) | `Common/Controls/DetailControls/DataTree.cs:199, 2000` | `FwSectionRuleBrush` (LightGray), `DataTree.SectionRuleHeight` (2) | Differs: 2 px, no register entry | +| Space above a section header rule | 10 px (`HeavyweightRuleAboveMargin`) | `Common/Controls/DetailControls/DataTree.cs:201` | `DataTree.SectionRuleMargin` (top 6) | Differs: 6 px, no register entry | +| Expand / collapse box outline | `SystemColors.ControlDark` (#A0A0A0) | `Common/Controls/DetailControls/SliceTreeNode.cs:334` | `FwTreeBoxBorderBrush` (#A0A0A0) | Match | +| Section command link text | `Color.Blue`, sans serif 10 pt, underlined | `Common/Controls/DetailControls/SummaryCommandControl.cs:45, 168` | `SemiColorLink` (through `FwAvaloniaDensity.HotlinkBrush`) | Differs: register, section command look (Provisional, LT-22693) | +| Unavailable section command | `Color.Gray` | `Common/Controls/DetailControls/SummaryCommandControl.cs:169` | `FwDisabledOptionBrush` (Gray) | Match | +| Selected item background | `kclrBackgroundSelRow` (#D7E6FF) | `Common/Controls/XMLViews/XmlBrowseViewBaseVc.cs:894` | `FwSelectedRowBrush` (#D7E6FF) | Match | +| Context menu item height | About 22 px (measured) | — | `DataTree.MenuItemMinHeight` (22) | Match | + +## Browse views + +| Element | WinForms value | Source | Avalonia token | Match / differs | +| --- | --- | --- | --- | --- | +| Row height | About 17 px (measured) | — | `DataTree.BrowseRowMinHeight` (18) | Check: 1 px taller | +| Tentative / selected row fill | RGB(200, 255, 255) (`kclrTentative`) | `Common/Controls/XMLViews/XmlBrowseViewBaseVc.cs:51` | — | Guide rule *Analysis trust colors* requires a color distinct from the approved-guess color | +| Grid line | — | — | `FwBrowseGridLineBrush` (#DCDCDC) | Check: WinForms source not yet cited | + +## Dialogs + +| Element | WinForms value | Source | Avalonia token | Match / differs | +| --- | --- | --- | --- | --- | +| OK / Cancel / Help button size | 75 × 23 px | `FwCoreDlgs/FwStylesDlg.resx:516-517, 546-547` | `DialogMinControlHeight` (Semi `SemiHeightControlSmall`, 24) | Differs: 24 px minimum height, kept for the pointer-target size (token comment); no register entry | +| Gap between dialog buttons | 6 px | `FwCoreDlgs/FwStylesDlg.resx:513-514, 543-544` | `DialogButtonStripGap` (Semi `SemiSpacingTight`) | Check: Semi step value not yet confirmed | +| Interface font | MS Sans Serif, 8.25 pt | Form designer defaults (for example `FwCoreDlgs/FwStylesDlg.resx`) | `FwSurfaceFontSize` (11 px, about 8.25 pt) | Match | + +## Interlinear text + +| Element | WinForms value | Source | Avalonia token | Match / differs | +| --- | --- | --- | --- | --- | +| Guess based on the user's approvals | RGB(150, 255, 255) | `LexText/Interlinear/InterlinVc.cs:446` | — | — | +| Several approved analyses could apply | RGB(255, 255, 50) | `LexText/Interlinear/InterlinVc.cs:454` | — | — | +| Machine (parser) guess | RGB(234, 220, 186) | `LexText/Interlinear/InterlinVc.cs:462` | — | — | +| Background of the word being analyzed | RGB(235, 235, 220) | `LexText/Interlinear/SandboxBase.SandboxVc.cs:27` | — | — | +| Border of the word being analyzed | `Color.Blue` | `LexText/Interlinear/SandboxBase.SandboxVc.cs:29` | — | — | +| Editable lines of the word being analyzed | `Color.White` | `LexText/Interlinear/SandboxBase.SandboxVc.cs:30` | — | — | + +## Status bar + +| Element | WinForms value | Source | Avalonia token | Match / differs | +| --- | --- | --- | --- | --- | +| "Filtered" indicator | `Brushes.Yellow` | `xWorks/RecordClerk.cs:2907` | — | — | +| Parser-development indicator | `Brushes.Tan` | `xWorks/RecordClerk.cs:2930` | — | — | +| "Sorted by" indicator | `Brushes.Lime` | `xWorks/RecordClerk.cs:2960` | — | — | From b058819f613bff8b0cd8adcde8db5ebacba93b74 Mon Sep 17 00:00:00 2001 From: Jason Naylor Date: Fri, 23 Oct 2026 14:46:28 -0700 Subject: [PATCH 2/3] LT-22687: Add accessibility and progress rules to the UX guide Answers the first review round on the UX guide. - Keyboard and assistive access: WCAG 2.2 AA contrast, a 24 DIP target size for controls, focus never fully hidden, and rules for automation ids. - New Long-running work rule: specific progress when the amount of work is known, indeterminate otherwise, reusing the existing progress classes. - Theme values: color tokens per theme variant via DynamicResource, and FieldWorks never redefines a Semi key. - Delete and can't-undo confirmations focus Cancel, so Enter does not delete. - Dialogs are checked at 100% and 150% scaling, and their minimum size keeps every control usable. - A command that can't be undone says so before it runs. - Decision register: add an ID column, add UX-6 to UX-8 for the three team-consensus notes, and give UX-4 a checkable trigger. - Baseline: the button-height row cites the target-size rule. Co-Authored-By: Claude Opus 5.5 --- Docs/ux/README.md | 72 ++++++++++++++++++++++-------- Docs/ux/winforms-theme-baseline.md | 2 +- 2 files changed, 54 insertions(+), 20 deletions(-) diff --git a/Docs/ux/README.md b/Docs/ux/README.md index fd7937cbbf..f40bc82eff 100644 --- a/Docs/ux/README.md +++ b/Docs/ux/README.md @@ -147,6 +147,11 @@ something needs a look the theme doesn't have, add a named token for its purpose (for example "approved guess background"), not a raw value at the point of use. The same purpose always uses the same token, so one meaning has one look everywhere, and a theme change reaches every screen. +Color tokens are defined per theme variant and referenced so they update when +the variant changes (in Avalonia, `ThemeDictionaries` and `DynamicResource`), +so a dark theme stays possible later. FieldWorks tokens alias Semi.Avalonia's +keys (ADR 0001) and never redefine a Semi key; a component that needs different +values uses its own token or control theme. ### Localizable text @@ -164,11 +169,20 @@ meant for the development team. **Everything works without a mouse and can be read by assistive tools.** Every control the user can act on can be reached and operated from the keyboard, in a sensible Tab order that follows the visual reading order, and the focused item -is always visibly marked. Every such control has an accessible name in the +is always visibly marked and never fully hidden behind other content. Every +such control has an accessible name in the interface language (usually its visible label) and a stable automation id that does not change with language or layout, so screen readers and automated tests -can find it. Icon-only buttons always have a tooltip that matches their -accessible name. +can find it. Automation ids are never built from translated text, are unique +within their window, and start with the name of their dialog or view +(`AddNewSense.Ok`). Icon-only buttons always have a tooltip that matches their +accessible name. Text and the parts of controls the user must see meet WCAG 2.2 +AA contrast: 4.5:1 for text (3:1 for large text), and 3:1 for control borders, +icons and focus marks. No automated check catches contrast, so check new colors +when adding them. Buttons, check boxes, links and other controls are at least +24 DIP high or spaced so that a 24 DIP target around each does not overlap its +neighbors (WCAG 2.5.8). Rows in dense data views follow the view's own row +height. ### Views remember their state @@ -183,6 +197,17 @@ These settings are kept per project and per user. Anything remembered can be returned to its default from where it was set (Show All in a filter, the default sort, the default columns). +### Long-running work + +**Long work never freezes the window.** Work that takes more than a moment says +in words what it is doing. When the amount of work is known, show specific +progress ("Parsing word 120 of 500" with a bar that fills); when it isn't, show +an indeterminate bar. Offer Cancel when stopping is safe, and say when the work +has finished or failed rather than just letting the bar disappear. Reuse the +existing progress classes (`ProgressDialogWithTask` / `IThreadedProgress` for +blocking work, `StatusBarProgressHandler` for the status bar) rather than +writing a new one. + ## Dialogs ### Dialog buttons @@ -194,7 +219,9 @@ alternative ways to confirm (Create and Edit); Cancel; Apply, if the dialog has it; then Help when a help topic exists. Buttons that act without closing the dialog (Browse, Restore Defaults, Select All, More) do not join that group: place them next to the content they affect, or at the bottom left. Enter -activates the confirming button and Esc cancels. A dialog that only shows +activates the confirming button and Esc cancels, except in a confirmation that +deletes data or can't be undone: there Cancel has the focus and no button is +the default, so Enter does not delete. A dialog that only shows information, or applies changes immediately, offers Close instead of OK and Cancel, and Esc closes it. Buttons share one standard size from the theme. @@ -205,13 +232,16 @@ opened it: it opens centered on that window, stays in front of it, has no minimize or maximize button, and doesn't appear separately in the taskbar. It shows the FieldWorks icon. Layout is compact, matching the density users know from FieldWorks rather than roomy default spacing. A dialog whose content can -grow (lists, trees, previews, long text) is resizable, has a sensible minimum -size, and remembers its size and position, always reopening fully on screen; a -dialog with fixed content is not resizable. +grow (lists, trees, previews, long text) is resizable, has a minimum size at +which every control stays visible and usable, and remembers its size and +position, always reopening fully on screen; a dialog with fixed content is not +resizable. Every screen is checked at 100% and 150% display scaling before it +ships. ### Checking input -> **Needs team consensus.** Intentional departure from WinForms; modernization. +> **Needs team consensus** (UX-6). Intentional departure from WinForms; +> modernization. **Show problems where they are, and never lose the user's input.** When something the user entered can't be accepted, say so next to that field, in @@ -233,7 +263,7 @@ title-bar "?" button is not used. ### Advanced options -> **Needs team consensus.** Replaces five WinForms patterns with one. +> **Needs team consensus** (UX-7). Replaces five WinForms patterns with one. **Advanced options use one pattern.** A dialog that has options most users don't need opens showing only the common ones, with a single "More options" expander @@ -430,8 +460,8 @@ and analysis writing systems, vernacular comes first. ### Saving and undo -> **Needs team consensus.** Last sentence: field-level problem display replaces -> WinForms message boxes. +> **Needs team consensus** (UX-8). Last sentence: field-level problem display +> replaces WinForms message boxes. **Edits save themselves, one undoable step per field.** There is no Save button in a detail view. A change to a field is committed when the user leaves that @@ -440,7 +470,8 @@ undo step, named for the field ("Undo change Gloss"), so Undo reverses exactly one field at a time. While the user is typing in a field, Undo works within the text first. If a value can't be accepted, the problem is shown at that field in plain words, the user's typing is kept, and focus stays there until it's fixed -or the change is undone, as in *Checking input* for dialogs. +or the change is undone, as in *Checking input* for dialogs. A command that +can't be undone says so before it runs. ### Tab and focus @@ -536,13 +567,16 @@ Each entry has one status: A superseded entry stays in the table, marked as superseded and pointing to the entry that replaces it. -| Decision | Status | Revisit trigger / end condition | Decided | -| --- | --- | --- | --- | -| Empty or appendable sequences in detail views show a "Type to add {item}" row as an extra in-place way to add; insert commands stay in the menus and section commands. | Adopted | — | 2026-08-11, LT-22687 | -| Sections that offer commands show them on the section header at all times (see *Sections and expansion*). | Adopted | — | 2026-08-11, LT-22687 | -| Section commands appear as one "Field options" link per section that opens a menu (WinForms shows one link per command), and that link is a Tab stop. | Provisional | LT-22693 | 2026-08-11, LT-22687 | -| Edit boxes in detail views have a visible border. | Provisional | Users push back on the look | 2026-08-11, LT-22687 | -| Tab stops at the first and last detail-view row instead of carrying on into the rest of the window. | Temporary | The whole window is Avalonia (LT-22688) | 2026-09-22, commit 23965cd67 | +| ID | Decision | Status | Revisit trigger / end condition | Decided | +| --- | --- | --- | --- | --- | +| UX-1 | Empty or appendable sequences in detail views show a "Type to add {item}" row as an extra in-place way to add; insert commands stay in the menus and section commands. | Adopted | — | 2026-08-11, LT-22687 | +| UX-2 | Sections that offer commands show them on the section header at all times (see *Sections and expansion*). | Adopted | — | 2026-08-11, LT-22687 | +| UX-3 | Section commands appear as one "Field options" link per section that opens a menu (WinForms shows one link per command), and that link is a Tab stop. | Provisional | LT-22693 | 2026-08-11, LT-22687 | +| UX-4 | Edit boxes in detail views have a visible border. | Provisional | A Jira issue or user-testing report asks to remove the border | 2026-08-11, LT-22687 | +| UX-5 | Tab stops at the first and last detail-view row instead of carrying on into the rest of the window. | Temporary | The whole window is Avalonia (LT-22688) | 2026-09-22, commit 23965cd67 | +| UX-6 | Input problems show next to the field, in plain words, keeping the user's input; WinForms message boxes are not used for them (see *Checking input*). | Provisional | Team consensus on LT-22687 | 2026-10-23, LT-22687 | +| UX-7 | Advanced options use one "More options" expander, replacing five WinForms patterns (see *Advanced options*). | Provisional | Team consensus on LT-22687 | 2026-10-23, LT-22687 | +| UX-8 | Detail views show field problems at the field, as in UX-6, not in message boxes (see *Saving and undo*). | Provisional | Team consensus on LT-22687 | 2026-10-23, LT-22687 | ## Appendix: terms and where they live in code diff --git a/Docs/ux/winforms-theme-baseline.md b/Docs/ux/winforms-theme-baseline.md index 67b433a843..917b62314a 100644 --- a/Docs/ux/winforms-theme-baseline.md +++ b/Docs/ux/winforms-theme-baseline.md @@ -50,7 +50,7 @@ How to read and keep it: | Element | WinForms value | Source | Avalonia token | Match / differs | | --- | --- | --- | --- | --- | -| OK / Cancel / Help button size | 75 × 23 px | `FwCoreDlgs/FwStylesDlg.resx:516-517, 546-547` | `DialogMinControlHeight` (Semi `SemiHeightControlSmall`, 24) | Differs: 24 px minimum height, kept for the pointer-target size (token comment); no register entry | +| OK / Cancel / Help button size | 75 × 23 px | `FwCoreDlgs/FwStylesDlg.resx:516-517, 546-547` | `DialogMinControlHeight` (Semi `SemiHeightControlSmall`, 24) | Differs: 24 px minimum height, per the target-size rule in [*Keyboard and assistive access*](README.md#keyboard-and-assistive-access) | | Gap between dialog buttons | 6 px | `FwCoreDlgs/FwStylesDlg.resx:513-514, 543-544` | `DialogButtonStripGap` (Semi `SemiSpacingTight`) | Check: Semi step value not yet confirmed | | Interface font | MS Sans Serif, 8.25 pt | Form designer defaults (for example `FwCoreDlgs/FwStylesDlg.resx`) | `FwSurfaceFontSize` (11 px, about 8.25 pt) | Match | From 48a65c92ce0cbf538b7105cd6ee12ae2d0f9a91d Mon Sep 17 00:00:00 2001 From: Jason Naylor Date: Fri, 23 Oct 2026 22:42:04 -0700 Subject: [PATCH 3/3] LT-22687: Add a modal and modeless windows rule to the UX guide A converted window keeps the modality of its WinForms version. In WinForms nearly every dialog is modal (ShowDialog); the few modeless windows are tools that act on the content behind them (Find and Replace) and companion windows kept open during work (Try A Word, parser reports). Changing a window's modality needs a register entry. Co-Authored-By: Claude Opus 5.5 --- Docs/ux/README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Docs/ux/README.md b/Docs/ux/README.md index f40bc82eff..0a08c2dc63 100644 --- a/Docs/ux/README.md +++ b/Docs/ux/README.md @@ -238,6 +238,19 @@ position, always reopening fully on screen; a dialog with fixed content is not resizable. Every screen is checked at 100% and 150% display scaling before it ships. +### Modal and modeless windows + +**A converted window blocks the rest of FieldWorks exactly when its WinForms +version did.** In WinForms almost every dialog is modal: a dialog that asks for +input, offers a choice, confirms an action or changes settings blocks the window +that opened it until it closes, and its result takes effect then. A window is +modeless only when the user works with it alongside the main window: a tool +that acts on the content behind it (Find and Replace, find in an HTML view), or +a companion window kept open during work (Try A Word, parser reports). Opening +a modeless tool again brings the open one forward instead of starting a second. +Progress windows follow *Long-running work*. An Avalonia window that changes +its modality from the WinForms one needs a decision register entry. + ### Checking input > **Needs team consensus** (UX-6). Intentional departure from WinForms;