pcbjam/docs/features/wx-dom-port/README.md
Viktor Vaczi 7dc1bf27e0 refactor: collapse dual-mode plumbing — the DOM port is the only WASM build
The canvas (wxUniversal) mode is gone (wxwidgets submodule); remove every
piece of side-by-side plumbing so there is exactly one build and one test
flow:

- scripts/build-wxuniversal-wasm.sh -> scripts/build-wx-wasm.sh; no
  --dom/--enable-universal; builds into build-wasm/wxwidgets
- build-wasm-test.sh: no DOM_BUILD / apps-dom rsync mirror / PORT=dom;
  apps build straight into tests/apps (Makefile.wasm PORT conditionals
  collapsed; wx.js + wx-dom.js always pre-js)
- docker/build.sh, build-kicad-target.sh, env.sh: WX_PORT / -dom /
  -universal suffixes removed; kicad builds to kicad-<app>, outputs to
  output/; wx.js/wx-dom.js copied from the real source path
  (/workspace/wxwidgets/build/wasm — the old build-wasm path never
  existed and silently failed)
- setup-kicad-wasm.sh: single target dir; the perl wx-dom.js injection is
  gone — the 7 checked-in kicad pages now reference wx-dom.js directly
- playwright configs serve apps/; fixtures drop the test-results/dom and
  logs/wxwidgets/dom namespacing; boot.spec asserts wxDomPort
  unconditionally; pcbnew.spec uses one reference image;
  appearance.spec assertions unconditional
- compare/update-baseline-screenshots.sh: --port removed
- tests/gal-regression/wasm/Makefile: links build-wasm/wxwidgets and
  carries wx-dom.js as a second pre-js — the gal-webgl suite (30 specs)
  now actually builds and runs here (it needed host-side boost+glm via
  scripts/deps; the bundle had been missing, timing the whole spec out)
- tests: clickCanvas() dispatches via page.mouse (DOM widgets
  legitimately cover the canvas; locator actionability refused the
  click); the comprehensive spec drives wxChoice through its native
  <select> (browser-owned popup cannot be coordinate-clicked)
- docs: README/CLAUDE.md/build.md script names and dirs;
  features/wx-dom-port README reframed (DOM is THE port), visual-notes
  bugs 26-28; FindwxWidgets.cmake config label drops 'wasmuniv'
- wxwidgets submodule -> 9dbacc9448 (DOM-only port, fork diff shrunk)

Gate: full wx e2e suite 292 passed / 1 skipped / 0 failed — first run
ever with the gal-webgl specs green (28 scenarios + load + sequential).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 20:19:48 +02:00

