1 /////////////////////////////////////////////////////////////////////////////
 
   2 // Name:        src/osx/cocoa/toolbar.mm
 
   4 // Author:      Stefan Csomor
 
   7 // Copyright:   (c) Stefan Csomor
 
   8 // Licence:     wxWindows licence
 
   9 /////////////////////////////////////////////////////////////////////////////
 
  11 #include "wx/wxprec.h"
 
  19 #include "wx/toolbar.h"
 
  21 #include "wx/osx/private.h"
 
  22 #include "wx/geometry.h"
 
  23 #include "wx/sysopt.h"
 
  25 const short kwxMacToolBarToolDefaultWidth = 16;
 
  26 const short kwxMacToolBarToolDefaultHeight = 16;
 
  27 const short kwxMacToolBarTopMargin = 4;
 
  28 const short kwxMacToolBarLeftMargin =  4;
 
  29 const short kwxMacToolBorder = 0;
 
  30 const short kwxMacToolSpacing = 6;
 
  32 BEGIN_EVENT_TABLE(wxToolBar, wxToolBarBase)
 
  33     EVT_PAINT( wxToolBar::OnPaint )
 
  38 #pragma mark Tool Implementation
 
  40 // ----------------------------------------------------------------------------
 
  42 // ----------------------------------------------------------------------------
 
  46 @interface wxNSToolBarButton : NSButton
 
  51 - (id)initWithFrame:(NSRect)frame;
 
  52 - (void) clickedAction: (id) sender;
 
  53 - (void)setImplementation: (wxToolBarTool *) theImplementation;
 
  54 - (wxToolBarTool*) implementation;
 
  59 // We have a dual implementation for each tool, WXWidget and NSToolbarItem*
 
  61 // when embedding native controls in the native toolbar we must make sure the
 
  62 // control does not get deleted behind our backs, so the retain count gets increased
 
  63 // (after creation it is 1), first be the creation of the custom NSToolbarItem wrapper
 
  64 // object, and second by the code 'creating' the custom HIView (which is the same as the
 
  65 // already existing native control, therefore we just increase the ref count)
 
  66 // when this view is removed from the native toolbar its count gets decremented again
 
  67 // and when the HITooolbarItem wrapper object gets destroyed it is decremented as well
 
  68 // so in the end the control lives with a refcount of one and can be disposed of by the
 
  69 // wxControl code. For embedded controls on a non-native toolbar this ref count is less
 
  70 // so we can only test against a range, not a specific value of the refcount.
 
  72 class wxToolBarTool : public wxToolBarToolBase
 
  78         const wxString& label,
 
  79         const wxBitmap& bmpNormal,
 
  80         const wxBitmap& bmpDisabled,
 
  83         const wxString& shortHelp,
 
  84         const wxString& longHelp );
 
  86     wxToolBarTool(wxToolBar *tbar, wxControl *control, const wxString& label)
 
  87         : wxToolBarToolBase(tbar, control, label)
 
  91             SetControlHandle( (WXWidget) control->GetHandle() );
 
  94     virtual ~wxToolBarTool()
 
  99     WXWidget GetControlHandle()
 
 101         return (WXWidget) m_controlHandle;
 
 104     void SetControlHandle( WXWidget handle )
 
 106         m_controlHandle = handle;
 
 109     void SetPosition( const wxPoint& position );
 
 113         if ( m_controlHandle )
 
 117                 [m_controlHandle retain];
 
 121                 // the embedded control is not under the responsibility of the tool, it gets disposed of in the
 
 122                 // proper wxControl destructor
 
 124             m_controlHandle = NULL ;
 
 127 #if wxOSX_USE_NATIVE_TOOLBAR
 
 130             [m_toolbarItem release];
 
 131             m_toolbarItem = NULL;
 
 133 #endif // wxOSX_USE_NATIVE_TOOLBAR
 
 136     wxSize GetSize() const
 
 142             curSize = GetControl()->GetSize();
 
 144         else if ( IsButton() )
 
 146             // curSize = GetToolBar()->GetToolSize();
 
 147             NSRect best = [(wxNSToolBarButton*)m_controlHandle frame];
 
 148             curSize = wxSize(best.size.width, best.size.height);
 
 153             curSize = GetToolBar()->GetToolSize();
 
 154             if ( GetToolBar()->IsVertical() )
 
 163     wxPoint GetPosition() const
 
 165         return wxPoint( m_x, m_y );
 
 168     bool Enable( bool enable );
 
 172     void UpdateToggleImage( bool toggle );
 
 176         wxString labelStr = wxStripMenuCodes(m_label);
 
 177         wxCFStringRef l(labelStr, GetToolBarFontEncoding());
 
 178         wxCFStringRef sh( GetShortHelp(), GetToolBarFontEncoding() );
 
 179 #if wxOSX_USE_NATIVE_TOOLBAR
 
 182             // strip mnemonics from the label for compatibility with the usual
 
 183             // labels in wxStaticText sense
 
 185             [m_toolbarItem setLabel:l.AsNSString()];
 
 187             [m_toolbarItem setToolTip:sh.AsNSString()];
 
 191             [(NSButton*)m_controlHandle setTitle:l.AsNSString()];
 
 193         if ( m_controlHandle )
 
 195             [m_controlHandle setToolTip:sh.AsNSString()];
 
 201         wxToolBar *tbar = (wxToolBar*) GetToolBar();
 
 206             shouldToggle = !IsToggled();
 
 207             tbar->ToggleTool( GetId(), shouldToggle );
 
 210         tbar->OnLeftClick( GetId(), IsToggled() );
 
 213 #if wxOSX_USE_NATIVE_TOOLBAR
 
 214     void SetToolbarItemRef( NSToolbarItem* ref )
 
 216         if ( m_controlHandle )
 
 217             [m_controlHandle setHidden:YES];
 
 219             [m_toolbarItem release];
 
 224     NSToolbarItem* GetToolbarItemRef() const
 
 226         return m_toolbarItem;
 
 229     void SetIndex( CFIndex idx )
 
 234     CFIndex GetIndex() const
 
 239     virtual void SetLabel(const wxString& label)
 
 241         wxToolBarToolBase::SetLabel(label);
 
 245     virtual bool SetShortHelp(const wxString& help)
 
 247         if ( !wxToolBarToolBase::SetShortHelp(help) )
 
 254 #endif // wxOSX_USE_NATIVE_TOOLBAR
 
 257 #if wxOSX_USE_NATIVE_TOOLBAR
 
 258     wxFontEncoding GetToolBarFontEncoding() const
 
 262             f = GetToolBar()->GetFont();
 
 263         return f.IsOk() ? f.GetEncoding() : wxFont::GetDefaultEncoding();
 
 265 #endif // wxOSX_USE_NATIVE_TOOLBAR
 
 269         m_controlHandle = NULL;
 
 271 #if wxOSX_USE_NATIVE_TOOLBAR
 
 272         m_toolbarItem = NULL;
 
 277     WXWidget m_controlHandle;
 
 280     wxBitmap    m_alternateBitmap;
 
 282 #if wxOSX_USE_NATIVE_TOOLBAR
 
 283     NSToolbarItem* m_toolbarItem;
 
 284     // position in its toolbar, -1 means not inserted
 
 289 #if wxOSX_USE_NATIVE_TOOLBAR
 
 291 @interface wxNSToolbarItem : NSToolbarItem
 
 296 - (id) initWithItemIdentifier: (NSString*) identifier;
 
 297 - (void)setImplementation: (wxToolBarTool *) theImplementation;
 
 298 - (wxToolBarTool*) implementation;
 
 299 - (void) clickedAction: (id) sender;
 
 300 - (BOOL) validateToolbarItem:(NSToolbarItem *)theItem;
 
 305 @interface wxNSToolbarDelegate : NSObject wxOSX_10_6_AND_LATER(<NSToolbarDelegate>)
 
 310 - (void)setSelectable:(bool) value;
 
 312 - (NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag;
 
 314 - (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar*)toolbar;
 
 316 - (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar*)toolbar;
 
 318 - (NSArray *)toolbarSelectableItemIdentifiers:(NSToolbar *)toolbar;
 
 326 #if wxOSX_USE_NATIVE_TOOLBAR
 
 328 @implementation wxNSToolbarItem
 
 330 - (id)initWithItemIdentifier: (NSString*) identifier
 
 332     self = [super initWithItemIdentifier:identifier];
 
 334     [self setTarget: self];
 
 335     [self setAction: @selector(clickedAction:)];
 
 339 - (void) clickedAction: (id) sender
 
 348 - (void)setImplementation: (wxToolBarTool *) theImplementation
 
 350     impl = theImplementation;
 
 353 - (wxToolBarTool*) implementation
 
 358 - (BOOL)validateToolbarItem:(NSToolbarItem *)theItem
 
 360     wxUnusedVar(theItem);
 
 361     return impl->IsEnabled() ? YES:NO;
 
 366 @implementation wxNSToolbarDelegate
 
 370     m_isSelectable = false;
 
 374 - (void)setSelectable:(bool) value
 
 376     m_isSelectable = true;
 
 379 - (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar*)toolbar
 
 381     wxUnusedVar(toolbar);
 
 385 - (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar*)toolbar
 
 387     wxUnusedVar(toolbar);
 
 391 - (NSArray *)toolbarSelectableItemIdentifiers:(NSToolbar *)toolbar
 
 393   if ( m_isSelectable )
 
 394       return [[toolbar items] valueForKey:@"itemIdentifier"];
 
 399 - (NSToolbarItem*) toolbar:(NSToolbar*) toolbar itemForItemIdentifier:(NSString*) itemIdentifier willBeInsertedIntoToolbar:(BOOL) flag
 
 401     wxUnusedVar(toolbar);
 
 403     wxToolBarTool* tool = (wxToolBarTool*) [itemIdentifier longLongValue];
 
 405     wxToolBarTool* tool = (wxToolBarTool*) [itemIdentifier intValue];
 
 409         wxNSToolbarItem* item = (wxNSToolbarItem*) tool->GetToolbarItemRef();
 
 410         if ( flag && tool->IsControl() )
 
 412             NSView* view = tool->GetControl()->GetHandle();
 
 413             [view removeFromSuperview];
 
 415             wxSize sz = tool->GetControl()->GetSize();
 
 416             NSSize size = NSMakeSize((float)sz.x, (float)sz.y);
 
 417             [item setMaxSize:size];
 
 418             [item setMinSize:size];
 
 430 @implementation wxNSToolBarButton
 
 432 - (id)initWithFrame:(NSRect)frame
 
 434     self = [super initWithFrame:frame];
 
 436     [self setTarget: self];
 
 437     [self setAction: @selector(clickedAction:)];
 
 441 - (void) clickedAction: (id) sender
 
 450 - (void)setImplementation: (wxToolBarTool *) theImplementation
 
 452     impl = theImplementation;
 
 455 - (wxToolBarTool*) implementation
 
 467 bool wxToolBarTool::Enable( bool enable )
 
 469     if ( wxToolBarToolBase::Enable( enable ) == false )
 
 474         GetControl()->Enable( enable );
 
 476     else if ( IsButton() )
 
 478 #if wxOSX_USE_NATIVE_TOOLBAR
 
 479         if ( m_toolbarItem != NULL )
 
 480             [m_toolbarItem setEnabled:enable];
 
 483         if ( m_controlHandle != NULL )
 
 484             [(NSControl*)m_controlHandle setEnabled:enable];
 
 490 void wxToolBarTool::SetPosition( const wxPoint& position )
 
 495     int mac_x = position.x;
 
 496     int mac_y = position.y;
 
 500         NSRect frame = [m_controlHandle frame];
 
 501         if ( frame.origin.x != mac_x || frame.origin.y != mac_y )
 
 503             frame.origin.x = mac_x;
 
 504             frame.origin.y = mac_y;
 
 505             [m_controlHandle setFrame:frame];
 
 508     else if ( IsControl() )
 
 510         // embedded native controls are moved by the OS
 
 511 #if wxOSX_USE_NATIVE_TOOLBAR
 
 512         if ( ((wxToolBar*)GetToolBar())->MacWantsNativeToolbar() == false )
 
 515             GetControl()->Move( position );
 
 520         NSRect frame = [m_controlHandle frame];
 
 521         if ( frame.origin.x != mac_x || frame.origin.y != mac_y )
 
 523             frame.origin.x = mac_x;
 
 524             frame.origin.y = mac_y;
 
 525             [m_controlHandle setFrame:frame];
 
 530 void wxToolBarTool::UpdateImages()
 
 532     [(NSButton*) m_controlHandle setImage:m_bmpNormal.GetNSImage()];
 
 534     if ( CanBeToggled() )
 
 536         int w = m_bmpNormal.GetWidth();
 
 537         int h = m_bmpNormal.GetHeight();
 
 538         m_alternateBitmap = wxBitmap( w, h );
 
 541         dc.SelectObject( m_alternateBitmap );
 
 542         dc.SetPen( wxPen(*wxBLACK) );
 
 543         dc.SetBrush( wxBrush( *wxLIGHT_GREY ));
 
 544         dc.DrawRoundedRectangle( 0, 0, w, h, 2 );
 
 545         dc.DrawBitmap( m_bmpNormal, 0, 0, true );
 
 546         dc.SelectObject( wxNullBitmap );
 
 548         [(NSButton*) m_controlHandle setAlternateImage:m_alternateBitmap.GetNSImage()];
 
 550     UpdateToggleImage( CanBeToggled() && IsToggled() );
 
 553 void wxToolBarTool::UpdateToggleImage( bool toggle )
 
 555 #if wxOSX_USE_NATIVE_TOOLBAR
 
 556     if (m_toolbarItem != NULL )
 
 558         // the native toolbar item only has a 'selected' state (one for one toolbar)
 
 559         // so we emulate the toggle here
 
 560         if ( CanBeToggled() && toggle )
 
 561             [m_toolbarItem setImage:m_alternateBitmap.GetNSImage()];
 
 563             [m_toolbarItem setImage:m_bmpNormal.GetNSImage()];
 
 569             [(NSButton*)m_controlHandle setState:(toggle ? NSOnState : NSOffState)];
 
 573 wxToolBarTool::wxToolBarTool(
 
 576     const wxString& label,
 
 577     const wxBitmap& bmpNormal,
 
 578     const wxBitmap& bmpDisabled,
 
 580     wxObject *clientData,
 
 581     const wxString& shortHelp,
 
 582     const wxString& longHelp )
 
 585         tbar, id, label, bmpNormal, bmpDisabled, kind,
 
 586         clientData, shortHelp, longHelp )
 
 592 #pragma mark Toolbar Implementation
 
 594 wxToolBarToolBase *wxToolBar::CreateTool(
 
 596     const wxString& label,
 
 597     const wxBitmap& bmpNormal,
 
 598     const wxBitmap& bmpDisabled,
 
 600     wxObject *clientData,
 
 601     const wxString& shortHelp,
 
 602     const wxString& longHelp )
 
 604     return new wxToolBarTool(
 
 605         this, id, label, bmpNormal, bmpDisabled, kind,
 
 606         clientData, shortHelp, longHelp );
 
 610 wxToolBar::CreateTool(wxControl *control, const wxString& label)
 
 612     return new wxToolBarTool(this, control, label);
 
 615 void wxToolBar::Init()
 
 619     m_defaultWidth = kwxMacToolBarToolDefaultWidth;
 
 620     m_defaultHeight = kwxMacToolBarToolDefaultHeight;
 
 622 #if wxOSX_USE_NATIVE_TOOLBAR
 
 624     m_macUsesNativeToolbar = false;
 
 628 // also for the toolbar we have the dual implementation:
 
 629 // only when MacInstallNativeToolbar is called is the native toolbar set as the window toolbar
 
 631 bool wxToolBar::Create(
 
 637     const wxString& name )
 
 639     if ( !wxToolBarBase::Create( parent, id, pos, size, style, wxDefaultValidator, name ) )
 
 644     OSStatus err = noErr;
 
 646 #if wxOSX_USE_NATIVE_TOOLBAR
 
 648     if (parent->IsKindOf(CLASSINFO(wxFrame)) && wxSystemOptions::GetOptionInt(wxT("mac.toolbar.no-native")) != 1)
 
 650         static wxNSToolbarDelegate* controller = nil;
 
 652         if ( controller == nil )
 
 653             controller = [[wxNSToolbarDelegate alloc] init];
 
 654         wxString identifier = wxString::Format( wxT("%p"), this );
 
 655         wxCFStringRef cfidentifier(identifier);
 
 656         NSToolbar* tb =  [[NSToolbar alloc] initWithIdentifier:cfidentifier.AsNSString()];
 
 660         if (m_macToolbar != NULL)
 
 662             [tb setDelegate:controller];
 
 664             NSToolbarDisplayMode mode = NSToolbarDisplayModeDefault;
 
 665             NSToolbarSizeMode displaySize = NSToolbarSizeModeSmall;
 
 667             if ( style & wxTB_NOICONS )
 
 668                 mode = NSToolbarDisplayModeLabelOnly;
 
 669             else if ( style & wxTB_TEXT )
 
 670                 mode = NSToolbarDisplayModeIconAndLabel;
 
 672                 mode = NSToolbarDisplayModeIconOnly;
 
 674             [tb setDisplayMode:mode];
 
 675             [tb setSizeMode:displaySize];
 
 678 #endif // wxOSX_USE_NATIVE_TOOLBAR
 
 680     return (err == noErr);
 
 683 wxToolBar::~wxToolBar()
 
 685     // removal only works while the toolbar is there
 
 686     wxFrame *frame = wxDynamicCast(GetParent(), wxFrame);
 
 687     if ( frame && frame->GetToolBar() == this )
 
 689         frame->SetToolBar(NULL);
 
 692     [(NSToolbar*)m_macToolbar setDelegate:nil];
 
 693     [(NSToolbar*)m_macToolbar release];
 
 697 bool wxToolBar::Show( bool show )
 
 699     WXWindow tlw = MacGetTopLevelWindowRef();
 
 700     bool bResult = (tlw != NULL);
 
 704 #if wxOSX_USE_NATIVE_TOOLBAR
 
 705         bool ownToolbarInstalled = false;
 
 706         MacTopLevelHasNativeToolbar( &ownToolbarInstalled );
 
 707         if (ownToolbarInstalled)
 
 709             bResult = ([(NSToolbar*)m_macToolbar isVisible] != show);
 
 711                 [(NSToolbar*)m_macToolbar setVisible:show];
 
 714             bResult = wxToolBarBase::Show( show );
 
 717         bResult = wxToolBarBase::Show( show );
 
 724 bool wxToolBar::IsShown() const
 
 728 #if wxOSX_USE_NATIVE_TOOLBAR
 
 729     bool ownToolbarInstalled;
 
 731     MacTopLevelHasNativeToolbar( &ownToolbarInstalled );
 
 732     if (ownToolbarInstalled)
 
 734         bResult = [(NSToolbar*)m_macToolbar isVisible];
 
 737         bResult = wxToolBarBase::IsShown();
 
 740     bResult = wxToolBarBase::IsShown();
 
 746 void wxToolBar::DoGetSize( int *width, int *height ) const
 
 748 #if wxOSX_USE_NATIVE_TOOLBAR
 
 749     bool    ownToolbarInstalled;
 
 751     MacTopLevelHasNativeToolbar( &ownToolbarInstalled );
 
 752     if ( ownToolbarInstalled )
 
 754         WXWindow tlw = MacGetTopLevelWindowRef();
 
 755         float toolbarHeight = 0.0;
 
 756         NSRect windowFrame = NSMakeRect(0, 0, 0, 0);
 
 758         if(m_macToolbar && [(NSToolbar*)m_macToolbar isVisible])
 
 760             windowFrame = [NSWindow contentRectForFrameRect:[tlw frame]
 
 761                                 styleMask:[tlw styleMask]];
 
 762             toolbarHeight = NSHeight(windowFrame)
 
 763                         - NSHeight([[tlw contentView] frame]);
 
 767             *width = (int)windowFrame.size.width;
 
 768         if ( height != NULL )
 
 769             *height = (int)toolbarHeight;
 
 772         wxToolBarBase::DoGetSize( width, height );
 
 775     wxToolBarBase::DoGetSize( width, height );
 
 779 void wxToolBar::DoGetPosition(int*x, int *y) const
 
 781 #if wxOSX_USE_NATIVE_TOOLBAR
 
 782     bool    ownToolbarInstalled;
 
 784     MacTopLevelHasNativeToolbar( &ownToolbarInstalled );
 
 785     if ( ownToolbarInstalled )
 
 787         WXWindow tlw = MacGetTopLevelWindowRef();
 
 788         float toolbarHeight = 0.0;
 
 789         NSRect windowFrame = NSMakeRect(0, 0, 0, 0);
 
 791         if(m_macToolbar && [(NSToolbar*)m_macToolbar isVisible])
 
 793             windowFrame = [NSWindow contentRectForFrameRect:[tlw frame]
 
 794                                                   styleMask:[tlw styleMask]];
 
 795             toolbarHeight = NSHeight(windowFrame)
 
 796             - NSHeight([[tlw contentView] frame]);
 
 799         // it is extending to the north of the content area
 
 807         wxToolBarBase::DoGetPosition( x, y );
 
 810     wxToolBarBase::DoGetPosition( x, y );
 
 814 wxSize wxToolBar::DoGetBestSize() const
 
 816     // was updated in Realize()
 
 818     wxSize size = GetMinSize();
 
 823 void wxToolBar::SetWindowStyleFlag( long style )
 
 825     wxToolBarBase::SetWindowStyleFlag( style );
 
 827 #if wxOSX_USE_NATIVE_TOOLBAR
 
 828     if (m_macToolbar != NULL)
 
 830         NSToolbarDisplayMode mode = NSToolbarDisplayModeDefault;
 
 832         if ( style & wxTB_NOICONS )
 
 833             mode = NSToolbarDisplayModeLabelOnly;
 
 834         else if ( style & wxTB_TEXT )
 
 835             mode = NSToolbarDisplayModeIconAndLabel;
 
 837             mode = NSToolbarDisplayModeIconOnly;
 
 839         [(NSToolbar*) m_macToolbar setDisplayMode:mode];
 
 844 #if wxOSX_USE_NATIVE_TOOLBAR
 
 845 bool wxToolBar::MacWantsNativeToolbar()
 
 847     return m_macUsesNativeToolbar;
 
 850 bool wxToolBar::MacTopLevelHasNativeToolbar(bool *ownToolbarInstalled) const
 
 852     bool bResultV = false;
 
 854     if (ownToolbarInstalled != NULL)
 
 855         *ownToolbarInstalled = false;
 
 857     WXWindow tlw = MacGetTopLevelWindowRef();
 
 860         NSToolbar* curToolbarRef = [tlw toolbar];
 
 861         bResultV = (curToolbarRef != NULL);
 
 862         if (bResultV && (ownToolbarInstalled != NULL))
 
 863             *ownToolbarInstalled = (curToolbarRef == m_macToolbar);
 
 869 bool wxToolBar::MacInstallNativeToolbar(bool usesNative)
 
 871     bool bResult = false;
 
 873     if (usesNative && (m_macToolbar == NULL))
 
 876     if (usesNative && HasFlag(wxTB_LEFT|wxTB_RIGHT|wxTB_BOTTOM) )
 
 879     WXWindow tlw = MacGetTopLevelWindowRef();
 
 883     // check the existing toolbar
 
 884     NSToolbar* curToolbarRef = [tlw toolbar];
 
 886     m_macUsesNativeToolbar = usesNative;
 
 888     if (m_macUsesNativeToolbar)
 
 890         // only install toolbar if there isn't one installed already
 
 891         if (curToolbarRef == NULL)
 
 894             [tlw setToolbar:(NSToolbar*) m_macToolbar];
 
 895             [(NSToolbar*) m_macToolbar setVisible:YES];
 
 897             GetPeer()->Move(0,0,0,0 );
 
 898             SetSize( wxSIZE_AUTO_WIDTH, 0 );
 
 899             GetPeer()->SetVisibility( false );
 
 900             wxToolBarBase::Show( false );
 
 905         // only deinstall toolbar if this is the installed one
 
 906         if (m_macToolbar == curToolbarRef)
 
 909             [(NSToolbar*) m_macToolbar setVisible:NO];
 
 910             MacUninstallNativeToolbar();
 
 911             GetPeer()->SetVisibility( true );
 
 916         InvalidateBestSize();
 
 918 // wxLogDebug( wxT("    --> [%lx] - result [%s]"), (long)this, bResult ? wxT("T") : wxT("F") );
 
 922 void wxToolBar::MacUninstallNativeToolbar()
 
 927     WXWindow tlw = MacGetTopLevelWindowRef();
 
 929         [tlw setToolbar:nil];
 
 933 void wxToolBar::DoLayout()
 
 935     int maxToolWidth = 0;
 
 936     int maxToolHeight = 0;
 
 941     // find the maximum tool width and height
 
 942     // and the number of stretchable items
 
 943     int numStretchableSpaces = 0;
 
 945     wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst();
 
 948         tool = (wxToolBarTool *) node->GetData();
 
 951             wxSize  sz = tool->GetSize();
 
 953             if ( sz.x > maxToolWidth )
 
 955             if ( sz.y > maxToolHeight )
 
 956                 maxToolHeight = sz.y;
 
 957             if ( tool->IsStretchableSpace() )
 
 958                 numStretchableSpaces++;
 
 961         node = node->GetNext();
 
 964     // layout non-native toolbar 
 
 966     bool isHorizontal =  !IsVertical();
 
 971     int x = m_xMargin + kwxMacToolBarLeftMargin;
 
 972     int y = m_yMargin + kwxMacToolBarTopMargin;
 
 974     node = m_tools.GetFirst();
 
 977         tool = (wxToolBarTool*) node->GetData();
 
 980             node = node->GetNext();
 
 984         // set tool position:
 
 985         // for the moment just perform a single row/column alignment
 
 986         wxSize  cursize = tool->GetSize();
 
 987         if ( x + cursize.x > maxWidth )
 
 988             maxWidth = x + cursize.x;
 
 989         if ( y + cursize.y > maxHeight )
 
 990             maxHeight = y + cursize.y;
 
 992         // update the item positioning state
 
 994             y += cursize.y + kwxMacToolSpacing;
 
 996             x += cursize.x + kwxMacToolSpacing;
 
 998         node = node->GetNext();
 
