Fix wxWidgets WASM rendering and add comprehensive tests

- Update wxwidgets submodule with bitmap, template, and listbox fixes
- Add pcre2 include path to build script
- Add comprehensive UI interaction test covering all tabs
- Update test app with full control demonstration
- Add Makefile.wasm with HEAP exports for Emscripten
- Fix .gitignore to not ignore Makefile.wasm

🤖 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-28 14:24:53 +01:00
commit 4069de6a0b
7 changed files with 1067 additions and 35 deletions

View file

@ -0,0 +1,31 @@
# Makefile for minimal wxWidgets WASM test app
# Uses the local wxWidgets build
WXCONFIG = ../../build-wasm/wxwidgets-universal/wx-config
TOOLS_ROOT = ../../wxwidgets/build/wasm
CXX = em++
WX_CXXFLAGS := $(shell $(WXCONFIG) --cxxflags)
WX_LDFLAGS := $(shell $(WXCONFIG) --libs base,core)
TARGET = minimal_test
SOURCES = minimal_test.cpp
CXXFLAGS = -O2 $(WX_CXXFLAGS)
LDFLAGS = -s TOTAL_MEMORY=32MB -s ERROR_ON_UNDEFINED_SYMBOLS=0 -s "EXPORTED_RUNTIME_METHODS=['HEAPU8','HEAP8','HEAP32']" $(WX_LDFLAGS)
JS = $(TOOLS_ROOT)/wx.js
HTML = $(TOOLS_ROOT)/template.html
all: $(TARGET).html
$(TARGET).o: $(SOURCES)
$(CXX) -c $(CXXFLAGS) $< -o $@
$(TARGET).html: $(TARGET).o
$(CXX) $(TARGET).o $(LDFLAGS) --pre-js $(JS) --shell-file $(HTML) -o $@
clean:
rm -f $(TARGET).o $(TARGET).html $(TARGET).js $(TARGET).wasm
.PHONY: all clean

View file

