Opening a Project.Diagram node’s view face (ScreenCore.viewExpanded(), the
view:<id> path) rendered the diagram collapsed to a thin strip at the bottom of the
screen, with the time-range selector squeezed to roughly one character wide (its
“Range”/”Minute”/”Hour” labels wrapped one letter per line). The same SVG rendered
correctly in the edit face’s Preview box, so the SVG pipeline itself was fine — this
was purely a layout bug in the view face.
Two independent defects compounded, and an earlier fix attempt addressed neither fully:
ViewScreenToolbar’s internal Spacer(Modifier.weight(1f, true)). A weight
child forces its Row to claim the entire incoming max width during Compose’s
unweighted-children-first measurement pass — regardless of what modifier the
caller applies to the toolbar. DiagramScreen’s header row placed
ViewScreenToolbar beside TimeRangeSelector(Modifier.weight(1f)); the toolbar’s
internal weight consumed the row before the selector’s own weight had anything
left to claim. A first fix attempt added an optional modifier parameter and
passed Modifier.wrapContentWidth() from the caller, but wrapContentWidth()
only relaxes the minimum width constraint passed to a child — it does not touch
the maximum, so the internal weight spacer kept expanding to the unchanged max
and the row stayed starved.fillMaxSize() inside an unbounded-height scroll container. DiagramScreen
renders inside NodeEditorContainer’s Settings-tab content column, which is
Modifier.fillMaxSize().verticalScroll(...). verticalScroll hands its content
an unbounded (Constraints.Infinity) max height so it can scroll past the
viewport. Modifier.fillMaxSize()/fillMaxHeight() has no effect once the
incoming max is Constraints.Infinity (documented Compose behavior) — so the
diagram’s image-hosting Box collapsed to whatever minimal height its own
children happened to report.ViewScreenToolbar (composeApp/.../ui/ViewScreenToolbar.kt) dropped the internal
weighted Spacer entirely and now takes a modifier: Modifier = Modifier.fillMaxWidth()
parameter applied directly to its Row, with Arrangement.End doing the
right-alignment Arrangement.End was always capable of doing on its own. The
default preserves the existing full-width, right-pinned look for standalone callers
(CameraScreen); DiagramScreen now passes Modifier.wrapContentWidth(), which
works correctly once there is no interior weight forcing the row to the max.DiagramScreen (composeApp/.../krillapp/project/diagram/DiagramScreen.kt) no
longer sizes its diagram Box with fillMaxSize(). It now derives an exact height
from the box’s (always-bounded) width via Modifier.aspectRatio(...), using the
loaded SVG’s own viewBox/width/height ratio when available (extracted as the
pure, unit-tested diagramBoxAspectRatio(SvgDimensions?)), falling back to a 16:9
placeholder before the SVG loads. This sidesteps the unbounded-max-height problem
entirely instead of fighting it — the same pattern CameraView.kt already used
successfully for its own full-screen node view.weight-based spacer to right-align content should not
also be usable beside another weighted sibling — the two interact through the
shared parent Row’s measurement pass in a way no modifier applied at the call
site can override. Prefer Arrangement.End/Arrangement.SpaceBetween on a row
whose width the caller controls via an accepted modifier parameter, so the row’s
own sizing is single-owner.Modifier.fillMaxSize()/fillMaxHeight() silently becomes a no-op once an
ancestor hands down Constraints.Infinity for that axis (any verticalScroll
content column, LazyColumn, etc.) — it does not throw or warn. A full-screen
“view” composable that will be embedded inside a scrollable container should size
its primary content from a bounded axis (aspectRatio, heightIn(min = ...), or
an explicit .height(...)) rather than fillMaxSize(), and should be spot-checked
by actually opening its view face — not just its edit face’s preview, which may sit
in a differently-constrained parent.DiagramScreenViewLayoutTest (composeApp/src/desktopTest/.../DiagramScreenViewLayoutTest.kt)
using runDesktopComposeUiTest to measure real layout output: it calls the actual
shipped ViewScreenToolbar + TimeRangeSelector composables in the same
side-by-side arrangement DiagramScreen uses and asserts the selector keeps the
majority of the header’s width, plus a pure-function test of
diagramBoxAspectRatio. Verified red before the fix (fails to even compile without
the new modifier parameter; reproduced the narrow-width assertion failure
directly by temporarily reintroducing the old weighted-spacer behavior against the
new signature).