1003         // if not set yet, only one row
 
1004         if ( m_maxRows <= 0 )
 
1007         maxWidth += m_xMargin + kwxMacToolBarLeftMargin;
 
1008         m_minWidth = maxWidth;
 
1009         m_minHeight = m_maxHeight = maxToolHeight + 2 * (m_yMargin + kwxMacToolBarTopMargin);
 
1013         // if not set yet, have one column
 
1014         if ( (GetToolsCount() > 0) && (m_maxRows <= 0) )
 
1015             SetRows( GetToolsCount() );
 
1017         maxHeight += m_yMargin + kwxMacToolBarTopMargin;
 
1018         m_minHeight = maxHeight;
 
1019         m_minWidth = m_maxWidth = maxToolWidth + 2 * (m_yMargin + kwxMacToolBarTopMargin);
 
1022     int totalStretchableSpace = 0;
 
1023     int spacePerStretchable = 0;
 
1024     if ( numStretchableSpaces > 0 )
 
1027             totalStretchableSpace = tw - maxWidth;
 
1029             totalStretchableSpace = th - maxHeight;
 
1031         if ( totalStretchableSpace > 0 )
 
1032             spacePerStretchable = totalStretchableSpace / numStretchableSpaces;            
 
1035     // perform real positioning
 
1037     x = m_xMargin + kwxMacToolBarLeftMargin;
 
