pcbjam/tests/apps/standalone/notebook/notebook_test.cpp
2026-06-16 11:22:18 +02:00

147 lines
4.5 KiB
C++

// wxNotebook page-relayout Test - regression coverage for the WASM DOM-port
// fix in wxwidgets/src/wasm/notebook.cpp (wxNotebook::WasmRelayoutSelectedPage).
//
// Bug (pcbjam#8): KiCad's APPEARANCE_CONTROLS::OnNotebookPageChanged calls
// Fit() on the just-selected page from a wxEVT_NOTEBOOK_PAGE_CHANGED handler.
// That collapses a wxScrolledWindow child's viewport to zero height; because
// DoSetSize() only re-runs layout when the size actually changes, resizing the
// page back was a no-op and the scrolled rows stayed clip-pathed away ("pages
// came back blank" after switching tabs away and back).
//
// This app reproduces the same shape in pure wxWidgets: a wxNotebook whose
// "Scrolled" page wraps a wxScrolledWindow full of labelled rows, plus a
// PAGE_CHANGED handler that calls page->Fit() exactly like KiCad. With the fix,
// OnDomEvent re-asserts the page geometry after SetSelection() so the rows stay
// painted; without it, they collapse. The rows are wxStaticText so the DOM port
// renders them as <span> elements the e2e spec can hit-test.
#include "wx/wxprec.h"
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
#include "wx/notebook.h"
#include "wx/scrolwin.h"
#ifdef __EMSCRIPTEN__
#include <emscripten/emscripten.h>
#endif
static const int kRowCount = 30;
class NotebookApp : public wxApp
{
public:
virtual bool OnInit() override;
};
class NotebookFrame : public wxFrame
{
public:
NotebookFrame();
private:
wxNotebook* m_notebook = nullptr;
wxWindow* CreatePlainPage();
wxWindow* CreateScrolledPage();
void Log(const wxString& msg);
void OnPageChanged(wxNotebookEvent& evt);
};
bool NotebookApp::OnInit()
{
if ( !wxApp::OnInit() )
return false;
(new NotebookFrame())->Show(true);
return true;
}
wxIMPLEMENT_APP(NotebookApp);
NotebookFrame::NotebookFrame()
: wxFrame(nullptr, wxID_ANY, "wxNotebook Page Relayout Test",
wxDefaultPosition, wxSize(420, 480))
{
wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
m_notebook = new wxNotebook(this, wxID_ANY);
m_notebook->AddPage(CreatePlainPage(), "Plain", true);
m_notebook->AddPage(CreateScrolledPage(), "Scrolled", false);
sizer->Add(m_notebook, 1, wxEXPAND | wxALL, 6);
SetSizer(sizer);
// Reproduce KiCad's APPEARANCE_CONTROLS::OnNotebookPageChanged: call Fit()
// on the selected page from the PAGE_CHANGED handler. This is what collapses
// the scrolled child; the DOM-port fix repairs it after this handler runs.
m_notebook->Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, &NotebookFrame::OnPageChanged, this);
Log("notebook test app started");
}
wxWindow* NotebookFrame::CreatePlainPage()
{
wxPanel* panel = new wxPanel(m_notebook);
wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
sizer->Add(new wxStaticText(panel, wxID_ANY, "Plain page"), 0, wxALL, 10);
sizer->Add(new wxStaticText(panel, wxID_ANY,
"Switch to the Scrolled page and back."),
0, wxLEFT | wxBOTTOM, 10);
panel->SetSizer(sizer);
return panel;
}
wxWindow* NotebookFrame::CreateScrolledPage()
{
// panel -> wxScrolledWindow -> many rows. Mirrors KiCad's layer panel:
// the page is a wxPanel that hosts a scrolled list; Fit() on the panel is
// what drives the viewport to zero.
wxPanel* panel = new wxPanel(m_notebook);
wxScrolledWindow* scrolled =
new wxScrolledWindow(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize,
wxVSCROLL | wxBORDER_SIMPLE);
scrolled->SetScrollRate(0, 10);
wxBoxSizer* rows = new wxBoxSizer(wxVERTICAL);
for ( int i = 0; i < kRowCount; ++i )
rows->Add(new wxStaticText(scrolled, wxID_ANY,
wxString::Format("Row %d", i)),
0, wxALL, 4);
scrolled->SetSizer(rows);
scrolled->FitInside();
wxBoxSizer* pageSizer = new wxBoxSizer(wxVERTICAL);
pageSizer->Add(scrolled, 1, wxEXPAND | wxALL, 4);
panel->SetSizer(pageSizer);
return panel;
}
void NotebookFrame::Log(const wxString& msg)
{
#ifdef __EMSCRIPTEN__
EM_ASM({
console.log('[NOTEBOOK_EVENT] ' + UTF8ToString($0));
}, (const char*)msg.utf8_str());
#else
wxLogMessage("[NOTEBOOK_EVENT] %s", msg);
#endif
}
void NotebookFrame::OnPageChanged(wxNotebookEvent& evt)
{
const int sel = evt.GetSelection();
if ( sel != wxNOT_FOUND )
{
if ( wxWindow* const page = m_notebook->GetPage(sel) )
page->Fit();
Log(wxString::Format("switched to page %d (%s)",
sel, m_notebook->GetPageText(sel)));
}
evt.Skip();
}