1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/carbon/toolbar.cpp
4 // Author: Stefan Csomor
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 #include "wx/wxprec.h"
16 #include "wx/toolbar.h"
23 #include "wx/osx/private.h"
24 #include "wx/geometry.h"
25 #include "wx/sysopt.h"
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;
34 BEGIN_EVENT_TABLE(wxToolBar, wxToolBarBase)
35 EVT_PAINT( wxToolBar::OnPaint )
40 #pragma mark Tool Implementation
42 // ----------------------------------------------------------------------------
44 // ----------------------------------------------------------------------------
48 @interface wxNSToolBarButton : NSButton
53 - (id)initWithFrame:(NSRect)frame;
54 - (void) clickedAction: (id) sender;
55 - (void)setImplementation: (wxToolBarTool *) theImplementation;
56 - (wxToolBarTool*) implementation;
61 // We have a dual implementation for each tool, WXWidget and NSToolbarItem*
63 // when embedding native controls in the native toolbar we must make sure the
64 // control does not get deleted behind our backs, so the retain count gets increased
65 // (after creation it is 1), first be the creation of the custom NSToolbarItem wrapper
66 // object, and second by the code 'creating' the custom HIView (which is the same as the
67 // already existing native control, therefore we just increase the ref count)
68 // when this view is removed from the native toolbar its count gets decremented again
69 // and when the HITooolbarItem wrapper object gets destroyed it is decremented as well
70 // so in the end the control lives with a refcount of one and can be disposed of by the
71 // wxControl code. For embedded controls on a non-native toolbar this ref count is less
72 // so we can only test against a range, not a specific value of the refcount.
74 class wxToolBarTool : public wxToolBarToolBase
80 const wxString& label,
81 const wxBitmap& bmpNormal,
82 const wxBitmap& bmpDisabled,
85 const wxString& shortHelp,
86 const wxString& longHelp );
88 wxToolBarTool(wxToolBar *tbar, wxControl *control, const wxString& label)
89 : wxToolBarToolBase(tbar, control, label)
93 SetControlHandle( (WXWidget) control->GetHandle() );
96 virtual ~wxToolBarTool()
101 WXWidget GetControlHandle()
103 return (WXWidget) m_controlHandle;
106 void SetControlHandle( WXWidget handle )
108 m_controlHandle = handle;
111 void SetPosition( const wxPoint& position );
115 if ( m_controlHandle )
119 [m_controlHandle retain];
123 // the embedded control is not under the responsibility of the tool, it gets disposed of in the
124 // proper wxControl destructor
126 m_controlHandle = NULL ;
129 #if wxOSX_USE_NATIVE_TOOLBAR
132 [m_toolbarItem release];
133 m_toolbarItem = NULL;
135 #endif // wxOSX_USE_NATIVE_TOOLBAR
138 wxSize GetSize() const
144 curSize = GetControl()->GetSize();
146 else if ( IsButton() )
148 // curSize = GetToolBar()->GetToolSize();
149 NSRect best = [(wxNSToolBarButton*)m_controlHandle frame];
150 curSize = wxSize(best.size.width, best.size.height);
155 curSize = GetToolBar()->GetToolSize();
156 if ( GetToolBar()->IsVertical() )
165 wxPoint GetPosition() const
167 return wxPoint( m_x, m_y );
170 bool Enable( bool enable );
174 void UpdateToggleImage( bool toggle );
178 wxString labelStr = wxStripMenuCodes(m_label);
179 wxCFStringRef l(labelStr, GetToolBarFontEncoding());
180 wxCFStringRef sh( GetShortHelp(), GetToolBarFontEncoding() );
181 #if wxOSX_USE_NATIVE_TOOLBAR
184 // strip mnemonics from the label for compatibility with the usual
185 // labels in wxStaticText sense
187 [m_toolbarItem setLabel:l.AsNSString()];
189 [m_toolbarItem setToolTip:sh.AsNSString()];
193 [(NSButton*)m_controlHandle setTitle:l.AsNSString()];
199 wxToolBar *tbar = (wxToolBar*) GetToolBar();
204 shouldToggle = !IsToggled();
205 tbar->ToggleTool( GetId(), shouldToggle );
208 tbar->OnLeftClick( GetId(), IsToggled() );
211 #if wxOSX_USE_NATIVE_TOOLBAR
212 void SetToolbarItemRef( NSToolbarItem* ref )
214 if ( m_controlHandle )
215 [m_controlHandle setHidden:YES];
217 [m_toolbarItem release];
222 NSToolbarItem* GetToolbarItemRef() const
224 return m_toolbarItem;
227 void SetIndex( CFIndex idx )
232 CFIndex GetIndex() const
237 virtual void SetLabel(const wxString& label)
239 wxToolBarToolBase::SetLabel(label);
243 virtual bool SetShortHelp(const wxString& help)
245 if ( !wxToolBarToolBase::SetShortHelp(help) )
252 #endif // wxOSX_USE_NATIVE_TOOLBAR
255 #if wxOSX_USE_NATIVE_TOOLBAR
256 wxFontEncoding GetToolBarFontEncoding() const
260 f = GetToolBar()->GetFont();
261 return f.IsOk() ? f.GetEncoding() : wxFont::GetDefaultEncoding();
263 #endif // wxOSX_USE_NATIVE_TOOLBAR
267 m_controlHandle = NULL;
269 #if wxOSX_USE_NATIVE_TOOLBAR
270 m_toolbarItem = NULL;
275 WXWidget m_controlHandle;
278 wxBitmap m_alternateBitmap;
280 #if wxOSX_USE_NATIVE_TOOLBAR
281 NSToolbarItem* m_toolbarItem;
282 // position in its toolbar, -1 means not inserted
287 #if wxOSX_USE_NATIVE_TOOLBAR
289 @interface wxNSToolbarItem : NSToolbarItem
294 - (id) initWithItemIdentifier: (NSString*) identifier;
295 - (void)setImplementation: (wxToolBarTool *) theImplementation;
296 - (wxToolBarTool*) implementation;
297 - (void) clickedAction: (id) sender;
298 - (BOOL) validateToolbarItem:(NSToolbarItem *)theItem;
303 @interface wxNSToolbarDelegate : NSObject wxOSX_10_6_AND_LATER(<NSToolbarDelegate>)
307 - (NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag;
309 - (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar*)toolbar;
311 - (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar*)toolbar;
313 - (NSArray *)toolbarSelectableItemIdentifiers:(NSToolbar *)toolbar;
321 #if wxOSX_USE_NATIVE_TOOLBAR
323 @implementation wxNSToolbarItem
325 - (id)initWithItemIdentifier: (NSString*) identifier
327 [super initWithItemIdentifier:identifier];
329 [self setTarget: self];
330 [self setAction: @selector(clickedAction:)];
334 - (void) clickedAction: (id) sender
343 - (void)setImplementation: (wxToolBarTool *) theImplementation
345 impl = theImplementation;
348 - (wxToolBarTool*) implementation
353 - (BOOL)validateToolbarItem:(NSToolbarItem *)theItem
355 wxUnusedVar(theItem);
356 return impl->IsEnabled() ? YES:NO;
361 @implementation wxNSToolbarDelegate
363 - (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar*)toolbar
365 wxUnusedVar(toolbar);
369 - (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar*)toolbar
371 wxUnusedVar(toolbar);
375 - (NSArray *)toolbarSelectableItemIdentifiers:(NSToolbar *)toolbar
377 wxUnusedVar(toolbar);
381 - (NSToolbarItem*) toolbar:(NSToolbar*) toolbar itemForItemIdentifier:(NSString*) itemIdentifier willBeInsertedIntoToolbar:(BOOL) flag
383 wxUnusedVar(toolbar);
385 wxToolBarTool* tool = (wxToolBarTool*) [itemIdentifier longLongValue];
387 wxToolBarTool* tool = (wxToolBarTool*) [itemIdentifier intValue];
391 wxNSToolbarItem* item = (wxNSToolbarItem*) tool->GetToolbarItemRef();
392 if ( flag && tool->IsControl() )
394 NSView* view = tool->GetControl()->GetHandle();
395 [view removeFromSuperview];
397 wxSize sz = tool->GetControl()->GetSize();
398 NSSize size = NSMakeSize((float)sz.x, (float)sz.y);
399 [item setMaxSize:size];
400 [item setMinSize:size];
412 @implementation wxNSToolBarButton
414 - (id)initWithFrame:(NSRect)frame
416 [super initWithFrame:frame];
418 [self setTarget: self];
419 [self setAction: @selector(clickedAction:)];
423 - (void) clickedAction: (id) sender
432 - (void)setImplementation: (wxToolBarTool *) theImplementation
434 impl = theImplementation;
437 - (wxToolBarTool*) implementation
449 bool wxToolBarTool::Enable( bool enable )
451 if ( wxToolBarToolBase::Enable( enable ) == false )
456 GetControl()->Enable( enable );
458 else if ( IsButton() )
460 #if wxOSX_USE_NATIVE_TOOLBAR
461 if ( m_toolbarItem != NULL )
462 [m_toolbarItem setEnabled:enable];
465 if ( m_controlHandle != NULL )
466 [(NSControl*)m_controlHandle setEnabled:enable];
472 void wxToolBarTool::SetPosition( const wxPoint& position )
477 int mac_x = position.x;
478 int mac_y = position.y;
482 NSRect frame = [m_controlHandle frame];
483 if ( frame.origin.x != mac_x || frame.origin.y != mac_y )
485 frame.origin.x = mac_x;
486 frame.origin.y = mac_y;
487 [m_controlHandle setFrame:frame];
490 else if ( IsControl() )
492 // embedded native controls are moved by the OS
493 #if wxOSX_USE_NATIVE_TOOLBAR
494 if ( ((wxToolBar*)GetToolBar())->MacWantsNativeToolbar() == false )
497 GetControl()->Move( position );
502 NSRect frame = [m_controlHandle frame];
503 if ( frame.origin.x != mac_x || frame.origin.y != mac_y )
505 frame.origin.x = mac_x;
506 frame.origin.y = mac_y;
507 [m_controlHandle setFrame:frame];
512 void wxToolBarTool::UpdateImages()
514 [(NSButton*) m_controlHandle setImage:m_bmpNormal.GetNSImage()];
516 if ( CanBeToggled() )
518 int w = m_bmpNormal.GetWidth();
519 int h = m_bmpNormal.GetHeight();
520 m_alternateBitmap = wxBitmap( w, h );
523 dc.SelectObject( m_alternateBitmap );
524 dc.SetPen( wxPen(*wxBLACK) );
525 dc.SetBrush( wxBrush( *wxLIGHT_GREY ));
526 dc.DrawRoundedRectangle( 0, 0, w, h, 2 );
527 dc.DrawBitmap( m_bmpNormal, 0, 0, true );
528 dc.SelectObject( wxNullBitmap );
530 [(NSButton*) m_controlHandle setAlternateImage:m_alternateBitmap.GetNSImage()];
532 UpdateToggleImage( CanBeToggled() && IsToggled() );
535 void wxToolBarTool::UpdateToggleImage( bool toggle )
537 #if wxOSX_USE_NATIVE_TOOLBAR
538 if (m_toolbarItem != NULL )
540 // the native toolbar item only has a 'selected' state (one for one toolbar)
541 // so we emulate the toggle here
542 if ( CanBeToggled() && toggle )
543 [m_toolbarItem setImage:m_alternateBitmap.GetNSImage()];
545 [m_toolbarItem setImage:m_bmpNormal.GetNSImage()];
551 [(NSButton*)m_controlHandle setState:(toggle ? NSOnState : NSOffState)];
555 wxToolBarTool::wxToolBarTool(
558 const wxString& label,
559 const wxBitmap& bmpNormal,
560 const wxBitmap& bmpDisabled,
562 wxObject *clientData,
563 const wxString& shortHelp,
564 const wxString& longHelp )
567 tbar, id, label, bmpNormal, bmpDisabled, kind,
568 clientData, shortHelp, longHelp )
574 #pragma mark Toolbar Implementation
576 wxToolBarToolBase *wxToolBar::CreateTool(
578 const wxString& label,
579 const wxBitmap& bmpNormal,
580 const wxBitmap& bmpDisabled,
582 wxObject *clientData,
583 const wxString& shortHelp,
584 const wxString& longHelp )
586 return new wxToolBarTool(
587 this, id, label, bmpNormal, bmpDisabled, kind,
588 clientData, shortHelp, longHelp );
592 wxToolBar::CreateTool(wxControl *control, const wxString& label)
594 return new wxToolBarTool(this, control, label);
597 void wxToolBar::Init()
601 m_defaultWidth = kwxMacToolBarToolDefaultWidth;
602 m_defaultHeight = kwxMacToolBarToolDefaultHeight;
604 #if wxOSX_USE_NATIVE_TOOLBAR
606 m_macUsesNativeToolbar = false;
610 // also for the toolbar we have the dual implementation:
611 // only when MacInstallNativeToolbar is called is the native toolbar set as the window toolbar
613 bool wxToolBar::Create(
619 const wxString& name )
621 if ( !wxToolBarBase::Create( parent, id, pos, size, style, wxDefaultValidator, name ) )
626 OSStatus err = noErr;
628 #if wxOSX_USE_NATIVE_TOOLBAR
630 if (parent->IsKindOf(CLASSINFO(wxFrame)) && wxSystemOptions::GetOptionInt(wxT("mac.toolbar.no-native")) != 1)
632 static wxNSToolbarDelegate* controller = nil;
634 if ( controller == nil )
635 controller = [[wxNSToolbarDelegate alloc] init];
636 wxString identifier = wxString::Format( wxT("%p"), this );
637 wxCFStringRef cfidentifier(identifier);
638 NSToolbar* tb = [[NSToolbar alloc] initWithIdentifier:cfidentifier.AsNSString()];
642 if (m_macToolbar != NULL)
644 [tb setDelegate:controller];
646 NSToolbarDisplayMode mode = NSToolbarDisplayModeDefault;
647 NSToolbarSizeMode displaySize = NSToolbarSizeModeSmall;
649 if ( style & wxTB_NOICONS )
650 mode = NSToolbarDisplayModeLabelOnly;
651 else if ( style & wxTB_TEXT )
652 mode = NSToolbarDisplayModeIconAndLabel;
654 mode = NSToolbarDisplayModeIconOnly;
656 [tb setDisplayMode:mode];
657 [tb setSizeMode:displaySize];
660 #endif // wxOSX_USE_NATIVE_TOOLBAR
662 return (err == noErr);
665 wxToolBar::~wxToolBar()
667 // removal only works while the toolbar is there
668 wxFrame *frame = wxDynamicCast(GetParent(), wxFrame);
669 if ( frame && frame->GetToolBar() == this )
671 frame->SetToolBar(NULL);
674 [(NSToolbar*)m_macToolbar setDelegate:nil];
675 [(NSToolbar*)m_macToolbar release];
679 bool wxToolBar::Show( bool show )
681 WXWindow tlw = MacGetTopLevelWindowRef();
682 bool bResult = (tlw != NULL);
686 #if wxOSX_USE_NATIVE_TOOLBAR
687 bool ownToolbarInstalled = false;
688 MacTopLevelHasNativeToolbar( &ownToolbarInstalled );
689 if (ownToolbarInstalled)
691 bResult = ([(NSToolbar*)m_macToolbar isVisible] != show);
693 [(NSToolbar*)m_macToolbar setVisible:show];
696 bResult = wxToolBarBase::Show( show );
699 bResult = wxToolBarBase::Show( show );
706 bool wxToolBar::IsShown() const
710 #if wxOSX_USE_NATIVE_TOOLBAR
711 bool ownToolbarInstalled;
713 MacTopLevelHasNativeToolbar( &ownToolbarInstalled );
714 if (ownToolbarInstalled)
716 bResult = [(NSToolbar*)m_macToolbar isVisible];
719 bResult = wxToolBarBase::IsShown();
722 bResult = wxToolBarBase::IsShown();
728 void wxToolBar::DoGetSize( int *width, int *height ) const
730 #if wxOSX_USE_NATIVE_TOOLBAR
731 bool ownToolbarInstalled;
733 MacTopLevelHasNativeToolbar( &ownToolbarInstalled );
734 if ( ownToolbarInstalled )
736 WXWindow tlw = MacGetTopLevelWindowRef();
737 float toolbarHeight = 0.0;
738 NSRect windowFrame = NSMakeRect(0, 0, 0, 0);
740 if(m_macToolbar && [(NSToolbar*)m_macToolbar isVisible])
742 windowFrame = [NSWindow contentRectForFrameRect:[tlw frame]
743 styleMask:[tlw styleMask]];
744 toolbarHeight = NSHeight(windowFrame)
745 - NSHeight([[tlw contentView] frame]);
749 *width = (int)windowFrame.size.width;
750 if ( height != NULL )
751 *height = (int)toolbarHeight;
754 wxToolBarBase::DoGetSize( width, height );
757 wxToolBarBase::DoGetSize( width, height );
761 wxSize wxToolBar::DoGetBestSize() const
763 // was updated in Realize()
765 wxSize size = GetMinSize();
770 void wxToolBar::SetWindowStyleFlag( long style )
772 wxToolBarBase::SetWindowStyleFlag( style );
774 #if wxOSX_USE_NATIVE_TOOLBAR
775 if (m_macToolbar != NULL)
777 NSToolbarDisplayMode mode = NSToolbarDisplayModeDefault;
779 if ( style & wxTB_NOICONS )
780 mode = NSToolbarDisplayModeLabelOnly;
781 else if ( style & wxTB_TEXT )
782 mode = NSToolbarDisplayModeIconAndLabel;
784 mode = NSToolbarDisplayModeIconOnly;
786 [(NSToolbar*) m_macToolbar setDisplayMode:mode];
791 #if wxOSX_USE_NATIVE_TOOLBAR
792 bool wxToolBar::MacWantsNativeToolbar()
794 return m_macUsesNativeToolbar;
797 bool wxToolBar::MacTopLevelHasNativeToolbar(bool *ownToolbarInstalled) const
799 bool bResultV = false;
801 if (ownToolbarInstalled != NULL)
802 *ownToolbarInstalled = false;
804 WXWindow tlw = MacGetTopLevelWindowRef();
807 NSToolbar* curToolbarRef = [tlw toolbar];
808 bResultV = (curToolbarRef != NULL);
809 if (bResultV && (ownToolbarInstalled != NULL))
810 *ownToolbarInstalled = (curToolbarRef == m_macToolbar);
816 bool wxToolBar::MacInstallNativeToolbar(bool usesNative)
818 bool bResult = false;
820 if (usesNative && (m_macToolbar == NULL))
823 if (usesNative && HasFlag(wxTB_LEFT|wxTB_RIGHT|wxTB_BOTTOM) )
826 WXWindow tlw = MacGetTopLevelWindowRef();
830 // check the existing toolbar
831 NSToolbar* curToolbarRef = [tlw toolbar];
833 m_macUsesNativeToolbar = usesNative;
835 if (m_macUsesNativeToolbar)
837 // only install toolbar if there isn't one installed already
838 if (curToolbarRef == NULL)
841 [tlw setToolbar:(NSToolbar*) m_macToolbar];
842 [(NSToolbar*) m_macToolbar setVisible:YES];
844 GetPeer()->Move(0,0,0,0 );
845 SetSize( wxSIZE_AUTO_WIDTH, 0 );
846 GetPeer()->SetVisibility( false );
847 wxToolBarBase::Show( false );
852 // only deinstall toolbar if this is the installed one
853 if (m_macToolbar == curToolbarRef)
856 [(NSToolbar*) m_macToolbar setVisible:NO];
857 MacUninstallNativeToolbar();
858 GetPeer()->SetVisibility( true );
863 InvalidateBestSize();
865 // wxLogDebug( wxT(" --> [%lx] - result [%s]"), (long)this, bResult ? wxT("T") : wxT("F") );
869 void wxToolBar::MacUninstallNativeToolbar()
874 WXWindow tlw = MacGetTopLevelWindowRef();
876 [tlw setToolbar:nil];
880 void wxToolBar::DoLayout()
882 int maxToolWidth = 0;
883 int maxToolHeight = 0;
888 // find the maximum tool width and height
889 // and the number of stretchable items
890 int numStretchableSpaces = 0;
892 wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst();
895 tool = (wxToolBarTool *) node->GetData();
898 wxSize sz = tool->GetSize();
900 if ( sz.x > maxToolWidth )
902 if ( sz.y > maxToolHeight )
903 maxToolHeight = sz.y;
904 if ( tool->IsStretchableSpace() )
905 numStretchableSpaces++;
908 node = node->GetNext();
911 // layout non-native toolbar
913 bool isHorizontal = !IsVertical();
918 int x = m_xMargin + kwxMacToolBarLeftMargin;
919 int y = m_yMargin + kwxMacToolBarTopMargin;
921 node = m_tools.GetFirst();
924 tool = (wxToolBarTool*) node->GetData();
927 node = node->GetNext();
931 // set tool position:
932 // for the moment just perform a single row/column alignment
933 wxSize cursize = tool->GetSize();
934 if ( x + cursize.x > maxWidth )
935 maxWidth = x + cursize.x;
936 if ( y + cursize.y > maxHeight )
937 maxHeight = y + cursize.y;
939 // update the item positioning state
941 y += cursize.y + kwxMacToolSpacing;
943 x += cursize.x + kwxMacToolSpacing;
945 node = node->GetNext();
950 // if not set yet, only one row
951 if ( m_maxRows <= 0 )
954 maxWidth += m_xMargin + kwxMacToolBarLeftMargin;
955 m_minWidth = maxWidth;
956 m_minHeight = m_maxHeight = maxToolHeight + 2 * (m_yMargin + kwxMacToolBarTopMargin);
960 // if not set yet, have one column
961 if ( (GetToolsCount() > 0) && (m_maxRows <= 0) )
962 SetRows( GetToolsCount() );
964 maxHeight += m_yMargin + kwxMacToolBarTopMargin;
965 m_minHeight = maxHeight;
966 m_minWidth = m_maxWidth = maxToolWidth + 2 * (m_yMargin + kwxMacToolBarTopMargin);
969 int totalStretchableSpace = 0;
970 int spacePerStretchable = 0;
971 if ( numStretchableSpaces > 0 )
974 totalStretchableSpace = tw - maxWidth;
976 totalStretchableSpace = th - maxHeight;
978 if ( totalStretchableSpace > 0 )
979 spacePerStretchable = totalStretchableSpace / numStretchableSpaces;
982 // perform real positioning
984 x = m_xMargin + kwxMacToolBarLeftMargin;
985 y = m_yMargin + kwxMacToolBarTopMargin;
987 node = m_tools.GetFirst();
988 int currentStretchable = 0;
991 tool = (wxToolBarTool*) node->GetData();
994 node = node->GetNext();
998 wxSize cursize = tool->GetSize();
999 if ( tool->IsStretchableSpace() )
1001 ++currentStretchable;
1002 int thisSpace = currentStretchable == numStretchableSpaces ?
1003 totalStretchableSpace - (currentStretchable-1)*spacePerStretchable :
1004 spacePerStretchable;
1006 cursize.x += thisSpace;
1008 cursize.y += thisSpace;
1011 if ( !isHorizontal )
1013 int x1 = x + ( maxToolWidth - cursize.x ) / 2;
1014 tool->SetPosition( wxPoint(x1, y) );
1018 int y1 = y + ( maxToolHeight - cursize.y ) / 2;
1019 tool->SetPosition( wxPoint(x, y1) );
1022 // update the item positioning state
1023 if ( !isHorizontal )
1024 y += cursize.y + kwxMacToolSpacing;
1026 x += cursize.x + kwxMacToolSpacing;
1028 node = node->GetNext();
1033 bool wxToolBar::Realize()
1035 if ( !wxToolBarBase::Realize() )
1038 wxToolBarTool *tool;
1039 wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst();
1041 #if wxOSX_USE_NATIVE_TOOLBAR
1042 CFIndex currentPosition = 0;
1043 bool insertAll = false;
1045 NSToolbar* refTB = (NSToolbar*)m_macToolbar;
1050 enc = f.GetEncoding();
1052 enc = wxFont::GetDefaultEncoding();
1054 node = m_tools.GetFirst();
1057 tool = (wxToolBarTool*) node->GetData();
1060 node = node->GetNext();
1064 // install in native NSToolbar
1067 NSToolbarItem* hiItemRef = tool->GetToolbarItemRef();
1068 if ( hiItemRef != NULL )
1070 // since setting the help texts is non-virtual we have to update
1072 wxCFStringRef sh( tool->GetShortHelp(), enc);
1073 [hiItemRef setToolTip:sh.AsNSString()];
1075 if ( insertAll || (tool->GetIndex() != currentPosition) )
1081 // if this is the first tool that gets newly inserted or repositioned
1082 // first remove all 'old' tools from here to the right, because of this
1083 // all following tools will have to be reinserted (insertAll).
1084 for ( wxToolBarToolsList::compatibility_iterator node2 = m_tools.GetLast();
1086 node2 = node2->GetPrevious() )
1088 wxToolBarTool *tool2 = (wxToolBarTool*) node2->GetData();
1090 const long idx = tool2->GetIndex();
1093 [refTB removeItemAtIndex:idx];
1094 tool2->SetIndex(-1);
1099 wxCFStringRef cfidentifier;
1101 if (tool->GetStyle() == wxTOOL_STYLE_SEPARATOR)
1103 nsItemId = tool->IsStretchable() ? NSToolbarFlexibleSpaceItemIdentifier
1104 : NSToolbarSeparatorItemIdentifier;
1108 cfidentifier = wxCFStringRef(wxString::Format("%ld", (long)tool));
1109 nsItemId = cfidentifier.AsNSString();
1112 [refTB insertItemWithItemIdentifier:nsItemId atIndex:currentPosition];
1113 tool->SetIndex( currentPosition );
1119 node = node->GetNext();
1126 // adjust radio items
1128 bool lastIsRadio = false;
1129 bool curIsRadio = false;
1131 node = m_tools.GetFirst();
1134 tool = (wxToolBarTool*) node->GetData();
1137 node = node->GetNext();
1141 // update radio button (and group) state
1142 lastIsRadio = curIsRadio;
1143 curIsRadio = ( tool->IsButton() && (tool->GetKind() == wxITEM_RADIO) );
1147 if ( tool->IsToggled() )
1148 DoToggleTool( tool, true );
1154 if ( tool->Toggle( true ) )
1156 DoToggleTool( tool, true );
1159 else if ( tool->IsToggled() )
1161 if ( tool->IsToggled() )
1162 DoToggleTool( tool, true );
1164 wxToolBarToolsList::compatibility_iterator nodePrev = node->GetPrevious();
1167 wxToolBarToolBase *toggleTool = nodePrev->GetData();
1168 if ( (toggleTool == NULL) || !toggleTool->IsButton() || (toggleTool->GetKind() != wxITEM_RADIO) )
1171 if ( toggleTool->Toggle( false ) )
1172 DoToggleTool( toggleTool, false );
1174 nodePrev = nodePrev->GetPrevious();
1179 node = node->GetNext();
1182 InvalidateBestSize();
1183 SetInitialSize( wxSize(m_minWidth, m_minHeight));
1185 SendSizeEventToParent();
1190 void wxToolBar::DoSetSize(int x, int y, int width, int height, int sizeFlags)
1192 wxToolBarBase::DoSetSize(x, y, width, height, sizeFlags);
1197 void wxToolBar::SetToolBitmapSize(const wxSize& size)
1199 m_defaultWidth = size.x + kwxMacToolBorder;
1200 m_defaultHeight = size.y + kwxMacToolBorder;
1202 #if wxOSX_USE_NATIVE_TOOLBAR
1203 if (m_macToolbar != NULL)
1205 int maxs = wxMax( size.x, size.y );
1206 NSToolbarSizeMode sizeSpec;
1208 sizeSpec = NSToolbarSizeModeRegular;
1209 else if ( maxs > 24 )
1210 sizeSpec = NSToolbarSizeModeDefault;
1212 sizeSpec = NSToolbarSizeModeSmall;
1214 [(NSToolbar*) m_macToolbar setSizeMode:sizeSpec ];
1219 // The button size is bigger than the bitmap size
1220 wxSize wxToolBar::GetToolSize() const
1222 return wxSize(m_defaultWidth + kwxMacToolBorder, m_defaultHeight + kwxMacToolBorder);
1225 void wxToolBar::SetRows(int nRows)
1227 // avoid resizing the frame uselessly
1228 if ( nRows != m_maxRows )
1232 void wxToolBar::MacSuperChangedPosition()
1234 wxWindow::MacSuperChangedPosition();
1237 #if wxOSX_USE_NATIVE_TOOLBAR
1238 if (! m_macUsesNativeToolbar )
1247 void wxToolBar::SetToolNormalBitmap( int id, const wxBitmap& bitmap )
1249 wxToolBarTool* tool = static_cast<wxToolBarTool*>(FindById(id));
1252 wxCHECK_RET( tool->IsButton(), wxT("Can only set bitmap on button tools."));
1254 tool->SetNormalBitmap(bitmap);
1256 // a side-effect of the UpdateToggleImage function is that it always changes the bitmap used on the button.
1257 tool->UpdateImages();
1261 void wxToolBar::SetToolDisabledBitmap( int id, const wxBitmap& bitmap )
1263 wxToolBarTool* tool = static_cast<wxToolBarTool*>(FindById(id));
1266 wxCHECK_RET( tool->IsButton(), wxT("Can only set bitmap on button tools."));
1268 tool->SetDisabledBitmap(bitmap);
1270 // TODO: what to do for this one?
1274 wxToolBarToolBase *wxToolBar::FindToolForPosition(wxCoord x, wxCoord y) const
1276 wxToolBarTool *tool;
1277 wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst();
1280 tool = (wxToolBarTool *)node->GetData();
1283 wxRect2DInt r( tool->GetPosition(), tool->GetSize() );
1284 if ( r.Contains( wxPoint( x, y ) ) )
1288 node = node->GetNext();
1294 wxString wxToolBar::MacGetToolTipString( wxPoint &pt )
1296 wxToolBarToolBase *tool = FindToolForPosition( pt.x, pt.y );
1298 return tool->GetShortHelp();
1300 return wxEmptyString;
1303 void wxToolBar::DoEnableTool(wxToolBarToolBase * WXUNUSED(t), bool WXUNUSED(enable))
1305 // everything already done in the tool's Enable implementation
1308 void wxToolBar::DoToggleTool(wxToolBarToolBase *t, bool toggle)
1310 wxToolBarTool *tool = (wxToolBarTool *)t;
1311 if ( ( tool != NULL ) && tool->IsButton() )
1312 tool->UpdateToggleImage( toggle );
1315 bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos), wxToolBarToolBase *toolBase)
1317 wxToolBarTool *tool = static_cast< wxToolBarTool*>(toolBase );
1321 long style = GetWindowStyleFlag();
1323 wxSize toolSize = GetToolSize();
1324 WXWidget controlHandle = NULL;
1325 NSRect toolrect = NSMakeRect(0, 0, toolSize.x, toolSize.y );
1327 #if wxOSX_USE_NATIVE_TOOLBAR
1328 wxString label = tool->GetLabel();
1329 if (m_macToolbar && !label.empty() )
1331 // strip mnemonics from the label for compatibility
1332 // with the usual labels in wxStaticText sense
1333 label = wxStripMenuCodes(label);
1335 #endif // wxOSX_USE_NATIVE_TOOLBAR
1337 switch (tool->GetStyle())
1339 case wxTOOL_STYLE_SEPARATOR:
1341 wxASSERT( tool->GetControlHandle() == NULL );
1345 toolrect.size.height = toolSize.y;
1347 toolrect.size.width = toolSize.x;
1349 // in flat style we need a visual separator
1350 #if wxOSX_USE_NATIVE_TOOLBAR
1351 if (m_macToolbar != NULL)
1353 NSString * nsItemId = tool->IsStretchable() ? NSToolbarFlexibleSpaceItemIdentifier
1354 : NSToolbarSeparatorItemIdentifier;
1355 NSToolbarItem* item = [[NSToolbarItem alloc] initWithItemIdentifier:nsItemId];
1356 tool->SetToolbarItemRef( item );
1358 #endif // wxOSX_USE_NATIVE_TOOLBAR
1360 NSBox* box = [[NSBox alloc] initWithFrame:toolrect];
1361 [box setBoxType:NSBoxSeparator];
1362 controlHandle = box;
1363 tool->SetControlHandle( controlHandle );
1367 case wxTOOL_STYLE_BUTTON:
1369 wxASSERT( tool->GetControlHandle() == NULL );
1371 wxNSToolBarButton* v = [[wxNSToolBarButton alloc] initWithFrame:toolrect];
1373 [v setBezelStyle:NSRegularSquareBezelStyle];
1375 [v setButtonType: ( tool->CanBeToggled() ? NSToggleButton : NSMomentaryPushInButton )];
1376 [v setImplementation:tool];
1378 if ( style & wxTB_NOICONS )
1379 [v setImagePosition:NSNoImage];
1380 else if ( style & wxTB_TEXT )
1381 [v setImagePosition:NSImageAbove];
1383 [v setImagePosition:NSImageOnly];
1388 #if wxOSX_USE_NATIVE_TOOLBAR
1389 if (m_macToolbar != NULL)
1391 wxString identifier = wxString::Format(wxT("%ld"), (long) tool);
1392 wxCFStringRef cfidentifier( identifier, wxFont::GetDefaultEncoding() );
1393 wxNSToolbarItem* item = [[wxNSToolbarItem alloc] initWithItemIdentifier:cfidentifier.AsNSString() ];
1394 [item setImplementation:tool];
1395 tool->SetToolbarItemRef( item );
1398 #endif // wxOSX_USE_NATIVE_TOOLBAR
1399 tool->SetControlHandle( controlHandle );
1400 tool->UpdateImages();
1401 tool->UpdateLabel();
1405 InstallControlEventHandler(
1406 (WXWidget) controlHandle, GetwxMacToolBarToolEventHandlerUPP(),
1407 GetEventTypeCount(eventList), eventList, tool, NULL );
1412 case wxTOOL_STYLE_CONTROL:
1414 #if wxOSX_USE_NATIVE_TOOLBAR
1415 if (m_macToolbar != NULL)
1417 WXWidget view = (WXWidget) tool->GetControl()->GetHandle() ;
1418 wxCHECK_MSG( view, false, wxT("control must be non-NULL") );
1420 wxString identifier = wxString::Format(wxT("%ld"), (long) tool);
1421 wxCFStringRef cfidentifier( identifier, wxFont::GetDefaultEncoding() );
1422 wxNSToolbarItem* item = [[wxNSToolbarItem alloc] initWithItemIdentifier:cfidentifier.AsNSString() ];
1423 [item setImplementation:tool];
1424 tool->SetToolbarItemRef( item );
1427 // right now there's nothing to do here
1429 tool->UpdateLabel();
1436 if ( controlHandle )
1438 WXWidget container = (WXWidget) GetHandle();
1439 wxASSERT_MSG( container != NULL, wxT("No valid Mac container control") );
1441 // SetControlVisibility( controlHandle, true, true );
1442 [container addSubview:controlHandle];
1445 // nothing special to do here - we relayout in Realize() later
1446 InvalidateBestSize();
1452 void wxToolBar::DoSetToggle(wxToolBarToolBase *WXUNUSED(tool), bool WXUNUSED(toggle))
1454 wxFAIL_MSG( wxT("not implemented") );
1457 bool wxToolBar::DoDeleteTool(size_t WXUNUSED(pos), wxToolBarToolBase *toolbase)
1459 wxToolBarTool* tool = static_cast< wxToolBarTool*>(toolbase );
1460 wxToolBarToolsList::compatibility_iterator node;
1461 for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
1463 wxToolBarToolBase *tool2 = node->GetData();
1464 if ( tool2 == tool )
1466 // let node point to the next node in the list
1467 node = node->GetNext();
1473 wxSize sz = ((wxToolBarTool*)tool)->GetSize();
1475 #if wxOSX_USE_NATIVE_TOOLBAR
1476 CFIndex removeIndex = tool->GetIndex();
1479 #if wxOSX_USE_NATIVE_TOOLBAR
1480 if (m_macToolbar != NULL)
1482 if ( removeIndex != -1 && m_macToolbar )
1484 [(NSToolbar*) m_macToolbar removeItemAtIndex:removeIndex];
1485 tool->SetIndex( -1 );
1490 tool->ClearControl();
1492 // and finally reposition all the controls after this one
1494 for ( /* node -> first after deleted */; node; node = node->GetNext() )
1496 wxToolBarTool *tool2 = (wxToolBarTool*) node->GetData();
1497 wxPoint pt = tool2->GetPosition();
1504 tool2->SetPosition( pt );
1506 #if wxOSX_USE_NATIVE_TOOLBAR
1507 if (m_macToolbar != NULL)
1509 if ( removeIndex != -1 && tool2->GetIndex() > removeIndex )
1510 tool2->SetIndex( tool2->GetIndex() - 1 );
1515 InvalidateBestSize();
1520 #include <Carbon/Carbon.h>
1522 void wxToolBar::OnPaint(wxPaintEvent& event)
1524 #if wxOSX_USE_NATIVE_TOOLBAR
1525 if ( m_macUsesNativeToolbar )
1527 // nothing to do here
1535 bool drawMetalTheme = MacGetTopLevelWindow()->GetExtraStyle() & wxFRAME_EX_METAL;
1537 if ( UMAGetSystemVersion() < 0x1050 )
1539 if ( !drawMetalTheme )
1541 HIThemePlacardDrawInfo info;
1542 memset( &info, 0, sizeof(info) );
1544 info.state = IsEnabled() ? kThemeStateActive : kThemeStateInactive;
1546 CGContextRef cgContext = (CGContextRef) MacGetCGContextRef();
1547 HIRect rect = CGRectMake( 0, 0, w, h );
1548 HIThemeDrawPlacard( &rect, &info, cgContext, kHIThemeOrientationNormal );
1552 // leave the background as it is (striped or metal)
1559 wxRect rect(0,0,w,h);
1561 dc.GradientFillLinear( rect , wxColour( 0xCC,0xCC,0xCC ), wxColour( 0xA8,0xA8,0xA8 ) , wxSOUTH );
1562 dc.SetPen( wxPen( wxColour( 0x51,0x51,0x51 ) ) );
1563 if ( HasFlag(wxTB_LEFT) )
1564 dc.DrawLine(w-1, 0, w-1, h);
1565 else if ( HasFlag(wxTB_RIGHT) )
1566 dc.DrawLine(0, 0, 0, h);
1567 else if ( HasFlag(wxTB_BOTTOM) )
1568 dc.DrawLine(0, 0, w, 0);
1569 else if ( HasFlag(wxTB_TOP) )
1570 dc.DrawLine(0, h-1, w, h-1);
1576 #endif // wxUSE_TOOLBAR