Commit Graph
11 Commits
Author SHA1 Message Date
38931c34be Selection bar: right margin for right-to-left text, and beside table rows (UI gap) (#2042)
* gap: selection bar RTL/table rows WIP

* gap: selection bar in the right margin for right-to-left paragraphs and beside table rows

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

* gap: selection bar review fixes (row bar only beside the table, Shift+click from outside, text-box tables)

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

* gap: selection bar review round 2 (0.5pt row-overlap tolerance, body-story check for Shift+click)

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

* gap: selection bar: triple-click or Ctrl+click beside a table row selects the document, as in Word

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

* gap: selection bar: ui-parity wording (only triple-click was checked in Word)

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

* gap: selection bar: fix docs after rebase onto main

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

* gap: selection bar: a Shift+click drag keeps the anchor row of its press

table.selectAt takes an optional anchorRow; the app reads the anchor at the
press and sends it on every drag frame, so pointer jitter after an upward
Shift+click no longer re-reads it from the rows the press selected.

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

* Selection bar RTL test: the left margin shows no bar arrow (Windows reports no cursor there)

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

* #2042: repair three doc status lines a #3882 merge left with a stray Target

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

---------

Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-23 13:24:33 -04:00
aiongg c91ac7f68f Merge PR #3291: #2428: the table's move and resize handles show while the caret is in it
ROADMAP.md, docs/ui-parity.md: main's status lines with this change added to the newest; log rows from both sides in date order.
2026-10-22 01:24:49 +00:00
aiongg c7d5a949a7 Merge PR #3232: #2038: a click below a floating table goes to the text, not its last row
ROADMAP.md, docs/layout-parity.md: main's status lines with this change added to the newest; log rows from both sides in date order.
2026-10-22 01:24:36 +00:00
rabisandClaude Opus 5.5 a03deeeb26 #2428: the caret table's handles show where it starts and ends, where the pointer handles are
A repeated header row or a row running on to the next page no longer puts them on every page,
and they come from the same geometry as the handles under the pointer, so they can be grabbed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 17:35:10 +02:00
rabisandClaude Opus 5.5 37f28eedd0 #2428: the table handles show while the caret is in the table
As in Word, the caret's table shows its move handle past the top-left
corner and its resize handle past the bottom-right one wherever the
pointer is, not only while the pointer is over the table.
table_mouse::caret_handles gives them per page; the app paints them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 13:00:38 +02:00
rabisandClaude Opus 5.5 fc36739622 #2038: a click below a floating table goes to the text, not its last row
A table dragged by its move handle floats and the empty paragraph after it
moves up beside it; a click below the table then landed in a cell of its last
row (the nearest line). Pages now list their floating body tables, and
DocLayout::hit leaves out a floating table's cell lines when the point is
outside the area its cells cover, as long as other lines are left. Checked
against Word 2019 for Windows: clicks below the table and Ctrl+End go to the
paragraph beside or after it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 08:31:15 +02:00
dfgodvanandClaude Opus 5.5 e4d9eb61b9 Tables: rows with gridBefore/gridAfter keep their grid columns (part of #1174)
A row that skips grid columns before its first cell (w:gridBefore) was laid
out from column 0, so its cells sat one or more columns to the left and
wrapped at the wrong width (a text cell landing on a 5 pt column sets one
letter per line). Row::first_grid() gives the column the row's first cell
starts at; Table::grid_col, cell_at_grid and cols(), the layout passes,
vertical-merge matching, cell selection and the insert-column spot count
from it, and cols() also counts gridAfter.

The skipped columns stay empty and borderless, as in Word: a row's own
first and last cell carry the table's outer side borders, and AutoFit gives
the skipped columns the row's wBefore/wAfter width.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 13:54:55 +03:00
fee9b984eb Tables: text running past an exact-height row is cut off (#1617)
* Tables: text running past an exact-height row is cut off

A row with an exact height (w:trHeight w:hRule="exact") keeps that
height whatever its cells hold. Word cuts the text that doesn't fit at
the cell's edge; WordCraft drew it over the rows below, so a certificate's
identification block came out as overlapping lines.

The cell is marked as clipped in layout (Placed::Cell clip), and display
draws its lines inside that cell's clip, on screen and in PDF. Hit
testing is unchanged: the lines stay where they are in the layout.

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

* Tables: keep row clipping compatible with Rust 1.90

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-14 20:15:39 -04:00
987c41364d Tables: AutoFit in a nested table, whole cells shaded for a selection through a table, Shift+Right at a cell's end (#1004)
* Tables: AutoFit in a nested table fits within its cell (#971)

A double-click on a nested table's column border let the table widen up to
the page's right margin, far past the cell around it. It now widens only up
to the right edge of that cell's text (a right-to-left table's start margin
on the right); the columns right of the border still keep their widths.

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

* Tables: a selection through a table shades its rows' whole cells (#971)

A selection from text into or across a table takes whole rows (#722), but
only the letters in the cells were highlighted. Every row it takes from start
to end now shades all its cells (an empty one too), as selected cells do, and
the letters in them aren't shaded twice (`table_mouse::selection_rects`, used
by the canvas). A selection that starts and ends in one table keeps its text
highlight, so selecting all the text of a cell doesn't look like selecting the
cell; a nested table in a shaded row shades with it.

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

* Typing: Shift+Right at a cell's end selects the cell first (#971)

Shift+Right out of the cell the selection is in selected that cell and the
next one at once. As in Word, the first step out of the cell now takes the
cell alone (its end-of-cell mark) and the next press goes on into the next
cell; in an empty cell the first press selects it. Shift+Left in
right-to-left text, the forward step there, does the same. Pinned in
`tests_typing.rs` and `docs/typing-parity.md`; progress docs for all three
table fixes of #971.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-14 15:08:57 -04:00
f24a5b22b2 Tables: drags and Shift+arrows over cells select whole cells (#722)
* Tables: select, insert and move with the mouse; double-click a border to AutoFit

Like Word, on top of the border resizing:

- Selection areas: just above a column the pointer becomes a down arrow,
  left of a row the row arrow, along a cell's left edge (inside it) the
  cell arrow. A click selects the column, row or cell; a drag selects every
  one up to the pointer. Selected cells are shaded as cells, empty ones too.
- Insert buttons: left of a row border and above a column border a "+"
  shows with the border marked; a click adds a row or column there and puts
  the caret in it.
- Move handle past the table's top-left corner: a click selects the table;
  a drag shows a dashed outline and, on release, the table floats where it
  is dropped with the text wrapping around it (Word's behaviour). One undo
  step. Nested tables and tables outside the main text are only selected.
- A double-click on a column border fits the column left of it to its
  contents (the right neighbour gives or takes the room; on the right edge
  the table's width changes, up to the right margin).
- Table Layout > Select > Select Column (catalog 418/449).

Whole-cell selection: a column (or a rectangle of cells over several rows)
is not one run of the text, so selecting it makes a block of its cells'
paragraphs (`CellRange` on the existing `ColumnBlock`). Bold, alignment,
Delete, typing, copy and numbering act on those cells only (a numbered
column is one list); table commands (shading, merge, delete columns) take
the rectangle; Tab moves on without clearing it; Undo brings the selection
back. Cells of one row, or whole rows, stay an ordinary stream selection.
The format painter no longer clears a block's text (edit.pasteFormat was
handled like a paste). The mini toolbar stays hidden over whole-cell
selections and during these drags: pinned above the selection it covered
the column areas, the "+" buttons and the move handle.

Engine: crates/engine/src/cmd/table_mouse.rs - table.selectAt,
table.insertAt, table.moveDrag, table.fitColumn (page coordinates, so
agents and the control channel can do the same) and table.selectColumn;
hit testing reuses table_resize's drawn geometry, and borders keep priority
for resizing. 10 engine tests (areas, a column edited cell by cell,
numbering, rows/cells/drags, insert buttons, move, fit, format painter,
hostile params).
UI: crates/ui-egui/src/table_mouse.rs, wired into the existing canvas mouse
handler (no extra ui.interact areas, so clicks in a cell's text still place
the caret); kittest tests with real pointer events: column click, row drag,
"+" button, move-handle drag in one undo step, double-click fit.
New labels translated in all eleven catalogs. Progress docs updated: gaps,
ui-parity, target-app-parity, ROADMAP, parity checklist.
`cargo xtask ci` passes (fmt, clippy, test, assets, layers, wasm).

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

* Tables: a selected column's word count is its cells'; merged cells shade once

With whole cells selected (a column, or a rectangle that isn't one run of
the text) the status bar said "12 of 23 words": `Session::selected_text`
took everything between the selection's ends. It now takes each piece's
own text, a line each, for a column block too, so the status bar, Word
Count and the other callers see what is selected.

Since #669 a vertically merged cell is one box as tall as its rows, with a
`covered` box for each continuation row; shading selected cells skips
those, so a merged cell isn't shaded twice. `selected_paths` follows
main's `para_paths_in` (#418): a selection ending at the start of the next
paragraph doesn't take it.

- Test: a selected column's text is its three cells' and Word Count says
  three words.

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

* Tables: double-click AutoFit and the "+" buttons work as in Word

Checked against Word (2019, Windows):

- A double-click on a column border fits the column left of it to its
  contents and the columns right of it keep their widths, moving with the
  border, so the table narrows or widens (up to the right margin). The
  right neighbour used to give or take the difference.
- A "+" insert button selects the new row or column (the caret used to
  go into it); typing then goes into its first cell. If the table can't
  take another row or column, nothing changes.
- A double-click along a cell's left edge (the cell selection area)
  selects its row.

- Tests: engine (fit keeps the columns on the right; insert selects the
  new row or column, typing lands in its first cell) and kittest (real
  double-click on a border; "+" selects the row; double-click by a cell's
  edge selects the row).

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

* Tables: drags and Shift+arrows over cells select whole cells

An ordinary drag, Shift+click or Shift+arrow from one table cell into
another now selects the rectangle of whole cells between them, as Word
does, instead of the run of text between the two points: bold, alignment
and Delete leave the cells outside the rectangle alone (they already did
for Select Column and the table's selection areas). Between a cell and
text outside its table the selection takes whole rows, from the cell's
row out to the table's edge, and the text beyond. Extending again goes on
from where the selection really started and ends: dragging back into the
first cell selects its text again, Shift+Up after Shift+Down shrinks the
rectangle, and from a nested table's cell into another cell of the table
around it the outer table's cells are taken.

- Engine: `table::extend_selection` (the rule, down through nested
  tables) and `Session::sel_ends` (where a widened selection really
  runs); every caret command run with `extend` goes through it in
  `column::dispatch`, so agents get the same with `caret.*`.
- UI: a text drag extends through `caret.set` (still straight to the
  session, so nothing scrolls on every frame); the view follows the real
  caret.
- Tests: engine (drag across cells and back, nested tables, Shift+Down
  and Shift+Up through and past a table, Shift+click, from text into a
  table) and a kittest with a real mouse drag.

Progress docs updated: gaps (the known gap from #637 is gone),
ui-parity, target-app-parity, ROADMAP. `cargo xtask ci` passes.

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

---------

Co-authored-by: rabis <340973947+rabis7575@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-12 10:34:10 -04:00
8ca285ca9d Tables: select, insert and move with the mouse; double-click a border to AutoFit (#637)
* Tables: select, insert and move with the mouse; double-click a border to AutoFit

Like Word, on top of the border resizing:

- Selection areas: just above a column the pointer becomes a down arrow,
  left of a row the row arrow, along a cell's left edge (inside it) the
  cell arrow. A click selects the column, row or cell; a drag selects every
  one up to the pointer. Selected cells are shaded as cells, empty ones too.
- Insert buttons: left of a row border and above a column border a "+"
  shows with the border marked; a click adds a row or column there and puts
  the caret in it.
- Move handle past the table's top-left corner: a click selects the table;
  a drag shows a dashed outline and, on release, the table floats where it
  is dropped with the text wrapping around it (Word's behaviour). One undo
  step. Nested tables and tables outside the main text are only selected.
- A double-click on a column border fits the column left of it to its
  contents (the right neighbour gives or takes the room; on the right edge
  the table's width changes, up to the right margin).
- Table Layout > Select > Select Column (catalog 418/449).

Whole-cell selection: a column (or a rectangle of cells over several rows)
is not one run of the text, so selecting it makes a block of its cells'
paragraphs (`CellRange` on the existing `ColumnBlock`). Bold, alignment,
Delete, typing, copy and numbering act on those cells only (a numbered
column is one list); table commands (shading, merge, delete columns) take
the rectangle; Tab moves on without clearing it; Undo brings the selection
back. Cells of one row, or whole rows, stay an ordinary stream selection.
The format painter no longer clears a block's text (edit.pasteFormat was
handled like a paste). The mini toolbar stays hidden over whole-cell
selections and during these drags: pinned above the selection it covered
the column areas, the "+" buttons and the move handle.

Engine: crates/engine/src/cmd/table_mouse.rs - table.selectAt,
table.insertAt, table.moveDrag, table.fitColumn (page coordinates, so
agents and the control channel can do the same) and table.selectColumn;
hit testing reuses table_resize's drawn geometry, and borders keep priority
for resizing. 10 engine tests (areas, a column edited cell by cell,
numbering, rows/cells/drags, insert buttons, move, fit, format painter,
hostile params).
UI: crates/ui-egui/src/table_mouse.rs, wired into the existing canvas mouse
handler (no extra ui.interact areas, so clicks in a cell's text still place
the caret); kittest tests with real pointer events: column click, row drag,
"+" button, move-handle drag in one undo step, double-click fit.
New labels translated in all eleven catalogs. Progress docs updated: gaps,
ui-parity, target-app-parity, ROADMAP, parity checklist.
`cargo xtask ci` passes (fmt, clippy, test, assets, layers, wasm).

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

* Tables: a selected column's word count is its cells'; merged cells shade once

With whole cells selected (a column, or a rectangle that isn't one run of
the text) the status bar said "12 of 23 words": `Session::selected_text`
took everything between the selection's ends. It now takes each piece's
own text, a line each, for a column block too, so the status bar, Word
Count and the other callers see what is selected.

Since #669 a vertically merged cell is one box as tall as its rows, with a
`covered` box for each continuation row; shading selected cells skips
those, so a merged cell isn't shaded twice. `selected_paths` follows
main's `para_paths_in` (#418): a selection ending at the start of the next
paragraph doesn't take it.

- Test: a selected column's text is its three cells' and Word Count says
  three words.

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

* Tables: double-click AutoFit and the "+" buttons work as in Word

Checked against Word (2019, Windows):

- A double-click on a column border fits the column left of it to its
  contents and the columns right of it keep their widths, moving with the
  border, so the table narrows or widens (up to the right margin). The
  right neighbour used to give or take the difference.
- A "+" insert button selects the new row or column (the caret used to
  go into it); typing then goes into its first cell. If the table can't
  take another row or column, nothing changes.
- A double-click along a cell's left edge (the cell selection area)
  selects its row.

- Tests: engine (fit keeps the columns on the right; insert selects the
  new row or column, typing lands in its first cell) and kittest (real
  double-click on a border; "+" selects the row; double-click by a cell's
  edge selects the row).

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

---------

Co-authored-by: rabis <340973947+rabis7575@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-12 10:15:31 -04:00