1038     y = m_yMargin + kwxMacToolBarTopMargin;
 
1040     node = m_tools.GetFirst();
 
1041     int currentStretchable = 0;
 
1044         tool = (wxToolBarTool*) node->GetData();
 
1047             node = node->GetNext();
 
1051         wxSize  cursize = tool->GetSize();
 
1052         if ( tool->IsStretchableSpace() )
 
1054             ++currentStretchable;
 
1055             int thisSpace = currentStretchable == numStretchableSpaces ? 
 
1056             totalStretchableSpace - (currentStretchable-1)*spacePerStretchable :
 
1057             spacePerStretchable;
 
1059                 cursize.x += thisSpace;
 
1061                 cursize.y += thisSpace;
 
1064         if ( !isHorizontal )
 
1066             int x1 = x + ( maxToolWidth - cursize.x ) / 2;
 
1067             tool->SetPosition( wxPoint(x1, y) );
 
1071             int y1 = y + ( maxToolHeight - cursize.y ) / 2;
 
1072             tool->SetPosition( wxPoint(x, y1) );
 
1075         // update the item positioning state
 
1076         if ( !isHorizontal )
 
1077             y += cursize.y + kwxMacToolSpacing;
 
1079             x += cursize.x + kwxMacToolSpacing;
 
1081         node = node->GetNext();
 
