Add standalone test apps and Playwright specs for wxWidgets WASM

- Add 10 standalone test apps for isolated component testing:
  - menu, toolbar, layout, aui, clipboard, filedialog, grid
  - dialog, timer, tree (3 new)
- Add 12 Playwright e2e test specs for automated testing
- Update Makefile with GL/non-GL build configurations
- Update build script to list all standalone tests
- Add WHATWORKS.md documenting KiCad wxWidgets coverage
- Update .gitignore for build artifacts

Test results:
- 79 Playwright tests pass
- wxGrid crashes (memory access out of bounds)
- wxTreeCtrl crashes (similar issue)
- wxDialog/wxMessageBox events fire but no visual popup

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Viktor Vaczi 2025-11-29 16:19:13 +01:00
commit 53e4603a41
26 changed files with 5070 additions and 30 deletions

View file

@ -1,45 +1,143 @@
# Makefile for wxWidgets WASM test app with OpenGL support
# Uses the local wxWidgets build with legacy GL emulation
# Makefile for wxWidgets WASM test apps
# Uses the local wxWidgets build
WXCONFIG = ../../build-wasm/wxwidgets-universal/wx-config
TOOLS_ROOT = ../../wxwidgets/build/wasm
CXX = em++
WX_CXXFLAGS := $(shell $(WXCONFIG) --cxxflags)
# Include GL library for OpenGL tests
WX_LDFLAGS := $(shell $(WXCONFIG) --libs base,core,gl)
TARGET = minimal_test
SOURCES = minimal_test.cpp
# Libraries for GL apps (minimal_test uses OpenGL)
WX_LDFLAGS_GL := $(shell $(WXCONFIG) --libs base,core,gl,aui)
# Libraries for non-GL apps (standalone tests don't need GL)
WX_LDFLAGS_NOGL := $(shell $(WXCONFIG) --libs base,core,aui)
CXXFLAGS = -O2 $(WX_CXXFLAGS)
# Emscripten flags:
# -sLEGACY_GL_EMULATION: Enable legacy OpenGL (glBegin/glEnd, etc.) emulation on WebGL
# -sMAX_WEBGL_VERSION=2: Enable WebGL 2.0 support (required since wxGLCanvas requests WebGL 2)
# Note: Cannot combine LEGACY_GL_EMULATION with FULL_ES2 - they are mutually exclusive
EM_GL_FLAGS = -sLEGACY_GL_EMULATION -sMAX_WEBGL_VERSION=2
# Base Emscripten flags (for all apps)
BASE_LDFLAGS = -sALLOW_MEMORY_GROWTH -sERROR_ON_UNDEFINED_SYMBOLS=0 \
-s "EXPORTED_RUNTIME_METHODS=['HEAPU8','HEAP8','HEAP32']"
# GL immediate mode shim - fixes Emscripten's color-per-vertex requirement
# and provides missing glVertex2d/glColor4d implementations
# GL-specific flags
EM_GL_FLAGS = -sLEGACY_GL_EMULATION -sMAX_WEBGL_VERSION=2
GL_SHIM = ../../lib/gl_immediate_shim.js
LDFLAGS = -sALLOW_MEMORY_GROWTH -sERROR_ON_UNDEFINED_SYMBOLS=0 \
-s "EXPORTED_RUNTIME_METHODS=['HEAPU8','HEAP8','HEAP32']" \
$(EM_GL_FLAGS) --js-library=$(GL_SHIM) $(WX_LDFLAGS)
# LDFLAGS for GL apps (minimal_test)
LDFLAGS_GL = $(BASE_LDFLAGS) $(EM_GL_FLAGS) --js-library=$(GL_SHIM) $(WX_LDFLAGS_GL)
# LDFLAGS for non-GL apps (standalone tests)
LDFLAGS_NOGL = $(BASE_LDFLAGS) $(WX_LDFLAGS_NOGL)
JS = $(TOOLS_ROOT)/wx.js
HTML = $(TOOLS_ROOT)/template.html
all: $(TARGET).html
# Standalone directories
S = standalone
$(TARGET).o: $(SOURCES)
all: minimal_test.html \
$(S)/menu/menu_test.html \
$(S)/clipboard/clipboard_test.html \
$(S)/filedialog/filedialog_test.html \
$(S)/layout/layout_test.html \
$(S)/aui/aui_test.html \
$(S)/toolbar/toolbar_test.html \
$(S)/grid/grid_test.html \
$(S)/dialog/dialog_test.html \
$(S)/timer/timer_test.html \
$(S)/tree/tree_test.html
# Main test app (uses GL)
minimal_test.o: minimal_test.cpp
$(CXX) -c $(CXXFLAGS) $< -o $@
$(TARGET).html: $(TARGET).o
$(CXX) $(TARGET).o $(LDFLAGS) --pre-js $(JS) --shell-file $(HTML) -o $@
minimal_test.html: minimal_test.o
$(CXX) $< $(LDFLAGS_GL) --pre-js $(JS) --shell-file $(HTML) -o $@
# Menu test (no GL)
$(S)/menu/menu_test.o: $(S)/menu/menu_test.cpp
$(CXX) -c $(CXXFLAGS) $< -o $@
$(S)/menu/menu_test.html: $(S)/menu/menu_test.o
$(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@
# Clipboard test (no GL)
$(S)/clipboard/clipboard_test.o: $(S)/clipboard/clipboard_test.cpp
$(CXX) -c $(CXXFLAGS) $< -o $@
$(S)/clipboard/clipboard_test.html: $(S)/clipboard/clipboard_test.o
$(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@
# FileDialog test (no GL)
$(S)/filedialog/filedialog_test.o: $(S)/filedialog/filedialog_test.cpp
$(CXX) -c $(CXXFLAGS) $< -o $@
$(S)/filedialog/filedialog_test.html: $(S)/filedialog/filedialog_test.o
$(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@
# Layout test (no GL)
$(S)/layout/layout_test.o: $(S)/layout/layout_test.cpp
$(CXX) -c $(CXXFLAGS) $< -o $@
$(S)/layout/layout_test.html: $(S)/layout/layout_test.o
$(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@
# AUI test (no GL)
$(S)/aui/aui_test.o: $(S)/aui/aui_test.cpp
$(CXX) -c $(CXXFLAGS) $< -o $@
$(S)/aui/aui_test.html: $(S)/aui/aui_test.o
$(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@
# Toolbar test (no GL)
$(S)/toolbar/toolbar_test.o: $(S)/toolbar/toolbar_test.cpp
$(CXX) -c $(CXXFLAGS) $< -o $@
$(S)/toolbar/toolbar_test.html: $(S)/toolbar/toolbar_test.o
$(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@
# Grid test (no GL)
$(S)/grid/grid_test.o: $(S)/grid/grid_test.cpp
$(CXX) -c $(CXXFLAGS) $< -o $@
$(S)/grid/grid_test.html: $(S)/grid/grid_test.o
$(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@
# Dialog test (no GL)
$(S)/dialog/dialog_test.o: $(S)/dialog/dialog_test.cpp
$(CXX) -c $(CXXFLAGS) $< -o $@
$(S)/dialog/dialog_test.html: $(S)/dialog/dialog_test.o
$(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@
# Timer test (no GL)
$(S)/timer/timer_test.o: $(S)/timer/timer_test.cpp
$(CXX) -c $(CXXFLAGS) $< -o $@
$(S)/timer/timer_test.html: $(S)/timer/timer_test.o
$(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@
# Tree test (no GL)
$(S)/tree/tree_test.o: $(S)/tree/tree_test.cpp
$(CXX) -c $(CXXFLAGS) $< -o $@
$(S)/tree/tree_test.html: $(S)/tree/tree_test.o
$(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@
# Convenience targets
menu: $(S)/menu/menu_test.html
clipboard: $(S)/clipboard/clipboard_test.html
filedialog: $(S)/filedialog/filedialog_test.html
layout: $(S)/layout/layout_test.html
aui: $(S)/aui/aui_test.html
toolbar: $(S)/toolbar/toolbar_test.html
grid: $(S)/grid/grid_test.html
dialog: $(S)/dialog/dialog_test.html
timer: $(S)/timer/timer_test.html
tree: $(S)/tree/tree_test.html
clean:
rm -f $(TARGET).o $(TARGET).html $(TARGET).js $(TARGET).wasm
rm -f minimal_test.o minimal_test.html minimal_test.js minimal_test.wasm
rm -f $(S)/*/*.o $(S)/*/*.html $(S)/*/*.js $(S)/*/*.wasm
.PHONY: all clean
.PHONY: all clean menu clipboard filedialog layout aui toolbar grid dialog timer tree

View file

@ -17,6 +17,9 @@
#include "wx/dcbuffer.h"
#include "wx/datetime.h"
#include "wx/glcanvas.h"
#include "wx/grid.h"
#include "wx/spinctrl.h"
#include "wx/srchctrl.h"
// OpenGL headers - using legacy GL with Emscripten's emulation
#ifdef __EMSCRIPTEN__
@ -61,7 +64,19 @@ enum {
ID_BTN_GL_TEST_MATRIX,
ID_BTN_GL_TEST_VERTEX_ARRAY,
ID_BTN_GL_RUN_ALL,
ID_GL_TEST_SELECT
ID_GL_TEST_SELECT,
// Grid tab IDs
ID_GRID,
ID_SPIN_CTRL,
ID_SEARCH_CTRL,
// Dialogs tab IDs
ID_BTN_MSGBOX_INFO,
ID_BTN_MSGBOX_YESNO,
ID_BTN_MSGBOX_ERROR,
ID_BTN_CUSTOM_DIALOG,
ID_BTN_TIMER_START,
ID_BTN_TIMER_STOP,
ID_TIMER
};
// Forward declarations
@ -638,6 +653,14 @@ private:
wxListBox* m_listBox;
GLTestCanvas* m_glCanvas;
wxChoice* m_glTestChoice;
// Grid tab controls
wxGrid* m_grid;
wxSpinCtrl* m_spinCtrl;
wxSearchCtrl* m_searchCtrl;
// Dialogs tab controls
wxTimer* m_timer;
wxStaticText* m_timerLabel;
int m_timerCount;
// Create tab pages
wxPanel* CreateControlsPage(wxNotebook* parent);
@ -645,6 +668,8 @@ private:
wxPanel* CreateDrawingPage(wxNotebook* parent);
wxPanel* CreateListsPage(wxNotebook* parent);
wxPanel* CreateOpenGLPage(wxNotebook* parent);
wxPanel* CreateGridPage(wxNotebook* parent);
wxPanel* CreateDialogsPage(wxNotebook* parent);
// Event handlers
void OnQuit(wxCommandEvent& evt);
@ -665,6 +690,20 @@ private:
void OnNotebookPageChanged(wxBookCtrlEvent& evt);
void OnGLTestSelect(wxCommandEvent& evt);
void OnGLRunAll(wxCommandEvent& evt);
// Grid tab event handlers
void OnGridCellChange(wxGridEvent& evt);
void OnGridCellSelect(wxGridEvent& evt);
void OnSpinCtrl(wxSpinEvent& evt);
void OnSearchCtrl(wxCommandEvent& evt);
void OnSearchCtrlEnter(wxCommandEvent& evt);
// Dialogs tab event handlers
void OnMsgBoxInfo(wxCommandEvent& evt);
void OnMsgBoxYesNo(wxCommandEvent& evt);
void OnMsgBoxError(wxCommandEvent& evt);
void OnCustomDialog(wxCommandEvent& evt);
void OnTimerStart(wxCommandEvent& evt);
void OnTimerStop(wxCommandEvent& evt);
void OnTimer(wxTimerEvent& evt);
wxDECLARE_EVENT_TABLE();
};
@ -688,6 +727,20 @@ wxBEGIN_EVENT_TABLE(TestFrame, wxFrame)
EVT_NOTEBOOK_PAGE_CHANGED(wxID_ANY, TestFrame::OnNotebookPageChanged)
EVT_CHOICE(ID_GL_TEST_SELECT, TestFrame::OnGLTestSelect)
EVT_BUTTON(ID_BTN_GL_RUN_ALL, TestFrame::OnGLRunAll)
// Grid tab events
EVT_GRID_CELL_CHANGED(TestFrame::OnGridCellChange)
EVT_GRID_SELECT_CELL(TestFrame::OnGridCellSelect)
EVT_SPINCTRL(ID_SPIN_CTRL, TestFrame::OnSpinCtrl)
EVT_SEARCHCTRL_SEARCH_BTN(ID_SEARCH_CTRL, TestFrame::OnSearchCtrl)
EVT_TEXT_ENTER(ID_SEARCH_CTRL, TestFrame::OnSearchCtrlEnter)
// Dialogs tab events
EVT_BUTTON(ID_BTN_MSGBOX_INFO, TestFrame::OnMsgBoxInfo)
EVT_BUTTON(ID_BTN_MSGBOX_YESNO, TestFrame::OnMsgBoxYesNo)
EVT_BUTTON(ID_BTN_MSGBOX_ERROR, TestFrame::OnMsgBoxError)
EVT_BUTTON(ID_BTN_CUSTOM_DIALOG, TestFrame::OnCustomDialog)
EVT_BUTTON(ID_BTN_TIMER_START, TestFrame::OnTimerStart)
EVT_BUTTON(ID_BTN_TIMER_STOP, TestFrame::OnTimerStop)
EVT_TIMER(ID_TIMER, TestFrame::OnTimer)
wxEND_EVENT_TABLE()
TestFrame::TestFrame(const wxString& title)
@ -721,6 +774,8 @@ TestFrame::TestFrame(const wxString& title)
m_notebook->AddPage(CreateDrawingPage(m_notebook), "Drawing");
m_notebook->AddPage(CreateListsPage(m_notebook), "Lists");
m_notebook->AddPage(CreateOpenGLPage(m_notebook), "OpenGL");
m_notebook->AddPage(CreateGridPage(m_notebook), "Grid");
m_notebook->AddPage(CreateDialogsPage(m_notebook), "Dialogs");
mainSizer->Add(m_notebook, 1, wxEXPAND | wxALL, 5);
@ -979,6 +1034,65 @@ wxPanel* TestFrame::CreateOpenGLPage(wxNotebook* parent)
return panel;
}
wxPanel* TestFrame::CreateGridPage(wxNotebook* parent)
{
wxPanel* panel = new wxPanel(parent);
wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
// Description
wxStaticText* desc = new wxStaticText(panel, wxID_ANY,
"Advanced Controls Test\n"
"Tests wxSpinCtrl and wxSearchCtrl which KiCad uses extensively.\n"
"NOTE: wxGrid is NOT YET SUPPORTED in WASM (causes function signature mismatch crash).");
mainSizer->Add(desc, 0, wxALL, 10);
// wxGrid - DISABLED: causes "function signature mismatch" crash in WASM
// This needs to be fixed in wxWidgets WASM port before we can test it
/*
wxStaticBox* gridBox = new wxStaticBox(panel, wxID_ANY, "wxGrid (editable cells)");
wxStaticBoxSizer* gridSizer = new wxStaticBoxSizer(gridBox, wxVERTICAL);
m_grid = new wxGrid(panel, ID_GRID, wxDefaultPosition, wxSize(400, 150));
m_grid->CreateGrid(5, 4);
// ... grid setup ...
gridSizer->Add(m_grid, 1, wxEXPAND | wxALL, 5);
mainSizer->Add(gridSizer, 1, wxEXPAND | wxALL, 5);
*/
m_grid = nullptr; // wxGrid not supported in WASM yet
// Row with wxSpinCtrl and wxSearchCtrl
wxBoxSizer* controlRow = new wxBoxSizer(wxHORIZONTAL);
// wxSpinCtrl
wxStaticBox* spinBox = new wxStaticBox(panel, wxID_ANY, "wxSpinCtrl");
wxStaticBoxSizer* spinSizer = new wxStaticBoxSizer(spinBox, wxHORIZONTAL);
spinSizer->Add(new wxStaticText(panel, wxID_ANY, "Value (0-100):"), 0,
wxALL | wxALIGN_CENTER_VERTICAL, 5);
m_spinCtrl = new wxSpinCtrl(panel, ID_SPIN_CTRL, "50",
wxDefaultPosition, wxSize(80, -1), wxSP_ARROW_KEYS, 0, 100, 50);
spinSizer->Add(m_spinCtrl, 0, wxALL, 5);
controlRow->Add(spinSizer, 0, wxALL, 5);
// wxSearchCtrl
wxStaticBox* searchBox = new wxStaticBox(panel, wxID_ANY, "wxSearchCtrl");
wxStaticBoxSizer* searchSizer = new wxStaticBoxSizer(searchBox, wxHORIZONTAL);
m_searchCtrl = new wxSearchCtrl(panel, ID_SEARCH_CTRL, "",
wxDefaultPosition, wxSize(200, -1), wxTE_PROCESS_ENTER);
m_searchCtrl->ShowSearchButton(true);
m_searchCtrl->ShowCancelButton(true);
m_searchCtrl->SetDescriptiveText("Search...");
searchSizer->Add(m_searchCtrl, 1, wxALL | wxEXPAND, 5);
controlRow->Add(searchSizer, 1, wxALL | wxEXPAND, 5);
mainSizer->Add(controlRow, 0, wxEXPAND);
panel->SetSizer(mainSizer);
return panel;
}
// Event handlers
void TestFrame::OnQuit(wxCommandEvent& WXUNUSED(evt))
{
@ -1111,6 +1225,45 @@ void TestFrame::OnGLRunAll(wxCommandEvent& WXUNUSED(evt))
LogEvent("All GL tests completed - check console for detailed results");
}
// Grid tab event handlers
void TestFrame::OnGridCellChange(wxGridEvent& evt)
{
if (!m_grid) { evt.Skip(); return; } // wxGrid not supported in WASM
int row = evt.GetRow();
int col = evt.GetCol();
wxString value = m_grid->GetCellValue(row, col);
LogEvent(wxString::Format("Grid cell changed: [%d,%d] = \"%s\"", row, col, value));
evt.Skip();
}
void TestFrame::OnGridCellSelect(wxGridEvent& evt)
{
if (!m_grid) { evt.Skip(); return; } // wxGrid not supported in WASM
int row = evt.GetRow();
int col = evt.GetCol();
wxString value = m_grid->GetCellValue(row, col);
LogEvent(wxString::Format("Grid cell selected: [%d,%d] \"%s\"", row, col, value));
evt.Skip();
}
void TestFrame::OnSpinCtrl(wxSpinEvent& evt)
{
int value = evt.GetValue();
LogEvent(wxString::Format("SpinCtrl value: %d", value));
}
void TestFrame::OnSearchCtrl(wxCommandEvent& evt)
{
wxString text = m_searchCtrl->GetValue();
LogEvent(wxString::Format("Search button clicked: \"%s\"", text));
}
void TestFrame::OnSearchCtrlEnter(wxCommandEvent& evt)
{
wxString text = evt.GetString();
LogEvent(wxString::Format("Search Enter pressed: \"%s\"", text));
}
// DrawingPanel event handlers (defined after TestFrame for g_frame access)
void DrawingPanel::OnMouseDown(wxMouseEvent& evt)
{
@ -1169,6 +1322,151 @@ void DrawingPanel::OnMouseLeave(wxMouseEvent& WXUNUSED(evt))
}
}
//-----------------------------------------------------------------------------
// CreateDialogsPage - Dialogs tab with message boxes and timer
//-----------------------------------------------------------------------------
wxPanel* TestFrame::CreateDialogsPage(wxNotebook* parent)
{
wxPanel* panel = new wxPanel(parent);
wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
// Description
wxStaticText* desc = new wxStaticText(panel, wxID_ANY,
"Dialog and Timer Tests\n"
"Tests wxMessageBox, wxDialog, and wxTimer which KiCad uses for alerts and animations.");
mainSizer->Add(desc, 0, wxALL, 10);
// Message Box section
wxStaticBox* msgBox = new wxStaticBox(panel, wxID_ANY, "wxMessageBox");
wxStaticBoxSizer* msgSizer = new wxStaticBoxSizer(msgBox, wxHORIZONTAL);
wxButton* btnInfo = new wxButton(panel, ID_BTN_MSGBOX_INFO, "Info Dialog");
wxButton* btnYesNo = new wxButton(panel, ID_BTN_MSGBOX_YESNO, "Yes/No Dialog");
wxButton* btnError = new wxButton(panel, ID_BTN_MSGBOX_ERROR, "Error Dialog");
msgSizer->Add(btnInfo, 0, wxALL, 5);
msgSizer->Add(btnYesNo, 0, wxALL, 5);
msgSizer->Add(btnError, 0, wxALL, 5);
mainSizer->Add(msgSizer, 0, wxEXPAND | wxALL, 10);
// Custom Dialog section
wxStaticBox* dlgBox = new wxStaticBox(panel, wxID_ANY, "wxDialog");
wxStaticBoxSizer* dlgSizer = new wxStaticBoxSizer(dlgBox, wxHORIZONTAL);
wxButton* btnCustom = new wxButton(panel, ID_BTN_CUSTOM_DIALOG, "Open Custom Dialog");
dlgSizer->Add(btnCustom, 0, wxALL, 5);
dlgSizer->Add(new wxStaticText(panel, wxID_ANY,
"Opens a modal dialog with OK/Cancel buttons"), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
mainSizer->Add(dlgSizer, 0, wxEXPAND | wxALL, 10);
// Timer section
wxStaticBox* timerBox = new wxStaticBox(panel, wxID_ANY, "wxTimer");
wxStaticBoxSizer* timerSizer = new wxStaticBoxSizer(timerBox, wxVERTICAL);
wxBoxSizer* timerBtnSizer = new wxBoxSizer(wxHORIZONTAL);
wxButton* btnStart = new wxButton(panel, ID_BTN_TIMER_START, "Start Timer");
wxButton* btnStop = new wxButton(panel, ID_BTN_TIMER_STOP, "Stop Timer");
timerBtnSizer->Add(btnStart, 0, wxALL, 5);
timerBtnSizer->Add(btnStop, 0, wxALL, 5);
timerSizer->Add(timerBtnSizer, 0, wxALIGN_CENTER);
m_timerLabel = new wxStaticText(panel, wxID_ANY, "Timer: 0");
wxFont font = m_timerLabel->GetFont();
font.SetPointSize(16);
m_timerLabel->SetFont(font);
timerSizer->Add(m_timerLabel, 0, wxALL | wxALIGN_CENTER, 10);
mainSizer->Add(timerSizer, 0, wxEXPAND | wxALL, 10);
// Initialize timer
m_timer = new wxTimer(this, ID_TIMER);
m_timerCount = 0;
panel->SetSizer(mainSizer);
return panel;
}
// Dialogs tab event handlers
void TestFrame::OnMsgBoxInfo(wxCommandEvent& WXUNUSED(evt))
{
LogEvent("Showing Info message box");
wxMessageBox("This is an information message.\n\nwxMessageBox is used throughout KiCad for notifications.",
"Information",
wxOK | wxICON_INFORMATION, this);
LogEvent("Info message box closed");
}
void TestFrame::OnMsgBoxYesNo(wxCommandEvent& WXUNUSED(evt))
{
LogEvent("Showing Yes/No message box");
int result = wxMessageBox("Do you want to proceed?\n\nThis tests wxYES_NO style dialogs.",
"Confirm Action",
wxYES_NO | wxICON_QUESTION, this);
LogEvent(wxString::Format("User clicked: %s", result == wxYES ? "Yes" : "No"));
}
void TestFrame::OnMsgBoxError(wxCommandEvent& WXUNUSED(evt))
{
LogEvent("Showing Error message box");
wxMessageBox("An error has occurred!\n\nThis tests wxICON_ERROR style dialogs.",
"Error",
wxOK | wxICON_ERROR, this);
LogEvent("Error message box closed");
}
void TestFrame::OnCustomDialog(wxCommandEvent& WXUNUSED(evt))
{
LogEvent("Opening custom dialog");
// Create a simple custom dialog
wxDialog dlg(this, wxID_ANY, "Custom Dialog",
wxDefaultPosition, wxSize(300, 200));
wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
sizer->Add(new wxStaticText(&dlg, wxID_ANY,
"This is a custom wxDialog.\n\n"
"KiCad uses wxDialog extensively for\n"
"property editors, settings panels, etc."),
1, wxALL | wxEXPAND, 20);
wxBoxSizer* btnSizer = new wxBoxSizer(wxHORIZONTAL);
btnSizer->Add(new wxButton(&dlg, wxID_OK, "OK"), 0, wxALL, 5);
btnSizer->Add(new wxButton(&dlg, wxID_CANCEL, "Cancel"), 0, wxALL, 5);
sizer->Add(btnSizer, 0, wxALIGN_CENTER | wxBOTTOM, 10);
dlg.SetSizer(sizer);
int result = dlg.ShowModal();
LogEvent(wxString::Format("Custom dialog closed with: %s",
result == wxID_OK ? "OK" : "Cancel"));
}
void TestFrame::OnTimerStart(wxCommandEvent& WXUNUSED(evt))
{
if (!m_timer->IsRunning()) {
m_timer->Start(1000); // 1 second interval
LogEvent("Timer started (1 second interval)");
}
}
void TestFrame::OnTimerStop(wxCommandEvent& WXUNUSED(evt))
{
if (m_timer->IsRunning()) {
m_timer->Stop();
LogEvent("Timer stopped");
}
}
void TestFrame::OnTimer(wxTimerEvent& WXUNUSED(evt))
{
m_timerCount++;
m_timerLabel->SetLabel(wxString::Format("Timer: %d", m_timerCount));
LogEvent(wxString::Format("Timer tick: %d", m_timerCount));
}
//-----------------------------------------------------------------------------
// TestApp - Application class
//-----------------------------------------------------------------------------

View file

@ -0,0 +1,143 @@
// wxAuiManager Test - Tests AUI docking functionality in WASM
// KiCad uses AUI extensively for dockable panels
#include "wx/wxprec.h"
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
#include "wx/aui/aui.h"
#ifdef __EMSCRIPTEN__
#include <emscripten/emscripten.h>
#endif
class AuiTestApp : public wxApp
{
public:
virtual bool OnInit() override;
};
class AuiTestFrame : public wxFrame
{
public:
AuiTestFrame();
~AuiTestFrame();
private:
wxAuiManager m_mgr;
wxTextCtrl* m_log;
void LogEvent(const wxString& msg);
void OnPaneClose(wxAuiManagerEvent& evt);
wxDECLARE_EVENT_TABLE();
};
wxBEGIN_EVENT_TABLE(AuiTestFrame, wxFrame)
EVT_AUI_PANE_CLOSE(AuiTestFrame::OnPaneClose)
wxEND_EVENT_TABLE()
wxIMPLEMENT_APP(AuiTestApp);
bool AuiTestApp::OnInit()
{
if (!wxApp::OnInit())
return false;
AuiTestFrame* frame = new AuiTestFrame();
frame->Show(true);
return true;
}
AuiTestFrame::AuiTestFrame()
: wxFrame(nullptr, wxID_ANY, "wxAuiManager WASM Test",
wxDefaultPosition, wxSize(800, 600))
{
m_mgr.SetManagedWindow(this);
// Create center pane with event log
m_log = new wxTextCtrl(this, wxID_ANY, "",
wxDefaultPosition, wxDefaultSize,
wxTE_MULTILINE | wxTE_READONLY);
m_mgr.AddPane(m_log, wxAuiPaneInfo().Name("log").Caption("Event Log")
.Center().CloseButton(false));
// Create left panel (like KiCad's properties panel)
wxPanel* leftPanel = new wxPanel(this);
leftPanel->SetBackgroundColour(*wxLIGHT_GREY);
wxBoxSizer* leftSizer = new wxBoxSizer(wxVERTICAL);
leftSizer->Add(new wxStaticText(leftPanel, wxID_ANY, "Properties Panel"), 0, wxALL, 10);
leftSizer->Add(new wxStaticText(leftPanel, wxID_ANY, "Like KiCad's"), 0, wxALL, 5);
leftSizer->Add(new wxStaticText(leftPanel, wxID_ANY, "property editor"), 0, wxALL, 5);
leftPanel->SetSizer(leftSizer);
m_mgr.AddPane(leftPanel, wxAuiPaneInfo().Name("properties").Caption("Properties")
.Left().Layer(1).Position(1).CloseButton(true).MaximizeButton(true)
.MinSize(150, 200));
// Create right panel (like KiCad's layer manager)
wxPanel* rightPanel = new wxPanel(this);
rightPanel->SetBackgroundColour(wxColour(240, 240, 255));
wxBoxSizer* rightSizer = new wxBoxSizer(wxVERTICAL);
rightSizer->Add(new wxStaticText(rightPanel, wxID_ANY, "Layers Panel"), 0, wxALL, 10);
rightSizer->Add(new wxStaticText(rightPanel, wxID_ANY, "Like KiCad's"), 0, wxALL, 5);
rightSizer->Add(new wxStaticText(rightPanel, wxID_ANY, "layer manager"), 0, wxALL, 5);
rightPanel->SetSizer(rightSizer);
m_mgr.AddPane(rightPanel, wxAuiPaneInfo().Name("layers").Caption("Layers")
.Right().Layer(1).Position(1).CloseButton(true).MaximizeButton(true)
.MinSize(150, 200));
// Create bottom panel (like KiCad's message panel)
wxPanel* bottomPanel = new wxPanel(this);
bottomPanel->SetBackgroundColour(wxColour(255, 255, 240));
wxBoxSizer* bottomSizer = new wxBoxSizer(wxVERTICAL);
bottomSizer->Add(new wxStaticText(bottomPanel, wxID_ANY,
"Message Panel - Like KiCad's message area"), 0, wxALL, 5);
bottomPanel->SetSizer(bottomSizer);
m_mgr.AddPane(bottomPanel, wxAuiPaneInfo().Name("messages").Caption("Messages")
.Bottom().Layer(0).Position(1).CloseButton(true)
.MinSize(-1, 80));
m_mgr.Update();
CreateStatusBar();
SetStatusText("AUI Manager ready - try dragging and docking panels");
LogEvent("AUI test app started");
LogEvent("Created dockable panels: Properties, Layers, Messages");
#ifdef __EMSCRIPTEN__
EM_ASM({
console.log('[AUI_TEST] wxAuiManager test app started successfully');
});
#endif
}
AuiTestFrame::~AuiTestFrame()
{
m_mgr.UnInit();
}
void AuiTestFrame::LogEvent(const wxString& msg)
{
m_log->AppendText(msg + "\n");
SetStatusText(msg);
#ifdef __EMSCRIPTEN__
EM_ASM({
console.log('[AUI_EVENT] ' + UTF8ToString($0));
}, msg.c_str().AsChar());
#endif
}
void AuiTestFrame::OnPaneClose(wxAuiManagerEvent& evt)
{
wxAuiPaneInfo* pane = evt.GetPane();
if (pane) {
LogEvent(wxString::Format("Pane closing: %s", pane->name));
}
}

View file

@ -0,0 +1,213 @@
// wxClipboard Test - Tests clipboard functionality in WASM
// KiCad uses clipboard for copy/paste of schematic symbols, PCB components, text
#include "wx/wxprec.h"
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
#include "wx/clipbrd.h"
#include "wx/dataobj.h"
#ifdef __EMSCRIPTEN__
#include <emscripten/emscripten.h>
#endif
class ClipboardTestApp : public wxApp
{
public:
virtual bool OnInit() override;
};
class ClipboardTestFrame : public wxFrame
{
public:
ClipboardTestFrame();
private:
wxTextCtrl* m_input;
wxTextCtrl* m_output;
wxTextCtrl* m_log;
void LogEvent(const wxString& msg);
void OnCopyText(wxCommandEvent& evt);
void OnPasteText(wxCommandEvent& evt);
void OnClearClipboard(wxCommandEvent& evt);
void OnCheckClipboard(wxCommandEvent& evt);
wxDECLARE_EVENT_TABLE();
};
enum {
ID_COPY_TEXT = wxID_HIGHEST + 1,
ID_PASTE_TEXT,
ID_CLEAR_CLIPBOARD,
ID_CHECK_CLIPBOARD
};
wxBEGIN_EVENT_TABLE(ClipboardTestFrame, wxFrame)
EVT_BUTTON(ID_COPY_TEXT, ClipboardTestFrame::OnCopyText)
EVT_BUTTON(ID_PASTE_TEXT, ClipboardTestFrame::OnPasteText)
EVT_BUTTON(ID_CLEAR_CLIPBOARD, ClipboardTestFrame::OnClearClipboard)
EVT_BUTTON(ID_CHECK_CLIPBOARD, ClipboardTestFrame::OnCheckClipboard)
wxEND_EVENT_TABLE()
wxIMPLEMENT_APP(ClipboardTestApp);
bool ClipboardTestApp::OnInit()
{
if (!wxApp::OnInit())
return false;
ClipboardTestFrame* frame = new ClipboardTestFrame();
frame->Show(true);
return true;
}
ClipboardTestFrame::ClipboardTestFrame()
: wxFrame(nullptr, wxID_ANY, "wxClipboard WASM Test",
wxDefaultPosition, wxSize(600, 500))
{
wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
// Description
wxStaticText* desc = new wxStaticText(this, wxID_ANY,
"wxClipboard Test\n\n"
"Tests clipboard operations that KiCad uses for copy/paste.\n"
"Note: Browser clipboard access may be restricted.");
mainSizer->Add(desc, 0, wxALL, 10);
// Input section
wxStaticBoxSizer* inputBox = new wxStaticBoxSizer(wxVERTICAL, this, "Text to Copy");
m_input = new wxTextCtrl(this, wxID_ANY, "Sample text for clipboard test",
wxDefaultPosition, wxSize(-1, 60), wxTE_MULTILINE);
inputBox->Add(m_input, 1, wxEXPAND | wxALL, 5);
mainSizer->Add(inputBox, 0, wxEXPAND | wxLEFT | wxRIGHT, 10);
// Buttons
wxBoxSizer* buttonSizer = new wxBoxSizer(wxHORIZONTAL);
buttonSizer->Add(new wxButton(this, ID_COPY_TEXT, "Copy to Clipboard"), 0, wxALL, 5);
buttonSizer->Add(new wxButton(this, ID_PASTE_TEXT, "Paste from Clipboard"), 0, wxALL, 5);
buttonSizer->Add(new wxButton(this, ID_CHECK_CLIPBOARD, "Check Clipboard"), 0, wxALL, 5);
buttonSizer->Add(new wxButton(this, ID_CLEAR_CLIPBOARD, "Clear Clipboard"), 0, wxALL, 5);
mainSizer->Add(buttonSizer, 0, wxALIGN_CENTER | wxALL, 10);
// Output section
wxStaticBoxSizer* outputBox = new wxStaticBoxSizer(wxVERTICAL, this, "Pasted Text");
m_output = new wxTextCtrl(this, wxID_ANY, "",
wxDefaultPosition, wxSize(-1, 60), wxTE_MULTILINE | wxTE_READONLY);
outputBox->Add(m_output, 1, wxEXPAND | wxALL, 5);
mainSizer->Add(outputBox, 0, wxEXPAND | wxLEFT | wxRIGHT, 10);
// Log section
wxStaticBoxSizer* logBox = new wxStaticBoxSizer(wxVERTICAL, this, "Event Log");
m_log = new wxTextCtrl(this, wxID_ANY, "",
wxDefaultPosition, wxSize(-1, 100), wxTE_MULTILINE | wxTE_READONLY);
logBox->Add(m_log, 1, wxEXPAND | wxALL, 5);
mainSizer->Add(logBox, 1, wxEXPAND | wxALL, 10);
SetSizer(mainSizer);
// Status bar
CreateStatusBar();
SetStatusText("Ready - Test clipboard operations");
LogEvent("Clipboard test app started");
#ifdef __EMSCRIPTEN__
EM_ASM({
console.log('[CLIPBOARD_TEST] wxClipboard test app started successfully');
});
#endif
}
void ClipboardTestFrame::LogEvent(const wxString& msg)
{
m_log->AppendText(msg + "\n");
SetStatusText(msg);
#ifdef __EMSCRIPTEN__
EM_ASM({
console.log('[CLIPBOARD_EVENT] ' + UTF8ToString($0));
}, msg.c_str().AsChar());
#endif
}
void ClipboardTestFrame::OnCopyText(wxCommandEvent& WXUNUSED(evt))
{
LogEvent("Attempting to copy text to clipboard...");
wxString text = m_input->GetValue();
if (text.IsEmpty()) {
LogEvent("ERROR: No text to copy");
return;
}
if (wxTheClipboard->Open()) {
wxTheClipboard->SetData(new wxTextDataObject(text));
wxTheClipboard->Close();
LogEvent(wxString::Format("SUCCESS: Copied %d characters to clipboard", (int)text.Length()));
} else {
LogEvent("ERROR: Could not open clipboard");
}
}
void ClipboardTestFrame::OnPasteText(wxCommandEvent& WXUNUSED(evt))
{
LogEvent("Attempting to paste from clipboard...");
if (wxTheClipboard->Open()) {
if (wxTheClipboard->IsSupported(wxDF_TEXT) ||
wxTheClipboard->IsSupported(wxDF_UNICODETEXT)) {
wxTextDataObject data;
wxTheClipboard->GetData(data);
wxString text = data.GetText();
m_output->SetValue(text);
LogEvent(wxString::Format("SUCCESS: Pasted %d characters from clipboard", (int)text.Length()));
} else {
LogEvent("WARNING: No text data in clipboard");
m_output->SetValue("");
}
wxTheClipboard->Close();
} else {
LogEvent("ERROR: Could not open clipboard");
}
}
void ClipboardTestFrame::OnClearClipboard(wxCommandEvent& WXUNUSED(evt))
{
LogEvent("Attempting to clear clipboard...");
if (wxTheClipboard->Open()) {
wxTheClipboard->Clear();
wxTheClipboard->Close();
LogEvent("SUCCESS: Clipboard cleared");
} else {
LogEvent("ERROR: Could not open clipboard");
}
}
void ClipboardTestFrame::OnCheckClipboard(wxCommandEvent& WXUNUSED(evt))
{
LogEvent("Checking clipboard contents...");
if (wxTheClipboard->Open()) {
bool hasText = wxTheClipboard->IsSupported(wxDF_TEXT) ||
wxTheClipboard->IsSupported(wxDF_UNICODETEXT);
bool hasBitmap = wxTheClipboard->IsSupported(wxDF_BITMAP);
bool hasFiles = wxTheClipboard->IsSupported(wxDF_FILENAME);
wxString status = "Clipboard contains: ";
if (hasText) status += "TEXT ";
if (hasBitmap) status += "BITMAP ";
if (hasFiles) status += "FILES ";
if (!hasText && !hasBitmap && !hasFiles) status += "(empty or unsupported format)";
LogEvent(status);
wxTheClipboard->Close();
} else {
LogEvent("ERROR: Could not open clipboard");
}
}

View file

@ -0,0 +1,225 @@
// wxDialog/wxMessageBox Test - Tests modal dialogs in WASM
// KiCad uses dialogs for alerts, confirmations, and custom dialogs
#include "wx/wxprec.h"
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
#ifdef __EMSCRIPTEN__
#include <emscripten/emscripten.h>
#endif
class DialogTestApp : public wxApp
{
public:
virtual bool OnInit() override;
};
class DialogTestFrame : public wxFrame
{
public:
DialogTestFrame();
private:
wxTextCtrl* m_log;
void LogEvent(const wxString& msg);
void OnInfoDialog(wxCommandEvent& evt);
void OnYesNoDialog(wxCommandEvent& evt);
void OnErrorDialog(wxCommandEvent& evt);
void OnCustomDialog(wxCommandEvent& evt);
void OnInputDialog(wxCommandEvent& evt);
wxDECLARE_EVENT_TABLE();
};
// Custom dialog class (like KiCad's property dialogs)
class CustomTestDialog : public wxDialog
{
public:
CustomTestDialog(wxWindow* parent);
wxString GetValue() const { return m_textCtrl->GetValue(); }
private:
wxTextCtrl* m_textCtrl;
};
enum {
ID_INFO_DIALOG = wxID_HIGHEST + 1,
ID_YESNO_DIALOG,
ID_ERROR_DIALOG,
ID_CUSTOM_DIALOG,
ID_INPUT_DIALOG
};
wxBEGIN_EVENT_TABLE(DialogTestFrame, wxFrame)
EVT_BUTTON(ID_INFO_DIALOG, DialogTestFrame::OnInfoDialog)
EVT_BUTTON(ID_YESNO_DIALOG, DialogTestFrame::OnYesNoDialog)
EVT_BUTTON(ID_ERROR_DIALOG, DialogTestFrame::OnErrorDialog)
EVT_BUTTON(ID_CUSTOM_DIALOG, DialogTestFrame::OnCustomDialog)
EVT_BUTTON(ID_INPUT_DIALOG, DialogTestFrame::OnInputDialog)
wxEND_EVENT_TABLE()
wxIMPLEMENT_APP(DialogTestApp);
bool DialogTestApp::OnInit()
{
if (!wxApp::OnInit())
return false;
DialogTestFrame* frame = new DialogTestFrame();
frame->Show(true);
return true;
}
DialogTestFrame::DialogTestFrame()
: wxFrame(nullptr, wxID_ANY, "wxDialog/wxMessageBox WASM Test",
wxDefaultPosition, wxSize(600, 500))
{
wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
wxStaticText* desc = new wxStaticText(this, wxID_ANY,
"wxDialog and wxMessageBox Test\n\n"
"KiCad uses dialogs for alerts, confirmations, and custom property dialogs.\n"
"Click buttons to test different dialog types.");
mainSizer->Add(desc, 0, wxALL, 10);
// wxMessageBox section
wxStaticBoxSizer* msgBoxSizer = new wxStaticBoxSizer(wxVERTICAL, this, "wxMessageBox");
wxBoxSizer* msgBtnSizer = new wxBoxSizer(wxHORIZONTAL);
msgBtnSizer->Add(new wxButton(this, ID_INFO_DIALOG, "Info Dialog"), 0, wxALL, 5);
msgBtnSizer->Add(new wxButton(this, ID_YESNO_DIALOG, "Yes/No Dialog"), 0, wxALL, 5);
msgBtnSizer->Add(new wxButton(this, ID_ERROR_DIALOG, "Error Dialog"), 0, wxALL, 5);
msgBoxSizer->Add(msgBtnSizer, 0, wxALIGN_CENTER);
mainSizer->Add(msgBoxSizer, 0, wxEXPAND | wxALL, 10);
// wxDialog section
wxStaticBoxSizer* dlgSizer = new wxStaticBoxSizer(wxVERTICAL, this, "wxDialog");
wxBoxSizer* dlgBtnSizer = new wxBoxSizer(wxHORIZONTAL);
dlgBtnSizer->Add(new wxButton(this, ID_CUSTOM_DIALOG, "Custom Dialog"), 0, wxALL, 5);
dlgBtnSizer->Add(new wxButton(this, ID_INPUT_DIALOG, "Input Dialog"), 0, wxALL, 5);
dlgSizer->Add(dlgBtnSizer, 0, wxALIGN_CENTER);
mainSizer->Add(dlgSizer, 0, wxEXPAND | wxALL, 10);
// Event log
wxStaticBoxSizer* logBox = new wxStaticBoxSizer(wxVERTICAL, this, "Event Log");
m_log = new wxTextCtrl(this, wxID_ANY, "",
wxDefaultPosition, wxSize(-1, 200), wxTE_MULTILINE | wxTE_READONLY);
logBox->Add(m_log, 1, wxEXPAND | wxALL, 5);
mainSizer->Add(logBox, 1, wxEXPAND | wxALL, 10);
SetSizer(mainSizer);
CreateStatusBar();
SetStatusText("Ready");
LogEvent("Dialog test app started");
#ifdef __EMSCRIPTEN__
EM_ASM({
console.log('[DIALOG_TEST] wxDialog test app started successfully');
});
#endif
}
void DialogTestFrame::LogEvent(const wxString& msg)
{
m_log->AppendText(msg + "\n");
SetStatusText(msg);
#ifdef __EMSCRIPTEN__
EM_ASM({
console.log('[DIALOG_EVENT] ' + UTF8ToString($0));
}, msg.c_str().AsChar());
#endif
}
void DialogTestFrame::OnInfoDialog(wxCommandEvent& WXUNUSED(evt))
{
LogEvent("Opening Info dialog...");
int result = wxMessageBox("This is an informational message.\n\nKiCad uses these for status updates.",
"Information", wxOK | wxICON_INFORMATION, this);
LogEvent(wxString::Format("Info dialog closed with result: %d", result));
}
void DialogTestFrame::OnYesNoDialog(wxCommandEvent& WXUNUSED(evt))
{
LogEvent("Opening Yes/No dialog...");
int result = wxMessageBox("Do you want to save changes?\n\nKiCad uses these for confirmations.",
"Confirm", wxYES_NO | wxCANCEL | wxICON_QUESTION, this);
wxString resultStr;
switch (result) {
case wxYES: resultStr = "YES"; break;
case wxNO: resultStr = "NO"; break;
case wxCANCEL: resultStr = "CANCEL"; break;
default: resultStr = wxString::Format("Unknown (%d)", result);
}
LogEvent(wxString::Format("Yes/No dialog closed with: %s", resultStr));
}
void DialogTestFrame::OnErrorDialog(wxCommandEvent& WXUNUSED(evt))
{
LogEvent("Opening Error dialog...");
int result = wxMessageBox("An error has occurred!\n\nKiCad uses these for error messages.",
"Error", wxOK | wxICON_ERROR, this);
LogEvent(wxString::Format("Error dialog closed with result: %d", result));
}
void DialogTestFrame::OnCustomDialog(wxCommandEvent& WXUNUSED(evt))
{
LogEvent("Opening Custom dialog...");
CustomTestDialog dlg(this);
int result = dlg.ShowModal();
if (result == wxID_OK) {
LogEvent(wxString::Format("Custom dialog OK - value: '%s'", dlg.GetValue()));
} else {
LogEvent("Custom dialog cancelled");
}
}
void DialogTestFrame::OnInputDialog(wxCommandEvent& WXUNUSED(evt))
{
LogEvent("Opening Input dialog...");
wxTextEntryDialog dlg(this, "Enter a component reference:",
"Input Dialog", "R1");
if (dlg.ShowModal() == wxID_OK) {
LogEvent(wxString::Format("Input dialog OK - value: '%s'", dlg.GetValue()));
} else {
LogEvent("Input dialog cancelled");
}
}
// Custom dialog implementation
CustomTestDialog::CustomTestDialog(wxWindow* parent)
: wxDialog(parent, wxID_ANY, "Custom Test Dialog",
wxDefaultPosition, wxSize(300, 200))
{
wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
wxStaticText* label = new wxStaticText(this, wxID_ANY,
"This is a custom wxDialog\nlike KiCad's property dialogs:");
mainSizer->Add(label, 0, wxALL, 10);
m_textCtrl = new wxTextCtrl(this, wxID_ANY, "Sample value");
mainSizer->Add(m_textCtrl, 0, wxEXPAND | wxLEFT | wxRIGHT, 10);
wxBoxSizer* btnSizer = new wxBoxSizer(wxHORIZONTAL);
btnSizer->Add(new wxButton(this, wxID_OK, "OK"), 0, wxALL, 5);
btnSizer->Add(new wxButton(this, wxID_CANCEL, "Cancel"), 0, wxALL, 5);
mainSizer->Add(btnSizer, 0, wxALIGN_CENTER | wxALL, 10);
SetSizer(mainSizer);
}

View file

@ -0,0 +1,162 @@
// wxFileDialog Test - Tests file dialog functionality in WASM
// KiCad uses file dialogs for opening/saving schematics, PCBs, footprints
#include "wx/wxprec.h"
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
#include "wx/filedlg.h"
#ifdef __EMSCRIPTEN__
#include <emscripten/emscripten.h>
#endif
class FileDialogTestApp : public wxApp
{
public:
virtual bool OnInit() override;
};
class FileDialogTestFrame : public wxFrame
{
public:
FileDialogTestFrame();
private:
wxTextCtrl* m_log;
void LogEvent(const wxString& msg);
void OnOpenFile(wxCommandEvent& evt);
void OnSaveFile(wxCommandEvent& evt);
void OnOpenMultiple(wxCommandEvent& evt);
wxDECLARE_EVENT_TABLE();
};
enum {
ID_OPEN_FILE = wxID_HIGHEST + 1,
ID_SAVE_FILE,
ID_OPEN_MULTIPLE
};
wxBEGIN_EVENT_TABLE(FileDialogTestFrame, wxFrame)
EVT_BUTTON(ID_OPEN_FILE, FileDialogTestFrame::OnOpenFile)
EVT_BUTTON(ID_SAVE_FILE, FileDialogTestFrame::OnSaveFile)
EVT_BUTTON(ID_OPEN_MULTIPLE, FileDialogTestFrame::OnOpenMultiple)
wxEND_EVENT_TABLE()
wxIMPLEMENT_APP(FileDialogTestApp);
bool FileDialogTestApp::OnInit()
{
if (!wxApp::OnInit())
return false;
FileDialogTestFrame* frame = new FileDialogTestFrame();
frame->Show(true);
return true;
}
FileDialogTestFrame::FileDialogTestFrame()
: wxFrame(nullptr, wxID_ANY, "wxFileDialog WASM Test",
wxDefaultPosition, wxSize(600, 400))
{
wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
wxStaticText* desc = new wxStaticText(this, wxID_ANY,
"wxFileDialog Test\n\n"
"Tests file dialog operations that KiCad uses for open/save.\n"
"Note: Browser file access is typically restricted.");
mainSizer->Add(desc, 0, wxALL, 10);
wxBoxSizer* buttonSizer = new wxBoxSizer(wxHORIZONTAL);
buttonSizer->Add(new wxButton(this, ID_OPEN_FILE, "Open File..."), 0, wxALL, 5);
buttonSizer->Add(new wxButton(this, ID_SAVE_FILE, "Save File..."), 0, wxALL, 5);
buttonSizer->Add(new wxButton(this, ID_OPEN_MULTIPLE, "Open Multiple..."), 0, wxALL, 5);
mainSizer->Add(buttonSizer, 0, wxALIGN_CENTER | wxALL, 10);
wxStaticBoxSizer* logBox = new wxStaticBoxSizer(wxVERTICAL, this, "Event Log");
m_log = new wxTextCtrl(this, wxID_ANY, "",
wxDefaultPosition, wxSize(-1, 200), wxTE_MULTILINE | wxTE_READONLY);
logBox->Add(m_log, 1, wxEXPAND | wxALL, 5);
mainSizer->Add(logBox, 1, wxEXPAND | wxALL, 10);
SetSizer(mainSizer);
CreateStatusBar();
SetStatusText("Ready");
LogEvent("FileDialog test app started");
#ifdef __EMSCRIPTEN__
EM_ASM({
console.log('[FILEDIALOG_TEST] wxFileDialog test app started successfully');
});
#endif
}
void FileDialogTestFrame::LogEvent(const wxString& msg)
{
m_log->AppendText(msg + "\n");
SetStatusText(msg);
#ifdef __EMSCRIPTEN__
EM_ASM({
console.log('[FILEDIALOG_EVENT] ' + UTF8ToString($0));
}, msg.c_str().AsChar());
#endif
}
void FileDialogTestFrame::OnOpenFile(wxCommandEvent& WXUNUSED(evt))
{
LogEvent("Opening file dialog...");
wxFileDialog openDialog(this, "Open File", "", "",
"All files (*.*)|*.*|KiCad files (*.kicad_*)|*.kicad_*",
wxFD_OPEN | wxFD_FILE_MUST_EXIST);
if (openDialog.ShowModal() == wxID_OK) {
wxString path = openDialog.GetPath();
LogEvent(wxString::Format("Selected file: %s", path));
} else {
LogEvent("Open dialog cancelled");
}
}
void FileDialogTestFrame::OnSaveFile(wxCommandEvent& WXUNUSED(evt))
{
LogEvent("Opening save dialog...");
wxFileDialog saveDialog(this, "Save File", "", "untitled.txt",
"Text files (*.txt)|*.txt|All files (*.*)|*.*",
wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
if (saveDialog.ShowModal() == wxID_OK) {
wxString path = saveDialog.GetPath();
LogEvent(wxString::Format("Save to: %s", path));
} else {
LogEvent("Save dialog cancelled");
}
}
void FileDialogTestFrame::OnOpenMultiple(wxCommandEvent& WXUNUSED(evt))
{
LogEvent("Opening multiple file dialog...");
wxFileDialog openDialog(this, "Open Multiple Files", "", "",
"All files (*.*)|*.*",
wxFD_OPEN | wxFD_MULTIPLE);
if (openDialog.ShowModal() == wxID_OK) {
wxArrayString paths;
openDialog.GetPaths(paths);
LogEvent(wxString::Format("Selected %zu files:", paths.GetCount()));
for (size_t i = 0; i < paths.GetCount(); i++) {
LogEvent(wxString::Format(" %s", paths[i]));
}
} else {
LogEvent("Multiple file dialog cancelled");
}
}

View file

@ -0,0 +1,190 @@
// Minimal wxGrid Test - Tests if wxGrid works in WASM
// This is a SEPARATE test app because wxGrid may crash the app at startup
// If this page loads successfully, wxGrid is working!
#include "wx/wxprec.h"
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
#include "wx/grid.h"
#ifdef __EMSCRIPTEN__
#include <emscripten/emscripten.h>
#endif
class GridTestApp : public wxApp
{
public:
virtual bool OnInit() override;
};
class GridTestFrame : public wxFrame
{
public:
GridTestFrame();
private:
wxGrid* m_grid;
wxTextCtrl* m_log;
void LogEvent(const wxString& msg);
// Grid event handlers
void OnGridCellSelect(wxGridEvent& evt);
void OnGridCellChange(wxGridEvent& evt);
void OnGridLabelClick(wxGridEvent& evt);
wxDECLARE_EVENT_TABLE();
};
enum {
ID_GRID = wxID_HIGHEST + 1,
ID_LOG
};
wxBEGIN_EVENT_TABLE(GridTestFrame, wxFrame)
EVT_GRID_SELECT_CELL(GridTestFrame::OnGridCellSelect)
EVT_GRID_CELL_CHANGED(GridTestFrame::OnGridCellChange)
EVT_GRID_LABEL_LEFT_CLICK(GridTestFrame::OnGridLabelClick)
wxEND_EVENT_TABLE()
wxIMPLEMENT_APP(GridTestApp);
bool GridTestApp::OnInit()
{
if (!wxApp::OnInit())
return false;
GridTestFrame* frame = new GridTestFrame();
frame->Show(true);
return true;
}
GridTestFrame::GridTestFrame()
: wxFrame(nullptr, wxID_ANY, "wxGrid WASM Test",
wxDefaultPosition, wxSize(600, 500))
{
wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
// Status message
wxStaticText* status = new wxStaticText(this, wxID_ANY,
"SUCCESS: wxGrid initialized! If you see this, wxGrid is working in WASM.");
status->SetForegroundColour(*wxGREEN);
mainSizer->Add(status, 0, wxALL, 10);
// Create wxGrid - THIS IS THE CRITICAL TEST
// If wxGrid doesn't work in WASM, the app will crash HERE
m_grid = new wxGrid(this, ID_GRID, wxDefaultPosition, wxSize(500, 200));
// Setup grid with sample data (like KiCad's property grids)
m_grid->CreateGrid(5, 4);
// Set column labels (similar to KiCad's property dialogs)
m_grid->SetColLabelValue(0, "Property");
m_grid->SetColLabelValue(1, "Value");
m_grid->SetColLabelValue(2, "Units");
m_grid->SetColLabelValue(3, "Description");
// Set column widths
m_grid->SetColSize(0, 100);
m_grid->SetColSize(1, 80);
m_grid->SetColSize(2, 50);
m_grid->SetColSize(3, 150);
// Fill with sample data (like KiCad track/via properties)
m_grid->SetCellValue(0, 0, "Track Width");
m_grid->SetCellValue(0, 1, "0.25");
m_grid->SetCellValue(0, 2, "mm");
m_grid->SetCellValue(0, 3, "Default track width");
m_grid->SetCellValue(1, 0, "Via Size");
m_grid->SetCellValue(1, 1, "0.80");
m_grid->SetCellValue(1, 2, "mm");
m_grid->SetCellValue(1, 3, "Via outer diameter");
m_grid->SetCellValue(2, 0, "Via Drill");
m_grid->SetCellValue(2, 1, "0.40");
m_grid->SetCellValue(2, 2, "mm");
m_grid->SetCellValue(2, 3, "Via drill diameter");
m_grid->SetCellValue(3, 0, "Clearance");
m_grid->SetCellValue(3, 1, "0.20");
m_grid->SetCellValue(3, 2, "mm");
m_grid->SetCellValue(3, 3, "Min clearance");
m_grid->SetCellValue(4, 0, "Net Class");
m_grid->SetCellValue(4, 1, "Default");
m_grid->SetCellValue(4, 2, "-");
m_grid->SetCellValue(4, 3, "Net class name");
// Make first column read-only (like property names in KiCad)
for (int row = 0; row < 5; row++) {
m_grid->SetReadOnly(row, 0);
m_grid->SetReadOnly(row, 2);
m_grid->SetReadOnly(row, 3);
}
mainSizer->Add(m_grid, 1, wxEXPAND | wxALL, 10);
// Event log
wxStaticBox* logBox = new wxStaticBox(this, wxID_ANY, "Event Log");
wxStaticBoxSizer* logSizer = new wxStaticBoxSizer(logBox, wxVERTICAL);
m_log = new wxTextCtrl(this, ID_LOG, "", wxDefaultPosition, wxSize(-1, 100),
wxTE_MULTILINE | wxTE_READONLY);
logSizer->Add(m_log, 1, wxEXPAND | wxALL, 5);
mainSizer->Add(logSizer, 0, wxEXPAND | wxALL, 10);
SetSizer(mainSizer);
LogEvent("wxGrid initialized successfully!");
LogEvent("Try clicking cells, editing values, etc.");
#ifdef __EMSCRIPTEN__
EM_ASM({
console.log('[GRID_TEST] wxGrid test app started successfully!');
console.log('[GRID_TEST] If you see this message, wxGrid is working in WASM!');
});
#endif
}
void GridTestFrame::LogEvent(const wxString& msg)
{
m_log->AppendText(msg + "\n");
#ifdef __EMSCRIPTEN__
EM_ASM({
console.log('[GRID_EVENT] ' + UTF8ToString($0));
}, msg.c_str().AsChar());
#endif
}
void GridTestFrame::OnGridCellSelect(wxGridEvent& evt)
{
LogEvent(wxString::Format("Cell selected: row=%d, col=%d, value='%s'",
evt.GetRow(), evt.GetCol(),
m_grid->GetCellValue(evt.GetRow(), evt.GetCol())));
evt.Skip();
}
void GridTestFrame::OnGridCellChange(wxGridEvent& evt)
{
LogEvent(wxString::Format("Cell changed: row=%d, col=%d, new value='%s'",
evt.GetRow(), evt.GetCol(),
m_grid->GetCellValue(evt.GetRow(), evt.GetCol())));
evt.Skip();
}
void GridTestFrame::OnGridLabelClick(wxGridEvent& evt)
{
if (evt.GetRow() >= 0) {
LogEvent(wxString::Format("Row label clicked: row=%d", evt.GetRow()));
} else if (evt.GetCol() >= 0) {
LogEvent(wxString::Format("Column label clicked: col=%d ('%s')",
evt.GetCol(), m_grid->GetColLabelValue(evt.GetCol())));
}
evt.Skip();
}

View file

@ -0,0 +1,142 @@
// Layout Test - Tests wxSplitterWindow and wxScrolledWindow in WASM
// KiCad uses splitters and scrolled windows extensively
#include "wx/wxprec.h"
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
#include "wx/splitter.h"
#include "wx/scrolwin.h"
#ifdef __EMSCRIPTEN__
#include <emscripten/emscripten.h>
#endif
class LayoutTestApp : public wxApp
{
public:
virtual bool OnInit() override;
};
class LayoutTestFrame : public wxFrame
{
public:
LayoutTestFrame();
private:
wxSplitterWindow* m_splitter;
wxScrolledWindow* m_scrollLeft;
wxScrolledWindow* m_scrollRight;
wxTextCtrl* m_log;
void LogEvent(const wxString& msg);
void OnSplitterSashPosChanged(wxSplitterEvent& evt);
void OnScrollWin(wxScrollWinEvent& evt);
wxDECLARE_EVENT_TABLE();
};
wxBEGIN_EVENT_TABLE(LayoutTestFrame, wxFrame)
EVT_SPLITTER_SASH_POS_CHANGED(wxID_ANY, LayoutTestFrame::OnSplitterSashPosChanged)
wxEND_EVENT_TABLE()
wxIMPLEMENT_APP(LayoutTestApp);
bool LayoutTestApp::OnInit()
{
if (!wxApp::OnInit())
return false;
LayoutTestFrame* frame = new LayoutTestFrame();
frame->Show(true);
return true;
}
LayoutTestFrame::LayoutTestFrame()
: wxFrame(nullptr, wxID_ANY, "wxSplitter/wxScrolled WASM Test",
wxDefaultPosition, wxSize(800, 600))
{
wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
wxStaticText* desc = new wxStaticText(this, wxID_ANY,
"wxSplitterWindow and wxScrolledWindow Test - KiCad layout controls");
mainSizer->Add(desc, 0, wxALL, 5);
// Create splitter
m_splitter = new wxSplitterWindow(this, wxID_ANY, wxDefaultPosition,
wxDefaultSize, wxSP_3D | wxSP_LIVE_UPDATE);
// Left scrolled window
m_scrollLeft = new wxScrolledWindow(m_splitter, wxID_ANY);
m_scrollLeft->SetBackgroundColour(*wxLIGHT_GREY);
m_scrollLeft->SetScrollbars(10, 10, 100, 100);
wxBoxSizer* leftSizer = new wxBoxSizer(wxVERTICAL);
for (int i = 0; i < 20; i++) {
leftSizer->Add(new wxStaticText(m_scrollLeft, wxID_ANY,
wxString::Format("Left Item %d", i+1)), 0, wxALL, 5);
}
m_scrollLeft->SetSizer(leftSizer);
// Right scrolled window
m_scrollRight = new wxScrolledWindow(m_splitter, wxID_ANY);
m_scrollRight->SetBackgroundColour(*wxWHITE);
m_scrollRight->SetScrollbars(10, 10, 100, 100);
wxBoxSizer* rightSizer = new wxBoxSizer(wxVERTICAL);
for (int i = 0; i < 20; i++) {
rightSizer->Add(new wxStaticText(m_scrollRight, wxID_ANY,
wxString::Format("Right Item %d", i+1)), 0, wxALL, 5);
}
m_scrollRight->SetSizer(rightSizer);
m_splitter->SplitVertically(m_scrollLeft, m_scrollRight, 300);
m_splitter->SetMinimumPaneSize(100);
mainSizer->Add(m_splitter, 1, wxEXPAND | wxALL, 5);
// Event log
wxStaticBoxSizer* logBox = new wxStaticBoxSizer(wxVERTICAL, this, "Event Log");
m_log = new wxTextCtrl(this, wxID_ANY, "",
wxDefaultPosition, wxSize(-1, 100), wxTE_MULTILINE | wxTE_READONLY);
logBox->Add(m_log, 1, wxEXPAND | wxALL, 5);
mainSizer->Add(logBox, 0, wxEXPAND | wxALL, 5);
SetSizer(mainSizer);
CreateStatusBar();
SetStatusText("Drag splitter sash or scroll the panes");
LogEvent("Layout test app started");
LogEvent("Splitter position: 300");
#ifdef __EMSCRIPTEN__
EM_ASM({
console.log('[LAYOUT_TEST] wxSplitter/wxScrolled test app started successfully');
});
#endif
}
void LayoutTestFrame::LogEvent(const wxString& msg)
{
m_log->AppendText(msg + "\n");
SetStatusText(msg);
#ifdef __EMSCRIPTEN__
EM_ASM({
console.log('[LAYOUT_EVENT] ' + UTF8ToString($0));
}, msg.c_str().AsChar());
#endif
}
void LayoutTestFrame::OnSplitterSashPosChanged(wxSplitterEvent& evt)
{
LogEvent(wxString::Format("Splitter sash moved to: %d", evt.GetSashPosition()));
}
void LayoutTestFrame::OnScrollWin(wxScrollWinEvent& evt)
{
LogEvent("Scroll event");
evt.Skip();
}

View file

@ -0,0 +1,300 @@
// wxMenuBar Test - Tests menu functionality in WASM
// KiCad uses extensive menus for File, Edit, View, Place, Route, etc.
#include "wx/wxprec.h"
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
#ifdef __EMSCRIPTEN__
#include <emscripten/emscripten.h>
#endif
class MenuTestApp : public wxApp
{
public:
virtual bool OnInit() override;
};
class MenuTestFrame : public wxFrame
{
public:
MenuTestFrame();
private:
wxTextCtrl* m_log;
void LogEvent(const wxString& msg);
// Menu event handlers
void OnMenuNew(wxCommandEvent& evt);
void OnMenuOpen(wxCommandEvent& evt);
void OnMenuSave(wxCommandEvent& evt);
void OnMenuSaveAs(wxCommandEvent& evt);
void OnMenuExit(wxCommandEvent& evt);
void OnMenuUndo(wxCommandEvent& evt);
void OnMenuRedo(wxCommandEvent& evt);
void OnMenuCut(wxCommandEvent& evt);
void OnMenuCopy(wxCommandEvent& evt);
void OnMenuPaste(wxCommandEvent& evt);
void OnMenuSelectAll(wxCommandEvent& evt);
void OnMenuZoomIn(wxCommandEvent& evt);
void OnMenuZoomOut(wxCommandEvent& evt);
void OnMenuZoomFit(wxCommandEvent& evt);
void OnMenuFullScreen(wxCommandEvent& evt);
void OnMenuPreferences(wxCommandEvent& evt);
void OnMenuAbout(wxCommandEvent& evt);
void OnMenuHelp(wxCommandEvent& evt);
wxDECLARE_EVENT_TABLE();
};
enum {
ID_NEW = wxID_HIGHEST + 1,
ID_OPEN,
ID_SAVE,
ID_SAVE_AS,
ID_UNDO,
ID_REDO,
ID_CUT,
ID_COPY,
ID_PASTE,
ID_SELECT_ALL,
ID_ZOOM_IN,
ID_ZOOM_OUT,
ID_ZOOM_FIT,
ID_FULLSCREEN,
ID_PREFERENCES,
ID_HELP_CONTENTS
};
wxBEGIN_EVENT_TABLE(MenuTestFrame, wxFrame)
EVT_MENU(ID_NEW, MenuTestFrame::OnMenuNew)
EVT_MENU(ID_OPEN, MenuTestFrame::OnMenuOpen)
EVT_MENU(ID_SAVE, MenuTestFrame::OnMenuSave)
EVT_MENU(ID_SAVE_AS, MenuTestFrame::OnMenuSaveAs)
EVT_MENU(wxID_EXIT, MenuTestFrame::OnMenuExit)
EVT_MENU(ID_UNDO, MenuTestFrame::OnMenuUndo)
EVT_MENU(ID_REDO, MenuTestFrame::OnMenuRedo)
EVT_MENU(ID_CUT, MenuTestFrame::OnMenuCut)
EVT_MENU(ID_COPY, MenuTestFrame::OnMenuCopy)
EVT_MENU(ID_PASTE, MenuTestFrame::OnMenuPaste)
EVT_MENU(ID_SELECT_ALL, MenuTestFrame::OnMenuSelectAll)
EVT_MENU(ID_ZOOM_IN, MenuTestFrame::OnMenuZoomIn)
EVT_MENU(ID_ZOOM_OUT, MenuTestFrame::OnMenuZoomOut)
EVT_MENU(ID_ZOOM_FIT, MenuTestFrame::OnMenuZoomFit)
EVT_MENU(ID_FULLSCREEN, MenuTestFrame::OnMenuFullScreen)
EVT_MENU(ID_PREFERENCES, MenuTestFrame::OnMenuPreferences)
EVT_MENU(wxID_ABOUT, MenuTestFrame::OnMenuAbout)
EVT_MENU(ID_HELP_CONTENTS, MenuTestFrame::OnMenuHelp)
wxEND_EVENT_TABLE()
wxIMPLEMENT_APP(MenuTestApp);
bool MenuTestApp::OnInit()
{
if (!wxApp::OnInit())
return false;
MenuTestFrame* frame = new MenuTestFrame();
frame->Show(true);
return true;
}
MenuTestFrame::MenuTestFrame()
: wxFrame(nullptr, wxID_ANY, "wxMenuBar WASM Test",
wxDefaultPosition, wxSize(600, 400))
{
// Create File menu
wxMenu* menuFile = new wxMenu;
menuFile->Append(ID_NEW, "&New\tCtrl+N", "Create a new file");
menuFile->Append(ID_OPEN, "&Open...\tCtrl+O", "Open an existing file");
menuFile->AppendSeparator();
menuFile->Append(ID_SAVE, "&Save\tCtrl+S", "Save the current file");
menuFile->Append(ID_SAVE_AS, "Save &As...\tCtrl+Shift+S", "Save with a new name");
menuFile->AppendSeparator();
menuFile->Append(wxID_EXIT, "E&xit\tAlt+F4", "Exit the application");
// Create Edit menu
wxMenu* menuEdit = new wxMenu;
menuEdit->Append(ID_UNDO, "&Undo\tCtrl+Z", "Undo the last action");
menuEdit->Append(ID_REDO, "&Redo\tCtrl+Y", "Redo the last undone action");
menuEdit->AppendSeparator();
menuEdit->Append(ID_CUT, "Cu&t\tCtrl+X", "Cut selection to clipboard");
menuEdit->Append(ID_COPY, "&Copy\tCtrl+C", "Copy selection to clipboard");
menuEdit->Append(ID_PASTE, "&Paste\tCtrl+V", "Paste from clipboard");
menuEdit->AppendSeparator();
menuEdit->Append(ID_SELECT_ALL, "Select &All\tCtrl+A", "Select all");
// Create View menu
wxMenu* menuView = new wxMenu;
menuView->Append(ID_ZOOM_IN, "Zoom &In\tCtrl++", "Zoom in");
menuView->Append(ID_ZOOM_OUT, "Zoom &Out\tCtrl+-", "Zoom out");
menuView->Append(ID_ZOOM_FIT, "Zoom to &Fit\tCtrl+0", "Fit view to window");
menuView->AppendSeparator();
menuView->AppendCheckItem(ID_FULLSCREEN, "&Full Screen\tF11", "Toggle full screen mode");
// Create Tools menu (like KiCad's preferences)
wxMenu* menuTools = new wxMenu;
menuTools->Append(ID_PREFERENCES, "&Preferences...", "Open preferences dialog");
// Create Help menu
wxMenu* menuHelp = new wxMenu;
menuHelp->Append(ID_HELP_CONTENTS, "&Help Contents\tF1", "Show help");
menuHelp->AppendSeparator();
menuHelp->Append(wxID_ABOUT, "&About...", "About this application");
// Create menu bar
wxMenuBar* menuBar = new wxMenuBar;
menuBar->Append(menuFile, "&File");
menuBar->Append(menuEdit, "&Edit");
menuBar->Append(menuView, "&View");
menuBar->Append(menuTools, "&Tools");
menuBar->Append(menuHelp, "&Help");
SetMenuBar(menuBar);
// Create main content - NO GL canvas
wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
wxStaticText* desc = new wxStaticText(this, wxID_ANY,
"wxMenuBar Test\n\n"
"This tests the menu system which KiCad uses extensively.\n"
"Click menu items to see events logged below.");
sizer->Add(desc, 0, wxALL, 10);
m_log = new wxTextCtrl(this, wxID_ANY, "", wxDefaultPosition, wxSize(-1, 200),
wxTE_MULTILINE | wxTE_READONLY);
sizer->Add(m_log, 1, wxEXPAND | wxALL, 10);
SetSizer(sizer);
// Create status bar
CreateStatusBar(2);
SetStatusText("Ready");
SetStatusText("Menu test", 1);
LogEvent("Menu test app started");
LogEvent("Menu bar created with File, Edit, View, Tools, Help menus");
#ifdef __EMSCRIPTEN__
EM_ASM({
console.log('[MENU_TEST] wxMenuBar test app started successfully');
});
#endif
}
void MenuTestFrame::LogEvent(const wxString& msg)
{
m_log->AppendText(msg + "\n");
SetStatusText(msg);
#ifdef __EMSCRIPTEN__
EM_ASM({
console.log('[MENU_EVENT] ' + UTF8ToString($0));
}, msg.c_str().AsChar());
#endif
}
// File menu handlers
void MenuTestFrame::OnMenuNew(wxCommandEvent& WXUNUSED(evt))
{
LogEvent("File > New clicked");
}
void MenuTestFrame::OnMenuOpen(wxCommandEvent& WXUNUSED(evt))
{
LogEvent("File > Open clicked");
}
void MenuTestFrame::OnMenuSave(wxCommandEvent& WXUNUSED(evt))
{
LogEvent("File > Save clicked");
}
void MenuTestFrame::OnMenuSaveAs(wxCommandEvent& WXUNUSED(evt))
{
LogEvent("File > Save As clicked");
}
void MenuTestFrame::OnMenuExit(wxCommandEvent& WXUNUSED(evt))
{
LogEvent("File > Exit clicked");
Close(true);
}
// Edit menu handlers
void MenuTestFrame::OnMenuUndo(wxCommandEvent& WXUNUSED(evt))
{
LogEvent("Edit > Undo clicked");
}
void MenuTestFrame::OnMenuRedo(wxCommandEvent& WXUNUSED(evt))
{
LogEvent("Edit > Redo clicked");
}
void MenuTestFrame::OnMenuCut(wxCommandEvent& WXUNUSED(evt))
{
LogEvent("Edit > Cut clicked");
}
void MenuTestFrame::OnMenuCopy(wxCommandEvent& WXUNUSED(evt))
{
LogEvent("Edit > Copy clicked");
}
void MenuTestFrame::OnMenuPaste(wxCommandEvent& WXUNUSED(evt))
{
LogEvent("Edit > Paste clicked");
}
void MenuTestFrame::OnMenuSelectAll(wxCommandEvent& WXUNUSED(evt))
{
LogEvent("Edit > Select All clicked");
}
// View menu handlers
void MenuTestFrame::OnMenuZoomIn(wxCommandEvent& WXUNUSED(evt))
{
LogEvent("View > Zoom In clicked");
}
void MenuTestFrame::OnMenuZoomOut(wxCommandEvent& WXUNUSED(evt))
{
LogEvent("View > Zoom Out clicked");
}
void MenuTestFrame::OnMenuZoomFit(wxCommandEvent& WXUNUSED(evt))
{
LogEvent("View > Zoom to Fit clicked");
}
void MenuTestFrame::OnMenuFullScreen(wxCommandEvent& evt)
{
bool isFullScreen = evt.IsChecked();
LogEvent(wxString::Format("View > Full Screen toggled: %s",
isFullScreen ? "ON" : "OFF"));
ShowFullScreen(isFullScreen);
}
// Tools menu handlers
void MenuTestFrame::OnMenuPreferences(wxCommandEvent& WXUNUSED(evt))
{
LogEvent("Tools > Preferences clicked");
}
// Help menu handlers
void MenuTestFrame::OnMenuAbout(wxCommandEvent& WXUNUSED(evt))
{
LogEvent("Help > About clicked");
}
void MenuTestFrame::OnMenuHelp(wxCommandEvent& WXUNUSED(evt))
{
LogEvent("Help > Help Contents clicked");
}

View file

@ -0,0 +1,235 @@
// wxTimer Test - Tests timer functionality in WASM
// KiCad uses timers for animations, auto-save, and periodic updates
#include "wx/wxprec.h"
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
#include "wx/timer.h"
#ifdef __EMSCRIPTEN__
#include <emscripten/emscripten.h>
#endif
class TimerTestApp : public wxApp
{
public:
virtual bool OnInit() override;
};
class TimerTestFrame : public wxFrame
{
public:
TimerTestFrame();
~TimerTestFrame();
private:
wxTimer* m_timer;
wxTimer* m_fastTimer;
int m_counter;
int m_fastCounter;
wxStaticText* m_counterDisplay;
wxStaticText* m_fastCounterDisplay;
wxGauge* m_progressGauge;
wxTextCtrl* m_log;
void LogEvent(const wxString& msg);
void OnStartTimer(wxCommandEvent& evt);
void OnStopTimer(wxCommandEvent& evt);
void OnStartFastTimer(wxCommandEvent& evt);
void OnStopFastTimer(wxCommandEvent& evt);
void OnResetCounters(wxCommandEvent& evt);
void OnTimer(wxTimerEvent& evt);
void OnFastTimer(wxTimerEvent& evt);
wxDECLARE_EVENT_TABLE();
};
enum {
ID_START_TIMER = wxID_HIGHEST + 1,
ID_STOP_TIMER,
ID_START_FAST_TIMER,
ID_STOP_FAST_TIMER,
ID_RESET_COUNTERS,
ID_TIMER,
ID_FAST_TIMER
};
wxBEGIN_EVENT_TABLE(TimerTestFrame, wxFrame)
EVT_BUTTON(ID_START_TIMER, TimerTestFrame::OnStartTimer)
EVT_BUTTON(ID_STOP_TIMER, TimerTestFrame::OnStopTimer)
EVT_BUTTON(ID_START_FAST_TIMER, TimerTestFrame::OnStartFastTimer)
EVT_BUTTON(ID_STOP_FAST_TIMER, TimerTestFrame::OnStopFastTimer)
EVT_BUTTON(ID_RESET_COUNTERS, TimerTestFrame::OnResetCounters)
EVT_TIMER(ID_TIMER, TimerTestFrame::OnTimer)
EVT_TIMER(ID_FAST_TIMER, TimerTestFrame::OnFastTimer)
wxEND_EVENT_TABLE()
wxIMPLEMENT_APP(TimerTestApp);
bool TimerTestApp::OnInit()
{
if (!wxApp::OnInit())
return false;
TimerTestFrame* frame = new TimerTestFrame();
frame->Show(true);
return true;
}
TimerTestFrame::TimerTestFrame()
: wxFrame(nullptr, wxID_ANY, "wxTimer WASM Test",
wxDefaultPosition, wxSize(600, 550))
, m_counter(0)
, m_fastCounter(0)
{
m_timer = new wxTimer(this, ID_TIMER);
m_fastTimer = new wxTimer(this, ID_FAST_TIMER);
wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
wxStaticText* desc = new wxStaticText(this, wxID_ANY,
"wxTimer Test\n\n"
"KiCad uses timers for auto-save, animations, and periodic updates.\n"
"Test both slow (1 sec) and fast (100ms) timers.");
mainSizer->Add(desc, 0, wxALL, 10);
// Slow timer section (1 second interval)
wxStaticBoxSizer* timerBox = new wxStaticBoxSizer(wxVERTICAL, this, "Slow Timer (1 second)");
wxBoxSizer* timerBtnSizer = new wxBoxSizer(wxHORIZONTAL);
timerBtnSizer->Add(new wxButton(this, ID_START_TIMER, "Start"), 0, wxALL, 5);
timerBtnSizer->Add(new wxButton(this, ID_STOP_TIMER, "Stop"), 0, wxALL, 5);
timerBox->Add(timerBtnSizer, 0, wxALIGN_CENTER);
m_counterDisplay = new wxStaticText(this, wxID_ANY, "Counter: 0",
wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER);
m_counterDisplay->SetFont(m_counterDisplay->GetFont().Scale(2.0));
timerBox->Add(m_counterDisplay, 0, wxALIGN_CENTER | wxALL, 10);
mainSizer->Add(timerBox, 0, wxEXPAND | wxALL, 10);
// Fast timer section (100ms interval)
wxStaticBoxSizer* fastTimerBox = new wxStaticBoxSizer(wxVERTICAL, this, "Fast Timer (100ms)");
wxBoxSizer* fastBtnSizer = new wxBoxSizer(wxHORIZONTAL);
fastBtnSizer->Add(new wxButton(this, ID_START_FAST_TIMER, "Start Fast"), 0, wxALL, 5);
fastBtnSizer->Add(new wxButton(this, ID_STOP_FAST_TIMER, "Stop Fast"), 0, wxALL, 5);
fastTimerBox->Add(fastBtnSizer, 0, wxALIGN_CENTER);
m_fastCounterDisplay = new wxStaticText(this, wxID_ANY, "Fast Counter: 0");
fastTimerBox->Add(m_fastCounterDisplay, 0, wxALIGN_CENTER | wxALL, 5);
m_progressGauge = new wxGauge(this, wxID_ANY, 100);
fastTimerBox->Add(m_progressGauge, 0, wxEXPAND | wxALL, 5);
mainSizer->Add(fastTimerBox, 0, wxEXPAND | wxALL, 10);
// Reset button
mainSizer->Add(new wxButton(this, ID_RESET_COUNTERS, "Reset All Counters"),
0, wxALIGN_CENTER | wxALL, 5);
// Event log
wxStaticBoxSizer* logBox = new wxStaticBoxSizer(wxVERTICAL, this, "Event Log");
m_log = new wxTextCtrl(this, wxID_ANY, "",
wxDefaultPosition, wxSize(-1, 120), wxTE_MULTILINE | wxTE_READONLY);
logBox->Add(m_log, 1, wxEXPAND | wxALL, 5);
mainSizer->Add(logBox, 1, wxEXPAND | wxALL, 10);
SetSizer(mainSizer);
CreateStatusBar();
SetStatusText("Ready");
LogEvent("Timer test app started");
#ifdef __EMSCRIPTEN__
EM_ASM({
console.log('[TIMER_TEST] wxTimer test app started successfully');
});
#endif
}
TimerTestFrame::~TimerTestFrame()
{
m_timer->Stop();
m_fastTimer->Stop();
delete m_timer;
delete m_fastTimer;
}
void TimerTestFrame::LogEvent(const wxString& msg)
{
m_log->AppendText(msg + "\n");
SetStatusText(msg);
#ifdef __EMSCRIPTEN__
EM_ASM({
console.log('[TIMER_EVENT] ' + UTF8ToString($0));
}, msg.c_str().AsChar());
#endif
}
void TimerTestFrame::OnStartTimer(wxCommandEvent& WXUNUSED(evt))
{
m_timer->Start(1000); // 1 second
LogEvent("Slow timer started (1 second interval)");
}
void TimerTestFrame::OnStopTimer(wxCommandEvent& WXUNUSED(evt))
{
m_timer->Stop();
LogEvent("Slow timer stopped");
}
void TimerTestFrame::OnStartFastTimer(wxCommandEvent& WXUNUSED(evt))
{
m_fastTimer->Start(100); // 100ms
LogEvent("Fast timer started (100ms interval)");
}
void TimerTestFrame::OnStopFastTimer(wxCommandEvent& WXUNUSED(evt))
{
m_fastTimer->Stop();
LogEvent("Fast timer stopped");
}
void TimerTestFrame::OnResetCounters(wxCommandEvent& WXUNUSED(evt))
{
m_counter = 0;
m_fastCounter = 0;
m_counterDisplay->SetLabel("Counter: 0");
m_fastCounterDisplay->SetLabel("Fast Counter: 0");
m_progressGauge->SetValue(0);
LogEvent("Counters reset");
}
void TimerTestFrame::OnTimer(wxTimerEvent& WXUNUSED(evt))
{
m_counter++;
m_counterDisplay->SetLabel(wxString::Format("Counter: %d", m_counter));
#ifdef __EMSCRIPTEN__
EM_ASM({
console.log('[TIMER_TICK] Slow timer tick: ' + $0);
}, m_counter);
#endif
}
void TimerTestFrame::OnFastTimer(wxTimerEvent& WXUNUSED(evt))
{
m_fastCounter++;
m_fastCounterDisplay->SetLabel(wxString::Format("Fast Counter: %d", m_fastCounter));
m_progressGauge->SetValue(m_fastCounter % 101);
// Log every 10 ticks to avoid flooding
if (m_fastCounter % 10 == 0) {
#ifdef __EMSCRIPTEN__
EM_ASM({
console.log('[TIMER_TICK] Fast timer tick: ' + $0);
}, m_fastCounter);
#endif
}
}

View file

@ -0,0 +1,188 @@
// wxToolBar/wxStatusBar Test - Tests toolbar and statusbar in WASM
// KiCad uses toolbars extensively for actions
#include "wx/wxprec.h"
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
#include "wx/artprov.h"
#ifdef __EMSCRIPTEN__
#include <emscripten/emscripten.h>
#endif
class ToolbarTestApp : public wxApp
{
public:
virtual bool OnInit() override;
};
class ToolbarTestFrame : public wxFrame
{
public:
ToolbarTestFrame();
private:
wxTextCtrl* m_log;
void LogEvent(const wxString& msg);
void OnToolNew(wxCommandEvent& evt);
void OnToolOpen(wxCommandEvent& evt);
void OnToolSave(wxCommandEvent& evt);
void OnToolZoomIn(wxCommandEvent& evt);
void OnToolZoomOut(wxCommandEvent& evt);
void OnToolToggle(wxCommandEvent& evt);
wxDECLARE_EVENT_TABLE();
};
enum {
ID_TOOL_NEW = wxID_HIGHEST + 1,
ID_TOOL_OPEN,
ID_TOOL_SAVE,
ID_TOOL_ZOOM_IN,
ID_TOOL_ZOOM_OUT,
ID_TOOL_TOGGLE
};
wxBEGIN_EVENT_TABLE(ToolbarTestFrame, wxFrame)
EVT_TOOL(ID_TOOL_NEW, ToolbarTestFrame::OnToolNew)
EVT_TOOL(ID_TOOL_OPEN, ToolbarTestFrame::OnToolOpen)
EVT_TOOL(ID_TOOL_SAVE, ToolbarTestFrame::OnToolSave)
EVT_TOOL(ID_TOOL_ZOOM_IN, ToolbarTestFrame::OnToolZoomIn)
EVT_TOOL(ID_TOOL_ZOOM_OUT, ToolbarTestFrame::OnToolZoomOut)
EVT_TOOL(ID_TOOL_TOGGLE, ToolbarTestFrame::OnToolToggle)
wxEND_EVENT_TABLE()
wxIMPLEMENT_APP(ToolbarTestApp);
bool ToolbarTestApp::OnInit()
{
if (!wxApp::OnInit())
return false;
ToolbarTestFrame* frame = new ToolbarTestFrame();
frame->Show(true);
return true;
}
ToolbarTestFrame::ToolbarTestFrame()
: wxFrame(nullptr, wxID_ANY, "wxToolBar/wxStatusBar WASM Test",
wxDefaultPosition, wxSize(700, 500))
{
// Create toolbar
wxToolBar* toolbar = CreateToolBar(wxTB_HORIZONTAL | wxTB_TEXT);
toolbar->AddTool(ID_TOOL_NEW, "New",
wxArtProvider::GetBitmap(wxART_NEW, wxART_TOOLBAR),
"Create new file");
toolbar->AddTool(ID_TOOL_OPEN, "Open",
wxArtProvider::GetBitmap(wxART_FILE_OPEN, wxART_TOOLBAR),
"Open existing file");
toolbar->AddTool(ID_TOOL_SAVE, "Save",
wxArtProvider::GetBitmap(wxART_FILE_SAVE, wxART_TOOLBAR),
"Save current file");
toolbar->AddSeparator();
toolbar->AddTool(ID_TOOL_ZOOM_IN, "Zoom In",
wxArtProvider::GetBitmap(wxART_PLUS, wxART_TOOLBAR),
"Zoom in");
toolbar->AddTool(ID_TOOL_ZOOM_OUT, "Zoom Out",
wxArtProvider::GetBitmap(wxART_MINUS, wxART_TOOLBAR),
"Zoom out");
toolbar->AddSeparator();
toolbar->AddCheckTool(ID_TOOL_TOGGLE, "Toggle",
wxArtProvider::GetBitmap(wxART_TICK_MARK, wxART_TOOLBAR),
wxNullBitmap,
"Toggle tool example");
toolbar->Realize();
// Create status bar with multiple fields
CreateStatusBar(3);
SetStatusText("Ready", 0);
SetStatusText("X: 0, Y: 0", 1);
SetStatusText("Zoom: 100%", 2);
// Set status bar field widths
int widths[] = {-1, 150, 100};
GetStatusBar()->SetStatusWidths(3, widths);
// Main content
wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
wxStaticText* desc = new wxStaticText(this, wxID_ANY,
"wxToolBar and wxStatusBar Test\n\n"
"KiCad uses toolbars for quick access to tools.\n"
"Click toolbar buttons to see events.");
mainSizer->Add(desc, 0, wxALL, 10);
wxStaticBoxSizer* logBox = new wxStaticBoxSizer(wxVERTICAL, this, "Event Log");
m_log = new wxTextCtrl(this, wxID_ANY, "",
wxDefaultPosition, wxSize(-1, 200), wxTE_MULTILINE | wxTE_READONLY);
logBox->Add(m_log, 1, wxEXPAND | wxALL, 5);
mainSizer->Add(logBox, 1, wxEXPAND | wxALL, 10);
SetSizer(mainSizer);
LogEvent("Toolbar test app started");
LogEvent("Toolbar created with 6 tools");
LogEvent("Status bar created with 3 fields");
#ifdef __EMSCRIPTEN__
EM_ASM({
console.log('[TOOLBAR_TEST] wxToolBar test app started successfully');
});
#endif
}
void ToolbarTestFrame::LogEvent(const wxString& msg)
{
m_log->AppendText(msg + "\n");
SetStatusText(msg, 0);
#ifdef __EMSCRIPTEN__
EM_ASM({
console.log('[TOOLBAR_EVENT] ' + UTF8ToString($0));
}, msg.c_str().AsChar());
#endif
}
void ToolbarTestFrame::OnToolNew(wxCommandEvent& WXUNUSED(evt))
{
LogEvent("Toolbar: New clicked");
}
void ToolbarTestFrame::OnToolOpen(wxCommandEvent& WXUNUSED(evt))
{
LogEvent("Toolbar: Open clicked");
}
void ToolbarTestFrame::OnToolSave(wxCommandEvent& WXUNUSED(evt))
{
LogEvent("Toolbar: Save clicked");
}
void ToolbarTestFrame::OnToolZoomIn(wxCommandEvent& WXUNUSED(evt))
{
LogEvent("Toolbar: Zoom In clicked");
SetStatusText("Zoom: 150%", 2);
}
void ToolbarTestFrame::OnToolZoomOut(wxCommandEvent& WXUNUSED(evt))
{
LogEvent("Toolbar: Zoom Out clicked");
SetStatusText("Zoom: 75%", 2);
}
void ToolbarTestFrame::OnToolToggle(wxCommandEvent& evt)
{
bool checked = evt.IsChecked();
LogEvent(wxString::Format("Toolbar: Toggle %s", checked ? "ON" : "OFF"));
}

View file

@ -0,0 +1,252 @@
// wxTreeCtrl Test - Tests tree control in WASM
// KiCad uses tree controls for hierarchy browsers (components, nets, etc.)
#include "wx/wxprec.h"
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
#include "wx/treectrl.h"
#include "wx/imaglist.h"
#ifdef __EMSCRIPTEN__
#include <emscripten/emscripten.h>
#endif
class TreeTestApp : public wxApp
{
public:
virtual bool OnInit() override;
};
class TreeTestFrame : public wxFrame
{
public:
TreeTestFrame();
private:
wxTreeCtrl* m_tree;
wxTextCtrl* m_log;
void LogEvent(const wxString& msg);
void PopulateTree();
void OnSelChanged(wxTreeEvent& evt);
void OnItemExpanding(wxTreeEvent& evt);
void OnItemCollapsing(wxTreeEvent& evt);
void OnItemActivated(wxTreeEvent& evt);
void OnExpandAll(wxCommandEvent& evt);
void OnCollapseAll(wxCommandEvent& evt);
void OnAddItem(wxCommandEvent& evt);
void OnDeleteItem(wxCommandEvent& evt);
wxDECLARE_EVENT_TABLE();
};
enum {
ID_TREE = wxID_HIGHEST + 1,
ID_EXPAND_ALL,
ID_COLLAPSE_ALL,
ID_ADD_ITEM,
ID_DELETE_ITEM
};
wxBEGIN_EVENT_TABLE(TreeTestFrame, wxFrame)
EVT_TREE_SEL_CHANGED(ID_TREE, TreeTestFrame::OnSelChanged)
EVT_TREE_ITEM_EXPANDING(ID_TREE, TreeTestFrame::OnItemExpanding)
EVT_TREE_ITEM_COLLAPSING(ID_TREE, TreeTestFrame::OnItemCollapsing)
EVT_TREE_ITEM_ACTIVATED(ID_TREE, TreeTestFrame::OnItemActivated)
EVT_BUTTON(ID_EXPAND_ALL, TreeTestFrame::OnExpandAll)
EVT_BUTTON(ID_COLLAPSE_ALL, TreeTestFrame::OnCollapseAll)
EVT_BUTTON(ID_ADD_ITEM, TreeTestFrame::OnAddItem)
EVT_BUTTON(ID_DELETE_ITEM, TreeTestFrame::OnDeleteItem)
wxEND_EVENT_TABLE()
wxIMPLEMENT_APP(TreeTestApp);
bool TreeTestApp::OnInit()
{
if (!wxApp::OnInit())
return false;
TreeTestFrame* frame = new TreeTestFrame();
frame->Show(true);
return true;
}
TreeTestFrame::TreeTestFrame()
: wxFrame(nullptr, wxID_ANY, "wxTreeCtrl WASM Test",
wxDefaultPosition, wxSize(600, 600))
{
wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
wxStaticText* desc = new wxStaticText(this, wxID_ANY,
"wxTreeCtrl Test\n\n"
"KiCad uses tree controls for hierarchy browsers, component trees, and net lists.\n"
"Click items to select, double-click to activate, +/- to expand/collapse.");
mainSizer->Add(desc, 0, wxALL, 10);
// Button bar
wxBoxSizer* btnSizer = new wxBoxSizer(wxHORIZONTAL);
btnSizer->Add(new wxButton(this, ID_EXPAND_ALL, "Expand All"), 0, wxALL, 5);
btnSizer->Add(new wxButton(this, ID_COLLAPSE_ALL, "Collapse All"), 0, wxALL, 5);
btnSizer->Add(new wxButton(this, ID_ADD_ITEM, "Add Item"), 0, wxALL, 5);
btnSizer->Add(new wxButton(this, ID_DELETE_ITEM, "Delete Selected"), 0, wxALL, 5);
mainSizer->Add(btnSizer, 0, wxALIGN_CENTER);
// Tree control
m_tree = new wxTreeCtrl(this, ID_TREE, wxDefaultPosition, wxSize(-1, 250),
wxTR_DEFAULT_STYLE | wxTR_EDIT_LABELS);
mainSizer->Add(m_tree, 1, wxEXPAND | wxALL, 10);
PopulateTree();
// Event log
wxStaticBoxSizer* logBox = new wxStaticBoxSizer(wxVERTICAL, this, "Event Log");
m_log = new wxTextCtrl(this, wxID_ANY, "",
wxDefaultPosition, wxSize(-1, 150), wxTE_MULTILINE | wxTE_READONLY);
logBox->Add(m_log, 1, wxEXPAND | wxALL, 5);
mainSizer->Add(logBox, 0, wxEXPAND | wxALL, 10);
SetSizer(mainSizer);
CreateStatusBar();
SetStatusText("Ready");
LogEvent("Tree test app started");
LogEvent("Tree populated with KiCad-like hierarchy");
#ifdef __EMSCRIPTEN__
EM_ASM({
console.log('[TREE_TEST] wxTreeCtrl test app started successfully');
});
#endif
}
void TreeTestFrame::PopulateTree()
{
// Create a KiCad-like component hierarchy
wxTreeItemId root = m_tree->AddRoot("Project: MyBoard");
// Schematic hierarchy
wxTreeItemId schematic = m_tree->AppendItem(root, "Schematic");
wxTreeItemId sheet1 = m_tree->AppendItem(schematic, "Sheet 1 - Main");
m_tree->AppendItem(sheet1, "U1 - MCU");
m_tree->AppendItem(sheet1, "U2 - Power Regulator");
m_tree->AppendItem(sheet1, "C1-C10 - Capacitors");
m_tree->AppendItem(sheet1, "R1-R20 - Resistors");
wxTreeItemId sheet2 = m_tree->AppendItem(schematic, "Sheet 2 - IO");
m_tree->AppendItem(sheet2, "J1 - USB Connector");
m_tree->AppendItem(sheet2, "J2 - GPIO Header");
m_tree->AppendItem(sheet2, "LED1-LED4 - Status LEDs");
// PCB hierarchy
wxTreeItemId pcb = m_tree->AppendItem(root, "PCB");
wxTreeItemId layers = m_tree->AppendItem(pcb, "Layers");
m_tree->AppendItem(layers, "F.Cu - Front Copper");
m_tree->AppendItem(layers, "B.Cu - Back Copper");
m_tree->AppendItem(layers, "F.SilkS - Front Silkscreen");
m_tree->AppendItem(layers, "B.SilkS - Back Silkscreen");
m_tree->AppendItem(layers, "Edge.Cuts - Board Outline");
wxTreeItemId nets = m_tree->AppendItem(pcb, "Nets");
m_tree->AppendItem(nets, "GND (45 pads)");
m_tree->AppendItem(nets, "VCC (12 pads)");
m_tree->AppendItem(nets, "3V3 (8 pads)");
m_tree->AppendItem(nets, "SDA (4 pads)");
m_tree->AppendItem(nets, "SCL (4 pads)");
// Libraries
wxTreeItemId libraries = m_tree->AppendItem(root, "Libraries");
m_tree->AppendItem(libraries, "Device.lib");
m_tree->AppendItem(libraries, "Connector.lib");
m_tree->AppendItem(libraries, "MCU_ST.lib");
m_tree->Expand(root);
m_tree->Expand(schematic);
m_tree->Expand(pcb);
}
void TreeTestFrame::LogEvent(const wxString& msg)
{
m_log->AppendText(msg + "\n");
SetStatusText(msg);
#ifdef __EMSCRIPTEN__
EM_ASM({
console.log('[TREE_EVENT] ' + UTF8ToString($0));
}, msg.c_str().AsChar());
#endif
}
void TreeTestFrame::OnSelChanged(wxTreeEvent& evt)
{
wxTreeItemId item = evt.GetItem();
if (item.IsOk()) {
LogEvent(wxString::Format("Selection changed: '%s'", m_tree->GetItemText(item)));
}
}
void TreeTestFrame::OnItemExpanding(wxTreeEvent& evt)
{
wxTreeItemId item = evt.GetItem();
if (item.IsOk()) {
LogEvent(wxString::Format("Expanding: '%s'", m_tree->GetItemText(item)));
}
}
void TreeTestFrame::OnItemCollapsing(wxTreeEvent& evt)
{
wxTreeItemId item = evt.GetItem();
if (item.IsOk()) {
LogEvent(wxString::Format("Collapsing: '%s'", m_tree->GetItemText(item)));
}
}
void TreeTestFrame::OnItemActivated(wxTreeEvent& evt)
{
wxTreeItemId item = evt.GetItem();
if (item.IsOk()) {
LogEvent(wxString::Format("Activated (double-click): '%s'", m_tree->GetItemText(item)));
}
}
void TreeTestFrame::OnExpandAll(wxCommandEvent& WXUNUSED(evt))
{
m_tree->ExpandAll();
LogEvent("All items expanded");
}
void TreeTestFrame::OnCollapseAll(wxCommandEvent& WXUNUSED(evt))
{
m_tree->CollapseAll();
LogEvent("All items collapsed");
}
void TreeTestFrame::OnAddItem(wxCommandEvent& WXUNUSED(evt))
{
wxTreeItemId sel = m_tree->GetSelection();
if (sel.IsOk()) {
static int itemNum = 1;
wxTreeItemId newItem = m_tree->AppendItem(sel,
wxString::Format("New Item %d", itemNum++));
m_tree->Expand(sel);
m_tree->SelectItem(newItem);
LogEvent(wxString::Format("Added new item under '%s'", m_tree->GetItemText(sel)));
} else {
LogEvent("No item selected - select a parent first");
}
}
void TreeTestFrame::OnDeleteItem(wxCommandEvent& WXUNUSED(evt))
{
wxTreeItemId sel = m_tree->GetSelection();
if (sel.IsOk() && sel != m_tree->GetRootItem()) {
wxString itemText = m_tree->GetItemText(sel);
m_tree->Delete(sel);
LogEvent(wxString::Format("Deleted item: '%s'", itemText));
} else {
LogEvent("Cannot delete root or no item selected");
}
}