Union Upstream Architecture#
Union is a theming engine (not a UI framework). It provides a CSS-based styling system for Qt Quick Controls 2 and Kirigami. This document describes the native C++ architecture to clarify what Union Web must replicate.
Processing Pipeline#
CSS files (.css)
↓
StyleRule[] + Variables
↓
QuickStyle (attached QML property) — queries StylePropertyGroup for a QQuickItem
↓
Output Plugin (QtQuick):
├── PositionerLayout — reads layout/icon/text alignment, positions children
└── StyledRectangle — reads background/border/outline/shadow, renders visuals
The CSS-to-property pipeline is shared; two independent output systems consume different subsets of each StylePropertyGroup.
PositionerLayout#
A micro-layout engine that positions a control's internal children (icon, text, indicator). Not a page-level layout system.
- Scope: Every control's
Union.Positioner.positionItems— always internal children like[contentItem, indicator], never sibling controls. - Control-to-control layout is done by Qt Quick Layouts (RowLayout, ColumnLayout) or anchoring, never by Positioner.
- Computes: x/y positions within the control's bounds, then calls
item->setX()/setY()/setSize()on child QQuickItems. - Alignment source: Each positioned item reads from one of three CSS property groups based on its
PositionedItem.source:
| Source | CSS property group |
|---|---|
| Layout | layout.alignment |
| Icon | icon.alignment |
| Text | text.alignment |
Three containers (coordinate reference frames)#
Layout {
itemContainer: // full parent box
├── start bucket
├── center bucket
├── end bucket
└── fill bucket
backgroundContainer: // parent minus start/end, offset by inset
contentContainer: // parent minus start/end, offset by padding
}
These are math rectangles, not visual elements. They exist only during Layout::layout() computation and are discarded after item positions are computed.
StyledRectangle#
A C++ QQuickItem that renders visual chrome via QSG (Qt Scene Graph) nodes.
- Scope: Used as
background:on every control (64 QML files in the theme). - Consumes:
background.*,border.*,outline.*,shadow.*,corner_radius.*,width,height,min-width,min-height. - Positioning: Automatically sized to fill the control by
QQuickControl's base class. - Never in Positioner: StyledRectangle is never in any
positionItems.
StyledRectangle-only controls (e.g., ApplicationWindow, Page) have no Positioner — they render visual chrome only, with child layout delegated to Qt Quick Layouts.
Three-Layer Control Architecture#
Every visual control has the same internal structure (Button example):
Button (QQuickAbstractButton)
│
├── background: StyledRectangle ← visual chrome (border, fill, shadow)
│ [NOT in Positioner]
│
├── contentItem: DefaultContentItem ← semantic content container
│ [IN Positioner.positionItems[0]; positionChildren: true]
│ │
│ ├── Icon (source: Icon) ← positioned via icon.alignment
│ └── Text (source: Text) ← positioned via text.alignment
│
└── indicator: Union.Icon ← optional visual indicator
[IN Positioner.positionItems[1]; source: Layout]
[positioned via layout.alignment]
| Layer | QML property | Managed by | CSS group |
|---|---|---|---|
| Background | background: |
QQuickControl (fills control) |
background.*, border.*, outline.*, shadow.* |
| Content container | contentItem: |
Positioner (via positionChildren: true) |
N/A (pass-through) |
| Icon | child of contentItem | Positioner (source: Icon) | icon.alignment |
| Text | child of contentItem | Positioner (source: Text) | text.alignment |
| Indicator | indicator: |
Positioner (source: Layout) | layout.alignment |
Background Naming Collision#
Two unrelated concepts share the name "background":
Layout::backgroundContainer— a math rectangle in Positioner's layout computation. Child items withlayout-alignment-container: backgroundare positioned relative to this inset-offset frame. Nothing renders here.control.background— a visualStyledRectangleQQuickItem that renders the control's background, border, outline, and shadow. It is never in anypositionItems.
Key Takeaways for Web Ports#
- Positioner is irrelevant for page-level layouts. Union Web positions controls using CSS flexbox/grid. The Positioner engine is only needed for internal control child layout (icon + text + indicator).
layout-alignmenton standalone controls like buttons is effectively dead code — controls are positioned by Qt Quick Layouts, not a parent Positioner.- StyledRectangle is the visual heart of every control. Without it, controls have no background, border, shadow, or outline.
- Positioner's three-container model can collapse to a single content container for web ports, since
itemContainerandbackgroundContainerare math frames that don't correspond to visual layers. - The element YAML files at
tools/elementdocgenerator/*.ymldefine every Union element's states, hints, attributes, and sub-elements — they are the definitive reference.