From ab29743097f6b454078e5c9dbbd807735b441a2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Va=CC=81clav=20Slavi=CC=81k?= Date: Thu, 27 Aug 2020 18:59:25 +0200 Subject: [PATCH 1/4] Use correct toolbar style for preferences on macOS 11 Code compiled against macOS 11 SDK must explicitly specify that the window should use preferences-style toolbar, otherwise the tabs would be moved to the right alongside window title, as is done with the standard toolbar now. --- src/osx/cocoa/preferences.mm | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/osx/cocoa/preferences.mm b/src/osx/cocoa/preferences.mm index bbc13a1ff9..d7dd66fb99 100644 --- a/src/osx/cocoa/preferences.mm +++ b/src/osx/cocoa/preferences.mm @@ -35,6 +35,7 @@ #include "wx/weakref.h" #include "wx/windowid.h" #include "wx/osx/private.h" +#include "wx/osx/private/available.h" #import @@ -62,6 +63,13 @@ public: m_toolbarRealized(false), m_visiblePage(NULL) { +#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_16 + if ( WX_IS_MACOS_AVAILABLE(11,0) ) + { + NSWindow *win = GetWXWindow(); + [win setToolbarStyle:NSWindowToolbarStylePreference]; + } +#endif m_toolbar = new wxToolBar(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTB_FLAT | wxTB_TEXT); m_toolbar->SetToolBitmapSize(wxSize(32,32)); From acf02be8088d63bb43898fbfc4746b9fcab7adb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Va=CC=81clav=20Slavi=CC=81k?= Date: Thu, 27 Aug 2020 18:56:12 +0200 Subject: [PATCH 2/4] Support SF Symbols images on macOS 11 Extend wxOSXGetSystemImage() and thus wxArtProvider with support for directly loading the new symbolic images in addition to existing support for named bundle resources. This enables usage such as wxArtProvider::GetBitmap("gearshape"). --- src/osx/carbon/utilscocoa.mm | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/osx/carbon/utilscocoa.mm b/src/osx/carbon/utilscocoa.mm index a3062ba261..4d3a182515 100644 --- a/src/osx/carbon/utilscocoa.mm +++ b/src/osx/carbon/utilscocoa.mm @@ -183,6 +183,16 @@ wxBitmap wxOSXCreateSystemBitmap(const wxString& name, const wxString &client, c WXImage wxOSXGetSystemImage(const wxString& name) { wxCFStringRef cfname(name); + +#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_16 + if ( WX_IS_MACOS_AVAILABLE(11, 0) ) + { + NSImage *symbol = [NSImage imageWithSystemSymbolName:cfname.AsNSString() accessibilityDescription:nil]; + if ( symbol ) + return symbol; + } +#endif + NSImage* nsimage = [NSImage imageNamed:cfname.AsNSString()]; return nsimage; } From b6bc50d16e42392dec0ee5ea861486280c27f9f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Va=CC=81clav=20Slavi=CC=81k?= Date: Thu, 27 Aug 2020 19:09:58 +0200 Subject: [PATCH 3/4] Use macOS 11 icons in wxStockPreferencesPage Ase the appropriate SF Symbols for General and Advanced preferences pages on macOS 11, while still using the old templates on older systems. --- src/osx/cocoa/preferences.mm | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/osx/cocoa/preferences.mm b/src/osx/cocoa/preferences.mm index d7dd66fb99..415a99fcfa 100644 --- a/src/osx/cocoa/preferences.mm +++ b/src/osx/cocoa/preferences.mm @@ -42,6 +42,19 @@ wxBitmap wxStockPreferencesPage::GetLargeIcon() const { +#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_16 + if ( WX_IS_MACOS_AVAILABLE(11, 0) ) + { + switch ( m_kind ) + { + case Kind_General: + return wxBitmap([NSImage imageWithSystemSymbolName:@"gearshape" accessibilityDescription:nil]); + case Kind_Advanced: + return wxBitmap([NSImage imageWithSystemSymbolName:@"gearshape.2" accessibilityDescription:nil]); + } + } +#endif + switch ( m_kind ) { case Kind_General: @@ -49,6 +62,7 @@ wxBitmap wxStockPreferencesPage::GetLargeIcon() const case Kind_Advanced: return wxBitmap([NSImage imageNamed:NSImageNameAdvanced]); } + return wxBitmap(); // silence compiler warning } From 587190c95c706ccb2008305a5cdf2f92833f3574 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Va=CC=81clav=20Slavi=CC=81k?= Date: Sat, 29 Aug 2020 19:53:32 +0200 Subject: [PATCH 4/4] Size preferences pages correctly on macOS 11 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- src/osx/cocoa/preferences.mm | 80 +++++++++++++++++++++++++++--------- 1 file changed, 60 insertions(+), 20 deletions(-) diff --git a/src/osx/cocoa/preferences.mm b/src/osx/cocoa/preferences.mm index 415a99fcfa..6cb962cdbf 100644 --- a/src/osx/cocoa/preferences.mm +++ b/src/osx/cocoa/preferences.mm @@ -143,19 +143,66 @@ protected: private: + struct PageInfo : public wxObject + { + PageInfo(wxPreferencesPage *p) : page(p), win(NULL) {} + + wxSharedPtr page; + wxWindow *win; + }; + + typedef wxVector< wxSharedPtr > 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(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 page; - wxWindow *win; - }; // All pages. Use shared pointer to be able to get pointers to PageInfo structs - wxVector< wxSharedPtr > m_pages; + Pages m_pages; wxToolBar *m_toolbar; bool m_toolbarRealized;