High-level overview of how a caQtDM .ui file becomes a React tree.
Implementation lives in src/lib/uiParser.ts and src/lib/UiRenderer.tsx.
.ui (Qt Designer XML)
└─ uiParser.ts → ParsedUi { nativeWidth, nativeHeight, widgets[] }
└─ UiRenderer.tsx → React tree
├─ widget dispatch (caLabel, caLineEdit, …)
├─ macro substitution ($(VAR))
├─ baseDir resolution for caInclude / caRelatedDisplay
├─ visibility evaluation (channel / visibility / visibilityCalc)
└─ tab and frame layout
uiParser.ts walks Qt Designer XML and emits a typed ParsedWidget
tree:
interface ParsedWidget {
class: string; // "caLineEdit", "caGraphics", …
name: string;
geometry: { x, y, width, height };
props: Record<string, string>; // all properties; colors as "rgba(…)"
zIndex: number;
tabs?: ParsedTab[]; // QTabWidget only
children?: ParsedWidget[]; // caFrame only — children are positioned
// relative to the frame, not flattened
}Geometry is absolute Qt pixels. The renderer scales the parsed tree to fit the host container while preserving aspect ratio.
UiRenderer.tsx is currently a single ~2.5k-line module. It contains:
- Contexts —
OpenContext(opens nested displays as overlays),BaseDirContext(anchor for resolving relative.ui/.adl/image paths),MacrosContext(the active macro map for$(VAR)substitution). - Widget dispatch — a switch on
widget.classthat picks the React component for eachca*widget. The widget catalog is in the project README. - Layout — positions children with absolute coordinates derived
from parsed geometry, with special handling for
caFrame(renders children relative to the frame so visibility can clip the group) andQTabWidget(children positioned relative to the tab page). - Macro substitution —
applyMacrosis exported fromuiParser.tsand used by the renderer when substituting prop values, channel names, and include filenames. - Path resolution —
caIncludeandcaRelatedDisplayreference other.uifiles by relative or absolute path; resolution is anchored onBaseDirContext..adlfiles are converted on the fly via/APSshare/bin/adl2uiand cached in.ui-cache/. See display-path-resolution.md. - Visibility —
caGraphics,caLabel,caPolyLine,caImage,caFrame, andcaIncludesupportvisibility/visibilityCalcconditional rendering against up to four PV variables (A/B/C/Dfromchannel/channelB/channelC/channelD).
UiRenderer.tsx is the biggest file in the codebase. Splitting it
into smaller modules (renderer/, widgets/caDispatch.tsx,
pathResolver.ts, macroSubstitution.ts) is queued — see the
"Open questions" section in
architecture.md.
Until then, treat it as a single dispatch surface and keep changes
local to the relevant widget block.