]> git.saurik.com Git - wxWidgets.git/blob - src/osx/cocoa/toolbar.mm
osx-cocoa updates
[wxWidgets.git] / src / osx / cocoa / toolbar.mm
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/carbon/toolbar.cpp
3 // Purpose: wxToolBar
4 // Author: Stefan Csomor
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id: toolbar.cpp 54954 2008-08-03 11:27:03Z VZ $
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #include "wx/wxprec.h"
13
14 #if wxUSE_TOOLBAR
15
16 #include "wx/toolbar.h"
17
18 #ifndef WX_PRECOMP
19 #include "wx/wx.h"
20 #endif
21
22 #include "wx/app.h"
23 #include "wx/osx/private.h"
24 #include "wx/geometry.h"
25 #include "wx/sysopt.h"
26
27 const short kwxMacToolBarToolDefaultWidth = 16;
28 const short kwxMacToolBarToolDefaultHeight = 16;
29 const short kwxMacToolBarTopMargin = 4;
30 const short kwxMacToolBarLeftMargin = 4;
31 const short kwxMacToolBorder = 0;
32 const short kwxMacToolSpacing = 6;
33
34 BEGIN_EVENT_TABLE(wxToolBar, wxToolBarBase)
35 EVT_PAINT( wxToolBar::OnPaint )
36 END_EVENT_TABLE()
37
38
39 #pragma mark -
40 #pragma mark Tool Implementation
41
42 #if wxOSX_USE_COCOA
43 #define wxOSX_USE_NATIVE_TOOLBAR 1
44 #endif
45
46 // ----------------------------------------------------------------------------
47 // private classes
48 // ----------------------------------------------------------------------------
49
50 // We have a dual implementation for each tool, WXWidget and NSToolbarItem*
51
52 // when embedding native controls in the native toolbar we must make sure the
53 // control does not get deleted behind our backs, so the retain count gets increased
54 // (after creation it is 1), first be the creation of the custom NSToolbarItem wrapper
55 // object, and second by the code 'creating' the custom HIView (which is the same as the
56 // already existing native control, therefore we just increase the ref count)
57 // when this view is removed from the native toolbar its count gets decremented again
58 // and when the HITooolbarItem wrapper object gets destroyed it is decremented as well
59 // so in the end the control lives with a refcount of one and can be disposed of by the
60 // wxControl code. For embedded controls on a non-native toolbar this ref count is less
61 // so we can only test against a range, not a specific value of the refcount.
62
63 class wxToolBarTool : public wxToolBarToolBase
64 {
65 public:
66 wxToolBarTool(
67 wxToolBar *tbar,
68 int id,
69 const wxString& label,
70 const wxBitmap& bmpNormal,
71 const wxBitmap& bmpDisabled,
72 wxItemKind kind,
73 wxObject *clientData,
74 const wxString& shortHelp,
75 const wxString& longHelp );
76
77 wxToolBarTool(wxToolBar *tbar, wxControl *control, const wxString& label)
78 : wxToolBarToolBase(tbar, control, label)
79 {
80 Init();
81 if (control != NULL)
82 SetControlHandle( (WXWidget) control->GetHandle() );
83 }
84
85 virtual ~wxToolBarTool()
86 {
87 ClearControl();
88 }
89
90 WXWidget GetControlHandle()
91 {
92 return (WXWidget) m_controlHandle;
93 }
94
95 void SetControlHandle( WXWidget handle )
96 {
97 m_controlHandle = handle;
98 }
99
100 void SetPosition( const wxPoint& position );
101
102 void ClearControl()
103 {
104 if ( m_controlHandle )
105 {
106 if ( !IsControl() )
107 {
108 [m_controlHandle retain];
109 }
110 else
111 {
112 // the embedded control is not under the responsibility of the tool, it gets disposed of in the
113 // proper wxControl destructor
114 }
115 m_controlHandle = NULL ;
116 }
117
118 #if wxOSX_USE_NATIVE_TOOLBAR
119 if ( m_toolbarItem )
120 {
121 [m_toolbarItem release];
122 m_toolbarItem = NULL;
123 }
124 #endif // wxOSX_USE_NATIVE_TOOLBAR
125 }
126
127 wxSize GetSize() const
128 {
129 wxSize curSize;
130
131 if ( IsControl() )
132 {
133 curSize = GetControl()->GetSize();
134 }
135 else if ( IsButton() )
136 {
137 curSize = GetToolBar()->GetToolSize();
138 }
139 else
140 {
141 // separator size
142 curSize = GetToolBar()->GetToolSize();
143 if ( GetToolBar()->GetWindowStyleFlag() & wxTB_VERTICAL )
144 curSize.y /= 4;
145 else
146 curSize.x /= 4;
147 }
148
149 return curSize;
150 }
151
152 wxPoint GetPosition() const
153 {
154 return wxPoint( m_x, m_y );
155 }
156
157 bool DoEnable( bool enable );
158
159 void UpdateImages();
160
161 void UpdateToggleImage( bool toggle );
162
163 void UpdateLabel()
164 {
165 if ( m_toolbarItem )
166 {
167 // strip mnemonics from the label for compatibility with the usual
168 // labels in wxStaticText sense
169 wxString labelStr = wxStripMenuCodes(m_label);
170 wxCFStringRef l(labelStr, GetToolBarFontEncoding());
171
172 [m_toolbarItem setLabel:l.AsNSString()];
173
174 wxCFStringRef sh( GetShortHelp(), GetToolBarFontEncoding() );
175 [m_toolbarItem setToolTip:sh.AsNSString()];
176 }
177 }
178
179 void Action()
180 {
181 wxToolBar *tbar = (wxToolBar*) GetToolBar();
182 if (CanBeToggled())
183 {
184 bool shouldToggle;
185
186 shouldToggle = !IsToggled();
187 tbar->ToggleTool( GetId(), shouldToggle );
188 }
189
190 tbar->OnLeftClick( GetId(), IsToggled() );
191 }
192
193 #if wxOSX_USE_NATIVE_TOOLBAR
194 void SetToolbarItemRef( NSToolbarItem* ref )
195 {
196 if ( m_controlHandle )
197 [m_controlHandle setHidden:YES];
198 if ( m_toolbarItem )
199 [m_toolbarItem release];
200
201 m_toolbarItem = ref;
202 }
203
204 NSToolbarItem* GetToolbarItemRef() const
205 {
206 return m_toolbarItem;
207 }
208
209 void SetIndex( CFIndex idx )
210 {
211 m_index = idx;
212 }
213
214 CFIndex GetIndex() const
215 {
216 return m_index;
217 }
218
219 virtual void SetLabel(const wxString& label)
220 {
221 wxToolBarToolBase::SetLabel(label);
222 UpdateLabel();
223 }
224 #endif // wxOSX_USE_NATIVE_TOOLBAR
225
226 private:
227 #if wxOSX_USE_NATIVE_TOOLBAR
228 wxFontEncoding GetToolBarFontEncoding() const
229 {
230 wxFont f;
231 if ( GetToolBar() )
232 f = GetToolBar()->GetFont();
233 return f.IsOk() ? f.GetEncoding() : wxFont::GetDefaultEncoding();
234 }
235 #endif // wxOSX_USE_NATIVE_TOOLBAR
236
237 void Init()
238 {
239 m_controlHandle = NULL;
240
241 #if wxOSX_USE_NATIVE_TOOLBAR
242 m_toolbarItem = NULL;
243 m_index = -1;
244 #endif
245 }
246
247 WXWidget m_controlHandle;
248 wxCoord m_x;
249 wxCoord m_y;
250 wxBitmap m_alternateBitmap;
251
252 #if wxOSX_USE_NATIVE_TOOLBAR
253 NSToolbarItem* m_toolbarItem;
254 // position in its toolbar, -1 means not inserted
255 CFIndex m_index;
256 #endif
257 };
258
259 @interface wxNSToolbarItem : NSToolbarItem
260 {
261 wxToolBarTool* impl;
262 }
263
264 - (id) initWithItemIdentifier: (NSString*) identifier;
265 - (void)setImplementation: (wxToolBarTool *) theImplementation;
266 - (wxToolBarTool*) implementation;
267 - (void) clickedAction: (id) sender;
268
269 @end
270
271
272 @interface wxNSToolbarDelegate : NSObject
273 {
274 }
275
276 - (NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag;
277
278 - (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar*)toolbar;
279
280 - (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar*)toolbar;
281
282 - (NSArray *)toolbarSelectableItemIdentifiers:(NSToolbar *)toolbar;
283
284
285 @end
286
287
288 @interface wxNSToolBarButton : NSButton
289 {
290 wxToolBarTool* impl;
291 }
292
293 - (id)initWithFrame:(NSRect)frame;
294 - (void) clickedAction: (id) sender;
295 - (void)setImplementation: (wxToolBarTool *) theImplementation;
296 - (wxToolBarTool*) implementation;
297 - (BOOL) isFlipped;
298
299 @end
300
301 @implementation wxNSToolbarItem
302
303 - (id)initWithItemIdentifier: (NSString*) identifier
304 {
305 [super initWithItemIdentifier:identifier];
306 impl = NULL;
307 [self setTarget: self];
308 [self setAction: @selector(clickedAction:)];
309 return self;
310 }
311
312 - (void) clickedAction: (id) sender
313 {
314 if ( impl )
315 {
316 impl->Action();
317 }
318 }
319
320 - (void)setImplementation: (wxToolBarTool *) theImplementation
321 {
322 impl = theImplementation;
323 }
324
325 - (wxToolBarTool*) implementation
326 {
327 return impl;
328 }
329
330 @end
331
332 @implementation wxNSToolbarDelegate
333
334 - (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar*)toolbar
335 {
336 return nil;
337 }
338
339 - (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar*)toolbar
340 {
341 return nil;
342 }
343
344 - (NSArray *)toolbarSelectableItemIdentifiers:(NSToolbar *)toolbar
345 {
346 return nil;
347 }
348
349 - (NSToolbarItem*) toolbar:(NSToolbar*) toolbar itemForItemIdentifier:(NSString*) itemIdentifier willBeInsertedIntoToolbar:(BOOL) flag
350 {
351 wxToolBarTool* tool = (wxToolBarTool*) [itemIdentifier intValue];
352 if ( tool )
353 {
354 wxNSToolbarItem* item = (wxNSToolbarItem*) tool->GetToolbarItemRef();
355 if ( flag && tool->IsControl() )
356 {
357 NSView* view = tool->GetControl()->GetHandle();
358 [view removeFromSuperview];
359 [item setView:view];
360 wxSize sz = tool->GetControl()->GetSize();
361 NSSize size = NSMakeSize((float)sz.x, (float)sz.y);
362 [item setMaxSize:size];
363 [item setMinSize:size];
364 [view setHidden:NO];
365 }
366 return item;
367 }
368 return nil;
369 }
370
371 @end
372
373 @implementation wxNSToolBarButton
374
375 - (id)initWithFrame:(NSRect)frame
376 {
377 [super initWithFrame:frame];
378 impl = NULL;
379 [self setTarget: self];
380 [self setAction: @selector(clickedAction:)];
381 return self;
382 }
383
384 - (void) clickedAction: (id) sender
385 {
386 if ( impl )
387 {
388 impl->Action();
389 }
390 }
391
392 - (void)setImplementation: (wxToolBarTool *) theImplementation
393 {
394 impl = theImplementation;
395 }
396
397 - (wxToolBarTool*) implementation
398 {
399 return impl;
400 }
401
402 - (BOOL) isFlipped
403 {
404 return YES;
405 }
406
407 @end
408
409 bool wxToolBarTool::DoEnable( bool enable )
410 {
411 if ( IsControl() )
412 {
413 GetControl()->Enable( enable );
414 }
415 else if ( IsButton() )
416 {
417 #if wxOSX_USE_NATIVE_TOOLBAR
418 if ( m_toolbarItem != NULL )
419 [m_toolbarItem setEnabled:enable];
420 #endif
421
422 if ( m_controlHandle != NULL )
423 [(NSControl*)m_controlHandle setEnabled:enable];
424 }
425
426 return true;
427 }
428
429 void wxToolBarTool::SetPosition( const wxPoint& position )
430 {
431 m_x = position.x;
432 m_y = position.y;
433
434 int mac_x = position.x;
435 int mac_y = position.y;
436
437 if ( IsButton() )
438 {
439 NSRect frame = [m_controlHandle frame];
440 if ( frame.origin.x != mac_x || frame.origin.y != mac_y )
441 {
442 frame.origin.x = mac_x;
443 frame.origin.y = mac_y;
444 [m_controlHandle setFrame:frame];
445 }
446 }
447 else if ( IsControl() )
448 {
449 // embedded native controls are moved by the OS
450 #if wxOSX_USE_NATIVE_TOOLBAR
451 if ( ((wxToolBar*)GetToolBar())->MacWantsNativeToolbar() == false )
452 #endif
453 {
454 GetControl()->Move( position );
455 }
456 }
457 else
458 {
459 NSRect frame = [m_controlHandle frame];
460 if ( frame.origin.x != mac_x || frame.origin.y != mac_y )
461 {
462 frame.origin.x = mac_x;
463 frame.origin.y = mac_y;
464 [m_controlHandle setFrame:frame];
465 }
466 }
467 }
468
469 void wxToolBarTool::UpdateImages()
470 {
471 [(NSButton*) m_controlHandle setImage:m_bmpNormal.GetNSImage()];
472
473 if ( CanBeToggled() )
474 {
475 int w = m_bmpNormal.GetWidth();
476 int h = m_bmpNormal.GetHeight();
477 m_alternateBitmap = wxBitmap( w, h );
478 wxMemoryDC dc;
479
480 dc.SelectObject( m_alternateBitmap );
481 dc.SetPen( wxPen(*wxBLACK) );
482 dc.SetBrush( wxBrush( *wxLIGHT_GREY ));
483 dc.DrawRectangle( 0, 0, w, h );
484 dc.DrawBitmap( m_bmpNormal, 0, 0, true );
485 dc.SelectObject( wxNullBitmap );
486
487 [(NSButton*) m_controlHandle setAlternateImage:m_alternateBitmap.GetNSImage()];
488 }
489 UpdateToggleImage( CanBeToggled() && IsToggled() );
490 }
491
492 void wxToolBarTool::UpdateToggleImage( bool toggle )
493 {
494 #if wxOSX_USE_NATIVE_TOOLBAR
495 if (m_toolbarItem != NULL )
496 {
497 // the native toolbar item only has a 'selected' state (one for one toolbar)
498 // so we emulate the toggle here
499 if ( CanBeToggled() && toggle )
500 [m_toolbarItem setImage:m_alternateBitmap.GetNSImage()];
501 else
502 [m_toolbarItem setImage:m_bmpNormal.GetNSImage()];
503 }
504 #endif
505 }
506
507 wxToolBarTool::wxToolBarTool(
508 wxToolBar *tbar,
509 int id,
510 const wxString& label,
511 const wxBitmap& bmpNormal,
512 const wxBitmap& bmpDisabled,
513 wxItemKind kind,
514 wxObject *clientData,
515 const wxString& shortHelp,
516 const wxString& longHelp )
517 :
518 wxToolBarToolBase(
519 tbar, id, label, bmpNormal, bmpDisabled, kind,
520 clientData, shortHelp, longHelp )
521 {
522 Init();
523 }
524
525 #pragma mark -
526 #pragma mark Toolbar Implementation
527
528 wxToolBarToolBase *wxToolBar::CreateTool(
529 int id,
530 const wxString& label,
531 const wxBitmap& bmpNormal,
532 const wxBitmap& bmpDisabled,
533 wxItemKind kind,
534 wxObject *clientData,
535 const wxString& shortHelp,
536 const wxString& longHelp )
537 {
538 return new wxToolBarTool(
539 this, id, label, bmpNormal, bmpDisabled, kind,
540 clientData, shortHelp, longHelp );
541 }
542
543 wxToolBarToolBase *
544 wxToolBar::CreateTool(wxControl *control, const wxString& label)
545 {
546 return new wxToolBarTool(this, control, label);
547 }
548
549 void wxToolBar::Init()
550 {
551 m_maxWidth = -1;
552 m_maxHeight = -1;
553 m_defaultWidth = kwxMacToolBarToolDefaultWidth;
554 m_defaultHeight = kwxMacToolBarToolDefaultHeight;
555
556 #if wxOSX_USE_NATIVE_TOOLBAR
557 m_macToolbar = NULL;
558 m_macUsesNativeToolbar = false;
559 #endif
560 }
561
562 // also for the toolbar we have the dual implementation:
563 // only when MacInstallNativeToolbar is called is the native toolbar set as the window toolbar
564
565 bool wxToolBar::Create(
566 wxWindow *parent,
567 wxWindowID id,
568 const wxPoint& pos,
569 const wxSize& size,
570 long style,
571 const wxString& name )
572 {
573 if ( !wxToolBarBase::Create( parent, id, pos, size, style, wxDefaultValidator, name ) )
574 return false;
575
576 FixupStyle();
577
578 OSStatus err = noErr;
579
580 #if wxOSX_USE_NATIVE_TOOLBAR
581
582 if (parent->IsKindOf(CLASSINFO(wxFrame)) && wxSystemOptions::GetOptionInt(wxT("mac.toolbar.no-native")) != 1)
583 {
584 static wxNSToolbarDelegate* controller = nil;
585
586 if ( controller == nil )
587 controller = [[wxNSToolbarDelegate alloc] init];
588 wxString identifier = wxString::Format( wxT("%p"), this );
589 wxCFStringRef cfidentifier(identifier);
590 NSToolbar* tb = [[NSToolbar alloc] initWithIdentifier:cfidentifier.AsNSString()];
591
592 m_macToolbar = tb ;
593
594 if (m_macToolbar != NULL)
595 {
596 [tb setDelegate:controller];
597
598 NSToolbarDisplayMode mode = NSToolbarDisplayModeDefault;
599 NSToolbarSizeMode displaySize = NSToolbarSizeModeSmall;
600
601 if ( style & wxTB_NOICONS )
602 mode = NSToolbarDisplayModeLabelOnly;
603 else if ( style & wxTB_TEXT )
604 mode = NSToolbarDisplayModeIconAndLabel;
605 else
606 mode = NSToolbarDisplayModeIconOnly;
607
608 [tb setDisplayMode:mode];
609 [tb setSizeMode:displaySize];
610 }
611 }
612 #endif // wxOSX_USE_NATIVE_TOOLBAR
613
614 return (err == noErr);
615 }
616
617 wxToolBar::~wxToolBar()
618 {
619 #if wxOSX_USE_NATIVE_TOOLBAR
620 if (m_macToolbar != NULL)
621 {
622 // if this is the installed toolbar, then deinstall it
623 if (m_macUsesNativeToolbar)
624 MacInstallNativeToolbar( false );
625
626 [(NSToolbar*)m_macToolbar release];
627 m_macToolbar = NULL;
628 }
629 #endif
630 }
631
632 bool wxToolBar::Show( bool show )
633 {
634 WXWindow tlw = MacGetTopLevelWindowRef();
635 bool bResult = (tlw != NULL);
636
637 if (bResult)
638 {
639 #if wxOSX_USE_NATIVE_TOOLBAR
640 bool ownToolbarInstalled = false;
641 MacTopLevelHasNativeToolbar( &ownToolbarInstalled );
642 if (ownToolbarInstalled)
643 {
644 bResult = ([(NSToolbar*)m_macToolbar isVisible] != show);
645 if ( bResult )
646 [(NSToolbar*)m_macToolbar setVisible:show];
647 }
648 else
649 bResult = wxToolBarBase::Show( show );
650 #else
651
652 bResult = wxToolBarBase::Show( show );
653 #endif
654 }
655
656 return bResult;
657 }
658
659 bool wxToolBar::IsShown() const
660 {
661 bool bResult;
662
663 #if wxOSX_USE_NATIVE_TOOLBAR
664 bool ownToolbarInstalled;
665
666 MacTopLevelHasNativeToolbar( &ownToolbarInstalled );
667 if (ownToolbarInstalled)
668 {
669 bResult = [(NSToolbar*)m_macToolbar isVisible];
670 }
671 else
672 bResult = wxToolBarBase::IsShown();
673 #else
674
675 bResult = wxToolBarBase::IsShown();
676 #endif
677
678 return bResult;
679 }
680
681 void wxToolBar::DoGetSize( int *width, int *height ) const
682 {
683 #if wxOSX_USE_NATIVE_TOOLBAR
684 bool ownToolbarInstalled;
685
686 MacTopLevelHasNativeToolbar( &ownToolbarInstalled );
687 if ( ownToolbarInstalled )
688 {
689 WXWindow tlw = MacGetTopLevelWindowRef();
690 float toolbarHeight = 0.0;
691 NSRect windowFrame;
692
693 if(m_macToolbar && [(NSToolbar*)m_macToolbar isVisible])
694 {
695 windowFrame = [NSWindow contentRectForFrameRect:[tlw frame]
696 styleMask:[tlw styleMask]];
697 toolbarHeight = NSHeight(windowFrame)
698 - NSHeight([[tlw contentView] frame]);
699 }
700
701 if ( width != NULL )
702 *width = windowFrame.size.width;
703 if ( height != NULL )
704 *height = toolbarHeight;
705 }
706 else
707 wxToolBarBase::DoGetSize( width, height );
708
709 #else
710 wxToolBarBase::DoGetSize( width, height );
711 #endif
712 }
713
714 wxSize wxToolBar::DoGetBestSize() const
715 {
716 int width, height;
717
718 DoGetSize( &width, &height );
719
720 return wxSize( width, height );
721 }
722
723 void wxToolBar::SetWindowStyleFlag( long style )
724 {
725 wxToolBarBase::SetWindowStyleFlag( style );
726
727 #if wxOSX_USE_NATIVE_TOOLBAR
728 if (m_macToolbar != NULL)
729 {
730 NSToolbarDisplayMode mode = NSToolbarDisplayModeDefault;
731
732 if ( style & wxTB_NOICONS )
733 mode = NSToolbarDisplayModeLabelOnly;
734 else if ( style & wxTB_TEXT )
735 mode = NSToolbarDisplayModeIconAndLabel;
736 else
737 mode = NSToolbarDisplayModeIconOnly;
738
739 [(NSToolbar*) m_macToolbar setDisplayMode:mode];
740 }
741 #endif
742 }
743
744 #if wxOSX_USE_NATIVE_TOOLBAR
745 bool wxToolBar::MacWantsNativeToolbar()
746 {
747 return m_macUsesNativeToolbar;
748 }
749
750 bool wxToolBar::MacTopLevelHasNativeToolbar(bool *ownToolbarInstalled) const
751 {
752 bool bResultV = false;
753
754 if (ownToolbarInstalled != NULL)
755 *ownToolbarInstalled = false;
756
757 WXWindow tlw = MacGetTopLevelWindowRef();
758 if (tlw != NULL)
759 {
760 NSToolbar* curToolbarRef = [tlw toolbar];
761 bResultV = (curToolbarRef != NULL);
762 if (bResultV && (ownToolbarInstalled != NULL))
763 *ownToolbarInstalled = (curToolbarRef == m_macToolbar);
764 }
765
766 return bResultV;
767 }
768
769 bool wxToolBar::MacInstallNativeToolbar(bool usesNative)
770 {
771 bool bResult = false;
772
773 if (usesNative && (m_macToolbar == NULL))
774 return bResult;
775
776 if (usesNative && ((GetWindowStyleFlag() & wxTB_VERTICAL) != 0))
777 return bResult;
778
779 WXWindow tlw = MacGetTopLevelWindowRef();
780 if (tlw == NULL)
781 return bResult;
782
783 // check the existing toolbar
784 NSToolbar* curToolbarRef = [tlw toolbar];
785
786 m_macUsesNativeToolbar = usesNative;
787
788 if (m_macUsesNativeToolbar)
789 {
790 // only install toolbar if there isn't one installed already
791 if (curToolbarRef == NULL)
792 {
793 bResult = true;
794 [tlw setToolbar:(NSToolbar*) m_macToolbar];
795 [(NSToolbar*) m_macToolbar setVisible:YES];
796
797 m_peer->Move(0,0,0,0 );
798 SetSize( wxSIZE_AUTO_WIDTH, 0 );
799 m_peer->SetVisibility( false );
800 wxToolBarBase::Show( false );
801 }
802 }
803 else
804 {
805 // only deinstall toolbar if this is the installed one
806 if (m_macToolbar == curToolbarRef)
807 {
808 bResult = true;
809 [(NSToolbar*) m_macToolbar setVisible:NO];
810 [tlw setToolbar:nil];
811 m_peer->SetVisibility( true );
812 }
813 }
814
815 if (bResult)
816 InvalidateBestSize();
817
818 // wxLogDebug( wxT(" --> [%lx] - result [%s]"), (long)this, bResult ? wxT("T") : wxT("F") );
819 return bResult;
820 }
821 #endif
822
823 bool wxToolBar::Realize()
824 {
825 if (m_tools.GetCount() == 0)
826 return false;
827
828 int maxWidth = 0;
829 int maxHeight = 0;
830
831 int maxToolWidth = 0;
832 int maxToolHeight = 0;
833
834 int x = m_xMargin + kwxMacToolBarLeftMargin;
835 int y = m_yMargin + kwxMacToolBarTopMargin;
836
837 int tw, th;
838 GetSize( &tw, &th );
839
840 // find the maximum tool width and height
841 wxToolBarTool *tool;
842 wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst();
843 while ( node )
844 {
845 tool = (wxToolBarTool *) node->GetData();
846 if ( tool != NULL )
847 {
848 wxSize sz = tool->GetSize();
849
850 if ( sz.x > maxToolWidth )
851 maxToolWidth = sz.x;
852 if ( sz.y > maxToolHeight )
853 maxToolHeight = sz.y;
854 }
855
856 node = node->GetNext();
857 }
858
859 bool lastIsRadio = false;
860 bool curIsRadio = false;
861
862 #if wxOSX_USE_NATIVE_TOOLBAR
863 CFIndex currentPosition = 0;
864 bool insertAll = false;
865
866 NSToolbar* refTB = (NSToolbar*)m_macToolbar;
867 wxFont f;
868 wxFontEncoding enc;
869 f = GetFont();
870 if ( f.IsOk() )
871 enc = f.GetEncoding();
872 else
873 enc = wxFont::GetDefaultEncoding();
874 #endif
875
876 node = m_tools.GetFirst();
877 while ( node )
878 {
879 tool = (wxToolBarTool*) node->GetData();
880 if ( tool == NULL )
881 {
882 node = node->GetNext();
883 continue;
884 }
885
886 // set tool position:
887 // for the moment just perform a single row/column alignment
888 wxSize cursize = tool->GetSize();
889 if ( x + cursize.x > maxWidth )
890 maxWidth = x + cursize.x;
891 if ( y + cursize.y > maxHeight )
892 maxHeight = y + cursize.y;
893
894 if ( GetWindowStyleFlag() & wxTB_VERTICAL )
895 {
896 int x1 = x + ( maxToolWidth - cursize.x ) / 2;
897 tool->SetPosition( wxPoint(x1, y) );
898 }
899 else
900 {
901 int y1 = y + ( maxToolHeight - cursize.y ) / 2;
902 tool->SetPosition( wxPoint(x, y1) );
903 }
904
905 // update the item positioning state
906 if ( GetWindowStyleFlag() & wxTB_VERTICAL )
907 y += cursize.y + kwxMacToolSpacing;
908 else
909 x += cursize.x + kwxMacToolSpacing;
910
911 #if wxOSX_USE_NATIVE_TOOLBAR
912 // install in native NSToolbar
913 if ( refTB )
914 {
915 NSToolbarItem* hiItemRef = tool->GetToolbarItemRef();
916 if ( hiItemRef != NULL )
917 {
918 // since setting the help texts is non-virtual we have to update
919 // the strings now
920 wxCFStringRef sh( tool->GetShortHelp(), enc);
921 [hiItemRef setToolTip:sh.AsNSString()];
922
923 if ( insertAll || (tool->GetIndex() != currentPosition) )
924 {
925 if ( !insertAll )
926 {
927 insertAll = true;
928
929 // if this is the first tool that gets newly inserted or repositioned
930 // first remove all 'old' tools from here to the right, because of this
931 // all following tools will have to be reinserted (insertAll).
932 for ( wxToolBarToolsList::compatibility_iterator node2 = m_tools.GetLast();
933 node2 != node;
934 node2 = node2->GetPrevious() )
935 {
936 wxToolBarTool *tool2 = (wxToolBarTool*) node2->GetData();
937
938 const long idx = tool2->GetIndex();
939 if ( idx != -1 )
940 {
941 [refTB removeItemAtIndex:idx];
942 tool2->SetIndex(-1);
943 }
944 }
945 }
946 wxString identifier = wxString::Format( wxT("%d"), (int) tool );
947 wxCFStringRef cfidentifier(identifier);
948
949 [refTB insertItemWithItemIdentifier:cfidentifier.AsNSString() atIndex:currentPosition];
950 tool->SetIndex( currentPosition );
951 }
952
953 currentPosition++;
954 }
955 }
956 #endif
957
958 // update radio button (and group) state
959 lastIsRadio = curIsRadio;
960 curIsRadio = ( tool->IsButton() && (tool->GetKind() == wxITEM_RADIO) );
961
962 if ( !curIsRadio )
963 {
964 if ( tool->IsToggled() )
965 DoToggleTool( tool, true );
966 }
967 else
968 {
969 if ( !lastIsRadio )
970 {
971 if ( tool->Toggle( true ) )
972 {
973 DoToggleTool( tool, true );
974 }
975 }
976 else if ( tool->IsToggled() )
977 {
978 if ( tool->IsToggled() )
979 DoToggleTool( tool, true );
980
981 wxToolBarToolsList::compatibility_iterator nodePrev = node->GetPrevious();
982 while ( nodePrev )
983 {
984 wxToolBarToolBase *toggleTool = nodePrev->GetData();
985 if ( (toggleTool == NULL) || !toggleTool->IsButton() || (toggleTool->GetKind() != wxITEM_RADIO) )
986 break;
987
988 if ( toggleTool->Toggle( false ) )
989 DoToggleTool( toggleTool, false );
990
991 nodePrev = nodePrev->GetPrevious();
992 }
993 }
994 }
995
996 node = node->GetNext();
997 }
998
999 if ( GetWindowStyleFlag() & wxTB_HORIZONTAL )
1000 {
1001 // if not set yet, only one row
1002 if ( m_maxRows <= 0 )
1003 SetRows( 1 );
1004
1005 m_minWidth = maxWidth;
1006 maxWidth = tw;
1007 maxHeight += m_yMargin + kwxMacToolBarTopMargin;
1008 m_minHeight = m_maxHeight = maxHeight;
1009 }
1010 else
1011 {
1012 // if not set yet, have one column
1013 if ( (GetToolsCount() > 0) && (m_maxRows <= 0) )
1014 SetRows( GetToolsCount() );
1015
1016 m_minHeight = maxHeight;
1017 maxHeight = th;
1018 maxWidth += m_xMargin + kwxMacToolBarLeftMargin;
1019 m_minWidth = m_maxWidth = maxWidth;
1020 }
1021
1022 #if 0
1023 // FIXME: should this be OSX-only?
1024 {
1025 bool wantNativeToolbar, ownToolbarInstalled;
1026
1027 // attempt to install the native toolbar
1028 wantNativeToolbar = ((GetWindowStyleFlag() & wxTB_VERTICAL) == 0);
1029 MacInstallNativeToolbar( wantNativeToolbar );
1030 (void)MacTopLevelHasNativeToolbar( &ownToolbarInstalled );
1031 if (!ownToolbarInstalled)
1032 {
1033 SetSize( maxWidth, maxHeight );
1034 InvalidateBestSize();
1035 }
1036 }
1037 #else
1038 SetSize( maxWidth, maxHeight );
1039 InvalidateBestSize();
1040 #endif
1041
1042 SetInitialSize();
1043
1044 return true;
1045 }
1046
1047 void wxToolBar::SetToolBitmapSize(const wxSize& size)
1048 {
1049 m_defaultWidth = size.x + kwxMacToolBorder;
1050 m_defaultHeight = size.y + kwxMacToolBorder;
1051
1052 #if wxOSX_USE_NATIVE_TOOLBAR
1053 if (m_macToolbar != NULL)
1054 {
1055 int maxs = wxMax( size.x, size.y );
1056 NSToolbarSizeMode sizeSpec;
1057 if ( maxs > 32 )
1058 sizeSpec = NSToolbarSizeModeRegular;
1059 else if ( maxs > 24 )
1060 sizeSpec = NSToolbarSizeModeDefault;
1061 else
1062 sizeSpec = NSToolbarSizeModeSmall;
1063
1064 [(NSToolbar*) m_macToolbar setSizeMode:sizeSpec ];
1065 }
1066 #endif
1067 }
1068
1069 // The button size is bigger than the bitmap size
1070 wxSize wxToolBar::GetToolSize() const
1071 {
1072 return wxSize(m_defaultWidth + kwxMacToolBorder, m_defaultHeight + kwxMacToolBorder);
1073 }
1074
1075 void wxToolBar::SetRows(int nRows)
1076 {
1077 // avoid resizing the frame uselessly
1078 if ( nRows != m_maxRows )
1079 m_maxRows = nRows;
1080 }
1081
1082 void wxToolBar::MacSuperChangedPosition()
1083 {
1084 wxWindow::MacSuperChangedPosition();
1085
1086 #if wxOSX_USE_NATIVE_TOOLBAR
1087 if (! m_macUsesNativeToolbar )
1088 Realize();
1089 #else
1090
1091 Realize();
1092 #endif
1093 }
1094
1095 void wxToolBar::SetToolNormalBitmap( int id, const wxBitmap& bitmap )
1096 {
1097 wxToolBarTool* tool = wx_static_cast(wxToolBarTool*, FindById(id));
1098 if ( tool )
1099 {
1100 wxCHECK_RET( tool->IsButton(), wxT("Can only set bitmap on button tools."));
1101
1102 tool->SetNormalBitmap(bitmap);
1103
1104 // a side-effect of the UpdateToggleImage function is that it always changes the bitmap used on the button.
1105 tool->UpdateImages();
1106 }
1107 }
1108
1109 void wxToolBar::SetToolDisabledBitmap( int id, const wxBitmap& bitmap )
1110 {
1111 wxToolBarTool* tool = wx_static_cast(wxToolBarTool*, FindById(id));
1112 if ( tool )
1113 {
1114 wxCHECK_RET( tool->IsButton(), wxT("Can only set bitmap on button tools."));
1115
1116 tool->SetDisabledBitmap(bitmap);
1117
1118 // TODO: what to do for this one?
1119 }
1120 }
1121
1122 wxToolBarToolBase *wxToolBar::FindToolForPosition(wxCoord x, wxCoord y) const
1123 {
1124 wxToolBarTool *tool;
1125 wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst();
1126 while ( node )
1127 {
1128 tool = (wxToolBarTool *)node->GetData();
1129 if (tool != NULL)
1130 {
1131 wxRect2DInt r( tool->GetPosition(), tool->GetSize() );
1132 if ( r.Contains( wxPoint( x, y ) ) )
1133 return tool;
1134 }
1135
1136 node = node->GetNext();
1137 }
1138
1139 return (wxToolBarToolBase*)NULL;
1140 }
1141
1142 wxString wxToolBar::MacGetToolTipString( wxPoint &pt )
1143 {
1144 wxToolBarToolBase *tool = FindToolForPosition( pt.x, pt.y );
1145 if ( tool != NULL )
1146 return tool->GetShortHelp();
1147
1148 return wxEmptyString;
1149 }
1150
1151 void wxToolBar::DoEnableTool(wxToolBarToolBase *t, bool enable)
1152 {
1153 if ( t != NULL )
1154 ((wxToolBarTool*)t)->DoEnable( enable );
1155 }
1156
1157 void wxToolBar::DoToggleTool(wxToolBarToolBase *t, bool toggle)
1158 {
1159 wxToolBarTool *tool = (wxToolBarTool *)t;
1160 if ( ( tool != NULL ) && tool->IsButton() )
1161 tool->UpdateToggleImage( toggle );
1162 }
1163
1164 bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos), wxToolBarToolBase *toolBase)
1165 {
1166 wxToolBarTool *tool = wx_static_cast( wxToolBarTool*, toolBase );
1167 if (tool == NULL)
1168 return false;
1169
1170 wxSize toolSize = GetToolSize();
1171 WXWidget controlHandle = NULL;
1172 NSRect toolrect = NSMakeRect(0, 0, toolSize.x, toolSize.y );
1173
1174 #if wxOSX_USE_NATIVE_TOOLBAR
1175 wxString label = tool->GetLabel();
1176 if (m_macToolbar && !label.empty() )
1177 {
1178 // strip mnemonics from the label for compatibility
1179 // with the usual labels in wxStaticText sense
1180 label = wxStripMenuCodes(label);
1181 }
1182 #endif // wxOSX_USE_NATIVE_TOOLBAR
1183
1184 switch (tool->GetStyle())
1185 {
1186 case wxTOOL_STYLE_SEPARATOR:
1187 {
1188 wxASSERT( tool->GetControlHandle() == NULL );
1189 toolSize.x /= 4;
1190 toolSize.y /= 4;
1191 if ( GetWindowStyleFlag() & wxTB_VERTICAL )
1192 toolrect.size.height = toolSize.y;
1193 else
1194 toolrect.size.width = toolSize.x;
1195
1196 // in flat style we need a visual separator
1197 #if wxOSX_USE_NATIVE_TOOLBAR
1198 if (m_macToolbar != NULL)
1199 {
1200 NSToolbarItem* item = [[NSToolbarItem alloc] initWithItemIdentifier:NSToolbarSeparatorItemIdentifier];
1201 tool->SetToolbarItemRef( item );
1202 }
1203 #endif // wxOSX_USE_NATIVE_TOOLBAR
1204
1205 NSBox* box = [[NSBox alloc] initWithFrame:toolrect];
1206 [box setBoxType:NSBoxSeparator];
1207 controlHandle = box;
1208 tool->SetControlHandle( controlHandle );
1209 }
1210 break;
1211
1212 case wxTOOL_STYLE_BUTTON:
1213 {
1214 wxASSERT( tool->GetControlHandle() == NULL );
1215
1216 wxNSToolBarButton* v = [[wxNSToolBarButton alloc] initWithFrame:toolrect];
1217
1218 [v setBezelStyle:NSRegularSquareBezelStyle];
1219 [v setBordered:NO];
1220 [v setButtonType: ( tool->CanBeToggled() ? NSOnOffButton : NSMomentaryPushInButton )];
1221 [v setImplementation:tool];
1222
1223 controlHandle = v;
1224
1225 #if wxOSX_USE_NATIVE_TOOLBAR
1226 if (m_macToolbar != NULL)
1227 {
1228 wxString identifier = wxString::Format(wxT("%d"), (int) tool);
1229 wxCFStringRef cfidentifier( identifier, wxFont::GetDefaultEncoding() );
1230 wxNSToolbarItem* item = [[wxNSToolbarItem alloc] initWithItemIdentifier:cfidentifier.AsNSString() ];
1231 [item setImplementation:tool];
1232 tool->SetToolbarItemRef( item );
1233 }
1234
1235 #endif // wxOSX_USE_NATIVE_TOOLBAR
1236 tool->SetControlHandle( controlHandle );
1237 tool->UpdateImages();
1238 tool->UpdateLabel();
1239 #if 0
1240 SetBevelButtonTextPlacement( m_controlHandle, kControlBevelButtonPlaceBelowGraphic );
1241 SetControlTitleWithCFString( m_controlHandle , wxCFStringRef( label, wxFont::GetDefaultEncoding() );
1242 #endif
1243 #if 0
1244 InstallControlEventHandler(
1245 (WXWidget) controlHandle, GetwxMacToolBarToolEventHandlerUPP(),
1246 GetEventTypeCount(eventList), eventList, tool, NULL );
1247 #endif
1248 }
1249 break;
1250
1251 case wxTOOL_STYLE_CONTROL:
1252
1253 #if wxOSX_USE_NATIVE_TOOLBAR
1254 if (m_macToolbar != NULL)
1255 {
1256 WXWidget view = (WXWidget) tool->GetControl()->GetHandle() ;
1257 wxCHECK_MSG( view, false, _T("control must be non-NULL") );
1258
1259 wxString identifier = wxString::Format(wxT("%d"), (int) tool);
1260 wxCFStringRef cfidentifier( identifier, wxFont::GetDefaultEncoding() );
1261 wxNSToolbarItem* item = [[wxNSToolbarItem alloc] initWithItemIdentifier:cfidentifier.AsNSString() ];
1262 [item setImplementation:tool];
1263 tool->SetToolbarItemRef( item );
1264 }
1265 #else
1266 // right now there's nothing to do here
1267 #endif
1268 tool->UpdateLabel();
1269 break;
1270
1271 default:
1272 break;
1273 }
1274
1275 if ( controlHandle )
1276 {
1277 WXWidget container = (WXWidget) GetHandle();
1278 wxASSERT_MSG( container != NULL, wxT("No valid Mac container control") );
1279
1280 // SetControlVisibility( controlHandle, true, true );
1281 [container addSubview:controlHandle];
1282 }
1283
1284 // nothing special to do here - we relayout in Realize() later
1285 InvalidateBestSize();
1286
1287 return true;
1288
1289 }
1290
1291 void wxToolBar::DoSetToggle(wxToolBarToolBase *WXUNUSED(tool), bool WXUNUSED(toggle))
1292 {
1293 wxFAIL_MSG( wxT("not implemented") );
1294 }
1295
1296 bool wxToolBar::DoDeleteTool(size_t WXUNUSED(pos), wxToolBarToolBase *toolbase)
1297 {
1298 wxToolBarTool* tool = wx_static_cast( wxToolBarTool*, toolbase );
1299 wxToolBarToolsList::compatibility_iterator node;
1300 for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
1301 {
1302 wxToolBarToolBase *tool2 = node->GetData();
1303 if ( tool2 == tool )
1304 {
1305 // let node point to the next node in the list
1306 node = node->GetNext();
1307
1308 break;
1309 }
1310 }
1311
1312 wxSize sz = ((wxToolBarTool*)tool)->GetSize();
1313
1314 #if wxOSX_USE_NATIVE_TOOLBAR
1315 CFIndex removeIndex = tool->GetIndex();
1316 #endif
1317
1318 #if wxOSX_USE_NATIVE_TOOLBAR
1319 if (m_macToolbar != NULL)
1320 {
1321 if ( removeIndex != -1 && m_macToolbar )
1322 {
1323 [(NSToolbar*) m_macToolbar removeItemAtIndex:removeIndex];
1324 tool->SetIndex( -1 );
1325 }
1326 }
1327 #endif
1328
1329 tool->ClearControl();
1330
1331 // and finally reposition all the controls after this one
1332
1333 for ( /* node -> first after deleted */; node; node = node->GetNext() )
1334 {
1335 wxToolBarTool *tool2 = (wxToolBarTool*) node->GetData();
1336 wxPoint pt = tool2->GetPosition();
1337
1338 if ( GetWindowStyleFlag() & wxTB_VERTICAL )
1339 pt.y -= sz.y;
1340 else
1341 pt.x -= sz.x;
1342
1343 tool2->SetPosition( pt );
1344
1345 #if wxOSX_USE_NATIVE_TOOLBAR
1346 if (m_macToolbar != NULL)
1347 {
1348 if ( removeIndex != -1 && tool2->GetIndex() > removeIndex )
1349 tool2->SetIndex( tool2->GetIndex() - 1 );
1350 }
1351 #endif
1352 }
1353
1354 InvalidateBestSize();
1355
1356 return true;
1357 }
1358
1359 #include <Carbon/Carbon.h>
1360
1361 void wxToolBar::OnPaint(wxPaintEvent& event)
1362 {
1363 #if wxOSX_USE_NATIVE_TOOLBAR
1364 if ( m_macUsesNativeToolbar )
1365 {
1366 event.Skip(true);
1367 return;
1368 }
1369 #endif
1370
1371 wxPaintDC dc(this);
1372
1373 int w, h;
1374 GetSize( &w, &h );
1375
1376 bool drawMetalTheme = MacGetTopLevelWindow()->GetExtraStyle() & wxFRAME_EX_METAL;
1377
1378 if ( !drawMetalTheme )
1379 {
1380 HIThemePlacardDrawInfo info;
1381 memset( &info, 0, sizeof(info) );
1382 info.version = 0;
1383 info.state = IsEnabled() ? kThemeStateActive : kThemeStateInactive;
1384
1385 CGContextRef cgContext = (CGContextRef) MacGetCGContextRef();
1386 HIRect rect = CGRectMake( 0, 0, w, h );
1387 HIThemeDrawPlacard( &rect, &info, cgContext, kHIThemeOrientationNormal );
1388 }
1389 else
1390 {
1391 // leave the background as it is (striped or metal)
1392 }
1393
1394 event.Skip();
1395 }
1396
1397 #endif // wxUSE_TOOLBAR