diff --git a/docs/changes.txt b/docs/changes.txt index 3c5e603335..357fcb20ce 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -267,8 +267,8 @@ wxMSW: wxOSX: -- Fix wxChoice default size under macOS 26 Tahoe (#26058). - Improve wxRichTextCtrl handling of cursor keys (Lee Ockert, #26064). +- Many appearance fixes for macOS 26 Tahoe (#26058, #25767, #26121). - Show applications launched from keyboard under macOS 26 (#26095). diff --git a/include/wx/osx/cocoa/private.h b/include/wx/osx/cocoa/private.h index daa79ed6fd..fa5bd4ccfc 100644 --- a/include/wx/osx/cocoa/private.h +++ b/include/wx/osx/cocoa/private.h @@ -232,6 +232,8 @@ public : // from the same pimpl class. virtual void controlTextDidChange(); + virtual void ClipsToBounds(bool clip) wxOVERRIDE; + virtual void AdjustClippingView(wxScrollBar* horizontal, wxScrollBar* vertical) wxOVERRIDE; virtual void UseClippingView(bool clip) wxOVERRIDE; virtual WXWidget GetContainer() const wxOVERRIDE { return m_osxClipView ? m_osxClipView : m_osxView; } diff --git a/include/wx/osx/core/private.h b/include/wx/osx/core/private.h index b907da8f52..8f5e833b87 100644 --- a/include/wx/osx/core/private.h +++ b/include/wx/osx/core/private.h @@ -366,6 +366,8 @@ public : virtual bool EnableTouchEvents(int eventsMask) = 0; + virtual void ClipsToBounds(bool clip); + // scrolling views need a clip subview that acts as parent for native children // (except for the scollbars) which are children of the view itself virtual void AdjustClippingView(wxScrollBar* horizontal, wxScrollBar* vertical); diff --git a/include/wx/osx/window.h b/include/wx/osx/window.h index 3a161a5ce4..bd8ceade0d 100644 --- a/include/wx/osx/window.h +++ b/include/wx/osx/window.h @@ -226,6 +226,9 @@ public: // returns the visible region of this control in window ie non-client coordinates const wxRegion& MacGetVisibleRegion( bool includeOuterStructures = false ) ; + // sets NSView.clipsToBounds property + void MacClipsToBounds( bool clip ); + // returns true if children have to clipped to the content area // (e.g., scrolled windows) bool MacClipChildren() const { return m_clipChildren ; } diff --git a/include/wx/platform.h b/include/wx/platform.h index 965507029d..23e848040c 100644 --- a/include/wx/platform.h +++ b/include/wx/platform.h @@ -491,6 +491,9 @@ # ifndef MAC_OS_VERSION_14_0 # define MAC_OS_VERSION_14_0 140000 # endif +# ifndef MAC_OS_VERSION_26_0 +# define MAC_OS_VERSION_26_0 260000 +# endif # if __MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_13 # ifndef NSAppKitVersionNumber10_10 # define NSAppKitVersionNumber10_10 1343 diff --git a/src/generic/spinctlg.cpp b/src/generic/spinctlg.cpp index 0396a4913c..1c6e5abb4f 100644 --- a/src/generic/spinctlg.cpp +++ b/src/generic/spinctlg.cpp @@ -50,11 +50,15 @@ wxIMPLEMENT_DYNAMIC_CLASS(wxSpinDoubleEvent, wxNotifyEvent); // ---------------------------------------------------------------------------- // The margin between the text control and the spin: the value here is the same -// as the margin between the spin button and its "buddy" text control in wxMSW -// so the generic control looks similarly to the native one there, we might -// need to use different value for the other platforms (and maybe even -// determine it dynamically?). +// as the margin between the spin button and its "buddy" text control in wxMSW, +// and the commonly used spacing on macOS, so the generic control looks +// similarly to the native one there, we might need to use different value for +// other platforms (and maybe even determine it dynamically?). +#ifdef __WXOSX__ +static const wxCoord MARGIN = 4; +#else static const wxCoord MARGIN = 1; +#endif #define SPINCTRLBUT_MAX 32000 // large to avoid wrap around trouble @@ -244,6 +248,10 @@ bool wxSpinCtrlGenericBase::Create(wxWindow *parent, m_value = AdjustAndSnap(d); } +#ifdef __WXOSX__ + MacClipsToBounds(false); +#endif + m_textCtrl = new wxSpinCtrlTextGeneric(this, DoValueToText(m_value), style); m_spinButton = new wxSpinCtrlButtonGeneric(this, styleWithoutBorder); diff --git a/src/osx/carbon/frame.cpp b/src/osx/carbon/frame.cpp index fdce201ced..2dcc8ae118 100644 --- a/src/osx/carbon/frame.cpp +++ b/src/osx/carbon/frame.cpp @@ -129,7 +129,17 @@ wxStatusBar *wxFrame::OnCreateStatusBar(int number, long style, wxWindowID id, void wxFrame::SetStatusBar(wxStatusBar *statbar) { wxFrameBase::SetStatusBar(statbar); - m_nowpeer->SetBottomBorderThickness(statbar ? GetMacStatusbarHeight() : 0); + +#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_11_0 + if ( WX_IS_MACOS_AVAILABLE(11, 0) ) + { + // textured borders are unwanted, statusbar renders w/o them + } + else +#endif + { + m_nowpeer->SetBottomBorderThickness(statbar ? GetMacStatusbarHeight() : 0); + } } void wxFrame::PositionStatusBar() diff --git a/src/osx/carbon/renderer.cpp b/src/osx/carbon/renderer.cpp index 4bffa8402e..feaa13788a 100644 --- a/src/osx/carbon/renderer.cpp +++ b/src/osx/carbon/renderer.cpp @@ -586,7 +586,7 @@ wxSize wxRendererMac::GetCollapseButtonSize(wxWindow *WXUNUSED(win), wxDC& WXUNU } // strict metrics size cutoff the button, increase the size - size.IncBy(1); + size.IncBy(3); return size; } diff --git a/src/osx/carbon/statbrma.cpp b/src/osx/carbon/statbrma.cpp index 91e78d80bc..de47d8e4df 100644 --- a/src/osx/carbon/statbrma.cpp +++ b/src/osx/carbon/statbrma.cpp @@ -34,6 +34,7 @@ wxBEGIN_EVENT_TABLE(wxStatusBarMac, wxStatusBarGeneric) EVT_PAINT(wxStatusBarMac::OnPaint) wxEND_EVENT_TABLE() +static wxColor s_bgActive, s_bgInactive, s_separator; wxStatusBarMac::wxStatusBarMac(wxWindow *parent, wxWindowID id, @@ -76,6 +77,51 @@ bool wxStatusBarMac::Create(wxWindow *parent, wxWindowID id, void wxStatusBarMac::InitColours() { +#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_26_0 + if ( WX_IS_MACOS_AVAILABLE(26, 0) ) + { + if ( wxSystemSettings::GetAppearance().IsDark() ) + { + m_textActive = wxColour(0x9B, 0x9F, 0x9F); + m_textInactive = wxColour(0x59, 0x5F, 0x60); + // native separator uses hairline black plus some shading, + // this approximates it well visually: + s_separator = wxColour(0x18, 0x18, 0x18); + } + else + { + m_textActive = wxColour(0x80, 0x80, 0x80); + m_textInactive = wxColour(0xB8, 0xB8, 0xB8); + s_separator = wxColour(0xD9, 0xD9, 0xD9); + } + } + else +#endif // MAC_OS_VERSION_26_0 +#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_11_0 + if ( WX_IS_MACOS_AVAILABLE(11, 0) ) + { + if ( wxSystemSettings::GetAppearance().IsDark() ) + { + m_textActive = wxColour(0xB1, 0xB2, 0xB2); + m_textInactive = wxColour(0x68, 0x69, 0x6A); + s_bgActive = wxColour(0x35, 0x36, 0x36); + s_bgInactive = wxColour(0x27, 0x28, 0x29); + // native separator uses hairline black plus some shading, + // this approximates it well visually: + s_separator = wxColour(0x18, 0x18, 0x18); + } + else + { + m_textActive = wxColour(0x73, 0x74, 0x74); + m_textInactive = wxColour(0xA5, 0xA6, 0xA6); + s_bgActive = wxColour(0xF3, 0xF3, 0xF3); + s_bgInactive = wxColour(0xE6, 0xE6, 0xE6); + s_separator = wxColour(0xCC, 0xCC, 0xCC); + } + } + else +#endif // MAC_OS_VERSION_11_0 +#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 if ( WX_IS_MACOS_AVAILABLE(10, 14) ) { if ( wxSystemSettings::GetAppearance().IsDark() ) @@ -89,7 +135,9 @@ void wxStatusBarMac::InitColours() m_textInactive = wxColour(0xB1, 0xB1, 0xB1); } } - else // 10.10 Yosemite to 10.13: + else +#endif // MAC_OS_X_VERSION_10_14 + // 10.10 Yosemite to 10.13: { m_textActive = wxColour(0x40, 0x40, 0x40); @@ -119,7 +167,34 @@ void wxStatusBarMac::OnPaint(wxPaintEvent& WXUNUSED(event)) break; } - // Don't paint any background, that's handled by the OS. Only draw text: +#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_26_0 + if ( WX_IS_MACOS_AVAILABLE(26, 0) ) + { + // don't paint the background, handled by the OS + } + else +#endif +#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_11_0 + if ( WX_IS_MACOS_AVAILABLE(11, 0) ) + { + // we _do_ need to paint the background on Big Sur up to Tahoe + // to match Finder's appearance: + dc.SetBackground(tlw == keyWindow ? s_bgActive : s_bgInactive); + dc.Clear(); + } + // else: background is rendered by OS, it is part of NSWindow border +#endif + +#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_11_0 + // Draw horizontal separator above the status bar: + if ( WX_IS_MACOS_AVAILABLE(11, 0) ) + { + dc.SetPen(s_separator); + dc.DrawLine(0, 0, GetSize().x, 0); + } +#endif + + // Draw the text: dc.SetTextForeground(tlw == keyWindow ? m_textActive : m_textInactive); @@ -131,7 +206,7 @@ void wxStatusBarMac::OnPaint(wxPaintEvent& WXUNUSED(event)) int textHeight = dc.GetCharHeight(); for ( size_t i = 0; i < m_panes.GetCount(); i ++ ) - DrawField(dc, i, textHeight); + DrawField(dc, (int)i, textHeight); } void wxStatusBarMac::MacHiliteChanged() diff --git a/src/osx/cocoa/anybutton.mm b/src/osx/cocoa/anybutton.mm index 299dcba2bc..5740582089 100644 --- a/src/osx/cocoa/anybutton.mm +++ b/src/osx/cocoa/anybutton.mm @@ -44,5 +44,5 @@ wxSize wxAnyButton::DoGetBestSize() const wxSize wxAnyButton::GetDefaultSize() { - return wxSize(84, 20); + return wxSize(74, 20); } diff --git a/src/osx/cocoa/notebook.mm b/src/osx/cocoa/notebook.mm index 05010eb906..783ab412df 100644 --- a/src/osx/cocoa/notebook.mm +++ b/src/osx/cocoa/notebook.mm @@ -24,6 +24,7 @@ #include "wx/string.h" #include "wx/private/bmpbndl.h" #include "wx/osx/private.h" +#include "wx/osx/private/available.h" // // controller @@ -87,7 +88,20 @@ if (!initialized) { initialized = YES; - wxOSXCocoaClassAddWXMethods( self ); + + // On macOS 26 Tahoe, the mere presence of drawRect: in derived class, + // even if it just calls super's implementation, triggers legacy + // rendering of NSTabView. +#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_26_0 + if (WX_IS_MACOS_AVAILABLE(26, 0)) + { + wxOSXCocoaClassAddWXMethods(self, wxOSXSKIP_DRAW); + } + else +#endif + { + wxOSXCocoaClassAddWXMethods(self); + } } } diff --git a/src/osx/cocoa/textctrl.mm b/src/osx/cocoa/textctrl.mm index 21fa5bbe6c..a5694828d8 100644 --- a/src/osx/cocoa/textctrl.mm +++ b/src/osx/cocoa/textctrl.mm @@ -1746,6 +1746,14 @@ wxSize wxNSTextFieldControl::GetBestSize() const sz.x = (int)ceil(best.size.width); sz.y = (int)ceil(best.size.height); + // never be smaller than single-line NSMiniControlSize field: + sz.y = wxMax(sz.y, 16); + + // !!! Any changes to these adjustments must be mirrored in wxTextCtrl::DoGetSizeFromTextSize() !!! + + sz.x -= 4; + sz.y -= 2; + if ( [m_textField isBezeled] || [m_textField isBordered] ) { // since this will be added again in DoGetSizeFromTextSize diff --git a/src/osx/cocoa/window.mm b/src/osx/cocoa/window.mm index 92610cf467..777dfa077e 100644 --- a/src/osx/cocoa/window.mm +++ b/src/osx/cocoa/window.mm @@ -2606,7 +2606,9 @@ wxWidgetImpl( peer, flags ) if ( m_osxView ) CFRetain(m_osxView); [m_osxView release]; - m_osxView.clipsToBounds = YES; + + if ( IsUserPane() ) + ClipsToBounds(true); } @@ -4166,6 +4168,11 @@ void wxWidgetCocoaImpl::UseClippingView(bool clip) #endif } +void wxWidgetCocoaImpl::ClipsToBounds(bool clip) +{ + m_osxView.clipsToBounds = clip; +} + // // Factory methods diff --git a/src/osx/spinbutt_osx.cpp b/src/osx/spinbutt_osx.cpp index ec06f25e06..6e3181f44e 100644 --- a/src/osx/spinbutt_osx.cpp +++ b/src/osx/spinbutt_osx.cpp @@ -14,6 +14,7 @@ #include "wx/spinbutt.h" #include "wx/osx/private.h" +#include "wx/osx/private/available.h" wxSpinButton::wxSpinButton() @@ -81,7 +82,16 @@ bool wxSpinButton::OSXHandleClicked( double WXUNUSED(timestampsec) ) wxSize wxSpinButton::DoGetBestSize() const { - return wxSize( 16, 24 ); +#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_26_0 + if ( WX_IS_MACOS_AVAILABLE(26, 0) ) + { + return wxSize(21, 28); + } + else +#endif + { + return wxSize(13, 22); + } } void wxSpinButton::TriggerScrollEvent(wxEventType scrollEvent) diff --git a/src/osx/textctrl_osx.cpp b/src/osx/textctrl_osx.cpp index 354bec8d85..e783310631 100644 --- a/src/osx/textctrl_osx.cpp +++ b/src/osx/textctrl_osx.cpp @@ -42,6 +42,7 @@ #include "wx/thread.h" #include "wx/osx/private.h" +#include "wx/osx/private/available.h" wxBEGIN_EVENT_TABLE(wxTextCtrl, wxTextCtrlBase) EVT_DROP_FILES(wxTextCtrl::OnDropFiles) @@ -209,23 +210,25 @@ wxSize wxTextCtrl::DoGetSizeFromTextSize(int xlen, int ylen) const // these are the numbers from the HIG: switch ( m_windowVariant ) { - case wxWINDOW_VARIANT_NORMAL : - hText = 22; - break ; - case wxWINDOW_VARIANT_SMALL : hText = 19; break ; case wxWINDOW_VARIANT_MINI : - hText = 15; + hText = 16; break ; + case wxWINDOW_VARIANT_NORMAL : default : - hText = 22; + hText = 21; break ; } +#if __MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_26_0 + if ( WX_IS_MACOS_AVAILABLE(26, 0) ) + hText += 3; +#endif + // the numbers above include the border size, so subtract it before // possibly adding it back below hText -= TEXTCTRL_BORDER_SIZE; @@ -242,6 +245,8 @@ wxSize wxTextCtrl::DoGetSizeFromTextSize(int xlen, int ylen) const // has small positive xlen, therefore don't compare just with > 0 anymore wxSize size(xlen > TEXTCTRL_MAX_EMPTY_WIDTH ? xlen : 100, hText); + // !!! Any changes to these adjustments must be mirrored in wxNSTextFieldControl::GetBestSize() !!! + // Use extra margin size which works under macOS 10.15: note that we don't // need the vertical margin when using the automatically determined hText. if ( xlen > TEXTCTRL_MAX_EMPTY_WIDTH ) diff --git a/src/osx/window_osx.cpp b/src/osx/window_osx.cpp index da2055f49e..1f80c41af1 100644 --- a/src/osx/window_osx.cpp +++ b/src/osx/window_osx.cpp @@ -263,6 +263,12 @@ wxWindowMac::~wxWindowMac() delete GetPeer() ; } +void wxWindowMac::MacClipsToBounds( bool clip ) +{ + if ( m_peer ) + m_peer->ClipsToBounds(clip); +} + void wxWindowMac::MacSetClipChildren( bool clip ) { m_clipChildren = clip ; @@ -1071,13 +1077,6 @@ wxSize wxWindowMac::DoGetBestSize() const r.height = 16 ; } else -#endif -#if wxUSE_SPINBTN - if ( IsKindOf( CLASSINFO( wxSpinButton ) ) ) - { - r.height = 24 ; - } - else #endif { // return wxWindowBase::DoGetBestSize() ; @@ -2762,6 +2761,10 @@ void wxWidgetImpl::SetDrawingEnabled(bool WXUNUSED(enabled)) { } +void wxWidgetImpl::ClipsToBounds(bool WXUNUSED(clip)) +{ +} + void wxWidgetImpl::AdjustClippingView(wxScrollBar* WXUNUSED(horizontal), wxScrollBar* WXUNUSED(vertical)) { }