Repository navigation
Conversation
This was referenced Oct 24, 2026
Open
Open
Open
Open
Yaraslaut
force-pushed
the
feat/lims-gallery
branch
19 times, most recently
from
October 29, 2026 00:22
bb9bb9b to
efde0e8
Compare
The theme gains actions.gap (0 keeps spacing step 2), the space between the actions of a row of actions. actionBar becomes a ui/1 kind, with children, align and justify and no gap or wrap, lowering to ui::ActionBar. It mounts in the footer of the overlay whose content holds it, as before, and now also in place anywhere else, where the mount used to throw. StackWidget::setActionRow marks the stack it makes: on Qt Quick its children are Theme.actionSpacing apart, as MorphFooter's now are, and the terminal keeps its step 2 in cells. stepperParts' footer is an actionBar. StackWidget::setActionRow is implemented by the Qt Quick stack, the table row view (a no-op), the terminal stack (a no-op) and the recording backend. The gallery example screen gains an actionBar, since its test requires every node kind. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BmVLNhUvbWZjv85Hx2saxn
HeadTrailEnd (None, Unframed, Framed) replaces ShellFrame::setTrailEndInset(bool). Compact, the line ends step 4 from the edge, the page's gutter, unless an unframed button (a ghost or icon-only action, or the head menu's trigger) ends it: that button carries its own padding. A line ending in text, a badge or a select used to stand step 1 from the edge. The bar's vertical padding keeps its rule (step 3 for a tall head or a framed end), and setHeadOneLine now ends in showTrail() beside showBarInset(). Workspace::activeHeadTrailEnd reads the last shown element of the trail in its order (tools, actions, menu) in place of activeHeadTrailEndsFramed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BmVLNhUvbWZjv85Hx2saxn
A text input (not masked) and a date input's typed field that has neither the focus nor a selection and holds text wider than its text room are drawn from the start, cut with an ellipsis, as a one-line text is. Qt Quick draws the cut text in a MorphFieldElision label over the editor's text box and makes the editor's own text transparent while the label shows; the label's text is the editor's, the elided form is never written into the value, and the widget's tooltip is the whole text while the label is cut. The terminal draws it with paintElidedField, in the room before the control's marks, so no mark is drawn over the ellipsis. Closes #1082. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BmVLNhUvbWZjv85Hx2saxn
A grid without tracks takes minColumnWidth (units, 1 to 64, a literal; refused with tracks, without columns, with columns: 1 and when computed). It shows as many of its columns as fit that width, at least one: floor((W + g) / (m * u + g) + 1e-6) capped at columns, the epsilon keeping a width that exactly holds n columns at n whatever the unit. The natural width stays the full column count's; the natural height follows the columns shown at the width the grid was last laid out at, on Qt Quick through MorphGrid.place and on the terminal through the drawn width, which paint records and re-lays-out on when it changes, as a wrapping row does. GridWidget::setMinColumnWidth is implemented by the Qt Quick grid, the terminal grid and the recording backend. Five layout conformance cases cover it on both frontends. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BmVLNhUvbWZjv85Hx2saxn
mountMinColumnGrid takes its width, least column width, gap and trailing text in a struct rather than as adjacent ints, and the elision tests declare what they only read const. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BmVLNhUvbWZjv85Hx2saxn
Tests for the branches of actionBar's author options and wrap refusal, a ghost head action with its label, a grid with tracks that gives a least column width, and the five least-column-width conformance cases run against the recording probe's faults. include/morph/ui branch coverage is 92.03 % on the clang coverage preset. The four default-arm allowlist hints in document.hpp follow the lines the new kinds and checks moved. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BmVLNhUvbWZjv85Hx2saxn
… column shows its whole name at 1215 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BmVLNhUvbWZjv85Hx2saxn
… px wide at 1215 and end at one edge Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BmVLNhUvbWZjv85Hx2saxn
…ubtitle stays on one line The label's rich-text implicit width is fractional (295.0156 for the plate's subtitle), and a layout that lays the item out in whole pixels gives it 295, a fraction under the ideal width, so the last word wrapped at every window width. The text now asks for the ceiling of that width. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BmVLNhUvbWZjv85Hx2saxn
…eir buttons sit 8 px apart Instrument, audit and samples had a hand-set 4 px gap; results, review and plate wrote the 8 px by hand and now take the theme's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BmVLNhUvbWZjv85Hx2saxn
…e gives its Time column 6 units The field grid shows 3 columns of at least 25 units and the check grid 2 of at least 32, so the sample type and the longest check read whole at 1000 px. The session pane is 33 % of the row so the Received badge stays whole beside the wider Time column. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BmVLNhUvbWZjv85Hx2saxn
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BmVLNhUvbWZjv85Hx2saxn
…o temporary string is bound per iteration Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BmVLNhUvbWZjv85Hx2saxn
…referenced Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BmVLNhUvbWZjv85Hx2saxn
…ch is its own share, while it computes the shares Qt 6.8 reports the read as a binding loop on stretchShares: a content-sized or stretching child's preferred length is the stack's share of it, so reading it from inside the share computation re-enters that computation. Only a fixed length or a wanted percent share is read now; the value used is unchanged, as the others read -1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BmVLNhUvbWZjv85Hx2saxn
…it still tells two columns from three Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BmVLNhUvbWZjv85Hx2saxn
…ned and in progress Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BmVLNhUvbWZjv85Hx2saxn
… so no temporary string is bound per iteration Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01No1NznPS3foEqTUMjvBEts
…ir is copied per iteration Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01No1NznPS3foEqTUMjvBEts
…e text measured alone, so no font can leave a fixed unit range Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01No1NznPS3foEqTUMjvBEts
A head's tools, actions and menu were a wrapping Row with gap 1 holding three ForEach stacks of gap 1, so they sat 4 px apart where the mockups space them 8 px. The trail is now an ActionBar with wrap, so its parts are the theme's actions.gap apart, and a workspace overlay's footer actions are an ActionBar too, so the same actions are spaced alike in a head and in an overlay. ActionBar gains wrap (the view tree, ActionBarOptions, and the ui/1 flag). A horizontal forEach that is a direct child of an actionBar is part of its row: the mount marks it as a row of actions and gives it step 2. A gap on such a forEach is refused at load for a literal horizontal axis and reported at lowering for a computed one. A wrapping action bar in an overlay's content is refused at mount, because the footer sizes its row to one line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BmVLNhUvbWZjv85Hx2saxn
The stock header background drew only a fill, so a theme that fills a header band could not close it with the 1 px line that separates the header from the first row. The token color.table.headerRule (transparent by default, so the stock look does not change) is a 1 px rule MorphTableHeaderBackground draws over the header's last pixel row, inside its height so nothing moves. The token follows color.table.header along every path that colour takes: Theme.tableHeaderRule, each of Theme.qml's seven built-in schemes (the joined toolbar from the bar scheme), the surfaces a theme declares, MorphScheme and MorphButton's role copy. A table in a card draws with the card scheme, so leaving that binding out would draw no rule in the common case. The terminal reads no table colour and is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BmVLNhUvbWZjv85Hx2saxn
…t 8 px apart Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BmVLNhUvbWZjv85Hx2saxn
…ch column Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BmVLNhUvbWZjv85Hx2saxn
…t 8 px apart Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BmVLNhUvbWZjv85Hx2saxn
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BmVLNhUvbWZjv85Hx2saxn
…olour Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01No1NznPS3foEqTUMjvBEts
…e pinned Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01No1NznPS3foEqTUMjvBEts
…one flag, so the ui branch figure clears its floor The two cases checked 'the container exists, holds two children, the reference text exists' once for the check and again for the guard, each as a short-circuit chain whose false arms only a failing backend takes. They now evaluate the conditions together through allHold and test the flag, which leaves the include/morph/ui branch figure at 92.11 % (it was 92.07 %). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01No1NznPS3foEqTUMjvBEts
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this is
examples/lims_galleryimplements ten real LIMS screens in ui/1 to find out what the declarative UI can and cannot express: a sample receipt, a sample list, a results worksheet, a review and sign-off, a plate layout, a stability study, an instrument console, an audit trail, an e-signature dialog and a scanner console. It has no backend: sample data lives in screen state. Each screen has a compact and an expanded layout, a recording-backend test and a Qt Quick render smoke at both widths. Green (#17784A) is the main colour.Run it with
morph_examples_client --app lims-gallery --ui=qt.Every gap the screens hit is in
examples/lims_gallery/design/gaps.md(G1–G56). The fixes landed in five framework batches, each designed and reviewed once (docs/superpowers/specs/2026-10-25-lims-gallery-batch-{b,c,d,e}-design.md). After each batch, the gallery dropped the workarounds that batch replaced.The framework batches
A: defects and responsive layout.
env.widthClassis set by every backend, measured in units.progressand component numbers.forEachkeeps its common properties.sizes, andclose: selfcloses the enclosing dialog.B: tables.
monotext role and afont.monotoken.alignandvalign.sortform.pageSizeandpage, and theslicefunction.runsform.groupheading rows.showHeaderis read as the flag it is.C: text, fields and small controls.
D: layout, overlays and navigation.
surfaceas an expression.stepperhelper.navigateas a dialog that answers its opener.E: expressions and charts.
getform.abs,sqrt,stdevandrsd, exact until one correct rounding.dateAdd.chartnode, drawn by every frontend, with colour-blind-safe series colours and a marker per series.Closes #1046, #1047, #1048, #1049, #1050, #1051, #1052, #1053, #1054, #1055, #1058, #1059, #1060, #1061, #1062, #1063, #1064, #1065, #1066.
Not closed here: #1056 (env
locale,platformandonlineare never set), #1067 (two default tones below 3:1 on the dark sidebar, weak evidence) and #1068 (a state declaredanywith an init takes the init's type; found by this PR's coverage tests and kept as a[!shouldfail]case).Verification
Run on the branch's tip (
linux-everything, clang,-Werror), Qt suites withQT_QPA_PLATFORM=offscreen:The full build: no warnings.
morph_tests: 3360 cases, 3358 passed, 2 failed as expected (the replay-ledger negative control and the ui/1: a state declared "any" with an init takes the init's type #1068 case, both marked so).morph_qt_quick_tests189 cases (also on Qt 6.8.1, which the ladder job uses),morph_tui_tests367,morph_client_tests38,lims_gallery_tests54,gallery_testsand all ten render smokes: all pass.include/morph/uibranch coverage 92.57%, measured locally with clang 21.qmllint (
qt_quick_qmllint) passes.Doxygen with warnings as errors passes.
clang-format 22 over every tracked C++ file: no differences.
54 conformance cases and 16 layout cases, run by the recording backend, Qt Quick and the TUI.
Every new test has a control: the feature was broken, the test was seen to fail, and the feature was restored.
clang-tidy 22 was run on changed lines in
include/andsrc/(Qt sources with a local clang-tidy, because the tidy container has no Qt).Not run locally: MSVC, GCC 15
-O3. The new looks were checked through grabs and the render smoke only.Known follow-ups
steppercannot pin its footer, so the stability screen's Continue button scrolls on compact.The run's tracker and handoff note are in
examples/lims_gallery/design/(status/,next.md).🤖 Generated with Claude Code
https://claude.ai/code/session_01BmVLNhUvbWZjv85Hx2saxn