1086 bool wxToolBar::Realize()
 
1088     if ( !wxToolBarBase::Realize() )
 
1091     wxToolBarTool *tool;
 
1092     wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst();
 
1094 #if wxOSX_USE_NATIVE_TOOLBAR
 
1095     CFIndex currentPosition = 0;
 
1096     bool insertAll = false;
 
1098     NSToolbar* refTB = (NSToolbar*)m_macToolbar;
 
1103         enc = f.GetEncoding();
 
1105         enc = wxFont::GetDefaultEncoding();
 
1107     node = m_tools.GetFirst();
 
1110         tool = (wxToolBarTool*) node->GetData();
 
1113             node = node->GetNext();
 
1117         // install in native NSToolbar
 
1120             NSToolbarItem* hiItemRef = tool->GetToolbarItemRef();
 
1121             if ( hiItemRef != NULL )
 
1123                 // since setting the help texts is non-virtual we have to update
 
1125                 wxCFStringRef sh( tool->GetShortHelp(), enc);
 
1126                 [hiItemRef setToolTip:sh.AsNSString()];
 
1128                 if ( insertAll || (tool->GetIndex() != currentPosition) )
 
1134                         // if this is the first tool that gets newly inserted or repositioned
 
1135                         // first remove all 'old' tools from here to the right, because of this
 
