A family installed as one family per weight ("Foo Bold" with Regular and
Italic faces) now lists Bold and Bold Italic, the names resolve draws them
by, with the faces' own weights when they are read. A W-numbered weight
counts after other words too ("Condensed W7 Italic" is 700).
next_style compared a custom wght value or a style the family lacks with
the weights the style names say, so Segoe UI Variable's Semilight (350)
counted as 300 and a wght of 325 stepped up to Regular. The family's
styles now come with the weights the style menu sorts them by
(figcraft_text::family_style_weights), and "W7 Italic" reads as 700.
Distinct image hashes pointing at one embedded blob shared its copy, but
the import resolved each hash separately: the blob was copied out and
hashed again for every alias. Aliases without an images/ member of their
own are now renamed to the first hash naming the blob before layers are
built, so the blob is copied and hashed once.
Image paints also spelled out their whole hash as hex for every layer,
whatever its length; hashes longer than any image can be named by (64
bytes) now resolve to nothing, as a missing hash does.
Review follow-up. The step now finds the chars' style in the family's list
(the style menu's order, lightest first) and takes its neighbour, so a style
whose name gives no distinct weight (Semilight) is reachable; a style the
family lacks or a custom wght value still goes by weight, ties going to the
nearer one in that order. "Extra", "Ultra", "Semi" and "Demi" are weight
words only before a weight ("Extra Bold"), so "Extra Condensed" keeps its
width; Oblique names count as slanted for the current style too; W3-style
names are weights; and style_weight reads Hairline as 100, not 400. The
installed-font test picks a family the step actually moves.
text.weightUp/weightDown stepped the CSS weight by 100 and stored a canonical
name ("Medium", "Semi Bold", ...) whether the family had that face or not, so
the first press on Arial Regular changed nothing visible and the stored style
named a face no font provides. They now move to the nearest heavier or lighter
style of the family with the same slant and width (Narrow stays Narrow), and
stay put at either end. A family that isn't installed keeps the old 100 steps.
FigApp::picked() also requires the layer to be on the page shown, so after page.select the cursor isn't drawn and Space selects nothing there. Test extended.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fill.pattern sets the layer's fill as its spec says. The gradient and crop handles read the paint from the stack fill.set writes (the selected regions' while there are any); for a region's paint, Upload from computer and image presets write the paint like any edit, and a drop on the picker goes to the canvas (image.replace and image.adjust edit layer paints). Tests in regions_tests, canvas/handles/region_tests and colorpicker image tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
UiState.pick is (uid, layer); FigApp::picked() answers only while that document is in front and the layer exists, so another document's layer with the same id is never walked to or selected. Test extended with a same-id layer in a new document.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Named regions are deduplicated; an inheriting region stays inheriting when an edit leaves its stack as it was, and its own stack is only replaced once the edit succeeds; fill.copy reads the selected regions' paint; the Fill section leaves the fill style, a variable bound to the layer's fill and the image crop off region rows. Tests in regions_tests and region_fill_rows_tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Tab or the chord again switches the box to a pick cursor; Tab/Shift+Tab move between sibling layers, Enter/Shift+Enter into and out of a layer, Space selects, Escape or a canvas press ends it; ui.key takes the same keys. Gesture and parity rows, catalog, test, docs.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
fill.set/add/remove/move/paste on the edited layer go to the selected regions' own fill stacks (or those named by regions), the layer's fills untouched; the Fill section and the colour picker list them. Test regions_tests::the_fill_commands_edit_the_selected_regions; docs.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
draws_shape includes BoardShape (tool.place lets the tool centre its own shape); a nudge past an edge of the view pans by the overshoot. Tests; docs.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Both sides of the merge added a documented row: the counts the parity test and the docs table quote move with them.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
egui keeps the position in interact_pos() for the frame of PointerGone, so a move and the leaving in one frame give the speed of that move; test.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The merge's union of two mod lines left upstream's text_link_tests without its cfg(test), so the library build pulled a test module in.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
ParagraphStyle beside TextStyle in StyleKind::Text: style.create takes it from the layer or a value, style.apply sets it (the list on the paragraphs touched for a range), style.update moves it, editing it unlinks, .fig files keep it with the style; tests in styles_behaviour_tests and fig_export_assets_tests.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
egui reports the pointer gone (no hover position) with the button still down when it leaves the window during a scrub; the speed stayed at the last rise rather than falling back to 1x and announcing it. Test in field_tests.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* M7: Minimize collapses the navigation bar and both sidebars, the right one back while something is selected (#1835)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* M7: a narrow window ignores Minimize, and a rename started while minimized waits without repaints
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* M2: a child resized to the full available space of its auto layout frame becomes Fill container
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* Auto layout: a child becomes Fill for the full space only across the flow or alone along it
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* Auto layout: the full available space is what layout leaves (padding and an included inside stroke), judged after a new path's size
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* M2: a rotated child resized to the frame's room stays Fixed (review)
CodeRabbit on #1859: a rotated layer's local size isn't the room layout
gives it, so Fill would squash its geometry.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* M2: a double-click on an auto layout edge sets Hug contents, with Alt Fill container (#1838)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* Auto layout edges: a text child fills with Alt too, and still enters on a plain double-click
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* M4: superscript and subscript are synthesised where the font has no glyphs for them (#1828)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* Text: a zero OS/2 script offset counts as unset, and the native-glyph check sees the case-mapped characters
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* M4: max lines on auto-width text keep it auto width, hugging that many lines
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* M4: an auto-width text with max lines hugs the ellipsis on its last line, and the editing test expects auto width
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* M4: Backspace or Delete at a list item's start keeps its indentation level
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* Lists: the level is kept by Backspace and Delete alone, and the tests read the text's own glyph
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* M2: fill container children share the free space by their content area, border-box fashion (#1824)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* Layout: rustfmt's line for the frozen-share closure
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* M2: one doc comment on distribute (review)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>