Fix Windows paint on resize issue. Automatically resize to fit tabs and button content

This commit is contained in:
Lam Wei Lun
2026-08-25 15:18:38 +08:00
parent d4cb739b8b
commit 795514900d
6 changed files with 58 additions and 4 deletions

View File

@@ -17,6 +17,7 @@
#include "libslic3r/PublishSettings.hpp" #include "libslic3r/PublishSettings.hpp"
#include <boost/algorithm/string/trim.hpp> #include <boost/algorithm/string/trim.hpp>
#include <wx/display.h>
#include <set> #include <set>
#include <algorithm> #include <algorithm>
@@ -97,7 +98,7 @@ PublishSettingsDialog::PublishSettingsDialog(wxWindow* parent)
_L("Publish 3MF..."), _L("Publish 3MF..."),
wxDefaultPosition, wxDefaultPosition,
wxDefaultSize, wxDefaultSize,
wxCAPTION | wxCLOSE_BOX | wxRESIZE_BORDER) wxCAPTION | wxCLOSE_BOX | wxRESIZE_BORDER | wxFULL_REPAINT_ON_RESIZE)
, m_search(this, "search", 16) , m_search(this, "search", 16)
, m_menu(this, "filter", 16) , m_menu(this, "filter", 16)
{ {
@@ -193,11 +194,42 @@ PublishSettingsDialog::PublishSettingsDialog(wxWindow* parent)
w_sizer->Add(dlg_btns, 0, wxEXPAND); w_sizer->Add(dlg_btns, 0, wxEXPAND);
SetSizerAndFit(w_sizer); SetSizerAndFit(w_sizer);
SetMinSize(FromDIP(wxSize(600, 500))); fit_to_content(); // initial size only; the dialog is resizable
SetSize(FromDIP(wxSize(600, 500))); // initial size only; the dialog is resizable
wxGetApp().UpdateDlgDarkUI(this); wxGetApp().UpdateDlgDarkUI(this);
} }
// Size the window to its content: width follows the widest tab strip so no filament tab is
// hidden (TabCtrl::relayout hides overflowing buttons), height scales proportionally. Both
// are floored at the 600x500 base and capped at hard DIP limits - deliberately not the whole
// display - with one last-resort clamp so the dialog can never open larger than the screen.
// Also owns the resize floor: the window cannot be resized below what the tabs need, so
// shrinking never re-hides a filament tab.
void PublishSettingsDialog::fit_to_content()
{
static const wxSize BASE{600, 500};
static const wxSize CAP{1300, 850};
int strip = m_outer_tabs->buttons_best_width();
for (const SectionGroup& section : m_sections)
strip = std::max(strip, section.tabs->buttons_best_width());
// Minimum width: whatever keeps every tab visible (never below the base). strip is device
// pixels (Button min sizes); BASE/CAP are DIP and converted over.
const int min_w = std::max(strip + 2 * FromDIP(10), FromDIP(BASE.x));
// Initial size: prefer proportional growth within the caps.
const int w = std::clamp(min_w, FromDIP(BASE.x), FromDIP(CAP.x));
const double f = double(w) / FromDIP(BASE.x);
const int h = std::clamp(int(FromDIP(BASE.y) * f), FromDIP(BASE.y), FromDIP(CAP.y));
const wxRect area = wxDisplay(this).GetClientArea();
const int max_w = area.width * 9 / 10;
const int max_h = area.height * 9 / 10;
SetMinSize(wxSize(std::min(min_w, max_w), std::min(FromDIP(BASE.y), max_h)));
SetSize(std::min(w, max_w), std::min(h, max_h));
}
PublishSettingsDialog::~PublishSettingsDialog() {} PublishSettingsDialog::~PublishSettingsDialog() {}
void PublishSettingsDialog::build_option_model() void PublishSettingsDialog::build_option_model()
@@ -1059,7 +1091,7 @@ void PublishSettingsDialog::on_dpi_changed(const wxRect& suggested_rect)
} }
} }
SetMinSize(FromDIP(wxSize(600, 500))); fit_to_content(); // tab buttons' min widths grew with the DPI: re-fit (incl. resize floor)
Refresh(); Refresh();
} }

View File

@@ -48,6 +48,8 @@ protected:
void on_dpi_changed(const wxRect& suggested_rect) override; void on_dpi_changed(const wxRect& suggested_rect) override;
private: private:
void fit_to_content();
// Which part of the settings the row/category came from. // Which part of the settings the row/category came from.
enum class Section { Print, Printer, Material }; enum class Section { Print, Printer, Material };

View File

@@ -7,6 +7,7 @@ BEGIN_EVENT_TABLE(StaticBox, wxWindow)
// catch paint events // catch paint events
//EVT_ERASE_BACKGROUND(StaticBox::eraseEvent) //EVT_ERASE_BACKGROUND(StaticBox::eraseEvent)
EVT_SIZE(StaticBox::sizeEvent)
EVT_PAINT(StaticBox::paintEvent) EVT_PAINT(StaticBox::paintEvent)
END_EVENT_TABLE() END_EVENT_TABLE()
@@ -140,6 +141,12 @@ void StaticBox::eraseEvent(wxEraseEvent& evt)
#endif #endif
} }
void StaticBox::sizeEvent(wxSizeEvent& evt)
{
Refresh();
evt.Skip();
}
void StaticBox::paintEvent(wxPaintEvent& evt) void StaticBox::paintEvent(wxPaintEvent& evt)
{ {
// depending on your system you may need to look at double-buffered dcs // depending on your system you may need to look at double-buffered dcs

View File

@@ -46,6 +46,8 @@ public:
protected: protected:
void eraseEvent(wxEraseEvent& evt); void eraseEvent(wxEraseEvent& evt);
void sizeEvent(wxSizeEvent& evt);
void paintEvent(wxPaintEvent& evt); void paintEvent(wxPaintEvent& evt);
void render(wxDC& dc); void render(wxDC& dc);

View File

@@ -295,6 +295,15 @@ void TabCtrl::relayout()
Layout(); Layout();
} }
int TabCtrl::buttons_best_width() const
{
// Mirrors relayout(): a 10px leading spacer plus every button's min width and spacing.
int width = 10;
for (const Button *btn : btns)
width += btn->GetMinSize().x + TAB_BUTTON_SPACE * 2;
return width;
}
void TabCtrl::buttonClicked(wxCommandEvent &event) void TabCtrl::buttonClicked(wxCommandEvent &event)
{ {
SetFocus(); SetFocus();

View File

@@ -73,6 +73,8 @@ private:
void relayout(); void relayout();
int buttons_best_width() const;
void buttonClicked(wxCommandEvent & event); void buttonClicked(wxCommandEvent & event);
void keyDown(wxKeyEvent &event); void keyDown(wxKeyEvent &event);