test: 💍 regression test for the notebook layer-list collapse
This commit is contained in:
parent
09cd9566ab
commit
d9264549bf
4 changed files with 294 additions and 2 deletions
|
|
@ -169,6 +169,7 @@ all: minimal_test.html \
|
|||
$(S)/propgrid/propgrid_test.html \
|
||||
$(S)/pickers/pickers_test.html \
|
||||
$(S)/collapsible/collapsible_test.html \
|
||||
$(S)/collapse-relayout/collapse-relayout_test.html \
|
||||
$(S)/listctrl/listctrl_test.html \
|
||||
$(S)/infobar/infobar_test.html \
|
||||
$(S)/dataviewvirtual/dataviewvirtual_test.html \
|
||||
|
|
@ -422,6 +423,13 @@ $(S)/collapsible/collapsible_test.o: $(S)/collapsible/collapsible_test.cpp
|
|||
$(S)/collapsible/collapsible_test.html: $(S)/collapsible/collapsible_test.o $(WX_CORE_LIB) $(JS_FILES)
|
||||
$(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@
|
||||
|
||||
# collapse-relayout: notebook page + proportion-1 scrolled list + collapsible pane (no GL)
|
||||
$(S)/collapse-relayout/collapse-relayout_test.o: $(S)/collapse-relayout/collapse-relayout_test.cpp
|
||||
$(CXX) -c $(CXXFLAGS) $< -o $@
|
||||
|
||||
$(S)/collapse-relayout/collapse-relayout_test.html: $(S)/collapse-relayout/collapse-relayout_test.o $(WX_CORE_LIB) $(JS_FILES)
|
||||
$(CXX) $< $(LDFLAGS_NOGL) --pre-js $(JS) --shell-file $(HTML) -o $@
|
||||
|
||||
# ListCtrl virtual mode test (no GL)
|
||||
$(S)/listctrl/listctrl_test.o: $(S)/listctrl/listctrl_test.cpp
|
||||
$(CXX) -c $(CXXFLAGS) $< -o $@
|
||||
|
|
@ -767,6 +775,7 @@ dnd: $(S)/dnd/dnd_test.html
|
|||
propgrid: $(S)/propgrid/propgrid_test.html
|
||||
pickers: $(S)/pickers/pickers_test.html
|
||||
collapsible: $(S)/collapsible/collapsible_test.html
|
||||
collapse-relayout: $(S)/collapse-relayout/collapse-relayout_test.html
|
||||
listctrl: $(S)/listctrl/listctrl_test.html
|
||||
infobar: $(S)/infobar/infobar_test.html
|
||||
dataviewvirtual: $(S)/dataviewvirtual/dataviewvirtual_test.html
|
||||
|
|
@ -813,7 +822,7 @@ clean:
|
|||
rm -f $(S)/*/*_test*.html $(S)/*/*_test*.js $(S)/*/*_test*.wasm
|
||||
rm -f $(S)/*/*_repro*.html $(S)/*/*_repro*.js $(S)/*/*_repro*.wasm
|
||||
|
||||
.PHONY: all clean menu contextmenu scrollbar clipboard filedialog layout aui toolbar grid dialog timer tree dataview htmlwin stc print dnd propgrid pickers collapsible listctrl infobar dataviewvirtual auinotebook wizard gridedit calendar gridrenderers printpreview bitmapbuttons specialized validators ownerdrawn popup xml wasmedge fontenum textdecor bitmask regions maximize earlysize selectheight threadpool logerror retinascale coroutine coroutine-nested asyncify-races notebook radiogroups
|
||||
.PHONY: all clean menu contextmenu scrollbar clipboard filedialog layout aui toolbar grid dialog timer tree dataview htmlwin stc print dnd propgrid pickers collapsible listctrl infobar dataviewvirtual auinotebook wizard gridedit calendar gridrenderers printpreview bitmapbuttons specialized validators ownerdrawn popup xml wasmedge fontenum textdecor bitmask regions maximize earlysize selectheight threadpool logerror retinascale coroutine coroutine-nested asyncify-races notebook radiogroups collapse-relayout
|
||||
|
||||
# === Coroutine pthread variant — reproduces the KiCad Asyncify-fiber x pthreads crash ===
|
||||
# Same modal-free harness as `coroutine`, but compiled/linked with pthreads to match
|
||||
|
|
|
|||
|
|
@ -0,0 +1,197 @@
|
|||
// collapse-relayout test — reproduces the pcbnew "Layer Display Options" bug.
|
||||
//
|
||||
// In pcbnew's Appearance sidebar, the Layers notebook page holds a proportion-1
|
||||
// wxScrolledCanvas layer list above a collapsible "Layer Display Options" pane.
|
||||
// On toggle, KiCad runs `Freeze(); page->Fit(); outerSizer->Layout(); Thaw();`.
|
||||
// In the WASM DOM port that permanently collapses the layer list: page->Fit()
|
||||
// shrinks the notebook page to content-min (a scrolled window reports a tiny
|
||||
// best height when vertical scrolling is enabled, see wxScrolledT_Helper::
|
||||
// FilterBestSize), and the following outer Layout() re-asserts the *notebook*
|
||||
// at its UNCHANGED size — which the DOM port's DoSetSize() treats as a no-op
|
||||
// that never fires wxEVT_SIZE, so wxNotebook::DoSize() never restores the page.
|
||||
// The list stays at height 0 (its rows clip-pathed away) until reload.
|
||||
//
|
||||
// This app mirrors that exact structure with stock widgets so the failure can
|
||||
// be reproduced and regression-tested without KiCad.
|
||||
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/wx.h"
|
||||
#endif
|
||||
|
||||
#include "wx/collpane.h"
|
||||
#include "wx/notebook.h"
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#include <emscripten/emscripten.h>
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
const char* const kLayerNames[] = {
|
||||
"top_cu", "bottom_cu", "F.Adhesive", "B.Adhesive",
|
||||
"F.Paste", "B.Paste", "F.Silkscreen", "B.Silkscreen",
|
||||
"F.Mask", "B.Mask", "User.Drawings", "User.Comments",
|
||||
"User.Eco1", "User.Eco2", "Edge.Cuts",
|
||||
};
|
||||
|
||||
const wxColour kSwatchColours[] = {
|
||||
wxColour(200, 52, 52), wxColour( 77, 127, 196), wxColour(107, 33, 125),
|
||||
wxColour( 20, 20, 120), wxColour(140, 130, 130), wxColour( 40, 160, 160),
|
||||
wxColour(224, 224, 122), wxColour(224, 160, 160), wxColour( 96, 40, 112),
|
||||
wxColour( 32, 112, 112), wxColour(200, 200, 210), wxColour( 90, 140, 200),
|
||||
wxColour(160, 224, 224), wxColour(200, 190, 60), wxColour(210, 210, 210),
|
||||
};
|
||||
}
|
||||
|
||||
class CollapseRelayoutApp : public wxApp
|
||||
{
|
||||
public:
|
||||
virtual bool OnInit() override;
|
||||
};
|
||||
|
||||
class CollapseRelayoutFrame : public wxFrame
|
||||
{
|
||||
public:
|
||||
CollapseRelayoutFrame();
|
||||
|
||||
private:
|
||||
wxNotebook* m_notebook = nullptr;
|
||||
wxPanel* m_page = nullptr; // the "Layers" notebook page
|
||||
wxScrolledWindow* m_scrolled = nullptr; // the layer list ("layerlist")
|
||||
wxCollapsiblePane* m_pane = nullptr; // "Layer Display Options"
|
||||
|
||||
void BuildLayerRows();
|
||||
void BuildDisplayOptions();
|
||||
void OnPaneChanged(wxCollapsiblePaneEvent& evt);
|
||||
|
||||
wxDECLARE_EVENT_TABLE();
|
||||
};
|
||||
|
||||
enum { ID_DISPLAY_PANE = wxID_HIGHEST + 1 };
|
||||
|
||||
wxBEGIN_EVENT_TABLE(CollapseRelayoutFrame, wxFrame)
|
||||
EVT_COLLAPSIBLEPANE_CHANGED(ID_DISPLAY_PANE, CollapseRelayoutFrame::OnPaneChanged)
|
||||
wxEND_EVENT_TABLE()
|
||||
|
||||
wxIMPLEMENT_APP(CollapseRelayoutApp);
|
||||
|
||||
bool CollapseRelayoutApp::OnInit()
|
||||
{
|
||||
if (!wxApp::OnInit())
|
||||
return false;
|
||||
|
||||
(new CollapseRelayoutFrame())->Show(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
CollapseRelayoutFrame::CollapseRelayoutFrame()
|
||||
: wxFrame(nullptr, wxID_ANY, "collapse-relayout WASM Test",
|
||||
wxDefaultPosition, wxSize(420, 820))
|
||||
{
|
||||
// Frame -> notebook (prop 1) -> page -> [ scrolled (prop 1), pane (prop 0) ]
|
||||
wxBoxSizer* frameSizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
m_notebook = new wxNotebook(this, wxID_ANY);
|
||||
|
||||
m_page = new wxPanel(m_notebook, wxID_ANY);
|
||||
wxBoxSizer* pageSizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
// The layer list: proportion 1, vertical scrolling. Named so the e2e test
|
||||
// can read its geometry from the element registry.
|
||||
m_scrolled = new wxScrolledWindow(m_page, wxID_ANY, wxDefaultPosition,
|
||||
wxDefaultSize, wxVSCROLL);
|
||||
m_scrolled->SetName("layerlist");
|
||||
m_scrolled->SetScrollRate(0, 5); // vertical scroll -> best height caps to ~0
|
||||
BuildLayerRows();
|
||||
pageSizer->Add(m_scrolled, 1, wxEXPAND);
|
||||
|
||||
// "Layer Display Options": proportion 0, starts collapsed (like KiCad).
|
||||
m_pane = new wxCollapsiblePane(m_page, ID_DISPLAY_PANE, "Layer Display Options");
|
||||
BuildDisplayOptions();
|
||||
pageSizer->Add(m_pane, 0, wxEXPAND | wxALL, 5);
|
||||
|
||||
m_page->SetSizer(pageSizer);
|
||||
m_notebook->AddPage(m_page, "Layers", true);
|
||||
|
||||
frameSizer->Add(m_notebook, 1, wxEXPAND);
|
||||
SetSizer(frameSizer);
|
||||
|
||||
// A plain wxScrolledWindow doesn't appear in the JS element registry (its
|
||||
// Create() runs during base construction, so it's skipped as a base type),
|
||||
// so the test can't read its geometry from the registry. Report the height
|
||||
// directly from C++ instead: once after the initial layout settles...
|
||||
CallAfter([this]() {
|
||||
#ifdef __EMSCRIPTEN__
|
||||
EM_ASM({ console.log('[COLLAPSE_RELAYOUT] initial layerlist height = ' + $0); },
|
||||
m_scrolled->GetSize().GetHeight());
|
||||
#endif
|
||||
});
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
EM_ASM({ console.log('[COLLAPSE_RELAYOUT] app started'); });
|
||||
#endif
|
||||
}
|
||||
|
||||
void CollapseRelayoutFrame::BuildLayerRows()
|
||||
{
|
||||
wxBoxSizer* listSizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
for (size_t i = 0; i < WXSIZEOF(kLayerNames); ++i)
|
||||
{
|
||||
wxPanel* row = new wxPanel(m_scrolled, wxID_ANY);
|
||||
wxBoxSizer* rowSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
wxPanel* swatch = new wxPanel(row, wxID_ANY, wxDefaultPosition, wxSize(24, 16));
|
||||
swatch->SetBackgroundColour(kSwatchColours[i]);
|
||||
rowSizer->Add(swatch, 0, wxALIGN_CENTER_VERTICAL | wxALL, 4);
|
||||
|
||||
rowSizer->Add(new wxStaticText(row, wxID_ANY, kLayerNames[i]),
|
||||
1, wxALIGN_CENTER_VERTICAL | wxALL, 4);
|
||||
|
||||
row->SetSizer(rowSizer);
|
||||
listSizer->Add(row, 0, wxEXPAND);
|
||||
}
|
||||
|
||||
m_scrolled->SetSizer(listSizer);
|
||||
m_scrolled->FitInside(); // grow the virtual area to hold all rows
|
||||
}
|
||||
|
||||
void CollapseRelayoutFrame::BuildDisplayOptions()
|
||||
{
|
||||
wxWindow* paneWin = m_pane->GetPane();
|
||||
wxBoxSizer* s = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
s->Add(new wxStaticText(paneWin, wxID_ANY, "Inactive layers (H):"), 0, wxALL, 4);
|
||||
|
||||
wxBoxSizer* modes = new wxBoxSizer(wxHORIZONTAL);
|
||||
modes->Add(new wxRadioButton(paneWin, wxID_ANY, "Normal",
|
||||
wxDefaultPosition, wxDefaultSize, wxRB_GROUP),
|
||||
0, wxALL, 4);
|
||||
modes->Add(new wxRadioButton(paneWin, wxID_ANY, "Dim"), 0, wxALL, 4);
|
||||
modes->Add(new wxRadioButton(paneWin, wxID_ANY, "Hide"), 0, wxALL, 4);
|
||||
s->Add(modes, 0, wxEXPAND);
|
||||
|
||||
s->Add(new wxCheckBox(paneWin, wxID_ANY, "Flip board view"), 0, wxALL, 4);
|
||||
|
||||
paneWin->SetSizer(s);
|
||||
s->Fit(paneWin);
|
||||
}
|
||||
|
||||
// Replicates KiCad's WX_COLLAPSIBLE_PANE_CHANGED handler in
|
||||
// pcbnew/widgets/appearance_controls.cpp (the Freeze / page->Fit / outer
|
||||
// Layout / Thaw idiom) that triggers the bug.
|
||||
void CollapseRelayoutFrame::OnPaneChanged(wxCollapsiblePaneEvent& WXUNUSED(evt))
|
||||
{
|
||||
Freeze();
|
||||
m_page->Fit(); // shrink the notebook page to content-min
|
||||
GetSizer()->Layout(); // re-assert the notebook at its UNCHANGED size
|
||||
Thaw();
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
// With the bug the list collapses to ~0; after the fix it stays tall.
|
||||
EM_ASM({ console.log('[COLLAPSE_RELAYOUT] layerlist height after toggle = ' + $0); },
|
||||
m_scrolled->GetSize().GetHeight());
|
||||
#endif
|
||||
}
|
||||
Loading…
Reference in a new issue