Skip to content

ui::screen has no way to mark part of its document as shell chrome, separate from the page body #1027

Closed

Description

@Yaraslaut

Problem

A screen's builder (`Screen::Builder = std::function<Node(Scope&)>`) returns one `Node` — the whole document mounts as a single tree in one place (via `DocumentScreenHost`/`mountInto`). There is no way for a screen to say "this part is shell chrome (a title bar with primary actions), this part is the scrollable page body" so a client's shell can lay the two out differently — e.g. a full-bleed, unpadded toolbar strip above a padded, scrollable body, which is a common app-shell pattern (also the Lastrada Design System's own shell: a white `.top` title bar flush with the window edges, above a padded `.body`).

Today, a screen that wants a distinct "title bar" row can only tag it with `.surface("toolbar")` and nest it as the first child of its own content tree. Since the whole tree mounts into one client-side container, that row is subject to whatever padding the shell's own content area applies uniformly — it can never reach the window's actual edges the way a true app-shell title bar does, no matter how it's styled. `ContainerWidget` also has no cross-container reparenting API (`moveChild` only reorders within the same parent), so a client can't pull a tagged sub-tree out after mounting either.

Suggested direction

Something at the `ui::screen`/document level that lets a screen declare two logical regions — chrome and body — which a `DocumentScreenHost`-based client can mount into two different widgets (e.g. the existing `ShellFrame`'s `topBar`/`page`, or a custom shell's equivalent slots), rather than being forced to interpret document structure/surface names after the fact. Even a minimal form — e.g. `ui::screen` accepting an optional second builder for chrome content, surfaced to the host as a second named slot in `Emitted` — would unblock this.

Context

Hit while matching a licence-management client's Qt Quick GUI to its design: every screen's title + primary actions row is tagged `.surface("toolbar")` already (confirmed the backend scheme/background-rectangle plumbing for that surface name works correctly, down to `MorphWidget.qml`'s generic background `Rectangle`), but the row can only ever render as a padded, inset rectangle — never the edge-to-edge bar the design calls for — because the client's shell has no way to mount it outside the body's own padding.

Activity

  1. Yaraslaut commented on Oct 23, 2026

    @Yaraslaut
    MemberAuthor

    Partially addressed by #1038, which leaves this issue open.

    What #1038 does: the active tab's ScreenHead row (title, status badges, actions) now also mounts in ShellFrame's top bar, through Workspace::headRowForActive(). That covers the common case of a title bar with primary actions on clients that use ShellFrame.

    What is still missing:

    • The row is rendered in addition to its place in the page body, not moved out of it. The issue asks for chrome mounted outside the body's padding, not a copy of it.
    • The mechanism only works for ShellFrame and for ScreenHead-shaped content. A screen still can't declare an arbitrary chrome region (the suggested second builder or a named slot in Emitted) that a custom DocumentScreenHost-based shell could mount on its own. The PR description lists this, "part (b)", as out of scope.
    • Aligning actions to the trailing edge inside the mounted head row isn't attempted.

    Verification status: inferred from the PR description and diff, not reproduced against the LicenceServer client.

    Close when: a screen can declare a chrome region that a host mounts in a separate slot instead of inside the body, and a custom shell (not just ShellFrame) can use it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions