Qt and keal-view agree about more than they disagree: both put a retained tree of widgets in front of you, both lay it out rather than positioning it, and both draw their own controls rather than asking the platform. The difference is what a widget is — a long-lived object you mutate in Qt, and a description rebuilt from state here.
| Qt | keal-view |
|---|---|
QLabel("Hi") | label("Hi") |
QPushButton + connect(…) | button("Go", { -> … }) |
QVBoxLayout / QHBoxLayout | column([…]) / row([…]) |
setStretch / stretch factor | .grows() and .shares() |
QWidget::paintEvent + QPainter | custom({ p -> … }) |
QDockWidget | Dock, leaf and split |
qApp->setStyleSheet(…) | useTheme(lightTheme()) |
A Qt widget holds state, so something has to tell it when the model changed — that is what a signal is for. Here the tree is thrown away and made again from the state, so a button's handler writes a Cell and the next frame is already right. There is no connect and nothing to disconnect.
Qt layouts negotiate: a widget has a minimum, a preferred and a maximum, and the engine finds a compromise. Here there is one axis of flexbox and no shrinking at all — what does not fit is clipped. That is a deliberate choice: a layout that silently compresses fails only on small windows, which is the last place anyone looks.
tools/build.sh yours.keal compiles the backend once and hands the object file to keal build. There is no code generator in the loop and no interface description to keep in step with the code that uses it.