@ -1,5 +1,5 @@
// Minimal wxWidgets WASM Test Application
// Purpose: Verify wxWidgets WASM port is working correctly
// Comprehensive wxWidgets WASM Test Application
// Purpose: Verify wxWidgets WASM port with full widget coverage and interaction testing
#include "wx/wxprec.h"
@ -7,16 +7,596 @@
#include "wx/wx.h"
#endif
class TestApp : public wxApp
{
public:
virtual bool OnInit() wxOVERRIDE;
#include "wx/notebook.h"
#include "wx/tglbtn.h"
#include "wx/listbox.h"
#include "wx/choice.h"
#include "wx/combobox.h"
#include "wx/slider.h"
#include "wx/gauge.h"
#include "wx/dcbuffer.h"
#include "wx/datetime.h"
#include <vector>
// Control IDs
enum {
ID_BTN_TEST = wxID_HIGHEST + 1,
ID_BTN_TOGGLE,
ID_CHK_FEATURE,
ID_RADIO_OPTIONS,
ID_SLIDER,
ID_GAUGE,
ID_TEXT_SINGLE,
ID_TEXT_MULTI,
ID_TEXT_PASSWORD,
ID_COMBO,
ID_LISTBOX,
ID_CHOICE,
ID_BTN_ADD_ITEM,
ID_BTN_REMOVE_ITEM,
ID_BTN_CLEAR,
ID_EVENT_LOG,
ID_DRAWING_PANEL
};
// Forward declarations
class TestFrame;
// Global pointer for logging from child panels
TestFrame* g_frame = nullptr;
//-----------------------------------------------------------------------------
// DrawingPanel - Custom drawing canvas for mouse interaction testing
//-----------------------------------------------------------------------------
class DrawingPanel : public wxPanel
{
public:
DrawingPanel(wxWindow* parent);
void Clear();
private:
std::vector<std::vector<wxPoint>> m_strokes; // Collection of strokes
std::vector<wxPoint> m_currentStroke; // Current stroke being drawn
bool m_drawing;
void OnPaint(wxPaintEvent& evt);
void OnMouseDown(wxMouseEvent& evt);
void OnMouseMove(wxMouseEvent& evt);
void OnMouseUp(wxMouseEvent& evt);
void OnMouseEnter(wxMouseEvent& evt);
void OnMouseLeave(wxMouseEvent& evt);
wxDECLARE_EVENT_TABLE();
};
wxBEGIN_EVENT_TABLE(DrawingPanel, wxPanel)
EVT_PAINT(DrawingPanel::OnPaint)
EVT_LEFT_DOWN(DrawingPanel::OnMouseDown)
EVT_LEFT_UP(DrawingPanel::OnMouseUp)
EVT_MOTION(DrawingPanel::OnMouseMove)
EVT_ENTER_WINDOW(DrawingPanel::OnMouseEnter)
EVT_LEAVE_WINDOW(DrawingPanel::OnMouseLeave)
wxEND_EVENT_TABLE()
DrawingPanel::DrawingPanel(wxWindow* parent)
: wxPanel(parent, ID_DRAWING_PANEL, wxDefaultPosition, wxSize(400, 300),
wxBORDER_SIMPLE | wxFULL_REPAINT_ON_RESIZE)
, m_drawing(false)
{
SetBackgroundColour(*wxWHITE);
SetBackgroundStyle(wxBG_STYLE_PAINT);
}
void DrawingPanel::Clear()
{
m_strokes.clear();
m_currentStroke.clear();
m_drawing = false;
Refresh();
}
void DrawingPanel::OnPaint(wxPaintEvent& WXUNUSED(evt))
{
wxBufferedPaintDC dc(this);
dc.SetBackground(*wxWHITE_BRUSH);
dc.Clear();
// Draw instructions
dc.SetTextForeground(wxColour(150, 150, 150));
dc.DrawText("Draw here with mouse", 10, 10);
// Draw all completed strokes
dc.SetPen(wxPen(*wxBLACK, 2));
for (const auto& stroke : m_strokes) {
if (stroke.size() > 1) {
for (size_t i = 1; i < stroke.size(); ++i) {
dc.DrawLine(stroke[i-1], stroke[i]);
}
}
}
// Draw current stroke
if (m_currentStroke.size() > 1) {
dc.SetPen(wxPen(*wxBLUE, 2));
for (size_t i = 1; i < m_currentStroke.size(); ++i) {
dc.DrawLine(m_currentStroke[i-1], m_currentStroke[i]);
}
}
}
//-----------------------------------------------------------------------------
// TestFrame - Main application frame
//-----------------------------------------------------------------------------
class TestFrame : public wxFrame
{
public:
TestFrame(const wxString& title);
void LogEvent(const wxString& msg);
private:
wxNotebook* m_notebook;
wxListBox* m_eventLog;
wxGauge* m_gauge;
wxTextCtrl* m_textSingle;
wxTextCtrl* m_textMulti;
DrawingPanel* m_drawingPanel;
wxListBox* m_listBox;
// Create tab pages
wxPanel* CreateControlsPage(wxNotebook* parent);
wxPanel* CreateTextPage(wxNotebook* parent);
wxPanel* CreateDrawingPage(wxNotebook* parent);
wxPanel* CreateListsPage(wxNotebook* parent);
// Event handlers
void OnQuit(wxCommandEvent& evt);
void OnAbout(wxCommandEvent& evt);
void OnButtonClick(wxCommandEvent& evt);
void OnToggleButton(wxCommandEvent& evt);
void OnCheckBox(wxCommandEvent& evt);
void OnRadioBox(wxCommandEvent& evt);
void OnSlider(wxCommandEvent& evt);
void OnTextChange(wxCommandEvent& evt);
void OnTextEnter(wxCommandEvent& evt);
void OnComboSelect(wxCommandEvent& evt);
void OnListBoxSelect(wxCommandEvent& evt);
void OnChoiceSelect(wxCommandEvent& evt);
void OnAddItem(wxCommandEvent& evt);
void OnRemoveItem(wxCommandEvent& evt);
void OnClearDrawing(wxCommandEvent& evt);
void OnNotebookPageChanged(wxBookCtrlEvent& evt);
wxDECLARE_EVENT_TABLE();
};
wxBEGIN_EVENT_TABLE(TestFrame, wxFrame)
EVT_MENU(wxID_EXIT, TestFrame::OnQuit)
EVT_MENU(wxID_ABOUT, TestFrame::OnAbout)
EVT_BUTTON(ID_BTN_TEST, TestFrame::OnButtonClick)
EVT_TOGGLEBUTTON(ID_BTN_TOGGLE, TestFrame::OnToggleButton)
EVT_CHECKBOX(ID_CHK_FEATURE, TestFrame::OnCheckBox)
EVT_RADIOBOX(ID_RADIO_OPTIONS, TestFrame::OnRadioBox)
EVT_SLIDER(ID_SLIDER, TestFrame::OnSlider)
EVT_TEXT(ID_TEXT_SINGLE, TestFrame::OnTextChange)
EVT_TEXT_ENTER(ID_TEXT_SINGLE, TestFrame::OnTextEnter)
EVT_COMBOBOX(ID_COMBO, TestFrame::OnComboSelect)
EVT_LISTBOX(ID_LISTBOX, TestFrame::OnListBoxSelect)
EVT_CHOICE(ID_CHOICE, TestFrame::OnChoiceSelect)
EVT_BUTTON(ID_BTN_ADD_ITEM, TestFrame::OnAddItem)
EVT_BUTTON(ID_BTN_REMOVE_ITEM, TestFrame::OnRemoveItem)
EVT_BUTTON(ID_BTN_CLEAR, TestFrame::OnClearDrawing)
EVT_NOTEBOOK_PAGE_CHANGED(wxID_ANY, TestFrame::OnNotebookPageChanged)
wxEND_EVENT_TABLE()
TestFrame::TestFrame(const wxString& title)
: wxFrame(nullptr, wxID_ANY, title, wxDefaultPosition, wxSize(640, 480))
{
g_frame = this;
// Menu bar
wxMenu* menuFile = new wxMenu;
menuFile->Append(wxID_EXIT, "E&xit\tAlt-X", "Quit the application");
wxMenu* menuHelp = new wxMenu;
menuHelp->Append(wxID_ABOUT, "&About\tF1", "Show about dialog");
wxMenuBar* menuBar = new wxMenuBar;
menuBar->Append(menuFile, "&File");
menuBar->Append(menuHelp, "&Help");
SetMenuBar(menuBar);
// Status bar
CreateStatusBar(2);
SetStatusText("Ready");
// Main layout: notebook on top, event log on bottom
wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
// Notebook with tabs
m_notebook = new wxNotebook(this, wxID_ANY);
m_notebook->AddPage(CreateControlsPage(m_notebook), "Controls");
m_notebook->AddPage(CreateTextPage(m_notebook), "Text Input");
m_notebook->AddPage(CreateDrawingPage(m_notebook), "Drawing");
m_notebook->AddPage(CreateListsPage(m_notebook), "Lists");
mainSizer->Add(m_notebook, 1, wxEXPAND | wxALL, 5);
// Event log panel
wxStaticBox* logBox = new wxStaticBox(this, wxID_ANY, "Event Log");
wxStaticBoxSizer* logSizer = new wxStaticBoxSizer(logBox, wxVERTICAL);
m_eventLog = new wxListBox(this, ID_EVENT_LOG, wxDefaultPosition, wxSize(-1, 100));
logSizer->Add(m_eventLog, 1, wxEXPAND);
mainSizer->Add(logSizer, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
SetSizer(mainSizer);
LogEvent("Application started");
}
void TestFrame::LogEvent(const wxString& msg)
{
// Get timestamp
wxDateTime now = wxDateTime::Now();
wxString timestamp = now.Format("[%H:%M:%S] ");
wxString fullMsg = timestamp + msg;
// Add to listbox
m_eventLog->Append(fullMsg);
// Keep max 100 entries
while (m_eventLog->GetCount() > 100) {
m_eventLog->Delete(0);
}
// Scroll to bottom
m_eventLog->SetSelection(m_eventLog->GetCount() - 1);
m_eventLog->SetSelection(wxNOT_FOUND);
// Also log to console for Playwright testing
wxPrintf("[EVENT] %s\n", msg);
fflush(stdout);
// Update status bar
SetStatusText(msg, 1);
}
wxPanel* TestFrame::CreateControlsPage(wxNotebook* parent)
{
wxPanel* panel = new wxPanel(parent);
wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
// Row 1: Buttons
wxStaticBox* btnBox = new wxStaticBox(panel, wxID_ANY, "Buttons");
wxStaticBoxSizer* btnSizer = new wxStaticBoxSizer(btnBox, wxHORIZONTAL);
wxButton* btnTest = new wxButton(panel, ID_BTN_TEST, "Click Me");
btnSizer->Add(btnTest, 0, wxALL, 5);
wxToggleButton* btnToggle = new wxToggleButton(panel, ID_BTN_TOGGLE, "Toggle");
btnSizer->Add(btnToggle, 0, wxALL, 5);
mainSizer->Add(btnSizer, 0, wxEXPAND | wxALL, 5);
// Row 2: Checkbox and Radio
wxBoxSizer* row2Sizer = new wxBoxSizer(wxHORIZONTAL);
wxCheckBox* chkFeature = new wxCheckBox(panel, ID_CHK_FEATURE, "Enable feature");
row2Sizer->Add(chkFeature, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
wxString radioChoices[] = { "Option A", "Option B", "Option C" };
wxRadioBox* radioBox = new wxRadioBox(panel, ID_RADIO_OPTIONS, "Options",
wxDefaultPosition, wxDefaultSize, 3, radioChoices, 1, wxRA_SPECIFY_ROWS);
row2Sizer->Add(radioBox, 0, wxALL, 5);
mainSizer->Add(row2Sizer, 0, wxEXPAND);
// Row 3: Slider and Gauge
wxStaticBox* rangeBox = new wxStaticBox(panel, wxID_ANY, "Range Controls");
wxStaticBoxSizer* rangeSizer = new wxStaticBoxSizer(rangeBox, wxVERTICAL);
wxBoxSizer* sliderRow = new wxBoxSizer(wxHORIZONTAL);
sliderRow->Add(new wxStaticText(panel, wxID_ANY, "Slider:"), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
wxSlider* slider = new wxSlider(panel, ID_SLIDER, 50, 0, 100,
wxDefaultPosition, wxSize(200, -1));
sliderRow->Add(slider, 1, wxALL, 5);
rangeSizer->Add(sliderRow, 0, wxEXPAND);
wxBoxSizer* gaugeRow = new wxBoxSizer(wxHORIZONTAL);
gaugeRow->Add(new wxStaticText(panel, wxID_ANY, "Gauge:"), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
m_gauge = new wxGauge(panel, ID_GAUGE, 100, wxDefaultPosition, wxSize(200, -1));
m_gauge->SetValue(50);
gaugeRow->Add(m_gauge, 1, wxALL, 5);
rangeSizer->Add(gaugeRow, 0, wxEXPAND);
mainSizer->Add(rangeSizer, 0, wxEXPAND | wxALL, 5);
panel->SetSizer(mainSizer);
return panel;
}
wxPanel* TestFrame::CreateTextPage(wxNotebook* parent)
{
wxPanel* panel = new wxPanel(parent);
wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
// Single-line text
wxBoxSizer* singleRow = new wxBoxSizer(wxHORIZONTAL);
singleRow->Add(new wxStaticText(panel, wxID_ANY, "Single-line:"), 0,
wxALL | wxALIGN_CENTER_VERTICAL, 5);
m_textSingle = new wxTextCtrl(panel, ID_TEXT_SINGLE, "",
wxDefaultPosition, wxSize(200, -1), wxTE_PROCESS_ENTER);
singleRow->Add(m_textSingle, 1, wxALL, 5);
mainSizer->Add(singleRow, 0, wxEXPAND);
// Multi-line text
wxStaticBox* multiBox = new wxStaticBox(panel, wxID_ANY, "Multi-line:");
wxStaticBoxSizer* multiSizer = new wxStaticBoxSizer(multiBox, wxVERTICAL);
m_textMulti = new wxTextCtrl(panel, ID_TEXT_MULTI, "",
wxDefaultPosition, wxSize(-1, 100), wxTE_MULTILINE);
multiSizer->Add(m_textMulti, 1, wxEXPAND | wxALL, 5);
mainSizer->Add(multiSizer, 1, wxEXPAND | wxALL, 5);
// Password field
wxBoxSizer* passRow = new wxBoxSizer(wxHORIZONTAL);
passRow->Add(new wxStaticText(panel, wxID_ANY, "Password:"), 0,
wxALL | wxALIGN_CENTER_VERTICAL, 5);
wxTextCtrl* textPass = new wxTextCtrl(panel, ID_TEXT_PASSWORD, "",
wxDefaultPosition, wxSize(200, -1), wxTE_PASSWORD);
passRow->Add(textPass, 0, wxALL, 5);
mainSizer->Add(passRow, 0, wxEXPAND);
// ComboBox
wxBoxSizer* comboRow = new wxBoxSizer(wxHORIZONTAL);
comboRow->Add(new wxStaticText(panel, wxID_ANY, "ComboBox:"), 0,
wxALL | wxALIGN_CENTER_VERTICAL, 5);
wxString comboChoices[] = { "Choice 1", "Choice 2", "Choice 3" };
wxComboBox* combo = new wxComboBox(panel, ID_COMBO, "",
wxDefaultPosition, wxSize(150, -1), 3, comboChoices);
comboRow->Add(combo, 0, wxALL, 5);
mainSizer->Add(comboRow, 0, wxEXPAND);
panel->SetSizer(mainSizer);
return panel;
}
wxPanel* TestFrame::CreateDrawingPage(wxNotebook* parent)
{
wxPanel* panel = new wxPanel(parent);
wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
// Instructions
mainSizer->Add(new wxStaticText(panel, wxID_ANY,
"Click and drag to draw. Mouse events are logged."),
0, wxALL, 10);
// Drawing canvas
m_drawingPanel = new DrawingPanel(panel);
mainSizer->Add(m_drawingPanel, 1, wxEXPAND | wxALL, 10);
// Clear button
wxButton* btnClear = new wxButton(panel, ID_BTN_CLEAR, "Clear Canvas");
mainSizer->Add(btnClear, 0, wxALL | wxALIGN_CENTER_HORIZONTAL, 10);
panel->SetSizer(mainSizer);
return panel;
}
wxPanel* TestFrame::CreateListsPage(wxNotebook* parent)
{
wxPanel* panel = new wxPanel(parent);
wxBoxSizer* mainSizer = new wxBoxSizer(wxHORIZONTAL);
// ListBox section
wxStaticBox* listBoxGroup = new wxStaticBox(panel, wxID_ANY, "ListBox");
wxStaticBoxSizer* listBoxSizer = new wxStaticBoxSizer(listBoxGroup, wxVERTICAL);
wxString listItems[] = { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" };
m_listBox = new wxListBox(panel, ID_LISTBOX, wxDefaultPosition,
wxSize(150, 150), 5, listItems);
listBoxSizer->Add(m_listBox, 1, wxEXPAND | wxALL, 5);
wxBoxSizer* listBtnSizer = new wxBoxSizer(wxHORIZONTAL);
listBtnSizer->Add(new wxButton(panel, ID_BTN_ADD_ITEM, "Add"), 0, wxALL, 2);
listBtnSizer->Add(new wxButton(panel, ID_BTN_REMOVE_ITEM, "Remove"), 0, wxALL, 2);
listBoxSizer->Add(listBtnSizer, 0, wxALIGN_CENTER);
mainSizer->Add(listBoxSizer, 1, wxEXPAND | wxALL, 10);
// Choice section
wxStaticBox* choiceGroup = new wxStaticBox(panel, wxID_ANY, "Choice");
wxStaticBoxSizer* choiceSizer = new wxStaticBoxSizer(choiceGroup, wxVERTICAL);
wxString choiceItems[] = { "Red", "Green", "Blue", "Yellow", "Purple" };
wxChoice* choice = new wxChoice(panel, ID_CHOICE, wxDefaultPosition,
wxSize(150, -1), 5, choiceItems);
choiceSizer->Add(choice, 0, wxALL, 5);
choiceSizer->Add(new wxStaticText(panel, wxID_ANY,
"Select a color from\nthe dropdown above."), 0, wxALL, 5);
mainSizer->Add(choiceSizer, 1, wxEXPAND | wxALL, 10);
panel->SetSizer(mainSizer);
return panel;
}
// Event handlers
void TestFrame::OnQuit(wxCommandEvent& WXUNUSED(evt))
{
Close(true);
}
void TestFrame::OnAbout(wxCommandEvent& WXUNUSED(evt))
{
wxMessageBox("wxWidgets WASM Comprehensive Test\n\n"
"This application tests various wxWidgets controls\n"
"running in WebAssembly via wxUniversal.",
"About", wxOK | wxICON_INFORMATION, this);
}
void TestFrame::OnButtonClick(wxCommandEvent& WXUNUSED(evt))
{
LogEvent("Button 'Click Me' clicked");
}
void TestFrame::OnToggleButton(wxCommandEvent& evt)
{
bool pressed = evt.IsChecked();
LogEvent(wxString::Format("Toggle button %s", pressed ? "pressed" : "released"));
}
void TestFrame::OnCheckBox(wxCommandEvent& evt)
{
bool checked = evt.IsChecked();
LogEvent(wxString::Format("Checkbox toggled: %s", checked ? "checked" : "unchecked"));
}
void TestFrame::OnRadioBox(wxCommandEvent& evt)
{
int sel = evt.GetSelection();
wxString option = wxString::Format("Option %c", 'A' + sel);
LogEvent(wxString::Format("Radio selection: %s", option));
}
void TestFrame::OnSlider(wxCommandEvent& evt)
{
int value = evt.GetInt();
m_gauge->SetValue(value);
LogEvent(wxString::Format("Slider value: %d", value));
}
void TestFrame::OnTextChange(wxCommandEvent& evt)
{
wxString text = evt.GetString();
LogEvent(wxString::Format("Text changed: \"%s\"", text));
}
void TestFrame::OnTextEnter(wxCommandEvent& evt)
{
wxString text = evt.GetString();
LogEvent(wxString::Format("Text entered (Enter pressed): \"%s\"", text));
}
void TestFrame::OnComboSelect(wxCommandEvent& evt)
{
wxString selection = evt.GetString();
LogEvent(wxString::Format("ComboBox selected: %s", selection));
}
void TestFrame::OnListBoxSelect(wxCommandEvent& evt)
{
wxString selection = evt.GetString();
LogEvent(wxString::Format("ListBox selected: %s", selection));
}
void TestFrame::OnChoiceSelect(wxCommandEvent& evt)
{
wxString selection = evt.GetString();
LogEvent(wxString::Format("Choice selected: %s", selection));
}
void TestFrame::OnAddItem(wxCommandEvent& WXUNUSED(evt))
{
static int itemCount = 5;
wxString newItem = wxString::Format("Item %d", ++itemCount);
m_listBox->Append(newItem);
LogEvent(wxString::Format("Added item: %s", newItem));
}
void TestFrame::OnRemoveItem(wxCommandEvent& WXUNUSED(evt))
{
int sel = m_listBox->GetSelection();
if (sel != wxNOT_FOUND) {
wxString item = m_listBox->GetString(sel);
m_listBox->Delete(sel);
LogEvent(wxString::Format("Removed item: %s", item));
} else {
LogEvent("Remove: No item selected");
}
}
void TestFrame::OnClearDrawing(wxCommandEvent& WXUNUSED(evt))
{
m_drawingPanel->Clear();
LogEvent("Drawing canvas cleared");
}
void TestFrame::OnNotebookPageChanged(wxBookCtrlEvent& evt)
{
int page = evt.GetSelection();
wxString pageName = m_notebook->GetPageText(page);
LogEvent(wxString::Format("Tab changed to: %s", pageName));
evt.Skip();
}
// DrawingPanel event handlers (defined after TestFrame for g_frame access)
void DrawingPanel::OnMouseDown(wxMouseEvent& evt)
{
m_drawing = true;
m_currentStroke.clear();
m_currentStroke.push_back(evt.GetPosition());
CaptureMouse();
if (g_frame) {
g_frame->LogEvent(wxString::Format("Mouse down at (%d, %d)",
evt.GetX(), evt.GetY()));
}
}
void DrawingPanel::OnMouseMove(wxMouseEvent& evt)
{
if (m_drawing) {
m_currentStroke.push_back(evt.GetPosition());
Refresh();
}
}
void DrawingPanel::OnMouseUp(wxMouseEvent& evt)
{
if (m_drawing) {
m_drawing = false;
if (HasCapture()) {
ReleaseMouse();
}
// Save the completed stroke
if (m_currentStroke.size() > 1) {
m_strokes.push_back(m_currentStroke);
}
m_currentStroke.clear();
Refresh();
if (g_frame) {
g_frame->LogEvent(wxString::Format("Mouse up at (%d, %d) - stroke completed",
evt.GetX(), evt.GetY()));
}
}
}
void DrawingPanel::OnMouseEnter(wxMouseEvent& WXUNUSED(evt))
{
if (g_frame) {
g_frame->LogEvent("Mouse entered drawing canvas");
}
}
void DrawingPanel::OnMouseLeave(wxMouseEvent& WXUNUSED(evt))
{
if (g_frame) {
g_frame->LogEvent("Mouse left drawing canvas");
}
}
//-----------------------------------------------------------------------------
// TestApp - Application class
//-----------------------------------------------------------------------------
class TestApp : public wxApp
{
public:
virtual bool OnInit() wxOVERRIDE;
};
wxIMPLEMENT_APP(TestApp);
@ -26,17 +606,8 @@ bool TestApp::OnInit()
if (!wxApp::OnInit())
return false;
TestFrame *frame = new TestFrame("wxWidgets WASM Test");
TestFrame* frame = new TestFrame("wxWidgets WASM Comprehensive Test");
frame->Show(true);
return true;
}
TestFrame::TestFrame(const wxString& title)
: wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(640, 480))
{
#if wxUSE_STATUSBAR
CreateStatusBar();
SetStatusText("wxWidgets WASM is working!");
#endif
}

View file

@ -46,6 +46,12 @@
var statusElement = document.getElementById('progress-text');
var progressElement = document.getElementById('progress-bar-position');
var showError = function(msg) {
console.error(msg);
statusElement.innerHTML = msg;
statusElement.style.color = 'red';
};
var createCanvas = function () {
var canvas = document.createElement('canvas');
canvas.id = 'canvas';