X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/4850cc8b2e1037cd394806db4ddcf73868588a4c..128ad183497f48ce80eb077b168fe2423bdb2b23:/src/osx/cocoa/button.mm diff --git a/src/osx/cocoa/button.mm b/src/osx/cocoa/button.mm index 60c1c45bf4..d4560769be 100644 --- a/src/osx/cocoa/button.mm +++ b/src/osx/cocoa/button.mm @@ -14,149 +14,48 @@ #include "wx/button.h" #ifndef WX_PRECOMP - #include "wx/panel.h" - #include "wx/toplevel.h" - #include "wx/dcclient.h" #endif -#include "wx/stockitem.h" - #include "wx/osx/private.h" wxSize wxButton::DoGetBestSize() const { - if ( GetId() == wxID_HELP ) - return wxSize( 20 , 20 ) ; - - wxSize sz = GetDefaultSize() ; - - switch (GetWindowVariant()) - { - case wxWINDOW_VARIANT_NORMAL: - case wxWINDOW_VARIANT_LARGE: - sz.y = 23 ; - break; - - case wxWINDOW_VARIANT_SMALL: - sz.y = 17 ; - break; - - case wxWINDOW_VARIANT_MINI: - sz.y = 15 ; - break; - - default: - break; - } + // 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); - if ( r.GetWidth() == 0 && r.GetHeight() == 0 ) - { - } - sz.x = r.GetWidth(); - sz.y = r.GetHeight(); + wxSize sz = r.GetSize(); - int wBtn = 96; - - if ((wBtn > sz.x) || ( GetWindowStyle() & wxBU_EXACTFIT)) - sz.x = wBtn; - -#if wxOSX_USE_CARBON - Rect bestsize = { 0 , 0 , 0 , 0 } ; - m_peer->GetBestRect( &bestsize ) ; + const int wBtnStd = GetDefaultSize().x; - int wBtn; - if ( EmptyRect( &bestsize ) || ( GetWindowStyle() & wxBU_EXACTFIT) ) - { - Point bounds; - - ControlFontStyleRec controlFont; - OSStatus err = m_peer->GetData( kControlEntireControl, kControlFontStyleTag, &controlFont ); - verify_noerr( err ); - - wxCFStringRef str( m_label, GetFont().GetEncoding() ); - -#if wxOSX_USE_ATSU_TEXT - SInt16 baseline; - if ( m_font.MacGetThemeFontID() != kThemeCurrentPortFont ) - { - err = GetThemeTextDimensions( - (!m_label.empty() ? (CFStringRef)str : CFSTR(" ")), - m_font.MacGetThemeFontID(), kThemeStateActive, false, &bounds, &baseline ); - verify_noerr( err ); - } - else -#endif - { - wxClientDC dc(const_cast(this)); - wxCoord width, height ; - dc.GetTextExtent( m_label , &width, &height); - bounds.h = width; - bounds.v = height; - } - - wBtn = bounds.h + sz.y; - } - else - { - wBtn = bestsize.right - bestsize.left ; - // non 'normal' window variants don't return the correct height - // sz.y = bestsize.bottom - bestsize.top ; - } - if ((wBtn > sz.x) || ( GetWindowStyle() & wxBU_EXACTFIT)) - sz.x = wBtn; -#endif + if ( (sz.x < wBtnStd) && !HasFlag(wxBU_EXACTFIT) ) + sz.x = wBtnStd; return sz ; } wxSize wxButton::GetDefaultSize() { - int wBtn = 70 ; - int hBtn = 20 ; - - return wxSize(wBtn, hBtn); + return wxSize(84, 23); } @implementation wxNSButton -- (id)initWithFrame:(NSRect)frame ++ (void)initialize { - [super initWithFrame:frame]; - impl = NULL; - [self setTarget: self]; - [self setAction: @selector(clickedAction:)]; - return self; -} - -- (void) clickedAction: (id) sender -{ - if ( impl ) + static BOOL initialized = NO; + if (!initialized) { - wxWindow* wxpeer = (wxWindow*) impl->GetWXPeer(); - if ( wxpeer ) - wxpeer->HandleClicked(0); + initialized = YES; + wxOSXCocoaClassAddWXMethods( self ); } } -- (void)setImplementation: (wxWidgetCocoaImpl *) theImplementation -{ - impl = theImplementation; -} - -- (wxWidgetCocoaImpl*) implementation -{ - return impl; -} - -- (BOOL) isFlipped -{ - return YES; -} - - (int) intValue { switch ( [self state] ) @@ -186,22 +85,95 @@ wxSize wxButton::GetDefaultSize() } } +- (void) setTrackingTag: (NSTrackingRectTag)tag +{ + rectTag = tag; +} + +- (NSTrackingRectTag) trackingTag +{ + return rectTag; +} + @end +namespace +{ + +class wxButtonCocoaImpl : public wxWidgetCocoaImpl, public wxButtonImpl +{ +public: + wxButtonCocoaImpl(wxWindowMac *wxpeer, wxNSButton *v) + : wxWidgetCocoaImpl(wxpeer, v) + { + } + + virtual void SetBitmap(const wxBitmap& bitmap) + { + // switch bezel style for plain pushbuttons + if ( bitmap.IsOk() && [GetNSButton() bezelStyle] == NSRoundedBezelStyle ) + [GetNSButton() setBezelStyle:NSRegularSquareBezelStyle ]; + + wxWidgetCocoaImpl::SetBitmap(bitmap); + } + + void SetPressedBitmap( const wxBitmap& bitmap ) + { + NSButton* button = GetNSButton(); + [button setAlternateImage: bitmap.GetNSImage()]; + [button setButtonType:NSMomentaryChangeButton]; + } -wxWidgetImplType* wxWidgetImpl::CreateButton( wxWindowMac* wxpeer, - wxWindowMac* parent, - wxWindowID id, +private: + NSButton *GetNSButton() const + { + wxASSERT( [m_osxView isKindOfClass:[NSButton class]] ); + + return static_cast(m_osxView); + } +}; + +extern "C" void SetBezelStyleFromBorderFlags(NSButton *v, long style); + +// set bezel style depending on the wxBORDER_XXX flags specified by the style +void SetBezelStyleFromBorderFlags(NSButton *v, long style) +{ + if ( style & wxBORDER_NONE ) + { + [v setBezelStyle:NSShadowlessSquareBezelStyle]; + [v setBordered:NO]; + } + else // we do have a border + { + // 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]; + } +} + +} // anonymous namespace + +wxWidgetImplType* wxWidgetImpl::CreateButton( wxWindowMac* wxpeer, + wxWindowMac* WXUNUSED(parent), + wxWindowID id, const wxString& label, - const wxPoint& pos, + const wxPoint& pos, const wxSize& size, - long style, - long extraStyle) + long WXUNUSED(style), + long WXUNUSED(extraStyle)) { NSRect r = wxOSXGetFrameForControl( wxpeer, pos , size ) ; wxNSButton* v = [[wxNSButton alloc] initWithFrame:r]; - - if ( id == wxID_HELP ) + + // 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]; } @@ -209,88 +181,199 @@ wxWidgetImplType* wxWidgetImpl::CreateButton( wxWindowMac* wxpeer, { [v setBezelStyle:NSRoundedBezelStyle]; } - + [v setButtonType:NSMomentaryPushInButton]; - wxWidgetCocoaImpl* c = new wxWidgetCocoaImpl( wxpeer, v ); - [v setImplementation:c]; + return new wxButtonCocoaImpl( wxpeer, v ); +} + +void wxWidgetCocoaImpl::SetDefaultButton( bool isDefault ) +{ + if ( isDefault && [m_osxView isKindOfClass:[NSButton class]] ) + // NOTE: setKeyEquivalent: nil will trigger an assert + // instead do not call in that case. + [(NSButton*)m_osxView setKeyEquivalent: @"\r" ]; +} + +void wxWidgetCocoaImpl::PerformClick() +{ + if ([m_osxView isKindOfClass:[NSControl class]]) + [(NSControl*)m_osxView performClick:nil]; +} + +#if wxUSE_BMPBUTTON + +wxWidgetImplType* wxWidgetImpl::CreateBitmapButton( wxWindowMac* wxpeer, + wxWindowMac* WXUNUSED(parent), + wxWindowID WXUNUSED(id), + const wxBitmap& bitmap, + const wxPoint& pos, + const wxSize& size, + long style, + long WXUNUSED(extraStyle)) +{ + NSRect r = wxOSXGetFrameForControl( wxpeer, pos , size ) ; + wxNSButton* v = [[wxNSButton alloc] initWithFrame:r]; + + SetBezelStyleFromBorderFlags(v, style); + + if (bitmap.Ok()) + [v setImage:bitmap.GetNSImage() ]; + + [v setButtonType:NSMomentaryPushInButton]; + wxWidgetCocoaImpl* c = new wxButtonCocoaImpl( wxpeer, v ); return c; -/* - OSStatus err; - Rect bounds = wxMacGetBoundsForControl( wxpeer , pos , size ) ; - wxMacControl* peer = new wxMacControl(wxpeer) ; - if ( id == wxID_HELP ) +} + +#endif // wxUSE_BMPBUTTON + +// +// wxDisclosureButton implementation +// + +@interface wxDisclosureNSButton : NSButton +{ + + BOOL isOpen; +} + +- (void) updateImage; + +- (void) toggle; + ++ (NSImage *)rotateImage: (NSImage *)image; + +@end + +static const char * disc_triangle_xpm[] = { +"10 9 4 1", +" c None", +". c #737373", +"+ c #989898", +"- c #c6c6c6", +" .- ", +" ..+- ", +" ....+ ", +" ......- ", +" .......- ", +" ......- ", +" ....+ ", +" ..+- ", +" .- ", +}; + +@implementation wxDisclosureNSButton + ++ (void)initialize +{ + static BOOL initialized = NO; + if (!initialized) { - ControlButtonContentInfo info ; - info.contentType = kControlContentIconRef ; - GetIconRef(kOnSystemDisk, kSystemIconsCreator, kHelpIcon, &info.u.iconRef); - err = CreateRoundButtonControl( - MAC_WXHWND(parent->MacGetTopLevelWindowRef()), - &bounds, kControlRoundButtonNormalSize, - &info, peer->GetControlRefAddr() ); + initialized = YES; + wxOSXCocoaClassAddWXMethods( self ); } - else if ( label.Find('\n' ) == wxNOT_FOUND && label.Find('\r' ) == wxNOT_FOUND) +} + +- (id) initWithFrame:(NSRect) frame +{ + self = [super initWithFrame:frame]; + isOpen = NO; + [self setImagePosition:NSImageLeft]; + [self updateImage]; + return self; +} + +- (int) intValue +{ + return isOpen ? 1 : 0; +} + +- (void) setIntValue: (int) v +{ + isOpen = ( v != 0 ); + [self updateImage]; +} + +- (void) toggle +{ + isOpen = !isOpen; + [self updateImage]; +} + +wxCFRef downArray ; + +- (void) updateImage +{ + static wxBitmap trianglebm(disc_triangle_xpm); + if ( downArray.get() == NULL ) { - // Button height is static in Mac, can't be changed, so we need to force it here - int maxHeight; - switch (wxpeer->GetWindowVariant() ) - { - case wxWINDOW_VARIANT_NORMAL: - case wxWINDOW_VARIANT_LARGE: - maxHeight = 20 ; - break; - case wxWINDOW_VARIANT_SMALL: - maxHeight = 17; - case wxWINDOW_VARIANT_MINI: - maxHeight = 15; - default: - break; - } - bounds.bottom = bounds.top + maxHeight ; - wxpeer->SetMaxSize( wxSize( wxpeer->GetMaxWidth() , maxHeight )); - err = CreatePushButtonControl( - MAC_WXHWND(parent->MacGetTopLevelWindowRef()), - &bounds, CFSTR(""), peer->GetControlRefAddr() ); + downArray.reset( [wxDisclosureNSButton rotateImage:trianglebm.GetNSImage()] ); } + + if ( isOpen ) + [self setImage:(NSImage*)downArray.get()]; else - { - ControlButtonContentInfo info ; - info.contentType = kControlNoContent ; - err = CreateBevelButtonControl( - MAC_WXHWND(parent->MacGetTopLevelWindowRef()) , &bounds, CFSTR(""), - kControlBevelButtonLargeBevel, kControlBehaviorPushbutton, - &info, 0, 0, 0, peer->GetControlRefAddr() ); - } - verify_noerr( err ); - return peer; - */ + [self setImage:trianglebm.GetNSImage()]; } -void wxWidgetCocoaImpl::SetDefaultButton( bool isDefault ) -{ - if ( [m_osxView isKindOfClass:[NSButton class]] ) - [(NSButton*)m_osxView setKeyEquivalent: isDefault ? @"\r" : nil ]; ++ (NSImage *)rotateImage: (NSImage *)image +{ + NSSize imageSize = [image size]; + NSSize newImageSize = NSMakeSize(imageSize.height, imageSize.width); + NSImage* newImage = [[NSImage alloc] initWithSize: newImageSize]; + + [newImage lockFocus]; + + NSAffineTransform* tm = [NSAffineTransform transform]; + [tm translateXBy:newImageSize.width/2 yBy:newImageSize.height/2]; + [tm rotateByDegrees:-90]; + [tm translateXBy:-newImageSize.width/2 yBy:-newImageSize.height/2]; + [tm concat]; + + + [image drawInRect:NSMakeRect(0,0,newImageSize.width, newImageSize.height) + fromRect:NSZeroRect operation:NSCompositeCopy fraction:1.0]; + + [newImage unlockFocus]; + return newImage; } -void wxWidgetCocoaImpl::PerformClick() +@end + +class wxDisclosureTriangleCocoaImpl : public wxWidgetCocoaImpl { -} +public : + wxDisclosureTriangleCocoaImpl(wxWindowMac* peer , WXWidget w) : + wxWidgetCocoaImpl(peer, w) + { + } + + ~wxDisclosureTriangleCocoaImpl() + { + } + + virtual void controlAction(WXWidget slf, void* _cmd, void *sender) + { + wxDisclosureNSButton* db = (wxDisclosureNSButton*)m_osxView; + [db toggle]; + wxWidgetCocoaImpl::controlAction(slf, _cmd, sender ); + } +}; -wxWidgetImplType* wxWidgetImpl::CreateDisclosureTriangle( wxWindowMac* wxpeer, - wxWindowMac* parent, - wxWindowID id, +wxWidgetImplType* wxWidgetImpl::CreateDisclosureTriangle( wxWindowMac* wxpeer, + wxWindowMac* WXUNUSED(parent), + wxWindowID WXUNUSED(winid), const wxString& label, - const wxPoint& pos, + const wxPoint& pos, const wxSize& size, - long style, - long extraStyle) + long style, + long WXUNUSED(extraStyle)) { NSRect r = wxOSXGetFrameForControl( wxpeer, pos , size ) ; - wxNSButton* v = [[wxNSButton alloc] initWithFrame:r]; - [v setBezelStyle:NSDisclosureBezelStyle]; - [v setButtonType:NSOnOffButton]; - [v setTitle:wxCFStringRef( label).AsNSString()]; - [v setImagePosition:NSImageRight]; - wxWidgetCocoaImpl* c = new wxWidgetCocoaImpl( wxpeer, v ); - [v setImplementation:c]; - return c; + wxDisclosureNSButton* v = [[wxDisclosureNSButton alloc] initWithFrame:r]; + if ( !label.empty() ) + [v setTitle:wxCFStringRef(label).AsNSString()]; + + SetBezelStyleFromBorderFlags(v, style); + + return new wxDisclosureTriangleCocoaImpl( wxpeer, v ); }