1136                         // all following tools will have to be reinserted (insertAll).
 
1137                         for ( wxToolBarToolsList::compatibility_iterator node2 = m_tools.GetLast();
 
1139                              node2 = node2->GetPrevious() )
 
1141                             wxToolBarTool *tool2 = (wxToolBarTool*) node2->GetData();
 
1143                             const long idx = tool2->GetIndex();
 
1146                                 [refTB removeItemAtIndex:idx];
 
1147                                 tool2->SetIndex(-1);
 
1152                     wxCFStringRef cfidentifier;
 
1154                     if (tool->GetStyle() == wxTOOL_STYLE_SEPARATOR)
 
1156                         if ( tool->IsStretchable() )
 
1157                             nsItemId = NSToolbarFlexibleSpaceItemIdentifier;
 
1160                             if ( UMAGetSystemVersion() < 0x1070 )
 
1161                                 nsItemId = NSToolbarSeparatorItemIdentifier;
 
1163                                 nsItemId = NSToolbarSpaceItemIdentifier;
 
1168                         cfidentifier = wxCFStringRef(wxString::Format("%ld", (long)tool));
 
1169                         nsItemId = cfidentifier.AsNSString();
 
1172                     [refTB insertItemWithItemIdentifier:nsItemId atIndex:currentPosition];
 
