Size preferences pages correctly on macOS 11

Preferences windows traditionally changed their size on macOS when going
between tabs (pages): the window would resize, with animation, to fit the
current tab’s content and avoid wasted space. This worked well, because the
icons toolbar was left-aligned and so changing window size by growing/shrinking
it to the right or down felt natural.

This changes in macOS 11 where preferences toolbar icons are centered and would
shift around if the window resized horizontally. Indeed, the new standard is to
keep the width and only change window height when switching between pages.

Implement this behavior in wxPreferencesEditor too. This requires us to
instantiate all pages early (as is done on other platforms), so this on Big Sur
or newer only.
This commit is contained in:
Václav Slavík
2020-08-29 19:53:32 +02:00
parent b6bc50d16e
commit 587190c95c

View File

@@ -143,19 +143,66 @@ protected:
private:
struct PageInfo : public wxObject
{
PageInfo(wxPreferencesPage *p) : page(p), win(NULL) {}
wxSharedPtr<wxPreferencesPage> page;
wxWindow *win;
};
typedef wxVector< wxSharedPtr<PageInfo> > Pages;
wxWindow *GetPageWindow(PageInfo& info)
{
if ( !info.win )
{
info.win = info.page->CreateWindow(this);
info.win->Hide();
// fill the page with data using wxEVT_INIT_DIALOG/TransferDataToWindow:
info.win->InitDialog();
}
return info.win;
}
int GetBiggestPageWidth()
{
int width = -1;
for ( Pages::const_iterator p = m_pages.begin(); p != m_pages.end(); ++p )
{
wxWindow *win = GetPageWindow(**p);
width = wxMax(width, win->GetBestSize().x);
}
return width;
}
void FitPageWindow(wxWindow *win)
{
// On macOS 11, preferences are resizable only vertically, because the
// icons are centered and horizontal resizing would move them around.
if ( WX_IS_MACOS_AVAILABLE(11,0) )
{
int width = GetBiggestPageWidth();
if (width > win->GetBestSize().x)
{
wxSize minsize = win->GetMinSize();
minsize.x = width;
win->SetMinSize(minsize);
}
}
win->Fit();
}
void OnSelectPageForTool(const wxToolBarToolBase *tool)
{
PageInfo *info = static_cast<PageInfo*>(tool->GetClientData());
wxCHECK_RET( info, "toolbar item lacks client data" );
if ( !info->win )
{
info->win = info->page->CreateWindow(this);
info->win->Hide();
info->win->Fit();
// fill the page with data using wxEVT_INIT_DIALOG/TransferDataToWindow:
info->win->InitDialog();
}
wxWindow *win = GetPageWindow(*info);
FitPageWindow(win);
// When the page changes in a native preferences dialog, the sequence
// of events is thus:
@@ -163,19 +210,19 @@ private:
// 1. the old page is hidden, only gray background remains
if ( m_visiblePage )
m_visiblePage->Hide();
m_visiblePage = info->win;
m_visiblePage = win;
// 2. window is resized to fix the new page, with animation
// (in our case, using overriden DoMoveWindow())
SetClientSize(info->win->GetSize());
SetClientSize(win->GetSize());
// 3. new page is shown and the title updated.
info->win->Show();
win->Show();
SetTitle(info->page->GetName());
// Refresh the page to ensure everything is drawn in 10.14's dark mode;
// without it, generic controls aren't shown at all
info->win->Refresh();
win->Refresh();
// TODO: Preferences window may have some pages resizeable and some
// non-resizable on OS X; the whole window is or is not resizable
@@ -200,15 +247,8 @@ private:
}
private:
struct PageInfo : public wxObject
{
PageInfo(wxPreferencesPage *p) : page(p), win(NULL) {}
wxSharedPtr<wxPreferencesPage> page;
wxWindow *win;
};
// All pages. Use shared pointer to be able to get pointers to PageInfo structs
wxVector< wxSharedPtr<PageInfo> > m_pages;
Pages m_pages;
wxToolBar *m_toolbar;
bool m_toolbarRealized;