]> git.saurik.com Git - wxWidgets.git/blob - src/osx/cocoa/button.mm
8e25f09c48e46210cfa193ca8e53d737a0ade4f4
[wxWidgets.git] / src / osx / cocoa / button.mm
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/cocoa/button.mm
3 // Purpose: wxButton
4 // Author: Stefan Csomor
5 // Modified by:
6 // Created: 1998-01-01
7 // RCS-ID: $Id: button.cpp 54845 2008-07-30 14:52:41Z SC $
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #include "wx/wxprec.h"
13
14 #include "wx/button.h"
15
16 #ifndef WX_PRECOMP
17 #endif
18
19 #include "wx/osx/private.h"
20
21 #if wxUSE_MARKUP
22 #include "wx/osx/cocoa/private/markuptoattr.h"
23 #endif // wxUSE_MARKUP
24
25
26 wxSize wxButton::DoGetBestSize() const
27 {
28 // We only use help button bezel if we don't have any (non standard) label
29 // to display in the button. Otherwise even wxID_HELP buttons look like
30 // normal push buttons.
31 if ( GetId() == wxID_HELP && GetLabel().empty() )
32 return wxSize( 23 , 23 ) ;
33
34 wxRect r ;
35 m_peer->GetBestRect(&r);
36
37 wxSize sz = r.GetSize();
38 sz.x = sz.x + MacGetLeftBorderSize() +
39 MacGetRightBorderSize();
40 sz.y = sz.y + MacGetTopBorderSize() +
41 MacGetBottomBorderSize();
42
43 const int wBtnStd = GetDefaultSize().x;
44
45 if ( (sz.x < wBtnStd) && !HasFlag(wxBU_EXACTFIT) )
46 sz.x = wBtnStd;
47
48 return sz ;
49 }
50
51 wxSize wxButton::GetDefaultSize()
52 {
53 return wxSize(84, 20);
54 }
55
56 @implementation wxNSButton
57
58 + (void)initialize
59 {
60 static BOOL initialized = NO;
61 if (!initialized)
62 {
63 initialized = YES;
64 wxOSXCocoaClassAddWXMethods( self );
65 }
66 }
67
68 - (int) intValue
69 {
70 switch ( [self state] )
71 {
72 case NSOnState:
73 return 1;
74 case NSMixedState:
75 return 2;
76 default:
77 return 0;
78 }
79 }
80
81 - (void) setIntValue: (int) v
82 {
83 switch( v )
84 {
85 case 2:
86 [self setState:NSMixedState];
87 break;
88 case 1:
89 [self setState:NSOnState];
90 break;
91 default :
92 [self setState:NSOffState];
93 break;
94 }
95 }
96
97 - (void) setTrackingTag: (NSTrackingRectTag)tag
98 {
99 rectTag = tag;
100 }
101
102 - (NSTrackingRectTag) trackingTag
103 {
104 return rectTag;
105 }
106
107 @end
108
109 @interface NSView(PossibleSizeMethods)
110 - (NSControlSize)controlSize;
111 @end
112
113 namespace
114 {
115
116 class wxButtonCocoaImpl : public wxWidgetCocoaImpl, public wxButtonImpl
117 {
118 public:
119 wxButtonCocoaImpl(wxWindowMac *wxpeer, wxNSButton *v)
120 : wxWidgetCocoaImpl(wxpeer, v)
121 {
122 }
123
124 virtual void SetBitmap(const wxBitmap& bitmap)
125 {
126 // switch bezel style for plain pushbuttons
127 if ( bitmap.IsOk() && [GetNSButton() bezelStyle] == NSRoundedBezelStyle )
128 [GetNSButton() setBezelStyle:NSRegularSquareBezelStyle ];
129
130 wxWidgetCocoaImpl::SetBitmap(bitmap);
131 }
132
133 virtual void SetLabelMarkup(const wxString& markup)
134 {
135 wxMarkupToAttrString toAttr(GetWXPeer(), markup);
136 NSMutableAttributedString *attrString = toAttr.GetNSAttributedString();
137
138 // Button text is always centered.
139 NSMutableParagraphStyle *
140 paragraphStyle = [[NSMutableParagraphStyle alloc] init];
141 [paragraphStyle setAlignment: NSCenterTextAlignment];
142 [attrString addAttribute:NSParagraphStyleAttributeName
143 value:paragraphStyle
144 range:NSMakeRange(0, [attrString length])];
145 [paragraphStyle release];
146
147 [GetNSButton() setAttributedTitle:attrString];
148 }
149
150 void SetPressedBitmap( const wxBitmap& bitmap )
151 {
152 NSButton* button = GetNSButton();
153 [button setAlternateImage: bitmap.GetNSImage()];
154 [button setButtonType:NSMomentaryChangeButton];
155 }
156
157 void GetLayoutInset(int &left , int &top , int &right, int &bottom) const
158 {
159 left = top = right = bottom = 0;
160 NSControlSize size = NSRegularControlSize;
161 if ( [m_osxView respondsToSelector:@selector(controlSize)] )
162 size = [m_osxView controlSize];
163 else if ([m_osxView respondsToSelector:@selector(cell)])
164 {
165 id cell = [(id)m_osxView cell];
166 if ([cell respondsToSelector:@selector(controlSize)])
167 size = [cell controlSize];
168 }
169
170 if ( [GetNSButton() bezelStyle] == NSRoundedBezelStyle )
171 {
172 switch( size )
173 {
174 case NSRegularControlSize:
175 left = right = 6;
176 top = 4;
177 bottom = 8;
178 break;
179 case NSSmallControlSize:
180 left = right = 5;
181 top = 4;
182 bottom = 7;
183 break;
184 case NSMiniControlSize:
185 left = right = 1;
186 top = 0;
187 bottom = 2;
188 break;
189 }
190 }
191 }
192
193
194 private:
195 NSButton *GetNSButton() const
196 {
197 wxASSERT( [m_osxView isKindOfClass:[NSButton class]] );
198
199 return static_cast<NSButton *>(m_osxView);
200 }
201 };
202
203 } // anonymous namespace
204
205 extern "C" void SetBezelStyleFromBorderFlags(NSButton *v, long style);
206
207 // set bezel style depending on the wxBORDER_XXX flags specified by the style
208 void SetBezelStyleFromBorderFlags(NSButton *v, long style)
209 {
210 if ( style & wxBORDER_NONE )
211 {
212 [v setBezelStyle:NSShadowlessSquareBezelStyle];
213 [v setBordered:NO];
214 }
215 else // we do have a border
216 {
217 // see trac #11128 for a thorough discussion
218 if ( (style & wxBORDER_MASK) == wxBORDER_RAISED )
219 [v setBezelStyle:NSRegularSquareBezelStyle];
220 else if ( (style & wxBORDER_MASK) == wxBORDER_SUNKEN )
221 [v setBezelStyle:NSSmallSquareBezelStyle];
222 else
223 [v setBezelStyle:NSShadowlessSquareBezelStyle];
224 }
225 }
226
227
228 wxWidgetImplType* wxWidgetImpl::CreateButton( wxWindowMac* wxpeer,
229 wxWindowMac* WXUNUSED(parent),
230 wxWindowID id,
231 const wxString& label,
232 const wxPoint& pos,
233 const wxSize& size,
234 long WXUNUSED(style),
235 long WXUNUSED(extraStyle))
236 {
237 NSRect r = wxOSXGetFrameForControl( wxpeer, pos , size ) ;
238 wxNSButton* v = [[wxNSButton alloc] initWithFrame:r];
239
240 // We can't display a custom label inside a button with help bezel style so
241 // we only use it if we are using the default label. wxButton itself checks
242 // if the label is just "Help" in which case it discards it and passes us
243 // an empty string.
244 if ( id == wxID_HELP && label.empty() )
245 {
246 [v setBezelStyle:NSHelpButtonBezelStyle];
247 }
248 else
249 {
250 [v setBezelStyle:NSRoundedBezelStyle];
251 }
252
253 [v setButtonType:NSMomentaryPushInButton];
254 return new wxButtonCocoaImpl( wxpeer, v );
255 }
256
257 void wxWidgetCocoaImpl::SetDefaultButton( bool isDefault )
258 {
259 if ( [m_osxView isKindOfClass:[NSButton class]] )
260 {
261 if ( isDefault )
262 [(NSButton*)m_osxView setKeyEquivalent: @"\r" ];
263 else
264 [(NSButton*)m_osxView setKeyEquivalent: @"" ];
265 }
266 }
267
268 void wxWidgetCocoaImpl::PerformClick()
269 {
270 if ([m_osxView isKindOfClass:[NSControl class]])
271 [(NSControl*)m_osxView performClick:nil];
272 }
273
274 #if wxUSE_BMPBUTTON
275
276 wxWidgetImplType* wxWidgetImpl::CreateBitmapButton( wxWindowMac* wxpeer,
277 wxWindowMac* WXUNUSED(parent),
278 wxWindowID WXUNUSED(id),
279 const wxBitmap& bitmap,
280 const wxPoint& pos,
281 const wxSize& size,
282 long style,
283 long WXUNUSED(extraStyle))
284 {
285 NSRect r = wxOSXGetFrameForControl( wxpeer, pos , size ) ;
286 wxNSButton* v = [[wxNSButton alloc] initWithFrame:r];
287
288 SetBezelStyleFromBorderFlags(v, style);
289
290 if (bitmap.Ok())
291 [v setImage:bitmap.GetNSImage() ];
292
293 [v setButtonType:NSMomentaryPushInButton];
294 wxWidgetCocoaImpl* c = new wxButtonCocoaImpl( wxpeer, v );
295 return c;
296 }
297
298 #endif // wxUSE_BMPBUTTON
299
300 //
301 // wxDisclosureButton implementation
302 //
303
304 @interface wxDisclosureNSButton : NSButton
305 {
306
307 BOOL isOpen;
308 }
309
310 - (void) updateImage;
311
312 - (void) toggle;
313
314 + (NSImage *)rotateImage: (NSImage *)image;
315
316 @end
317
318 static const char * disc_triangle_xpm[] = {
319 "10 9 4 1",
320 " c None",
321 ". c #737373",
322 "+ c #989898",
323 "- c #c6c6c6",
324 " .- ",
325 " ..+- ",
326 " ....+ ",
327 " ......- ",
328 " .......- ",
329 " ......- ",
330 " ....+ ",
331 " ..+- ",
332 " .- ",
333 };
334
335 @implementation wxDisclosureNSButton
336
337 + (void)initialize
338 {
339 static BOOL initialized = NO;
340 if (!initialized)
341 {
342 initialized = YES;
343 wxOSXCocoaClassAddWXMethods( self );
344 }
345 }
346
347 - (id) initWithFrame:(NSRect) frame
348 {
349 self = [super initWithFrame:frame];
350 isOpen = NO;
351 [self setImagePosition:NSImageLeft];
352 [self updateImage];
353 return self;
354 }
355
356 - (int) intValue
357 {
358 return isOpen ? 1 : 0;
359 }
360
361 - (void) setIntValue: (int) v
362 {
363 isOpen = ( v != 0 );
364 [self updateImage];
365 }
366
367 - (void) toggle
368 {
369 isOpen = !isOpen;
370 [self updateImage];
371 }
372
373 wxCFRef<NSImage*> downArray ;
374
375 - (void) updateImage
376 {
377 static wxBitmap trianglebm(disc_triangle_xpm);
378 if ( downArray.get() == NULL )
379 {
380 downArray.reset( [wxDisclosureNSButton rotateImage:trianglebm.GetNSImage()] );
381 }
382
383 if ( isOpen )
384 [self setImage:(NSImage*)downArray.get()];
385 else
386 [self setImage:trianglebm.GetNSImage()];
387 }
388
389 + (NSImage *)rotateImage: (NSImage *)image
390 {
391 NSSize imageSize = [image size];
392 NSSize newImageSize = NSMakeSize(imageSize.height, imageSize.width);
393 NSImage* newImage = [[NSImage alloc] initWithSize: newImageSize];
394
395 [newImage lockFocus];
396
397 NSAffineTransform* tm = [NSAffineTransform transform];
398 [tm translateXBy:newImageSize.width/2 yBy:newImageSize.height/2];
399 [tm rotateByDegrees:-90];
400 [tm translateXBy:-newImageSize.width/2 yBy:-newImageSize.height/2];
401 [tm concat];
402
403
404 [image drawInRect:NSMakeRect(0,0,newImageSize.width, newImageSize.height)
405 fromRect:NSZeroRect operation:NSCompositeCopy fraction:1.0];
406
407 [newImage unlockFocus];
408 return newImage;
409 }
410
411 @end
412
413 class wxDisclosureTriangleCocoaImpl : public wxWidgetCocoaImpl
414 {
415 public :
416 wxDisclosureTriangleCocoaImpl(wxWindowMac* peer , WXWidget w) :
417 wxWidgetCocoaImpl(peer, w)
418 {
419 }
420
421 ~wxDisclosureTriangleCocoaImpl()
422 {
423 }
424
425 virtual void controlAction(WXWidget slf, void* _cmd, void *sender)
426 {
427 wxDisclosureNSButton* db = (wxDisclosureNSButton*)m_osxView;
428 [db toggle];
429 wxWidgetCocoaImpl::controlAction(slf, _cmd, sender );
430 }
431 };
432
433 wxWidgetImplType* wxWidgetImpl::CreateDisclosureTriangle( wxWindowMac* wxpeer,
434 wxWindowMac* WXUNUSED(parent),
435 wxWindowID WXUNUSED(winid),
436 const wxString& label,
437 const wxPoint& pos,
438 const wxSize& size,
439 long style,
440 long WXUNUSED(extraStyle))
441 {
442 NSRect r = wxOSXGetFrameForControl( wxpeer, pos , size ) ;
443 wxDisclosureNSButton* v = [[wxDisclosureNSButton alloc] initWithFrame:r];
444 if ( !label.empty() )
445 [v setTitle:wxCFStringRef(label).AsNSString()];
446
447 SetBezelStyleFromBorderFlags(v, style);
448
449 return new wxDisclosureTriangleCocoaImpl( wxpeer, v );
450 }