1173                     tool->SetIndex( currentPosition );
 
1179         node = node->GetNext();
 
1186     // adjust radio items
 
1188     bool lastIsRadio = false;
 
1189     bool curIsRadio = false;
 
1191     node = m_tools.GetFirst();
 
1194         tool = (wxToolBarTool*) node->GetData();
 
1197             node = node->GetNext();
 
1201         // update radio button (and group) state
 
1202         lastIsRadio = curIsRadio;
 
1203         curIsRadio = ( tool->IsButton() && (tool->GetKind() == wxITEM_RADIO) );
 
1207             if ( tool->IsToggled() )
 
1208                 DoToggleTool( tool, true );
 
1214                 if ( tool->Toggle( true ) )
 
1216                     DoToggleTool( tool, true );
 
1219             else if ( tool->IsToggled() )
 
1221                 if ( tool->IsToggled() )
 
1222                     DoToggleTool( tool, true );
 
1224                 wxToolBarToolsList::compatibility_iterator  nodePrev = node->GetPrevious();
 
1227                     wxToolBarToolBase   *toggleTool = nodePrev->GetData();
 
1228                     if ( (toggleTool == NULL) || !toggleTool->IsButton() || (toggleTool->GetKind() != wxITEM_RADIO) )
 
1231                     if ( toggleTool->Toggle( false ) )
 
1232                         DoToggleTool( toggleTool, false );
 
1234                     nodePrev = nodePrev->GetPrevious();
 
1239         node = node->GetNext();
 
1242     InvalidateBestSize();
 
1243     SetInitialSize( wxSize(m_minWidth, m_minHeight));
 
1245     SendSizeEventToParent();
 
1250 void wxToolBar::DoSetSize(int x, int y, int width, int height, int sizeFlags)
 
1252     wxToolBarBase::DoSetSize(x, y, width, height, sizeFlags);
 
1257 void wxToolBar::SetToolBitmapSize(const wxSize& size)
 
1259     m_defaultWidth = size.x + kwxMacToolBorder;
 
1260     m_defaultHeight = size.y + kwxMacToolBorder;
 
1262 #if wxOSX_USE_NATIVE_TOOLBAR
 
1263     if (m_macToolbar != NULL)
 
1265         int maxs = wxMax( size.x, size.y );
 
1266         NSToolbarSizeMode sizeSpec;
 
1268             sizeSpec = NSToolbarSizeModeRegular;
 
1269         else if ( maxs > 24 )
 
1270             sizeSpec = NSToolbarSizeModeDefault;
 
1272             sizeSpec = NSToolbarSizeModeSmall;
 
1274         [(NSToolbar*) m_macToolbar setSizeMode:sizeSpec ];
 
1279 // The button size is bigger than the bitmap size
 
1280 wxSize wxToolBar::GetToolSize() const
 
1282     return wxSize(m_defaultWidth + kwxMacToolBorder, m_defaultHeight + kwxMacToolBorder);
 
1285 void wxToolBar::SetRows(int nRows)
 
1287     // avoid resizing the frame uselessly
 
1288     if ( nRows != m_maxRows )
 
1292 void wxToolBar::MacSuperChangedPosition()
 
1294     wxWindow::MacSuperChangedPosition();
 
1297 #if wxOSX_USE_NATIVE_TOOLBAR
 
1298     if (! m_macUsesNativeToolbar )
 
1307 void wxToolBar::SetToolNormalBitmap( int id, const wxBitmap& bitmap )
 
1309     wxToolBarTool* tool = static_cast<wxToolBarTool*>(FindById(id));
 