106 lines
5.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# wxWidgets DOM port (`feature/wx-dom-port`)
THE wxWidgets WASM port: widgets are **real HTML elements**
(`wxButton` → `<button>`, `wxTextCtrl` → `<input>`, menus → popup divs)
instead of pixels on a canvas. Goals: styleable modern UI, native text
input/IME, accessibility, crisp rendering.
Status: COMPLETE and consolidated (2026-06-12). The original canvas
(wxUniversal) mode and all dual-build plumbing have been **removed** —
`--with-wasm` builds the DOM port, full stop. All `src/univ/` +
`include/wx/univ/` modifications were reverted to upstream v3.2.6, so the
wxwidgets fork is upstream + new `src/wasm/` + `include/wx/wasm/` +
`build/wasm/` files + thin hooks. All six KiCad apps (pcbnew, eeschema,
calculator, pl_editor, symbol_editor, gerbview) build and run on it.
Build: `docker/build.sh <app>` (outputs in `output/`), wx standalone via
`scripts/build-wx-wasm.sh`, test apps via `scripts/build-wasm-test.sh`.
Test: `npm test` / `npm run test:kicad` from `tests/` (no env vars).
Work intentionally stays on `feature/wx-dom-port` (root + wxwidgets +
kicad) — not merged to `main`/`wasm-port`.
## Architecture in one page
- **C++ owns state; the DOM is a projection.** Controls call
`WasmCreateDomNode("type")` once in `Create()`; the shared
`wxWindowWasm` machinery then syncs geometry (TLW-relative absolute
positioning, recursing into descendants; ancestor-viewport clipping via
`clip-path`), visibility (`IsShownOnScreen`, whole subtree),
enabled/font/focus/destruction. DOM-native state (typed text, checked,
selection) syncs back through events into C++ caches so getters stay
synchronous. NB: `GetScreenPosition()` is the CLIENT-AREA origin
(`ClientToScreen(0,0)`), not the top-left — the projection subtracts
`GetClientAreaOrigin()` (matters for wxNotebook's tab strip).
- **Layout is wx sizers, not CSS.** DOM contributes intrinsic measurement
only (clone-based, in an offscreen always-rendered host — sizers run
before `Show()`); positions are written as absolute `left/top/w/h`.
- **Events** flow element listener → `ccall('wx_dom_event')` →
`domevents.cpp` routing table → virtual `wxWindowWasm::OnDomEvent` —
the same direct-dispatch pattern as the port's mouse callbacks (proven
against Asyncify-suspended modals). Document-level listeners forward
mouse activity over DOM children into the wx hit-test pipeline
(`wx_dom_mouse`); wheel events walk up the window hierarchy. Keyboard
arbitration: keystrokes go untouched to focused DOM editables (Escape
excepted).
- **Canvas islands.** Owner-drawn/generic widgets (wxGrid, listctrl,
tree, AUI, STC, calendar...) keep painting via the shared `dc.cpp`
Canvas2D path inside per-window canvases — the same architecture native
ports use for owner-drawn widgets.
- **Menus/toolbars** serialize C++→JS as JSON; popups are DOM divs;
command ids route back via `wxDOM_EVENT_MENU`/`TOOL`. The DOM-native
wxNotebook renders a real tab strip (`<button role=tab>`).
- **E2E registry.** `window.wxElementRegistry` (wx.js) carries element
geometry for Playwright. wxWindow-level entries come from
`src/wasm/window.cpp`; canvas-island content (grid cells, list rows,
calendar dates, AUI parts...) is published from thin paint-site hooks
that call helpers in `src/wasm/elementtracker.cpp`; DOM-native
composites (tabs, menu items, tools, spin arrows, text fields) are
mirrored by wx-dom.js. One contract for everything.
Key files: `wxwidgets/build/wasm/wx-dom.js` (the whole JS control layer),
`wxwidgets/include/wx/wasm/private/dom.h` (C++→JS bridge),
`wxwidgets/src/wasm/domevents.cpp` (event routing + bitmap data URLs),
`wxwidgets/src/wasm/window.cpp` (DOM-backing machinery),
`wxwidgets/src/wasm/elementtracker.cpp` (e2e registry bridge).
## What works (e2e-verified)
Full `tests/e2e` suite green; full kicad suite green.
- Native DOM: stattext, button (stock labels, default size), textctrl
(single/multi/password, two-way sync, wxEVT_TEXT/_ENTER), checkbox,
radiobutton (HTML name groups from wxRB_GROUP chains), radiobox,
togglebutton, gauge, slider, statline, statbox, statbmp (PNG data
URLs), bitmap buttons, choice, listbox, editable combobox
(input+datalist), checklistbox, spinbutton (drives generic wxSpinCtrl),
notebook (DOM tab strip), menubar+menus, toolbar, tooltips (#wx-tooltip
layer, island widgets included), dialogs (shared Asyncify ShowModal),
frame bar geometry.
- Canvas islands verified visually: AUI, calendar, virtual listctrl,
grid, tree, propgrid, STC.
## Known gaps / polish (tracked in visual-notes.md)
- wxSpinCtrl text field collapses beside the spin pair (generic composite
sizing); bitmap-button vertical centering; checklistbox selection
highlight; wxLB_SINGLE uses a multiple `<select>`; native scrollbars
replace univ gutters.
- Element-registry hooks remain in `src/generic/` + aui/stc/propgrid as
thin guarded one-liners (canvas islands have no per-item DOM, so tests
need C++-fed geometry); everything heavier lives in
`src/wasm/elementtracker.cpp`.
## Fork surface (vs upstream wxWidgets v3.2.6)
Upstream + new files (`src/wasm/`, `include/wx/wasm/`, `build/wasm/`),
the `__WXWASM__` dispatch branches in `include/wx/*.h` (2–4 lines each),
WASM toolkit registration in the build system (bakefile-generated),
wasm-generic fixes in `src/common/`, a handful of unguarded island
rendering tweaks in `src/generic/` (renderg/gridctrl/stattextg/msgdlgg/
spinctlg/filedlgg), and thin `#ifdef __EMSCRIPTEN__` tracker shims at
paint sites. `src/univ/`, `include/wx/univ/`, `src/generic/notebook.cpp`,
`tabg.cpp`, `build/msw/`, `tests/makefile.vc` are byte-identical to
upstream.
See `visual-notes.md` for the full bug log the cross-port screenshot
comparison protocol produced.