diff --git a/docs/03-PHASE3-WXWIDGETS-WASM.md b/docs/03-PHASE3-WXWIDGETS-WASM.md index f294fd4..3356fc2 100644 --- a/docs/03-PHASE3-WXWIDGETS-WASM.md +++ b/docs/03-PHASE3-WXWIDGETS-WASM.md @@ -131,7 +131,53 @@ git apply ../patches/0002-touch-to-mouse-events.patch git commit -m "Add Emscripten/WASM support" ``` -### Step 4: Create Build Script +### Step 4: Submodule Setup After Cloning + +The wxwidgets submodule is a fork (`VV-EE/wxWidgets`) with all WASM changes already committed. However, wxWidgets has **nested submodules** (pcre, expat, jpeg, png, tiff, zlib) that need config.sub modifications for Emscripten support. These nested submodules are separate repositories, so their changes are NOT tracked by the wxwidgets fork. + +**After cloning kicad-wasm, you must:** + +```bash +git clone +cd kicad-wasm + +# 1. Initialize wxwidgets submodule +git submodule update --init wxwidgets + +# 2. Initialize wxwidgets' nested submodules +cd wxwidgets +git submodule update --init --recursive + +# 3. Copy config.sub to nested submodules (required for Emscripten) +# The main wxwidgets/config.sub already has emscripten/wasm32 support. +# Copy it to all nested submodule locations: +cp config.sub 3rdparty/pcre/config.sub +cp config.sub src/expat/expat/conftools/config.sub +cp config.sub src/jpeg/config.sub +cp config.sub src/png/config.sub +cp config.sub src/tiff/config/config.sub + +cd .. +``` + +**Why is this needed?** +- wxWidgets bundles libraries (pcre, expat, jpeg, png, tiff) as git submodules +- Each submodule has its own `config.sub` that must recognize `emscripten` and `wasm32` hosts +- These submodules point to upstream repos, so we can't commit changes to them +- The same modified config.sub must be copied to all 5 locations after every fresh clone + +**Reproducibility Testing** (optional): + +A patch-based build system exists for validation: +```bash +# Generate patches from current wxwidgets state +./scripts/generate-wxwidgets-patches.sh + +# Build from clean clone + patches (validates reproducibility) +./scripts/build-wxwidgets-wasm-clean.sh --clean +``` + +### Step 5: Create Build Script Create `scripts/build-wxuniversal-wasm.sh`: diff --git a/docs/WXWIDGETS-WASM-PORT-PROGRESS.md b/docs/WXWIDGETS-WASM-PORT-PROGRESS.md new file mode 100644 index 0000000..927ae64 --- /dev/null +++ b/docs/WXWIDGETS-WASM-PORT-PROGRESS.md @@ -0,0 +1,310 @@ +# wxWidgets 3.2.6 WASM Port Progress + +## Build Command +```bash +cd /Users/V/IdeaProjects/kicad-wasm/build-wasm/wxwidgets-universal +emmake make -j1 2>&1 | tail -30 +``` + +## Current Status: BUILD PASSING + +Last verified: Build completes successfully with all libraries generated. + +--- + +## COMPLETED CHANGES + +### 1. build/wasm/ directory (DONE) +Copied from reference: +- `wxwidgets/build/wasm/common.mk` +- `wxwidgets/build/wasm/wxwasm.mk` +- `wxwidgets/build/wasm/wx.js` (JavaScript glue layer - critical!) +- `wxwidgets/build/wasm/template.html` +- `wxwidgets/build/wasm/httpd.py` + +### 2. Locale warning fix (DONE) +**src/common/intl.cpp** - Added `#ifndef __WXWASM__` guard around locale warning at line ~394 + +**src/common/wxcrt.cpp** - Added `#ifdef __WXWASM__` to return NULL from wxSetlocale at line ~121 + +### 3. src/common/ modifications (DONE) +**include/wx/config.h** - Added WASM case to include wx/wasm/config.h and define wxConfig as wxLocalStorageConfig + +**src/common/config.cpp** - Added WASM case to use wxLocalStorageConfig + +**src/common/event.cpp** - Added `m_clickCount = event.m_clickCount;` in wxMouseEvent::Assign() at line ~615 + +**src/common/fontcmn.cpp** - Multiple changes: +- Added `#if !defined(__WXWASM__)` guard around FromString()/ToString() (lines 735-827) +- Added `m_isRendered = false;` in Init() for WASM (line 839-841) +- Added `#if !defined(__WXWASM__)` guard around setter functions (lines 884-927) + +**include/wx/fontutil.h** - Added WASM-specific members at line ~222: +```cpp +#if defined(__WXWASM__) + mutable bool m_isRendered; + mutable wxString m_renderedString; +#endif +``` + +**src/common/combocmn.cpp** - Added WASM configuration block at line ~165: +```cpp +#elif defined(__WXWASM__) +#include "wx/dialog.h" +#define wxComboCtrlGenericTLW wxDialog +#define USE_TRANSIENT_POPUP 1 +#define TRANSIENT_POPUPWIN_IS_PERFECT 1 +#define POPUPWIN_IS_PERFECT 1 +#define TEXTCTRL_TEXT_CENTERED 0 +#define FOCUS_RING 0 +``` + +### 4. src/univ/ Dialog async modal support (DONE) +**include/wx/univ/dialog.h** - Added: +- `#include ` at top +- `virtual void ShowModal(std::function callback) wxOVERRIDE;` declaration +- `std::function m_modalCallback;` member + +**include/wx/dialog.h** (base class) - Added: +- `#include ` at top +- `virtual void ShowModal(std::function callback) = 0;` declaration +- Public `PopupMenu()` callback overloads + +**include/wx/window.h** - Added: +- `#include ` +- Public `PopupMenu()` callback overloads +- `virtual void DoPopupMenu(wxMenu *menu, int x, int y, std::function callback) = 0;` + +**src/univ/dialog.cpp** - Added: +- `#include ` +- `m_modalCallback = NULL;` in Init() +- `EM_JS(int, startModal, ...)` JavaScript bridge function +- Modified ShowModal() to use async approach (returns wxID_CANCEL for now) +- Added `ShowModal(callback)` overload +- Modified EndModal() to call callback when present + +### 5. src/univ/ Window modifications (DONE) +**include/wx/univ/window.h** - Added: +- `#include ` at top +- WASM case for wxWindowNative (already present) +- `virtual void DoPopupMenu(wxMenu *menu, int x, int y, std::function callback) wxOVERRIDE;` +- `std::function m_popupCallback;` member + +**src/univ/winuniv.cpp** - Added: +- WASM case in `wxIMPLEMENT_DYNAMIC_CLASS` +- Commented out `EVT_KEY_DOWN(wxWindow::OnKeyDown)` +- `m_popupCallback = NULL;` in Init() +- SetScrollbar assertion already updated + +### 6. src/univ/ Control rendering (DONE) +**src/univ/ctrlrend.cpp** - Changed GetLabel() to GetLabelText() in: +- DrawLabel() +- DrawButtonLabel() +- DrawFrame() + +**src/univ/stdrend.cpp** - Changed wxBORDER_SIMPLE to use DrawStaticBorder() + +### 7. src/univ/ Widget fixes (DONE) +**src/univ/anybutton.cpp** - Fixed: +- Moved Refresh() before Click() in Toggle() +- Changed GetLabel() to GetLabelText() in DoGetBestClientSize() + +**src/univ/checkbox.cpp** - Changed GetLabel() to GetLabelText() in: +- DrawCheckButton() call +- GetMultiLineTextExtent() call + +**src/univ/stattext.cpp** - Added: +- AutoResizeIfNecessary() call after WXSetVisibleLabel() +- Changed GetLabel() to GetLabelText() in WXGetVisibleLabel() + +**src/univ/radiobut.cpp** - Added: +- Toggle() method +- PerformAction() override +- Changed GetLabel() to GetLabelText() in DoDraw() + +**include/wx/univ/radiobut.h** - Added: +- Toggle() declaration +- PerformAction() override declaration + +**src/univ/textctrl.cpp** - Added: +- SetBackgroundColour(*wxWHITE) in Create() +- DoGetSizeFromTextSize() method + +**include/wx/univ/textctrl.h** - Changed: +- GetDefaultBorder() returns wxBORDER_STATIC instead of wxBORDER_SUNKEN +- Added DoGetSizeFromTextSize() declaration + +### 8. GetScrollbarArrowSize signature + slider/spinbutt changes (DONE) +**include/wx/univ/renderer.h** - Changed: +- `GetScrollbarArrowSize()` to `GetScrollbarArrowSize(wxOrientation orientation)` +- `DrawSliderShaft` to add `double fracValue` parameter +- Added `GetOverflowHeight()` to wxMenuGeometryInfo +- Added `DrawMenuOverflowArrow()` method +- Updated wxDelegateRenderer wrappers + +**src/univ/themes/gtk.cpp, mono.cpp, win32.cpp** - Updated: +- `GetScrollbarArrowSize(wxOrientation WXUNUSED(orientation))` signature +- `DrawSliderShaft` signature with `double WXUNUSED(fracValue)` parameter + +**src/univ/scrolbar.cpp** - Added: +- `thumbSize = wxMax(wxMin(thumbSize, range), 0);` in SetScrollbar +- `GetScrollbarArrowSize()` helper method that calls renderer with orientation +- Changed all `m_renderer->GetScrollbarArrowSize()` to `GetScrollbarArrowSize()` +- Changed `size.x = SIZE` to `size.y = 15` for horizontal scrollbar + +**include/wx/univ/scrolbar.h** - Added: +- `wxSize GetScrollbarArrowSize() const;` declaration + +**src/univ/spinbutt.cpp** - Updated: +- `DoGetBestClientSize()` calls renderer with orientation +- `CalcArrowRects()` rewritten with hardcoded ARROW_WIDTH/HEIGHT + +**src/univ/settingsuniv.cpp** - Updated: +- `GetMetric()` calls use orientation parameter + +**src/univ/slider.cpp** - Updated: +- Added `IsInverted()` logic in CalcThumbRect +- Added fracValue calculation in DoDraw +- Updated PixelToThumbPos with IsInverted logic +- Simplified OnThumbDragStart/OnThumbDrag/OnThumbDragEnd + +**include/wx/univ/slider.h** - Added: +- `bool IsInverted() const { return IsVert() != HasFlag(wxSL_INVERSE); }` + +--- + +### 9. src/univ/menu.cpp (DONE) + +Complete rewrite of popup menu handling for WASM: + +**Timer-based submenu opening** - In browsers, no modal event loops. Timer allows diagonal mouse movement toward submenus without accidentally closing them. +- `m_subMenuTimer` - delays submenu opening (50ms) +- `m_subMenuPoint` - tracks mouse position when starting submenu tracking +- `IsPointTrackingToSubMenu()` - geometry check if mouse moving toward submenu +- `OnSubMenuTimer()` - timer callback + +**Overflow handling** - Browser windows can be smaller than desktop. Menus need to scroll. +- `m_offsetY` - scroll offset +- `m_overflowTimer` - continuous scrolling when hovering arrows +- `HasOverflow()`, `HasOverflowArrowUp()`, `HasOverflowArrowDown()` +- `GetOverflowArrowUpRect()`, `GetOverflowArrowDownRect()` +- `OverflowArrowHitTest()` +- `GetMaxClientHeight()` - available screen height +- `SetOffsetY()` - set scroll and refresh +- `OnOverflowTimer()`, `OnMouseWheel()` + +**Async popup menus** - DoPopupMenu skips blocking event loop for WASM +- Wrap blocking code in `#ifndef __WXWASM__` +- Add callback-based overload +- DismissPopupMenu calls callback + +**Other changes:** +- Border from `wxBORDER_RAISED` to `wxBORDER_STATIC` +- ClickItem BEFORE DismissAndNotify (was after) +- GetRootWindow uses GetWindow() instead of GetInvokingWindow() +- Detach adds GetParent()->RemoveChild(this) +- OnLeftDown uses IsShowingMenu()/DismissMenu() instead of HasCapture()/OnDismiss() + +--- + +### 10. src/generic/ modifications (DONE - partial) + +**src/generic/spinctlg.cpp** - MARGIN=0, null check for m_spinButton in DoMoveWindow +**src/generic/msgdlgg.cpp** - Async ShowModal overload added +**include/wx/generic/msgdlgg.h** - ShowModal callback declaration added +**src/generic/renderg.cpp** - Visual tweaks (3DLIGHT color, transparent pen, highlight color) +**src/generic/treectlg.cpp** - Smaller indent/spacing (10 instead of 15/18), transparent pen +**src/generic/vlbox.cpp** - SetBackgroundColour(*wxWHITE) + +Not yet applied (may not be needed for wxWidgets 3.2.6): +- **src/generic/caret.cpp** - Different API in 3.2.6 +- **src/generic/grid.cpp** - Visual tweaks (low priority) +- **src/generic/gridctrl.cpp** - 4 lines (low priority) +- **src/generic/filedlgg.cpp** - 2 lines +- **src/generic/listctrl.cpp** - 2 lines +- **src/generic/stattextg.cpp** - 2 lines + +--- + +## REMAINING CHANGES (NOT YET APPLIED) + +### Priority 1: include/wx/ header modifications (Low priority - complex) + +**include/wx/platinfo.h** - 77 lines (browser detection, wxBrowserInfo class, wxPORT_WASM) +**src/common/platinfo.cpp** - 6 lines (browser info init) +**src/common/utilscmn.cpp** - 57 lines (async wxMessageBox, wxPORT_WASM check) +**src/common/wincmn.cpp** - 19 lines (async popup menu) + +Many other headers need `#elif defined(__WXWASM__)` or `#ifdef __WXWASM__` additions. + +### Priority 4: Build system files + +**Makefile.in** - 897 lines of changes +**autoconf_inc.m4** - 13 lines +**build/bakefiles/files.bkl** - 74 lines +**build/bakefiles/wx.bkl** - 2 lines +**build/cmake/files.cmake** - 71 lines +**build/cmake/setup.cmake** - 2 lines +**build/cmake/toolkit.cmake** - 6 lines +**build/files** - 71 lines + +--- + +## HOW TO CHECK REFERENCE CHANGES + +To see what a file changed in the reference: +```bash +cd /Users/V/IdeaProjects/kicad-wasm/wxWidgets-wasm-reference +git show d262364a0a -- path/to/file +``` + +The last 10 commits in reference (oldest to newest): +1. d262364a0a - Initial commit of wasm sources (main changes) +2. 595b16b855 - Add wasm files (theme, demo makefiles) +3. 0dbfab6b4c - Update README.md +4. 31a467a173 - Update README.md +5. 3c0f3b1954 - Update link to wavacity +6. 57ea7c9a04 - Fix crash if mouse window reset in event handler +7. ae94f56bd3 - Size top window before run +8. 255970e5e2 - Support font size in pixels +9. b44707a19a - Translate touch events to mouse events +10. 293bd9feba - Suppress locale warnings + +Bug fixes 6-10 are already applied in wxwidgets/src/wasm/ files. + +--- + +## KEY INSIGHT: Why config.sub in Submodules + +wxWidgets 3.2.6 uses git submodules for bundled libraries (pcre, expat, jpeg, png, tiff). Each has its own config.sub that must recognize wasm32. The reference (older ~3.0.x) had libraries directly in-tree without submodules. + +Current submodule config.sub files are already updated (showing `m` modified status in git). + +--- + +## SKIPPED CHANGES (Low Priority or Complex) + +- **src/common/appcmn.cpp** - Just debug printf (not needed) +- **src/common/init.cpp** - Just debug printf (not needed) +- **src/common/dcbufcmn.cpp** - Different API in 3.2.6 (already correct) +- **Browser info in platinfo.h/cpp** - Complex, adds wxBrowserInfo class (not critical) +- **Async wxMessageBox** - Changes function signature (complex) + +--- + +## NEXT STEPS + +1. **Complete menu.cpp changes** - Follow the 20-step list above +2. Apply src/generic/ changes +3. Apply remaining include/wx/ header changes +4. Test with a minimal WASM app + +--- + +## FILES IN wxwidgets/ FOLDER + +Key WASM-specific directories already present: +- `wxwidgets/src/wasm/` - 29 source files +- `wxwidgets/include/wx/wasm/` - 31 header files +- `wxwidgets/src/univ/themes/wasm.cpp` - WASM theme (98KB) +- `wxwidgets/build/wasm/` - Build support files (copied from reference)