1312         wxCHECK_RET( tool->IsButton(), wxT("Can only set bitmap on button tools."));
 
1314         tool->SetNormalBitmap(bitmap);
 
1316         // a side-effect of the UpdateToggleImage function is that it always changes the bitmap used on the button.
 
1317         tool->UpdateImages();
 
1321 void wxToolBar::SetToolDisabledBitmap( int id, const wxBitmap& bitmap )
 
1323     wxToolBarTool* tool = static_cast<wxToolBarTool*>(FindById(id));
 
1326         wxCHECK_RET( tool->IsButton(), wxT("Can only set bitmap on button tools."));
 
1328         tool->SetDisabledBitmap(bitmap);
 
1330         // TODO:  what to do for this one?
 
1334 wxToolBarToolBase *wxToolBar::FindToolForPosition(wxCoord x, wxCoord y) const
 
1336     wxToolBarTool *tool;
 
1337     wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst();
 
1340         tool = (wxToolBarTool *)node->GetData();
 
1343             wxRect2DInt r( tool->GetPosition(), tool->GetSize() );
 
1344             if ( r.Contains( wxPoint( x, y ) ) )
 
1348         node = node->GetNext();
 
1354 wxString wxToolBar::MacGetToolTipString( wxPoint &pt )
 
1356     wxToolBarToolBase *tool = FindToolForPosition( pt.x, pt.y );
 
1358         return tool->GetShortHelp();
 
1360     return wxEmptyString;
 
1363 void wxToolBar::DoEnableTool(wxToolBarToolBase * WXUNUSED(t), bool WXUNUSED(enable))
 
1365     // everything already done in the tool's Enable implementation
 
1368 void wxToolBar::DoToggleTool(wxToolBarToolBase *t, bool toggle)
 
1370     wxToolBarTool *tool = (wxToolBarTool *)t;
 
1371     if ( ( tool != NULL ) && tool->IsButton() )
 
1372         tool->UpdateToggleImage( toggle );
 
1375 bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos), wxToolBarToolBase *toolBase)
 
1377     wxToolBarTool *tool = static_cast< wxToolBarTool*>(toolBase );
 
1381     long style = GetWindowStyleFlag();
 
1383     wxSize toolSize = GetToolSize();
 
1384     WXWidget controlHandle = NULL;
 
1385     NSRect toolrect = NSMakeRect(0, 0, toolSize.x, toolSize.y );
 
1387 #if wxOSX_USE_NATIVE_TOOLBAR
 
1388     wxString label = tool->GetLabel();
 
1389     if (m_macToolbar && !label.empty() )
 
1391         // strip mnemonics from the label for compatibility
 
1392         // with the usual labels in wxStaticText sense
 
1393         label = wxStripMenuCodes(label);
 
1395 #endif // wxOSX_USE_NATIVE_TOOLBAR
 
1397     switch (tool->GetStyle())
 
1399         case wxTOOL_STYLE_SEPARATOR:
 
1401                 wxASSERT( tool->GetControlHandle() == NULL );
 
1405                     toolrect.size.height = toolSize.y;
 
1407                     toolrect.size.width = toolSize.x;
 
1409                 // in flat style we need a visual separator
 
1410 #if wxOSX_USE_NATIVE_TOOLBAR
 
1411                 if (m_macToolbar != NULL)
 
1413                     NSString * nsItemId = nil;
 
1415                     if ( tool->IsStretchable() )
 
1416                         nsItemId = NSToolbarFlexibleSpaceItemIdentifier;
 
1419                         if ( UMAGetSystemVersion() < 0x1070 )
 
1420                             nsItemId = NSToolbarSeparatorItemIdentifier;
 
1422                             nsItemId = NSToolbarSpaceItemIdentifier;
 
1425                     NSToolbarItem* item = [[NSToolbarItem alloc] initWithItemIdentifier:nsItemId];
 
1426                     tool->SetToolbarItemRef( item );
 
1428 #endif // wxOSX_USE_NATIVE_TOOLBAR
 
1430                 NSBox* box = [[NSBox alloc] initWithFrame:toolrect];
 
1431                 [box setBoxType:NSBoxSeparator];
 
1432                 controlHandle = box;
 
1433                 tool->SetControlHandle( controlHandle );
 
1437         case wxTOOL_STYLE_BUTTON:
 
1439                 wxASSERT( tool->GetControlHandle() == NULL );
 
1441                 wxNSToolBarButton* v = [[wxNSToolBarButton alloc] initWithFrame:toolrect];
 
1443                 [v setBezelStyle:NSSmallSquareBezelStyle];
 
1444                 [[v cell] setControlSize:NSSmallControlSize];
 
1445                 [v setFont:[NSFont fontWithName:[[v font] fontName] size:[NSFont systemFontSizeForControlSize:NSSmallControlSize]]];
 
1447                 [v setButtonType: ( tool->CanBeToggled() ? NSToggleButton : NSMomentaryPushInButton )];
 
1448                 [v setImplementation:tool];
 
1452 #if wxOSX_USE_NATIVE_TOOLBAR
 
1453                 if (m_macToolbar != NULL)
 
1455                     wxString identifier = wxString::Format(wxT("%ld"), (long) tool);
 
1456                     wxCFStringRef cfidentifier( identifier, wxFont::GetDefaultEncoding() );
 
1457                     wxNSToolbarItem* item = [[wxNSToolbarItem alloc] initWithItemIdentifier:cfidentifier.AsNSString() ];
 
1458                     [item setImplementation:tool];
 
1459                     tool->SetToolbarItemRef( item );
 
1462 #endif // wxOSX_USE_NATIVE_TOOLBAR
 
1463                 tool->SetControlHandle( controlHandle );
 
1464                 if ( !(style & wxTB_NOICONS) )
 
1465                     tool->UpdateImages();
 
1466                 tool->UpdateLabel();
 
1468                 if ( style & wxTB_NOICONS )
 
1469                     [v setImagePosition:NSNoImage];
 
1470                 else if ( style & wxTB_TEXT )
 
