1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/cocoa/button.mm
4 // Author: Stefan Csomor
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 #include "wx/wxprec.h"
15 #include "wx/object.h"
18 #include "wx/button.h"
19 #include "wx/toplevel.h"
21 #include "wx/osx/private.h"
24 #include "wx/osx/cocoa/private/markuptoattr.h"
25 #endif // wxUSE_MARKUP
28 @implementation wxNSButton
32 static BOOL initialized = NO;
36 wxOSXCocoaClassAddWXMethods( self );
42 switch ( [self state] )
53 - (void) setIntValue: (int) v
58 [self setState:NSMixedState];
61 [self setState:NSOnState];
64 [self setState:NSOffState];
69 - (void) setTrackingTag: (NSTrackingRectTag)tag
74 - (NSTrackingRectTag) trackingTag
81 @interface NSView(PossibleSizeMethods)
82 - (NSControlSize)controlSize;
88 class wxButtonCocoaImpl : public wxWidgetCocoaImpl, public wxButtonImpl
91 wxButtonCocoaImpl(wxWindowMac *wxpeer, wxNSButton *v)
92 : wxWidgetCocoaImpl(wxpeer, v)
97 virtual void SetBitmap(const wxBitmap& bitmap)
99 // switch bezel style for plain pushbuttons
102 if ([GetNSButton() bezelStyle] == NSRoundedBezelStyle)
103 [GetNSButton() setBezelStyle:NSRegularSquareBezelStyle];
107 [GetNSButton() setBezelStyle:NSRoundedBezelStyle];
110 wxWidgetCocoaImpl::SetBitmap(bitmap);
114 virtual void SetLabelMarkup(const wxString& markup)
116 wxMarkupToAttrString toAttr(GetWXPeer(), markup);
117 NSMutableAttributedString *attrString = toAttr.GetNSAttributedString();
119 // Button text is always centered.
120 NSMutableParagraphStyle *
121 paragraphStyle = [[NSMutableParagraphStyle alloc] init];
122 [paragraphStyle setAlignment: NSCenterTextAlignment];
123 [attrString addAttribute:NSParagraphStyleAttributeName
125 range:NSMakeRange(0, [attrString length])];
126 [paragraphStyle release];
128 [GetNSButton() setAttributedTitle:attrString];
130 #endif // wxUSE_MARKUP
132 void SetPressedBitmap( const wxBitmap& bitmap )
134 NSButton* button = GetNSButton();
135 [button setAlternateImage: bitmap.GetNSImage()];
136 [button setButtonType:NSMomentaryChangeButton];
139 void GetLayoutInset(int &left , int &top , int &right, int &bottom) const
141 left = top = right = bottom = 0;
142 NSControlSize size = NSRegularControlSize;
143 if ( [m_osxView respondsToSelector:@selector(controlSize)] )
144 size = [m_osxView controlSize];
145 else if ([m_osxView respondsToSelector:@selector(cell)])
147 id cell = [(id)m_osxView cell];
148 if ([cell respondsToSelector:@selector(controlSize)])
149 size = [cell controlSize];
152 if ( [GetNSButton() bezelStyle] == NSRoundedBezelStyle )
156 case NSRegularControlSize:
161 case NSSmallControlSize:
166 case NSMiniControlSize:
175 void SetAcceleratorFromLabel(const wxString& label)
177 const int accelPos = wxControl::FindAccelIndex(label);
178 if ( accelPos != wxNOT_FOUND )
180 wxString accelstring(label[accelPos + 1]); // Skip '&' itself
181 accelstring.MakeLower();
182 wxCFStringRef cfText(accelstring);
183 [GetNSButton() setKeyEquivalent:cfText.AsNSString()];
184 [GetNSButton() setKeyEquivalentModifierMask:NSCommandKeyMask];
188 [GetNSButton() setKeyEquivalent:@""];
194 NSButton *GetNSButton() const
196 wxASSERT( [m_osxView isKindOfClass:[NSButton class]] );
198 return static_cast<NSButton *>(m_osxView);
202 } // anonymous namespace
204 // Set the keyboard accelerator key from the label (e.g. "Click &Me")
205 void wxButton::OSXSetAcceleratorFromLabel(const wxString& label)
207 // Skip setting the accelerator for the default buttons as this would
208 // overwrite the default "Enter" which should be preserved.
209 wxTopLevelWindow * const
210 tlw = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow);
213 if ( tlw->GetDefaultItem() == this )
217 wxButtonCocoaImpl *impl = static_cast<wxButtonCocoaImpl*>(GetPeer());
218 impl->SetAcceleratorFromLabel(label);
221 extern "C" void SetBezelStyleFromBorderFlags(NSButton *v, long style);
223 // set bezel style depending on the wxBORDER_XXX flags specified by the style
224 void SetBezelStyleFromBorderFlags(NSButton *v, long style)
226 if ( style & wxBORDER_NONE )
228 [v setBezelStyle:NSShadowlessSquareBezelStyle];
231 else // we do have a border
233 // see trac #11128 for a thorough discussion
234 if ( (style & wxBORDER_MASK) == wxBORDER_RAISED )
235 [v setBezelStyle:NSRegularSquareBezelStyle];
236 else if ( (style & wxBORDER_MASK) == wxBORDER_SUNKEN )
237 [v setBezelStyle:NSSmallSquareBezelStyle];
238 else if ( (style & wxBORDER_MASK) == wxBORDER_SIMPLE )
239 [v setBezelStyle:NSShadowlessSquareBezelStyle];
241 [v setBezelStyle:NSRegularSquareBezelStyle];
246 wxWidgetImplType* wxWidgetImpl::CreateButton( wxWindowMac* wxpeer,
247 wxWindowMac* WXUNUSED(parent),
249 const wxString& label,
253 long WXUNUSED(extraStyle))
255 NSRect r = wxOSXGetFrameForControl( wxpeer, pos , size ) ;
256 wxNSButton* v = [[wxNSButton alloc] initWithFrame:r];
258 // We can't display a custom label inside a button with help bezel style so
259 // we only use it if we are using the default label. wxButton itself checks
260 // if the label is just "Help" in which case it discards it and passes us
262 if ( id == wxID_HELP && label.empty() )
264 [v setBezelStyle:NSHelpButtonBezelStyle];
268 if ( style & wxBORDER_NONE )
270 [v setBezelStyle:NSShadowlessSquareBezelStyle];
275 // the following styles only exist for certain sizes, so avoid them for
277 if ( label.Find('\n' ) == wxNOT_FOUND && label.Find('\r' ) == wxNOT_FOUND)
279 if ( (style & wxBORDER_MASK) == wxBORDER_RAISED )
280 [v setBezelStyle:NSRoundedBezelStyle];
281 else if ( (style & wxBORDER_MASK) == wxBORDER_SUNKEN )
282 [v setBezelStyle:NSTexturedRoundedBezelStyle];
283 else if ( (style & wxBORDER_MASK) == wxBORDER_SIMPLE )
284 [v setBezelStyle:NSShadowlessSquareBezelStyle];
286 [v setBezelStyle:NSRoundedBezelStyle];
290 if ( (style & wxBORDER_MASK) == wxBORDER_RAISED )
291 [v setBezelStyle:NSRegularSquareBezelStyle];
292 else if ( (style & wxBORDER_MASK) == wxBORDER_SUNKEN )
293 [v setBezelStyle:NSSmallSquareBezelStyle];
294 else if ( (style & wxBORDER_MASK) == wxBORDER_SIMPLE )
295 [v setBezelStyle:NSShadowlessSquareBezelStyle];
297 [v setBezelStyle:NSRegularSquareBezelStyle];
303 [v setButtonType:NSMomentaryPushInButton];
304 wxButtonCocoaImpl* const impl = new wxButtonCocoaImpl( wxpeer, v );
305 impl->SetAcceleratorFromLabel(label);
309 void wxWidgetCocoaImpl::SetDefaultButton( bool isDefault )
311 if ( [m_osxView isKindOfClass:[NSButton class]] )
315 [(NSButton*)m_osxView setKeyEquivalent: @"\r" ];
316 [(NSButton*)m_osxView setKeyEquivalentModifierMask: 0];
319 [(NSButton*)m_osxView setKeyEquivalent: @"" ];
323 void wxWidgetCocoaImpl::PerformClick()
325 if ([m_osxView isKindOfClass:[NSControl class]])
326 [(NSControl*)m_osxView performClick:nil];
331 wxWidgetImplType* wxWidgetImpl::CreateBitmapButton( wxWindowMac* wxpeer,
332 wxWindowMac* WXUNUSED(parent),
333 wxWindowID WXUNUSED(id),
334 const wxBitmap& bitmap,
338 long WXUNUSED(extraStyle))
340 NSRect r = wxOSXGetFrameForControl( wxpeer, pos , size ) ;
341 wxNSButton* v = [[wxNSButton alloc] initWithFrame:r];
343 SetBezelStyleFromBorderFlags(v, style);
346 [v setImage:bitmap.GetNSImage() ];
348 [v setButtonType:NSMomentaryPushInButton];
349 wxWidgetCocoaImpl* c = new wxButtonCocoaImpl( wxpeer, v );
353 #endif // wxUSE_BMPBUTTON
356 // wxDisclosureButton implementation
359 @interface wxDisclosureNSButton : NSButton
365 - (void) updateImage;
369 + (NSImage *)rotateImage: (NSImage *)image;
373 static const char * disc_triangle_xpm[] = {
390 @implementation wxDisclosureNSButton
394 static BOOL initialized = NO;
398 wxOSXCocoaClassAddWXMethods( self );
402 - (id) initWithFrame:(NSRect) frame
404 self = [super initWithFrame:frame];
406 [self setImagePosition:NSImageLeft];
413 return isOpen ? 1 : 0;
416 - (void) setIntValue: (int) v
428 wxCFRef<NSImage*> downArray ;
432 static wxBitmap trianglebm(disc_triangle_xpm);
433 if ( downArray.get() == NULL )
435 downArray.reset( [[wxDisclosureNSButton rotateImage:trianglebm.GetNSImage()] retain] );
439 [self setImage:(NSImage*)downArray.get()];
441 [self setImage:trianglebm.GetNSImage()];
444 + (NSImage *)rotateImage: (NSImage *)image
446 NSSize imageSize = [image size];
447 NSSize newImageSize = NSMakeSize(imageSize.height, imageSize.width);
448 NSImage* newImage = [[NSImage alloc] initWithSize: newImageSize];
450 [newImage lockFocus];
452 NSAffineTransform* tm = [NSAffineTransform transform];
453 [tm translateXBy:newImageSize.width/2 yBy:newImageSize.height/2];
454 [tm rotateByDegrees:-90];
455 [tm translateXBy:-newImageSize.width/2 yBy:-newImageSize.height/2];
459 [image drawInRect:NSMakeRect(0,0,newImageSize.width, newImageSize.height)
460 fromRect:NSZeroRect operation:NSCompositeCopy fraction:1.0];
462 [newImage unlockFocus];
463 return [newImage autorelease];
468 class wxDisclosureTriangleCocoaImpl : public wxWidgetCocoaImpl
471 wxDisclosureTriangleCocoaImpl(wxWindowMac* peer , WXWidget w) :
472 wxWidgetCocoaImpl(peer, w)
476 ~wxDisclosureTriangleCocoaImpl()
480 virtual void controlAction(WXWidget slf, void* _cmd, void *sender)
482 wxDisclosureNSButton* db = (wxDisclosureNSButton*)m_osxView;
484 wxWidgetCocoaImpl::controlAction(slf, _cmd, sender );
488 wxWidgetImplType* wxWidgetImpl::CreateDisclosureTriangle( wxWindowMac* wxpeer,
489 wxWindowMac* WXUNUSED(parent),
490 wxWindowID WXUNUSED(winid),
491 const wxString& label,
495 long WXUNUSED(extraStyle))
497 NSRect r = wxOSXGetFrameForControl( wxpeer, pos , size ) ;
498 wxDisclosureNSButton* v = [[wxDisclosureNSButton alloc] initWithFrame:r];
499 if ( !label.empty() )
500 [v setTitle:wxCFStringRef(label).AsNSString()];
502 SetBezelStyleFromBorderFlags(v, style);
504 return new wxDisclosureTriangleCocoaImpl( wxpeer, v );