X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/f672c969519f7565cd80f85adeca5a6efdace8f5..ab67e8874db324fab5223cc8d5dff8a8de3e2b77:/src/osx/cocoa/button.mm diff --git a/src/osx/cocoa/button.mm b/src/osx/cocoa/button.mm index 8e25f09c48..df1e092402 100644 --- a/src/osx/cocoa/button.mm +++ b/src/osx/cocoa/button.mm @@ -4,18 +4,21 @@ // Author: Stefan Csomor // Modified by: // Created: 1998-01-01 -// RCS-ID: $Id: button.cpp 54845 2008-07-30 14:52:41Z SC $ +// RCS-ID: $Id$ // Copyright: (c) Stefan Csomor // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// #include "wx/wxprec.h" -#include "wx/button.h" - #ifndef WX_PRECOMP +#include "wx/object.h" #endif +#include "wx/button.h" +#include "wx/toplevel.h" +#include "wx/tglbtn.h" + #include "wx/osx/private.h" #if wxUSE_MARKUP @@ -23,36 +26,6 @@ #endif // wxUSE_MARKUP -wxSize wxButton::DoGetBestSize() const -{ - // We only use help button bezel if we don't have any (non standard) label - // to display in the button. Otherwise even wxID_HELP buttons look like - // normal push buttons. - if ( GetId() == wxID_HELP && GetLabel().empty() ) - return wxSize( 23 , 23 ) ; - - wxRect r ; - m_peer->GetBestRect(&r); - - wxSize sz = r.GetSize(); - sz.x = sz.x + MacGetLeftBorderSize() + - MacGetRightBorderSize(); - sz.y = sz.y + MacGetTopBorderSize() + - MacGetBottomBorderSize(); - - const int wBtnStd = GetDefaultSize().x; - - if ( (sz.x < wBtnStd) && !HasFlag(wxBU_EXACTFIT) ) - sz.x = wBtnStd; - - return sz ; -} - -wxSize wxButton::GetDefaultSize() -{ - return wxSize(84, 20); -} - @implementation wxNSButton + (void)initialize @@ -110,148 +83,231 @@ wxSize wxButton::GetDefaultSize() - (NSControlSize)controlSize; @end -namespace +wxButtonCocoaImpl::wxButtonCocoaImpl(wxWindowMac *wxpeer, wxNSButton *v) +: wxWidgetCocoaImpl(wxpeer, v) { + SetNeedsFrame(false); +} -class wxButtonCocoaImpl : public wxWidgetCocoaImpl, public wxButtonImpl +void wxButtonCocoaImpl::SetBitmap(const wxBitmap& bitmap) { -public: - wxButtonCocoaImpl(wxWindowMac *wxpeer, wxNSButton *v) - : wxWidgetCocoaImpl(wxpeer, v) + // switch bezel style for plain pushbuttons + if ( bitmap.IsOk() ) { + if ([GetNSButton() bezelStyle] == NSRoundedBezelStyle) + [GetNSButton() setBezelStyle:NSRegularSquareBezelStyle]; } - - virtual void SetBitmap(const wxBitmap& bitmap) + else { - // switch bezel style for plain pushbuttons - if ( bitmap.IsOk() && [GetNSButton() bezelStyle] == NSRoundedBezelStyle ) - [GetNSButton() setBezelStyle:NSRegularSquareBezelStyle ]; - - wxWidgetCocoaImpl::SetBitmap(bitmap); + [GetNSButton() setBezelStyle:NSRoundedBezelStyle]; } + + wxWidgetCocoaImpl::SetBitmap(bitmap); +} + +#if wxUSE_MARKUP +void wxButtonCocoaImpl::SetLabelMarkup(const wxString& markup) +{ + wxMarkupToAttrString toAttr(GetWXPeer(), markup); + NSMutableAttributedString *attrString = toAttr.GetNSAttributedString(); + + // Button text is always centered. + NSMutableParagraphStyle * + paragraphStyle = [[NSMutableParagraphStyle alloc] init]; + [paragraphStyle setAlignment: NSCenterTextAlignment]; + [attrString addAttribute:NSParagraphStyleAttributeName + value:paragraphStyle + range:NSMakeRange(0, [attrString length])]; + [paragraphStyle release]; + + [GetNSButton() setAttributedTitle:attrString]; +} +#endif // wxUSE_MARKUP - virtual void SetLabelMarkup(const wxString& markup) +void wxButtonCocoaImpl::SetPressedBitmap( const wxBitmap& bitmap ) +{ + NSButton* button = GetNSButton(); + [button setAlternateImage: bitmap.GetNSImage()]; + if ( GetWXPeer()->IsKindOf(wxCLASSINFO(wxToggleButton)) ) { - wxMarkupToAttrString toAttr(GetWXPeer(), markup); - NSMutableAttributedString *attrString = toAttr.GetNSAttributedString(); - - // Button text is always centered. - NSMutableParagraphStyle * - paragraphStyle = [[NSMutableParagraphStyle alloc] init]; - [paragraphStyle setAlignment: NSCenterTextAlignment]; - [attrString addAttribute:NSParagraphStyleAttributeName - value:paragraphStyle - range:NSMakeRange(0, [attrString length])]; - [paragraphStyle release]; - - [GetNSButton() setAttributedTitle:attrString]; + [button setButtonType:NSToggleButton]; } - - void SetPressedBitmap( const wxBitmap& bitmap ) + else { - NSButton* button = GetNSButton(); - [button setAlternateImage: bitmap.GetNSImage()]; [button setButtonType:NSMomentaryChangeButton]; } +} - void GetLayoutInset(int &left , int &top , int &right, int &bottom) const +void wxButtonCocoaImpl::GetLayoutInset(int &left , int &top , int &right, int &bottom) const +{ + left = top = right = bottom = 0; + NSControlSize size = NSRegularControlSize; + if ( [m_osxView respondsToSelector:@selector(controlSize)] ) + size = [m_osxView controlSize]; + else if ([m_osxView respondsToSelector:@selector(cell)]) { - left = top = right = bottom = 0; - NSControlSize size = NSRegularControlSize; - if ( [m_osxView respondsToSelector:@selector(controlSize)] ) - size = [m_osxView controlSize]; - else if ([m_osxView respondsToSelector:@selector(cell)]) - { - id cell = [(id)m_osxView cell]; - if ([cell respondsToSelector:@selector(controlSize)]) - size = [cell controlSize]; - } - - if ( [GetNSButton() bezelStyle] == NSRoundedBezelStyle ) - { - switch( size ) - { - case NSRegularControlSize: - left = right = 6; - top = 4; - bottom = 8; - break; - case NSSmallControlSize: - left = right = 5; - top = 4; - bottom = 7; - break; - case NSMiniControlSize: - left = right = 1; - top = 0; - bottom = 2; - break; - } - } + id cell = [(id)m_osxView cell]; + if ([cell respondsToSelector:@selector(controlSize)]) + size = [cell controlSize]; } - -private: - NSButton *GetNSButton() const + if ( [GetNSButton() bezelStyle] == NSRoundedBezelStyle ) { - wxASSERT( [m_osxView isKindOfClass:[NSButton class]] ); - - return static_cast(m_osxView); + switch( size ) + { + case NSRegularControlSize: + left = right = 6; + top = 4; + bottom = 8; + break; + case NSSmallControlSize: + left = right = 5; + top = 4; + bottom = 7; + break; + case NSMiniControlSize: + left = right = 1; + top = 0; + bottom = 2; + break; + } } -}; +} -} // anonymous namespace +void wxButtonCocoaImpl::SetAcceleratorFromLabel(const wxString& label) +{ + const int accelPos = wxControl::FindAccelIndex(label); + if ( accelPos != wxNOT_FOUND ) + { + wxString accelstring(label[accelPos + 1]); // Skip '&' itself + accelstring.MakeLower(); + wxCFStringRef cfText(accelstring); + [GetNSButton() setKeyEquivalent:cfText.AsNSString()]; + [GetNSButton() setKeyEquivalentModifierMask:NSCommandKeyMask]; + } + else + { + [GetNSButton() setKeyEquivalent:@""]; + } +} -extern "C" void SetBezelStyleFromBorderFlags(NSButton *v, long style); +NSButton *wxButtonCocoaImpl::GetNSButton() const +{ + wxASSERT( [m_osxView isKindOfClass:[NSButton class]] ); -// set bezel style depending on the wxBORDER_XXX flags specified by the style -void SetBezelStyleFromBorderFlags(NSButton *v, long style) + return static_cast(m_osxView); +} + +// Set bezel style depending on the wxBORDER_XXX flags specified by the style +// and also accounting for the label (bezels are different for multiline +// buttons and normal ones) and the ID (special bezel is used for help button). +// +// This is extern because it's also used in src/osx/cocoa/tglbtn.mm. +extern "C" +void +SetBezelStyleFromBorderFlags(NSButton *v, + long style, + wxWindowID winid, + const wxString& label = wxString(), + const wxBitmap& bitmap = wxBitmap()) { - if ( style & wxBORDER_NONE ) + // We can't display a custom label inside a button with help bezel style so + // we only use it if we are using the default label. wxButton itself checks + // if the label is just "Help" in which case it discards it and passes us + // an empty string. + if ( winid == wxID_HELP && label.empty() ) { - [v setBezelStyle:NSShadowlessSquareBezelStyle]; - [v setBordered:NO]; + [v setBezelStyle:NSHelpButtonBezelStyle]; } - else // we do have a border + else { - // see trac #11128 for a thorough discussion - if ( (style & wxBORDER_MASK) == wxBORDER_RAISED ) - [v setBezelStyle:NSRegularSquareBezelStyle]; - else if ( (style & wxBORDER_MASK) == wxBORDER_SUNKEN ) - [v setBezelStyle:NSSmallSquareBezelStyle]; - else - [v setBezelStyle:NSShadowlessSquareBezelStyle]; + // We can't use rounded bezel styles neither for multiline buttons nor + // for buttons containing (big) icons as they are only meant to be used + // at certain sizes, so the style used depends on whether the label is + // single or multi line. + const bool + isSimpleText = (label.find_first_of("\n\r") == wxString::npos) + && (!bitmap.IsOk() || bitmap.GetHeight() < 20); + + NSBezelStyle bezel; + switch ( style & wxBORDER_MASK ) + { + case wxBORDER_NONE: + bezel = NSShadowlessSquareBezelStyle; + [v setBordered:NO]; + break; + + case wxBORDER_SIMPLE: + bezel = NSShadowlessSquareBezelStyle; + break; + + case wxBORDER_SUNKEN: + bezel = isSimpleText ? NSTexturedRoundedBezelStyle + : NSSmallSquareBezelStyle; + break; + + default: + wxFAIL_MSG( "Unknown border style" ); + // fall through + + case 0: + case wxBORDER_STATIC: + case wxBORDER_RAISED: + case wxBORDER_THEME: + bezel = isSimpleText ? NSRoundedBezelStyle + : NSRegularSquareBezelStyle; + break; + } + + [v setBezelStyle:bezel]; + } +} + +// Set the keyboard accelerator key from the label (e.g. "Click &Me") +void wxButton::OSXUpdateAfterLabelChange(const wxString& label) +{ + wxButtonCocoaImpl *impl = static_cast(GetPeer()); + + // Update the bezel style as may be necessary if our new label is multi + // line while the old one wasn't (or vice versa). + SetBezelStyleFromBorderFlags(impl->GetNSButton(), + GetWindowStyle(), + GetId(), + label); + + + // Skip setting the accelerator for the default buttons as this would + // overwrite the default "Enter" which should be preserved. + wxTopLevelWindow * const + tlw = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow); + if ( tlw ) + { + if ( tlw->GetDefaultItem() == this ) + return; } + + impl->SetAcceleratorFromLabel(label); } wxWidgetImplType* wxWidgetImpl::CreateButton( wxWindowMac* wxpeer, wxWindowMac* WXUNUSED(parent), - wxWindowID id, + wxWindowID winid, const wxString& label, const wxPoint& pos, const wxSize& size, - long WXUNUSED(style), + long style, long WXUNUSED(extraStyle)) { NSRect r = wxOSXGetFrameForControl( wxpeer, pos , size ) ; wxNSButton* v = [[wxNSButton alloc] initWithFrame:r]; - // We can't display a custom label inside a button with help bezel style so - // we only use it if we are using the default label. wxButton itself checks - // if the label is just "Help" in which case it discards it and passes us - // an empty string. - if ( id == wxID_HELP && label.empty() ) - { - [v setBezelStyle:NSHelpButtonBezelStyle]; - } - else - { - [v setBezelStyle:NSRoundedBezelStyle]; - } + SetBezelStyleFromBorderFlags(v, style, winid, label); [v setButtonType:NSMomentaryPushInButton]; - return new wxButtonCocoaImpl( wxpeer, v ); + wxButtonCocoaImpl* const impl = new wxButtonCocoaImpl( wxpeer, v ); + impl->SetAcceleratorFromLabel(label); + return impl; } void wxWidgetCocoaImpl::SetDefaultButton( bool isDefault ) @@ -259,7 +315,10 @@ void wxWidgetCocoaImpl::SetDefaultButton( bool isDefault ) if ( [m_osxView isKindOfClass:[NSButton class]] ) { if ( isDefault ) + { [(NSButton*)m_osxView setKeyEquivalent: @"\r" ]; + [(NSButton*)m_osxView setKeyEquivalentModifierMask: 0]; + } else [(NSButton*)m_osxView setKeyEquivalent: @"" ]; } @@ -275,7 +334,7 @@ void wxWidgetCocoaImpl::PerformClick() wxWidgetImplType* wxWidgetImpl::CreateBitmapButton( wxWindowMac* wxpeer, wxWindowMac* WXUNUSED(parent), - wxWindowID WXUNUSED(id), + wxWindowID winid, const wxBitmap& bitmap, const wxPoint& pos, const wxSize& size, @@ -285,9 +344,9 @@ wxWidgetImplType* wxWidgetImpl::CreateBitmapButton( wxWindowMac* wxpeer, NSRect r = wxOSXGetFrameForControl( wxpeer, pos , size ) ; wxNSButton* v = [[wxNSButton alloc] initWithFrame:r]; - SetBezelStyleFromBorderFlags(v, style); + SetBezelStyleFromBorderFlags(v, style, winid, wxString(), bitmap); - if (bitmap.Ok()) + if (bitmap.IsOk()) [v setImage:bitmap.GetNSImage() ]; [v setButtonType:NSMomentaryPushInButton]; @@ -377,7 +436,7 @@ wxCFRef downArray ; static wxBitmap trianglebm(disc_triangle_xpm); if ( downArray.get() == NULL ) { - downArray.reset( [wxDisclosureNSButton rotateImage:trianglebm.GetNSImage()] ); + downArray.reset( [[wxDisclosureNSButton rotateImage:trianglebm.GetNSImage()] retain] ); } if ( isOpen ) @@ -405,7 +464,7 @@ wxCFRef downArray ; fromRect:NSZeroRect operation:NSCompositeCopy fraction:1.0]; [newImage unlockFocus]; - return newImage; + return [newImage autorelease]; } @end @@ -432,7 +491,7 @@ public : wxWidgetImplType* wxWidgetImpl::CreateDisclosureTriangle( wxWindowMac* wxpeer, wxWindowMac* WXUNUSED(parent), - wxWindowID WXUNUSED(winid), + wxWindowID winid, const wxString& label, const wxPoint& pos, const wxSize& size, @@ -444,7 +503,7 @@ wxWidgetImplType* wxWidgetImpl::CreateDisclosureTriangle( wxWindowMac* wxpeer, if ( !label.empty() ) [v setTitle:wxCFStringRef(label).AsNSString()]; - SetBezelStyleFromBorderFlags(v, style); + SetBezelStyleFromBorderFlags(v, style, winid, label); return new wxDisclosureTriangleCocoaImpl( wxpeer, v ); }