1471                     [v setImagePosition:NSImageAbove];
 
1473                     [v setImagePosition:NSImageOnly];
 
1477                 InstallControlEventHandler(
 
1478                     (WXWidget) controlHandle, GetwxMacToolBarToolEventHandlerUPP(),
 
1479                     GetEventTypeCount(eventList), eventList, tool, NULL );
 
1484         case wxTOOL_STYLE_CONTROL:
 
1486 #if wxOSX_USE_NATIVE_TOOLBAR
 
1487             if (m_macToolbar != NULL)
 
1489                 WXWidget view = (WXWidget) tool->GetControl()->GetHandle() ;
 
1490                 wxCHECK_MSG( view, false, wxT("control must be non-NULL") );
 
1492                 wxString identifier = wxString::Format(wxT("%ld"), (long) tool);
 
1493                 wxCFStringRef cfidentifier( identifier, wxFont::GetDefaultEncoding() );
 
1494                 wxNSToolbarItem* item = [[wxNSToolbarItem alloc] initWithItemIdentifier:cfidentifier.AsNSString() ];
 
1495                 [item setImplementation:tool];
 
1496                 tool->SetToolbarItemRef( item );
 
1499             // right now there's nothing to do here
 
1501             tool->UpdateLabel();
 
1508     if ( controlHandle )
 
1510         WXWidget container = (WXWidget) GetHandle();
 
1511         wxASSERT_MSG( container != NULL, wxT("No valid Mac container control") );
 
1513 //        SetControlVisibility( controlHandle, true, true );
 
1514         [container addSubview:controlHandle];
 
1517     // nothing special to do here - we relayout in Realize() later
 
1518     InvalidateBestSize();
 
1524 void wxToolBar::DoSetToggle(wxToolBarToolBase *WXUNUSED(tool), bool WXUNUSED(toggle))
 
1526     wxFAIL_MSG( wxT("not implemented") );
 
1529 bool wxToolBar::DoDeleteTool(size_t WXUNUSED(pos), wxToolBarToolBase *toolbase)
 
1531     wxToolBarTool* tool = static_cast< wxToolBarTool*>(toolbase );
 
1532     wxToolBarToolsList::compatibility_iterator node;
 
1533     for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
 
1535         wxToolBarToolBase *tool2 = node->GetData();
 
1536         if ( tool2 == tool )
 
1538             // let node point to the next node in the list
 
1539             node = node->GetNext();
 
1545     wxSize sz = ((wxToolBarTool*)tool)->GetSize();
 
1547 #if wxOSX_USE_NATIVE_TOOLBAR
 
1548     CFIndex removeIndex = tool->GetIndex();
 
1551 #if wxOSX_USE_NATIVE_TOOLBAR
 
1552     if (m_macToolbar != NULL)
 
1554         if ( removeIndex != -1 && m_macToolbar )
 
1556             [(NSToolbar*) m_macToolbar removeItemAtIndex:removeIndex];
 
1557             tool->SetIndex( -1 );
 
1562     tool->ClearControl();
 
1564     // and finally reposition all the controls after this one
 
1566     for ( /* node -> first after deleted */; node; node = node->GetNext() )
 
1568         wxToolBarTool *tool2 = (wxToolBarTool*) node->GetData();
 
1569         wxPoint pt = tool2->GetPosition();
 
1576         tool2->SetPosition( pt );
 
1578 #if wxOSX_USE_NATIVE_TOOLBAR
 
1579         if (m_macToolbar != NULL)
 
1581             if ( removeIndex != -1 && tool2->GetIndex() > removeIndex )
 
1582                 tool2->SetIndex( tool2->GetIndex() - 1 );
 
1587     InvalidateBestSize();
 
1592 #include <Carbon/Carbon.h>
 
1594 void wxToolBar::OnPaint(wxPaintEvent& event)
 
1596 #if wxOSX_USE_NATIVE_TOOLBAR
 
1597     if ( m_macUsesNativeToolbar )
 
1599         // nothing to do here
 
1609         wxRect rect(0,0,w,h);
 
1611         dc.GradientFillLinear( rect , wxColour( 0xCC,0xCC,0xCC ), wxColour( 0xA8,0xA8,0xA8 ) , wxSOUTH );
 
1612         dc.SetPen( wxPen( wxColour( 0x51,0x51,0x51 ) ) );
 
1613         if ( HasFlag(wxTB_LEFT) )
 
1614             dc.DrawLine(w-1, 0, w-1, h);
 
1615         else if ( HasFlag(wxTB_RIGHT) )
 
1616             dc.DrawLine(0, 0, 0, h);
 
1617         else if ( HasFlag(wxTB_BOTTOM) )
 
1618             dc.DrawLine(0, 0, w, 0);
 
1619         else if ( HasFlag(wxTB_TOP) )
 
1620             dc.DrawLine(0, h-1, w, h-1);
 
1625 #if wxOSX_USE_NATIVE_TOOLBAR
 
1626 void wxToolBar::OSXSetSelectableTools(bool set)
 
1628     wxCHECK_RET( m_macToolbar, "toolbar must be non-NULL" );
 
1629     [(wxNSToolbarDelegate*)[(NSToolbar*)m_macToolbar delegate] setSelectable:set];
 
1632 void wxToolBar::OSXSelectTool(int toolId)
 
1634     wxToolBarToolBase *tool = FindById(toolId);
 
1635     wxCHECK_RET( tool, "invalid tool ID" );
 
1636     wxCHECK_RET( m_macToolbar, "toolbar must be non-NULL" );
 
1638     wxString identifier = wxString::Format(wxT("%ld"), (long)tool);
 
1639     wxCFStringRef cfidentifier(identifier, wxFont::GetDefaultEncoding());
 
1640     [(NSToolbar*)m_macToolbar setSelectedItemIdentifier:cfidentifier.AsNSString()];
 
1642 #endif // wxOSX_USE_NATIVE_TOOLBAR
 
1644 #endif // wxUSE_TOOLBAR