1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/osx/carbon/toolbar.cpp
3 // Purpose:     wxToolBar
4 // Author:      Stefan Csomor
5 // Modified by:
6 // Created:     04/01/98
7 // Copyright:   (c) Stefan Csomor
8 // Licence:     wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10 
11 #include "wx/wxprec.h"
12 
13 #if wxUSE_TOOLBAR
14 
15 #include "wx/toolbar.h"
16 
17 #ifndef WX_PRECOMP
18     #include "wx/wx.h"
19 #endif
20 
21 #include "wx/app.h"
22 #include "wx/osx/private.h"
23 #include "wx/geometry.h"
24 #include "wx/sysopt.h"
25 
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 // ----------------------------------------------------------------------------
43 // private classes
44 // ----------------------------------------------------------------------------
45 
46 // We have a dual implementation for each tool, ControlRef and HIToolbarItemRef
47 
48 // when embedding native controls in the native toolbar we must make sure the
49 // control does not get deleted behind our backs, so the retain count gets increased
50 // (after creation it is 1), first be the creation of the custom HIToolbarItem wrapper
51 // object, and second by the code 'creating' the custom HIView (which is the same as the
52 // already existing native control, therefore we just increase the ref count)
53 // when this view is removed from the native toolbar its count gets decremented again
54 // and when the HITooolbarItem wrapper object gets destroyed it is decremented as well
55 // so in the end the control lives with a refcount of one and can be disposed of by the
56 // wxControl code. For embedded controls on a non-native toolbar this ref count is less
57 // so we can only test against a range, not a specific value of the refcount.
58 
59 class wxToolBarTool : public wxToolBarToolBase
60 {
61 public:
62     wxToolBarTool(
63         wxToolBar *tbar,
64         int id,
65         const wxString& label,
66         const wxBitmap& bmpNormal,
67         const wxBitmap& bmpDisabled,
68         wxItemKind kind,
69         wxObject *clientData,
70         const wxString& shortHelp,
71         const wxString& longHelp );
72 
wxToolBarTool(wxToolBar * tbar,wxControl * control,const wxString & label)73     wxToolBarTool(wxToolBar *tbar, wxControl *control, const wxString& label)
74         : wxToolBarToolBase(tbar, control, label)
75     {
76         Init();
77         if (control != NULL)
78             SetControlHandle( (ControlRef) control->GetHandle() );
79     }
80 
~wxToolBarTool()81     virtual ~wxToolBarTool()
82     {
83         ClearControl();
84     }
85 
GetControlHandle()86     WXWidget GetControlHandle()
87     {
88         return (WXWidget) m_controlHandle;
89     }
90 
SetControlHandle(ControlRef handle)91     void SetControlHandle( ControlRef handle )
92     {
93         m_controlHandle = handle;
94     }
95 
96     void SetPosition( const wxPoint& position );
97 
ClearControl()98     void ClearControl()
99     {
100         if ( m_controlHandle )
101         {
102             if ( !IsControl() )
103                 DisposeControl( m_controlHandle );
104             else
105             {
106                 // the embedded control is not under the responsibility of the tool, it gets disposed of in the
107                 // proper wxControl destructor
108             }
109             m_controlHandle = NULL ;
110         }
111 
112 #if wxOSX_USE_NATIVE_TOOLBAR
113         if ( m_toolbarItemRef )
114         {
115             CFIndex count = CFGetRetainCount( m_toolbarItemRef ) ;
116             wxTheApp->MacAddToAutorelease(m_toolbarItemRef);
117             CFRelease(m_toolbarItemRef);
118             m_toolbarItemRef = NULL;
119         }
120 #endif // wxOSX_USE_NATIVE_TOOLBAR
121     }
122 
GetSize() const123     wxSize GetSize() const
124     {
125         wxSize curSize;
126 
127         if ( IsControl() )
128         {
129             curSize = GetControl()->GetSize();
130         }
131         else if ( IsButton() )
132         {
133             curSize = GetToolBar()->GetToolSize();
134         }
135         else
136         {
137             // separator size
138             curSize = GetToolBar()->GetToolSize();
139             if ( GetToolBar()->GetWindowStyleFlag() & (wxTB_LEFT|wxTB_RIGHT) )
140                 curSize.y /= 4;
141             else
142                 curSize.x /= 4;
143         }
144 
145         return curSize;
146     }
147 
GetPosition() const148     wxPoint GetPosition() const
149     {
150         return wxPoint( m_x, m_y );
151     }
152 
153     virtual bool Enable( bool enable );
154 
155     void UpdateToggleImage( bool toggle );
156 
Toggle(bool toggle)157     virtual bool Toggle(bool toggle)
158     {
159         if ( wxToolBarToolBase::Toggle( toggle ) == false )
160             return false;
161 
162         UpdateToggleImage(toggle);
163         return true;
164     }
165 
UpdateHelpStrings()166     void UpdateHelpStrings()
167     {
168 #if wxOSX_USE_NATIVE_TOOLBAR
169         if ( m_toolbarItemRef )
170         {
171             wxFontEncoding enc = GetToolBarFontEncoding();
172 
173             HIToolbarItemSetHelpText(
174                 m_toolbarItemRef,
175                 wxCFStringRef( GetShortHelp(), enc ),
176                 wxCFStringRef( GetLongHelp(), enc ) );
177         }
178 #endif
179     }
180 
SetShortHelp(const wxString & help)181     virtual bool SetShortHelp(const wxString& help)
182     {
183         if ( wxToolBarToolBase::SetShortHelp( help ) == false )
184             return false;
185 
186         UpdateHelpStrings();
187         return true;
188     }
189 
SetLongHelp(const wxString & help)190     virtual bool SetLongHelp(const wxString& help)
191     {
192         if ( wxToolBarToolBase::SetLongHelp( help ) == false )
193             return false;
194 
195         UpdateHelpStrings();
196         return true;
197     }
198 
SetNormalBitmap(const wxBitmap & bmp)199     virtual void SetNormalBitmap(const wxBitmap& bmp)
200     {
201         wxToolBarToolBase::SetNormalBitmap(bmp);
202         UpdateToggleImage(CanBeToggled() && IsToggled());
203     }
204 
SetLabel(const wxString & label)205     virtual void SetLabel(const wxString& label)
206     {
207         wxToolBarToolBase::SetLabel(label);
208 #if wxOSX_USE_NATIVE_TOOLBAR
209         if ( m_toolbarItemRef )
210         {
211             // strip mnemonics from the label for compatibility with the usual
212             // labels in wxStaticText sense
213             wxString labelStr = wxStripMenuCodes(label);
214 
215             HIToolbarItemSetLabel(
216                 m_toolbarItemRef,
217                 wxCFStringRef(labelStr, GetToolBarFontEncoding()) );
218         }
219 #endif
220     }
221 
222 #if wxOSX_USE_NATIVE_TOOLBAR
SetToolbarItemRef(HIToolbarItemRef ref)223     void SetToolbarItemRef( HIToolbarItemRef ref )
224     {
225         if ( m_controlHandle )
226             HideControl( m_controlHandle );
227         if ( m_toolbarItemRef )
228             CFRelease( m_toolbarItemRef );
229 
230         m_toolbarItemRef = ref;
231         UpdateHelpStrings();
232     }
233 
GetToolbarItemRef() const234     HIToolbarItemRef GetToolbarItemRef() const
235     {
236         return m_toolbarItemRef;
237     }
238 
SetIndex(CFIndex idx)239     void SetIndex( CFIndex idx )
240     {
241         m_index = idx;
242     }
243 
GetIndex() const244     CFIndex GetIndex() const
245     {
246         return m_index;
247     }
248 #endif // wxOSX_USE_NATIVE_TOOLBAR
249 
250 private:
251 #if wxOSX_USE_NATIVE_TOOLBAR
GetToolBarFontEncoding() const252     wxFontEncoding GetToolBarFontEncoding() const
253     {
254         wxFont f;
255         if ( GetToolBar() )
256             f = GetToolBar()->GetFont();
257         return f.IsOk() ? f.GetEncoding() : wxFont::GetDefaultEncoding();
258     }
259 #endif // wxOSX_USE_NATIVE_TOOLBAR
260 
Init()261     void Init()
262     {
263         m_controlHandle = NULL;
264 
265 #if wxOSX_USE_NATIVE_TOOLBAR
266         m_toolbarItemRef = NULL;
267         m_index = -1;
268 #endif
269     }
270 
271     ControlRef m_controlHandle;
272     wxCoord     m_x;
273     wxCoord     m_y;
274 
275 #if wxOSX_USE_NATIVE_TOOLBAR
276     HIToolbarItemRef m_toolbarItemRef;
277     // position in its toolbar, -1 means not inserted
278     CFIndex m_index;
279 #endif
280 };
281 
282 static const EventTypeSpec eventList[] =
283 {
284     { kEventClassControl, kEventControlHit },
285     { kEventClassControl, kEventControlHitTest },
286 };
287 
wxMacToolBarToolControlEventHandler(EventHandlerCallRef WXUNUSED (handler),EventRef event,void * data)288 static pascal OSStatus wxMacToolBarToolControlEventHandler( EventHandlerCallRef WXUNUSED(handler), EventRef event, void *data )
289 {
290     OSStatus result = eventNotHandledErr;
291     ControlRef controlRef;
292     wxMacCarbonEvent cEvent( event );
293 
294     cEvent.GetParameter( kEventParamDirectObject, &controlRef );
295 
296     switch ( GetEventKind( event ) )
297     {
298         case kEventControlHit:
299             {
300                 wxToolBarTool *tbartool = (wxToolBarTool*)data;
301                 wxToolBar *tbar = tbartool != NULL ? (wxToolBar*) (tbartool->GetToolBar()) : NULL;
302                 if ((tbartool != NULL) && tbartool->CanBeToggled())
303                 {
304                     bool    shouldToggle;
305 
306                     shouldToggle = !tbartool->IsToggled();
307 
308                     tbar->ToggleTool( tbartool->GetId(), shouldToggle );
309                 }
310 
311                 if (tbartool != NULL)
312                     tbar->OnLeftClick( tbartool->GetId(), tbartool->IsToggled() );
313                 result = noErr;
314             }
315             break;
316 
317         case kEventControlHitTest:
318             {
319                 HIPoint pt = cEvent.GetParameter<HIPoint>(kEventParamMouseLocation);
320                 HIRect rect;
321                 HIViewGetBounds( controlRef, &rect );
322 
323                 ControlPartCode pc = kControlNoPart;
324                 if ( CGRectContainsPoint( rect, pt ) )
325                     pc = kControlIconPart;
326                 cEvent.SetParameter( kEventParamControlPart, typeControlPartCode, pc );
327                 result = noErr;
328             }
329             break;
330 
331         default:
332             break;
333     }
334 
335     return result;
336 }
337 
wxMacToolBarToolEventHandler(EventHandlerCallRef handler,EventRef event,void * data)338 static pascal OSStatus wxMacToolBarToolEventHandler( EventHandlerCallRef handler, EventRef event, void *data )
339 {
340     OSStatus result = eventNotHandledErr;
341 
342     switch ( GetEventClass( event ) )
343     {
344         case kEventClassControl:
345             result = wxMacToolBarToolControlEventHandler( handler, event, data );
346             break;
347 
348         default:
349             break;
350     }
351 
352     return result;
353 }
354 
355 DEFINE_ONE_SHOT_HANDLER_GETTER( wxMacToolBarToolEventHandler )
356 
357 #if wxOSX_USE_NATIVE_TOOLBAR
358 
359 static const EventTypeSpec toolBarEventList[] =
360 {
361     { kEventClassToolbarItem, kEventToolbarItemPerformAction },
362 };
363 
wxMacToolBarCommandEventHandler(EventHandlerCallRef WXUNUSED (handler),EventRef event,void * data)364 static pascal OSStatus wxMacToolBarCommandEventHandler( EventHandlerCallRef WXUNUSED(handler), EventRef event, void *data )
365 {
366     OSStatus result = eventNotHandledErr;
367 
368     switch ( GetEventKind( event ) )
369     {
370         case kEventToolbarItemPerformAction:
371             {
372                 wxToolBarTool* tbartool = (wxToolBarTool*) data;
373                 if ( tbartool != NULL )
374                 {
375                     wxToolBar *tbar = (wxToolBar*)(tbartool->GetToolBar());
376                     int toolID = tbartool->GetId();
377 
378                     if ( tbartool->CanBeToggled() )
379                     {
380                         if ( tbar != NULL )
381                             tbar->ToggleTool(toolID, !tbartool->IsToggled() );
382                     }
383 
384                     if ( tbar != NULL )
385                         tbar->OnLeftClick( toolID, tbartool->IsToggled() );
386                     result = noErr;
387                 }
388             }
389             break;
390 
391         default:
392             break;
393     }
394 
395     return result;
396 }
397 
wxMacToolBarEventHandler(EventHandlerCallRef handler,EventRef event,void * data)398 static pascal OSStatus wxMacToolBarEventHandler( EventHandlerCallRef handler, EventRef event, void *data )
399 {
400     OSStatus result = eventNotHandledErr;
401 
402     switch ( GetEventClass( event ) )
403     {
404         case kEventClassToolbarItem:
405             result = wxMacToolBarCommandEventHandler( handler, event, data );
406             break;
407 
408         default:
409             break;
410     }
411 
412     return result;
413 }
414 
DEFINE_ONE_SHOT_HANDLER_GETTER(wxMacToolBarEventHandler)415 DEFINE_ONE_SHOT_HANDLER_GETTER( wxMacToolBarEventHandler )
416 
417 #endif
418 
419 bool wxToolBarTool::Enable( bool enable )
420 {
421     if ( wxToolBarToolBase::Enable( enable ) == false )
422         return false;
423 
424     if ( IsControl() )
425     {
426         GetControl()->Enable( enable );
427     }
428     else if ( IsButton() )
429     {
430 #if wxOSX_USE_NATIVE_TOOLBAR
431         if ( m_toolbarItemRef != NULL )
432             HIToolbarItemSetEnabled( m_toolbarItemRef, enable );
433 #endif
434 
435         if ( m_controlHandle != NULL )
436         {
437             if ( enable )
438                 EnableControl( m_controlHandle );
439             else
440                 DisableControl( m_controlHandle );
441         }
442     }
443 
444     return true;
445 }
446 
SetPosition(const wxPoint & position)447 void wxToolBarTool::SetPosition( const wxPoint& position )
448 {
449     m_x = position.x;
450     m_y = position.y;
451 
452     int mac_x = position.x;
453     int mac_y = position.y;
454 
455     if ( IsButton() )
456     {
457         Rect contrlRect;
458         GetControlBounds( m_controlHandle, &contrlRect );
459         int former_mac_x = contrlRect.left;
460         int former_mac_y = contrlRect.top;
461         GetToolBar()->GetToolSize();
462 
463         if ( mac_x != former_mac_x || mac_y != former_mac_y )
464         {
465             ::MoveControl( m_controlHandle, mac_x, mac_y );
466         }
467     }
468     else if ( IsControl() )
469     {
470         // embedded native controls are moved by the OS
471 #if wxOSX_USE_NATIVE_TOOLBAR
472         if ( ((wxToolBar*)GetToolBar())->MacWantsNativeToolbar() == false )
473 #endif
474         {
475             GetControl()->Move( position );
476         }
477     }
478     else
479     {
480         // separator
481         Rect contrlRect;
482         GetControlBounds( m_controlHandle, &contrlRect );
483         int former_mac_x = contrlRect.left;
484         int former_mac_y = contrlRect.top;
485 
486         if ( mac_x != former_mac_x || mac_y != former_mac_y )
487             ::MoveControl( m_controlHandle, mac_x, mac_y );
488     }
489 }
490 
UpdateToggleImage(bool toggle)491 void wxToolBarTool::UpdateToggleImage( bool toggle )
492 {
493     if ( toggle )
494     {
495         int w = m_bmpNormal.GetWidth() + 6;
496         int h = m_bmpNormal.GetHeight() + 6;
497         wxBitmap bmp( w, h );
498         wxMemoryDC dc;
499 
500         dc.SelectObject( bmp );
501         wxColour mid_grey_75   = wxColour(128, 128, 128, 196);
502         wxColour light_grey_75 = wxColour(196, 196, 196, 196);
503         dc.GradientFillLinear( wxRect(1, 1, w - 1, h-1),
504                                light_grey_75, mid_grey_75, wxNORTH);
505         wxColour black_50 = wxColour(0, 0, 0, 127);
506         dc.SetPen( wxPen(black_50) );
507         dc.DrawRoundedRectangle( 0, 0, w, h, 1.5 );
508         dc.DrawBitmap( m_bmpNormal, 3, 3, true );
509         dc.SelectObject( wxNullBitmap );
510         ControlButtonContentInfo info;
511         wxMacCreateBitmapButton( &info, bmp );
512         SetControlData( m_controlHandle, 0, kControlIconContentTag, sizeof(info), (Ptr)&info );
513 #if wxOSX_USE_NATIVE_TOOLBAR
514         if (m_toolbarItemRef != NULL)
515         {
516             ControlButtonContentInfo info2;
517             wxMacCreateBitmapButton( &info2, bmp, kControlContentCGImageRef);
518             HIToolbarItemSetImage( m_toolbarItemRef, info2.u.imageRef );
519             wxMacReleaseBitmapButton( &info2 );
520         }
521 #endif
522         wxMacReleaseBitmapButton( &info );
523     }
524     else
525     {
526         ControlButtonContentInfo info;
527         wxMacCreateBitmapButton( &info, m_bmpNormal );
528         SetControlData( m_controlHandle, 0, kControlIconContentTag, sizeof(info), (Ptr)&info );
529 #if wxOSX_USE_NATIVE_TOOLBAR
530         if (m_toolbarItemRef != NULL)
531         {
532             ControlButtonContentInfo info2;
533             wxMacCreateBitmapButton( &info2, m_bmpNormal, kControlContentCGImageRef);
534             HIToolbarItemSetImage( m_toolbarItemRef, info2.u.imageRef );
535             wxMacReleaseBitmapButton( &info2 );
536         }
537 #endif
538         wxMacReleaseBitmapButton( &info );
539     }
540 
541     IconTransformType transform = toggle ? kTransformSelected : kTransformNone;
542     SetControlData(
543         m_controlHandle, 0, kControlIconTransformTag,
544         sizeof(transform), (Ptr)&transform );
545     HIViewSetNeedsDisplay( m_controlHandle, true );
546 
547 }
548 
wxToolBarTool(wxToolBar * tbar,int id,const wxString & label,const wxBitmap & bmpNormal,const wxBitmap & bmpDisabled,wxItemKind kind,wxObject * clientData,const wxString & shortHelp,const wxString & longHelp)549 wxToolBarTool::wxToolBarTool(
550     wxToolBar *tbar,
551     int id,
552     const wxString& label,
553     const wxBitmap& bmpNormal,
554     const wxBitmap& bmpDisabled,
555     wxItemKind kind,
556     wxObject *clientData,
557     const wxString& shortHelp,
558     const wxString& longHelp )
559     :
560     wxToolBarToolBase(
561         tbar, id, label, bmpNormal, bmpDisabled, kind,
562         clientData, shortHelp, longHelp )
563 {
564     Init();
565 }
566 
567 #pragma mark -
568 #pragma mark Toolbar Implementation
569 
CreateTool(int id,const wxString & label,const wxBitmap & bmpNormal,const wxBitmap & bmpDisabled,wxItemKind kind,wxObject * clientData,const wxString & shortHelp,const wxString & longHelp)570 wxToolBarToolBase *wxToolBar::CreateTool(
571     int id,
572     const wxString& label,
573     const wxBitmap& bmpNormal,
574     const wxBitmap& bmpDisabled,
575     wxItemKind kind,
576     wxObject *clientData,
577     const wxString& shortHelp,
578     const wxString& longHelp )
579 {
580     return new wxToolBarTool(
581         this, id, label, bmpNormal, bmpDisabled, kind,
582         clientData, shortHelp, longHelp );
583 }
584 
585 wxToolBarToolBase *
CreateTool(wxControl * control,const wxString & label)586 wxToolBar::CreateTool(wxControl *control, const wxString& label)
587 {
588     return new wxToolBarTool(this, control, label);
589 }
590 
Init()591 void wxToolBar::Init()
592 {
593     m_maxWidth = -1;
594     m_maxHeight = -1;
595     m_defaultWidth = kwxMacToolBarToolDefaultWidth;
596     m_defaultHeight = kwxMacToolBarToolDefaultHeight;
597 
598 #if wxOSX_USE_NATIVE_TOOLBAR
599     m_macToolbar = NULL;
600     m_macUsesNativeToolbar = false;
601 #endif
602 }
603 
604 #define kControlToolbarItemClassID      CFSTR( "org.wxwidgets.controltoolbaritem" )
605 
606 const EventTypeSpec kEvents[] =
607 {
608     { kEventClassHIObject, kEventHIObjectConstruct },
609     { kEventClassHIObject, kEventHIObjectInitialize },
610     { kEventClassHIObject, kEventHIObjectDestruct },
611 
612     { kEventClassToolbarItem, kEventToolbarItemCreateCustomView }
613 };
614 
615 const EventTypeSpec kViewEvents[] =
616 {
617     { kEventClassControl, kEventControlGetSizeConstraints }
618 };
619 
620 struct ControlToolbarItem
621 {
622     HIToolbarItemRef    toolbarItem;
623     HIViewRef           viewRef;
624     wxSize              lastValidSize ;
625 };
626 
ControlToolbarItemHandler(EventHandlerCallRef inCallRef,EventRef inEvent,void * inUserData)627 static pascal OSStatus ControlToolbarItemHandler( EventHandlerCallRef inCallRef, EventRef inEvent, void* inUserData )
628 {
629     OSStatus            result = eventNotHandledErr;
630     ControlToolbarItem* object = (ControlToolbarItem*)inUserData;
631 
632     switch ( GetEventClass( inEvent ) )
633     {
634         case kEventClassHIObject:
635             switch ( GetEventKind( inEvent ) )
636             {
637                 case kEventHIObjectConstruct:
638                     {
639                         HIObjectRef         toolbarItem;
640                         ControlToolbarItem* item;
641 
642                         GetEventParameter( inEvent, kEventParamHIObjectInstance, typeHIObjectRef, NULL,
643                             sizeof( HIObjectRef ), NULL, &toolbarItem );
644 
645                         item = (ControlToolbarItem*) malloc(sizeof(ControlToolbarItem)) ;
646                         item->toolbarItem = toolbarItem ;
647                         item->lastValidSize = wxSize(-1,-1);
648                         item->viewRef = NULL ;
649 
650                         SetEventParameter( inEvent, kEventParamHIObjectInstance, typeVoidPtr, sizeof( void * ), &item );
651 
652                         result = noErr ;
653                     }
654                     break;
655 
656                 case kEventHIObjectInitialize:
657                     result = CallNextEventHandler( inCallRef, inEvent );
658                     if ( result == noErr )
659                     {
660                         CFDataRef           data;
661                         GetEventParameter( inEvent, kEventParamToolbarItemConfigData, typeCFTypeRef, NULL,
662                             sizeof( CFTypeRef ), NULL, &data );
663 
664                         HIViewRef viewRef ;
665 
666                         wxASSERT_MSG( CFDataGetLength( data ) == sizeof( viewRef ) , wxT("Illegal Data passed") ) ;
667                         memcpy( &viewRef , CFDataGetBytePtr( data ) , sizeof( viewRef ) ) ;
668 
669                         object->viewRef = (HIViewRef) viewRef ;
670                         // make sure we keep that control during our lifetime
671                         CFRetain( object->viewRef ) ;
672 
673                         verify_noerr(InstallEventHandler( GetControlEventTarget( viewRef ), ControlToolbarItemHandler,
674                                             GetEventTypeCount( kViewEvents ), kViewEvents, object, NULL ));
675                         result = noErr ;
676                     }
677                     break;
678 
679                 case kEventHIObjectDestruct:
680                     {
681                         HIViewRef viewRef = object->viewRef ;
682                         if( viewRef && IsValidControlHandle( viewRef)  )
683                         {
684                             // depending whether the wxControl corresponding to this HIView has already been destroyed or
685                             // not, ref counts differ, so we cannot assert a special value
686                             CFIndex count =  CFGetRetainCount( viewRef ) ;
687                             if ( count >= 1 )
688                             {
689                                 CFRelease( viewRef ) ;
690                             }
691                         }
692                         free( object ) ;
693                         result = noErr;
694                     }
695                     break;
696             }
697             break;
698 
699         case kEventClassToolbarItem:
700             switch ( GetEventKind( inEvent ) )
701             {
702                 case kEventToolbarItemCreateCustomView:
703                 {
704                     HIViewRef viewRef = object->viewRef ;
705                     HIViewRemoveFromSuperview( viewRef ) ;
706                     HIViewSetVisible(viewRef, true) ;
707                     CFRetain( viewRef ) ;
708                     result = SetEventParameter( inEvent, kEventParamControlRef, typeControlRef, sizeof( HIViewRef ), &viewRef );
709                 }
710                 break;
711             }
712             break;
713 
714         case kEventClassControl:
715             switch ( GetEventKind( inEvent ) )
716             {
717                 case kEventControlGetSizeConstraints:
718                 {
719                     wxWindow* wxwindow = wxFindWindowFromWXWidget( (WXWidget) object->viewRef ) ;
720                     if ( wxwindow )
721                     {
722                         // during toolbar layout the native window sometimes gets negative sizes,
723                         // sometimes it just gets shrunk behind our back, so in order to avoid
724                         // ever shrinking more, once a valid size is captured, we keep it
725 
726                         wxSize sz = object->lastValidSize;
727                         if ( sz.x <= 0 || sz.y <= 0 )
728                         {
729                             sz = wxwindow->GetSize() ;
730                             sz.x -= wxwindow->MacGetLeftBorderSize() + wxwindow->MacGetRightBorderSize();
731                             sz.y -= wxwindow->MacGetTopBorderSize() + wxwindow->MacGetBottomBorderSize();
732                             if ( sz.x > 0 && sz.y > 0 )
733                                 object->lastValidSize = sz ;
734                             else
735                                 sz = wxSize(0,0) ;
736                         }
737 
738                         // Extra width to avoid edge of combobox being cut off
739                         sz.x += 3;
740 
741                         HISize min, max;
742                         min.width = max.width = sz.x ;
743                         min.height = max.height = sz.y ;
744 
745                         result = SetEventParameter( inEvent, kEventParamMinimumSize, typeHISize,
746                                                         sizeof( HISize ), &min );
747 
748                         result = SetEventParameter( inEvent, kEventParamMaximumSize, typeHISize,
749                                                         sizeof( HISize ), &max );
750                         result = noErr ;
751                     }
752                 }
753                 break;
754             }
755             break;
756     }
757 
758     return result;
759 }
760 
RegisterControlToolbarItemClass()761 void RegisterControlToolbarItemClass()
762 {
763     static bool sRegistered;
764 
765     if ( !sRegistered )
766     {
767         HIObjectRegisterSubclass( kControlToolbarItemClassID, kHIToolbarItemClassID, 0,
768                 ControlToolbarItemHandler, GetEventTypeCount( kEvents ), kEvents, 0, NULL );
769 
770         sRegistered = true;
771     }
772 }
773 
CreateControlToolbarItem(CFStringRef inIdentifier,CFTypeRef inConfigData)774 HIToolbarItemRef CreateControlToolbarItem(CFStringRef inIdentifier, CFTypeRef inConfigData)
775 {
776     RegisterControlToolbarItemClass();
777 
778     OSStatus            err;
779     EventRef            event;
780     UInt32              options = kHIToolbarItemAllowDuplicates;
781     HIToolbarItemRef    result = NULL;
782 
783     err = CreateEvent( NULL, kEventClassHIObject, kEventHIObjectInitialize, GetCurrentEventTime(), 0, &event );
784     require_noerr( err, CantCreateEvent );
785 
786     SetEventParameter( event, kEventParamAttributes, typeUInt32, sizeof( UInt32 ), &options );
787     SetEventParameter( event, kEventParamToolbarItemIdentifier, typeCFStringRef, sizeof( CFStringRef ), &inIdentifier );
788 
789     if ( inConfigData )
790         SetEventParameter( event, kEventParamToolbarItemConfigData, typeCFTypeRef, sizeof( CFTypeRef ), &inConfigData );
791 
792     err = HIObjectCreate( kControlToolbarItemClassID, event, (HIObjectRef*)&result );
793     check_noerr( err );
794 
795     ReleaseEvent( event );
796 CantCreateEvent :
797     return result ;
798 }
799 
800 #if wxOSX_USE_NATIVE_TOOLBAR
801 static const EventTypeSpec kToolbarEvents[] =
802 {
803     { kEventClassToolbar, kEventToolbarGetDefaultIdentifiers },
804     { kEventClassToolbar, kEventToolbarGetAllowedIdentifiers },
805     { kEventClassToolbar, kEventToolbarCreateItemWithIdentifier },
806 };
807 
ToolbarDelegateHandler(EventHandlerCallRef WXUNUSED (inCallRef),EventRef inEvent,void * WXUNUSED (inUserData))808 static OSStatus ToolbarDelegateHandler(EventHandlerCallRef WXUNUSED(inCallRef),
809                                        EventRef inEvent,
810                                        void* WXUNUSED(inUserData))
811 {
812     OSStatus result = eventNotHandledErr;
813     // Not yet needed
814     // wxToolBar* toolbar = (wxToolBar*) inUserData ;
815     CFMutableArrayRef   array;
816 
817     switch ( GetEventKind( inEvent ) )
818     {
819         case kEventToolbarGetDefaultIdentifiers:
820             {
821                 GetEventParameter( inEvent, kEventParamMutableArray, typeCFMutableArrayRef, NULL,
822                     sizeof( CFMutableArrayRef ), NULL, &array );
823                 // not implemented yet
824                 // GetToolbarDefaultItems( array );
825                 result = noErr;
826             }
827             break;
828 
829         case kEventToolbarGetAllowedIdentifiers:
830             {
831                 GetEventParameter( inEvent, kEventParamMutableArray, typeCFMutableArrayRef, NULL,
832                     sizeof( CFMutableArrayRef ), NULL, &array );
833                 // not implemented yet
834                 // GetToolbarAllowedItems( array );
835                 result = noErr;
836             }
837             break;
838         case kEventToolbarCreateItemWithIdentifier:
839             {
840                 HIToolbarItemRef        item = NULL;
841                 CFTypeRef               data = NULL;
842                 CFStringRef             identifier = NULL ;
843 
844                 GetEventParameter( inEvent, kEventParamToolbarItemIdentifier, typeCFStringRef, NULL,
845                         sizeof( CFStringRef ), NULL, &identifier );
846 
847                 GetEventParameter( inEvent, kEventParamToolbarItemConfigData, typeCFTypeRef, NULL,
848                         sizeof( CFTypeRef ), NULL, &data );
849 
850                 if ( CFStringCompare( kControlToolbarItemClassID, identifier, kCFCompareBackwards ) == kCFCompareEqualTo )
851                 {
852                     item = CreateControlToolbarItem( kControlToolbarItemClassID, data );
853                     if ( item )
854                     {
855                         SetEventParameter( inEvent, kEventParamToolbarItem, typeHIToolbarItemRef,
856                             sizeof( HIToolbarItemRef ), &item );
857                         result = noErr;
858                     }
859                 }
860 
861             }
862             break;
863     }
864     return result ;
865 }
866 #endif // wxOSX_USE_NATIVE_TOOLBAR
867 
868 // also for the toolbar we have the dual implementation:
869 // only when MacInstallNativeToolbar is called is the native toolbar set as the window toolbar
870 
Create(wxWindow * parent,wxWindowID id,const wxPoint & pos,const wxSize & size,long style,const wxString & name)871 bool wxToolBar::Create(
872     wxWindow *parent,
873     wxWindowID id,
874     const wxPoint& pos,
875     const wxSize& size,
876     long style,
877     const wxString& name )
878 {
879     if ( !wxToolBarBase::Create( parent, id, pos, size, style, wxDefaultValidator, name ) )
880         return false;
881 
882     FixupStyle();
883 
884     OSStatus err = noErr;
885 
886 #if wxOSX_USE_NATIVE_TOOLBAR
887     if (parent->IsKindOf(CLASSINFO(wxFrame)) && wxSystemOptions::GetOptionInt(wxT("mac.toolbar.no-native")) != 1)
888     {
889         wxString labelStr = wxString::Format( wxT("%p"), this );
890         err = HIToolbarCreate(
891           wxCFStringRef( labelStr, wxFont::GetDefaultEncoding() ), 0,
892           (HIToolbarRef*) &m_macToolbar );
893 
894         if (m_macToolbar != NULL)
895         {
896             InstallEventHandler( HIObjectGetEventTarget((HIToolbarRef)m_macToolbar ), ToolbarDelegateHandler,
897                     GetEventTypeCount( kToolbarEvents ), kToolbarEvents, this, NULL );
898 
899             HIToolbarDisplayMode mode = kHIToolbarDisplayModeDefault;
900             HIToolbarDisplaySize displaySize = kHIToolbarDisplaySizeSmall;
901 
902             if ( style & wxTB_NOICONS )
903                 mode = kHIToolbarDisplayModeLabelOnly;
904             else if ( style & wxTB_TEXT )
905                 mode = kHIToolbarDisplayModeIconAndLabel;
906             else
907                 mode = kHIToolbarDisplayModeIconOnly;
908 
909             HIToolbarSetDisplayMode( (HIToolbarRef) m_macToolbar, mode );
910           HIToolbarSetDisplaySize( (HIToolbarRef) m_macToolbar, displaySize );
911        }
912     }
913 #endif // wxOSX_USE_NATIVE_TOOLBAR
914 
915     return (err == noErr);
916 }
917 
~wxToolBar()918 wxToolBar::~wxToolBar()
919 {
920 #if wxOSX_USE_NATIVE_TOOLBAR
921     // We could be not using a native tool bar at all, this happens when we're
922     // created with something other than the frame as parent for example.
923     if ( !m_macToolbar )
924         return;
925 
926     // it might already have been uninstalled due to a previous call to Destroy, but in case
927     // wasn't, do so now, otherwise redraw events may occur for deleted objects
928     bool ownToolbarInstalled = false;
929     MacTopLevelHasNativeToolbar( &ownToolbarInstalled );
930     if (ownToolbarInstalled)
931     {
932         MacUninstallNativeToolbar();
933     }
934 
935     CFIndex count = CFGetRetainCount( m_macToolbar ) ;
936     CFRelease( (HIToolbarRef)m_macToolbar );
937     m_macToolbar = NULL;
938 #endif // wxOSX_USE_NATIVE_TOOLBAR
939 }
940 
Show(bool show)941 bool wxToolBar::Show( bool show )
942 {
943     WindowRef tlw = MAC_WXHWND(MacGetTopLevelWindowRef());
944     bool bResult = (tlw != NULL);
945 
946     if (bResult)
947     {
948 #if wxOSX_USE_NATIVE_TOOLBAR
949         bool ownToolbarInstalled = false;
950         MacTopLevelHasNativeToolbar( &ownToolbarInstalled );
951         if (ownToolbarInstalled)
952         {
953             bResult = (IsWindowToolbarVisible( tlw ) != show);
954             if ( bResult )
955                 ShowHideWindowToolbar( tlw, show, false );
956         }
957         else
958             bResult = wxToolBarBase::Show( show );
959 #else
960 
961         bResult = wxToolBarBase::Show( show );
962 #endif
963     }
964 
965     return bResult;
966 }
967 
IsShown() const968 bool wxToolBar::IsShown() const
969 {
970     bool bResult;
971 
972 #if wxOSX_USE_NATIVE_TOOLBAR
973     bool ownToolbarInstalled;
974 
975     MacTopLevelHasNativeToolbar( &ownToolbarInstalled );
976     if (ownToolbarInstalled)
977     {
978         WindowRef tlw = MAC_WXHWND(MacGetTopLevelWindowRef());
979         bResult = IsWindowToolbarVisible( tlw );
980     }
981     else
982         bResult = wxToolBarBase::IsShown();
983 #else
984 
985     bResult = wxToolBarBase::IsShown();
986 #endif
987 
988     return bResult;
989 }
990 
DoGetSize(int * width,int * height) const991 void wxToolBar::DoGetSize( int *width, int *height ) const
992 {
993 #if wxOSX_USE_NATIVE_TOOLBAR
994     Rect    boundsR;
995     bool    ownToolbarInstalled;
996 
997     MacTopLevelHasNativeToolbar( &ownToolbarInstalled );
998     if ( ownToolbarInstalled )
999     {
1000         // TODO: is this really a control ?
1001         GetControlBounds( (ControlRef) m_macToolbar, &boundsR );
1002         if ( width != NULL )
1003             *width = boundsR.right - boundsR.left;
1004         if ( height != NULL )
1005             *height = boundsR.bottom - boundsR.top;
1006     }
1007     else
1008         wxToolBarBase::DoGetSize( width, height );
1009 
1010 #else
1011     wxToolBarBase::DoGetSize( width, height );
1012 #endif
1013 }
1014 
DoGetBestSize() const1015 wxSize wxToolBar::DoGetBestSize() const
1016 {
1017     int width, height;
1018 
1019     DoGetSize( &width, &height );
1020 
1021     return wxSize( width, height );
1022 }
1023 
SetWindowStyleFlag(long style)1024 void wxToolBar::SetWindowStyleFlag( long style )
1025 {
1026     wxToolBarBase::SetWindowStyleFlag( style );
1027 
1028 #if wxOSX_USE_NATIVE_TOOLBAR
1029     if (m_macToolbar != NULL)
1030     {
1031         HIToolbarDisplayMode mode = kHIToolbarDisplayModeDefault;
1032 
1033         if ( style & wxTB_NOICONS )
1034             mode = kHIToolbarDisplayModeLabelOnly;
1035         else if ( style & wxTB_TEXT )
1036             mode = kHIToolbarDisplayModeIconAndLabel;
1037         else
1038             mode = kHIToolbarDisplayModeIconOnly;
1039 
1040        HIToolbarSetDisplayMode( (HIToolbarRef) m_macToolbar, mode );
1041     }
1042 #endif
1043 }
1044 
1045 #if wxOSX_USE_NATIVE_TOOLBAR
MacWantsNativeToolbar()1046 bool wxToolBar::MacWantsNativeToolbar()
1047 {
1048     return m_macUsesNativeToolbar;
1049 }
1050 
MacTopLevelHasNativeToolbar(bool * ownToolbarInstalled) const1051 bool wxToolBar::MacTopLevelHasNativeToolbar(bool *ownToolbarInstalled) const
1052 {
1053     bool bResultV = false;
1054 
1055     if (ownToolbarInstalled != NULL)
1056         *ownToolbarInstalled = false;
1057 
1058     WindowRef tlw = MAC_WXHWND(MacGetTopLevelWindowRef());
1059     if (tlw != NULL)
1060     {
1061         HIToolbarRef curToolbarRef = NULL;
1062         OSStatus err = GetWindowToolbar( tlw, &curToolbarRef );
1063         bResultV = ((err == noErr) && (curToolbarRef != NULL));
1064         if (bResultV && (ownToolbarInstalled != NULL))
1065             *ownToolbarInstalled = (curToolbarRef == m_macToolbar);
1066     }
1067 
1068     return bResultV;
1069 }
1070 
MacInstallNativeToolbar(bool usesNative)1071 bool wxToolBar::MacInstallNativeToolbar(bool usesNative)
1072 {
1073     bool bResult = false;
1074 
1075     if (usesNative && (m_macToolbar == NULL))
1076         return bResult;
1077 
1078     if (usesNative && ((GetWindowStyleFlag() & (wxTB_LEFT|wxTB_RIGHT|wxTB_BOTTOM)) != 0))
1079         return bResult;
1080 
1081     WindowRef tlw = MAC_WXHWND(MacGetTopLevelWindowRef());
1082     if (tlw == NULL)
1083         return bResult;
1084 
1085     // check the existing toolbar
1086     HIToolbarRef curToolbarRef = NULL;
1087     OSStatus err = GetWindowToolbar( tlw, &curToolbarRef );
1088     if (err != noErr)
1089         curToolbarRef = NULL;
1090 
1091     m_macUsesNativeToolbar = usesNative;
1092 
1093     if (m_macUsesNativeToolbar)
1094     {
1095         // only install toolbar if there isn't one installed already
1096         if (curToolbarRef == NULL)
1097         {
1098             bResult = true;
1099 
1100             SetWindowToolbar( tlw, (HIToolbarRef) m_macToolbar );
1101 
1102             // ShowHideWindowToolbar will make the wxFrame grow
1103             // which we don't want in this case
1104             wxSize sz = GetParent()->GetSize();
1105             ShowHideWindowToolbar( tlw, true, false );
1106             // Restore the original size
1107             GetParent()->SetSize( sz );
1108 
1109             ChangeWindowAttributes( tlw, kWindowToolbarButtonAttribute, 0 );
1110 
1111             SetAutomaticControlDragTrackingEnabledForWindow( tlw, true );
1112 
1113             GetPeer()->Move(0,0,0,0 );
1114             SetSize( wxSIZE_AUTO_WIDTH, 0 );
1115             GetPeer()->SetVisibility( false );
1116             wxToolBarBase::Show( false );
1117         }
1118     }
1119     else
1120     {
1121         // only deinstall toolbar if this is the installed one
1122         if (m_macToolbar == curToolbarRef)
1123         {
1124             bResult = true;
1125 
1126             ShowHideWindowToolbar( tlw, false, false );
1127             ChangeWindowAttributes( tlw, 0, kWindowToolbarButtonAttribute );
1128             MacUninstallNativeToolbar();
1129 
1130             GetPeer()->SetVisibility( true );
1131         }
1132     }
1133 
1134     if (bResult)
1135         InvalidateBestSize();
1136 
1137 // wxLogDebug( wxT("    --> [%lx] - result [%s]"), (long)this, bResult ? wxT("T") : wxT("F") );
1138     return bResult;
1139 }
1140 
MacUninstallNativeToolbar()1141 void wxToolBar::MacUninstallNativeToolbar()
1142 {
1143     if (!m_macToolbar)
1144         return;
1145 
1146     WindowRef tlw = MAC_WXHWND(MacGetTopLevelWindowRef());
1147     if (tlw)
1148         SetWindowToolbar( tlw, NULL );
1149 }
1150 #endif
1151 
Realize()1152 bool wxToolBar::Realize()
1153 {
1154     if ( !wxToolBarBase::Realize() )
1155         return false;
1156 
1157     wxSize tlw_sz = GetParent()->GetSize();
1158 
1159     int maxWidth = 0;
1160     int maxHeight = 0;
1161 
1162     int maxToolWidth = 0;
1163     int maxToolHeight = 0;
1164 
1165     int x = m_xMargin + kwxMacToolBarLeftMargin;
1166     int y = m_yMargin + kwxMacToolBarTopMargin;
1167 
1168     int tw, th;
1169     GetSize( &tw, &th );
1170 
1171     // find the maximum tool width and height
1172     wxToolBarTool *tool;
1173     wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst();
1174     while ( node )
1175     {
1176         tool = (wxToolBarTool *) node->GetData();
1177         if ( tool != NULL )
1178         {
1179             wxSize  sz = tool->GetSize();
1180 
1181             if ( sz.x > maxToolWidth )
1182                 maxToolWidth = sz.x;
1183             if ( sz.y > maxToolHeight )
1184                 maxToolHeight = sz.y;
1185         }
1186 
1187         node = node->GetNext();
1188     }
1189 
1190     bool lastIsRadio = false;
1191     bool curIsRadio = false;
1192 
1193 #if wxOSX_USE_NATIVE_TOOLBAR
1194     CFIndex currentPosition = 0;
1195     bool insertAll = false;
1196 
1197     HIToolbarRef refTB = (HIToolbarRef)m_macToolbar;
1198     wxFont f;
1199     wxFontEncoding enc;
1200     f = GetFont();
1201     if ( f.IsOk() )
1202         enc = f.GetEncoding();
1203     else
1204         enc = wxFont::GetDefaultEncoding();
1205 #endif
1206 
1207     node = m_tools.GetFirst();
1208     while ( node )
1209     {
1210         tool = (wxToolBarTool*) node->GetData();
1211         if ( tool == NULL )
1212         {
1213             node = node->GetNext();
1214             continue;
1215         }
1216 
1217         // set tool position:
1218         // for the moment just perform a single row/column alignment
1219         wxSize  cursize = tool->GetSize();
1220         if ( x + cursize.x > maxWidth )
1221             maxWidth = x + cursize.x;
1222         if ( y + cursize.y > maxHeight )
1223             maxHeight = y + cursize.y;
1224 
1225         if ( GetWindowStyleFlag() & (wxTB_LEFT|wxTB_RIGHT) )
1226         {
1227             int x1 = x + ( maxToolWidth - cursize.x ) / 2;
1228             tool->SetPosition( wxPoint(x1, y) );
1229         }
1230         else
1231         {
1232             int y1 = y + ( maxToolHeight - cursize.y ) / 2;
1233             tool->SetPosition( wxPoint(x, y1) );
1234         }
1235 
1236         // update the item positioning state
1237         if ( GetWindowStyleFlag() & (wxTB_LEFT|wxTB_RIGHT) )
1238             y += cursize.y + kwxMacToolSpacing;
1239         else
1240             x += cursize.x + kwxMacToolSpacing;
1241 
1242 #if wxOSX_USE_NATIVE_TOOLBAR
1243         // install in native HIToolbar
1244         if ( refTB )
1245         {
1246             HIToolbarItemRef hiItemRef = tool->GetToolbarItemRef();
1247             if ( hiItemRef != NULL )
1248             {
1249                 // since setting the help texts is non-virtual we have to update
1250                 // the strings now
1251                 if ( insertAll || (tool->GetIndex() != currentPosition) )
1252                 {
1253                     OSStatus err = noErr;
1254                     if ( !insertAll )
1255                     {
1256                         insertAll = true;
1257 
1258                         // if this is the first tool that gets newly inserted or repositioned
1259                         // first remove all 'old' tools from here to the right, because of this
1260                         // all following tools will have to be reinserted (insertAll).
1261                         for ( wxToolBarToolsList::compatibility_iterator node2 = m_tools.GetLast();
1262                               node2 != node;
1263                               node2 = node2->GetPrevious() )
1264                         {
1265                             wxToolBarTool *tool2 = (wxToolBarTool*) node2->GetData();
1266 
1267                             const long idx = tool2->GetIndex();
1268                             if ( idx != -1 )
1269                             {
1270                                 if ( tool2->IsControl() )
1271                                 {
1272                                     CFIndex count = CFGetRetainCount( tool2->GetControl()->GetPeer()->GetControlRef() ) ;
1273                                     if ( count != 3 && count != 2 )
1274                                     {
1275                                         wxFAIL_MSG("Reference count of native tool was illegal before removal");
1276                                     }
1277 
1278                                     wxASSERT( IsValidControlHandle(tool2->GetControl()->GetPeer()->GetControlRef() )) ;
1279                                 }
1280                                 err = HIToolbarRemoveItemAtIndex(refTB, idx);
1281                                 if ( err != noErr )
1282                                 {
1283                                     wxLogDebug(wxT("HIToolbarRemoveItemAtIndex(%ld) failed [%ld]"),
1284                                                idx, (long)err);
1285                                 }
1286                                 if ( tool2->IsControl() )
1287                                 {
1288                                     CFIndex count = CFGetRetainCount( tool2->GetControl()->GetPeer()->GetControlRef() ) ;
1289                                     if ( count != 2 )
1290                                     {
1291                                         wxFAIL_MSG("Reference count of native tool was not 2 after removal");
1292                                     }
1293 
1294                                     wxASSERT( IsValidControlHandle(tool2->GetControl()->GetPeer()->GetControlRef() )) ;
1295                                 }
1296 
1297                                 tool2->SetIndex(-1);
1298                             }
1299                         }
1300                     }
1301 
1302                     err = HIToolbarInsertItemAtIndex( refTB, hiItemRef, currentPosition );
1303                     if (err != noErr)
1304                     {
1305                         wxLogDebug( wxT("HIToolbarInsertItemAtIndex failed [%ld]"), (long)err );
1306                     }
1307 
1308                     tool->SetIndex( currentPosition );
1309                     if ( tool->IsControl() )
1310                     {
1311                         CFIndex count = CFGetRetainCount( tool->GetControl()->GetPeer()->GetControlRef() ) ;
1312                         if ( count != 3 && count != 2 )
1313                         {
1314                             wxFAIL_MSG("Reference count of native tool was illegal before removal");
1315                         }
1316                         wxASSERT( IsValidControlHandle(tool->GetControl()->GetPeer()->GetControlRef() )) ;
1317 
1318                         wxString label = tool->GetLabel();
1319                         if ( !label.empty() )
1320                             HIToolbarItemSetLabel( hiItemRef, wxCFStringRef(label, GetFont().GetEncoding()) );
1321                     }
1322                 }
1323 
1324                 currentPosition++;
1325             }
1326         }
1327 #endif
1328 
1329         // update radio button (and group) state
1330         lastIsRadio = curIsRadio;
1331         curIsRadio = ( tool->IsButton() && (tool->GetKind() == wxITEM_RADIO) );
1332 
1333         if ( !curIsRadio )
1334         {
1335             if ( tool->IsToggled() )
1336                 DoToggleTool( tool, true );
1337         }
1338         else
1339         {
1340             if ( !lastIsRadio )
1341             {
1342                 if ( tool->Toggle( true ) )
1343                 {
1344                     DoToggleTool( tool, true );
1345                 }
1346             }
1347             else if ( tool->IsToggled() )
1348             {
1349                 if ( tool->IsToggled() )
1350                     DoToggleTool( tool, true );
1351 
1352                 wxToolBarToolsList::compatibility_iterator  nodePrev = node->GetPrevious();
1353                 while ( nodePrev )
1354                 {
1355                     wxToolBarToolBase   *toggleTool = nodePrev->GetData();
1356                     if ( (toggleTool == NULL) || !toggleTool->IsButton() || (toggleTool->GetKind() != wxITEM_RADIO) )
1357                         break;
1358 
1359                     if ( toggleTool->Toggle( false ) )
1360                         DoToggleTool( toggleTool, false );
1361 
1362                     nodePrev = nodePrev->GetPrevious();
1363                 }
1364             }
1365         }
1366 
1367         node = node->GetNext();
1368     }
1369 
1370     if (m_macUsesNativeToolbar)
1371         GetParent()->SetSize( tlw_sz );
1372 
1373     if ( GetWindowStyleFlag() &  (wxTB_TOP|wxTB_BOTTOM) )
1374     {
1375         // if not set yet, only one row
1376         if ( m_maxRows <= 0 )
1377             SetRows( 1 );
1378 
1379         m_minWidth = maxWidth;
1380         maxHeight += m_yMargin + kwxMacToolBarTopMargin;
1381         m_minHeight = m_maxHeight = maxHeight;
1382     }
1383     else
1384     {
1385         // if not set yet, have one column
1386         if ( (GetToolsCount() > 0) && (m_maxRows <= 0) )
1387             SetRows( GetToolsCount() );
1388 
1389         m_minHeight = maxHeight;
1390         maxWidth += m_xMargin + kwxMacToolBarLeftMargin;
1391         m_minWidth = m_maxWidth = maxWidth;
1392     }
1393 
1394 #if 0
1395     // FIXME: should this be OSX-only?
1396     {
1397         bool wantNativeToolbar, ownToolbarInstalled;
1398 
1399         // attempt to install the native toolbar
1400         wantNativeToolbar = ((GetWindowStyleFlag() & (wxTB_LEFT|wxTB_BOTTOM|wxTB_RIGHT)) == 0);
1401         MacInstallNativeToolbar( wantNativeToolbar );
1402         (void)MacTopLevelHasNativeToolbar( &ownToolbarInstalled );
1403         if (!ownToolbarInstalled)
1404         {
1405            SetSize( maxWidth, maxHeight );
1406            InvalidateBestSize();
1407         }
1408     }
1409 #else
1410     SetSize( maxWidth, maxHeight );
1411     InvalidateBestSize();
1412 #endif
1413 
1414     SetInitialSize();
1415 
1416     return true;
1417 }
1418 
DoLayout()1419 void wxToolBar::DoLayout()
1420 {
1421     // TODO port back osx_cocoa layout solution
1422 }
1423 
DoSetSize(int x,int y,int width,int height,int sizeFlags)1424 void wxToolBar::DoSetSize(int x, int y, int width, int height, int sizeFlags)
1425 {
1426     wxToolBarBase::DoSetSize(x, y, width, height, sizeFlags);
1427 
1428     DoLayout();
1429 }
1430 
SetToolBitmapSize(const wxSize & size)1431 void wxToolBar::SetToolBitmapSize(const wxSize& size)
1432 {
1433     m_defaultWidth = size.x + kwxMacToolBorder;
1434     m_defaultHeight = size.y + kwxMacToolBorder;
1435 
1436 #if wxOSX_USE_NATIVE_TOOLBAR
1437     if (m_macToolbar != NULL)
1438     {
1439         int maxs = wxMax( size.x, size.y );
1440         HIToolbarDisplaySize sizeSpec;
1441         if ( maxs > 32 )
1442             sizeSpec = kHIToolbarDisplaySizeNormal;
1443         else if ( maxs > 24 )
1444             sizeSpec = kHIToolbarDisplaySizeDefault;
1445         else
1446             sizeSpec = kHIToolbarDisplaySizeSmall;
1447 
1448         HIToolbarSetDisplaySize( (HIToolbarRef) m_macToolbar, sizeSpec );
1449     }
1450 #endif
1451 }
1452 
1453 // The button size is bigger than the bitmap size
GetToolSize() const1454 wxSize wxToolBar::GetToolSize() const
1455 {
1456     return wxSize(m_defaultWidth + kwxMacToolBorder, m_defaultHeight + kwxMacToolBorder);
1457 }
1458 
SetRows(int nRows)1459 void wxToolBar::SetRows(int nRows)
1460 {
1461     // avoid resizing the frame uselessly
1462     if ( nRows != m_maxRows )
1463         m_maxRows = nRows;
1464 }
1465 
MacSuperChangedPosition()1466 void wxToolBar::MacSuperChangedPosition()
1467 {
1468     wxWindow::MacSuperChangedPosition();
1469 
1470 #if wxOSX_USE_NATIVE_TOOLBAR
1471     if (! m_macUsesNativeToolbar )
1472         Realize();
1473 #else
1474 
1475     Realize();
1476 #endif
1477 }
1478 
SetToolNormalBitmap(int id,const wxBitmap & bitmap)1479 void wxToolBar::SetToolNormalBitmap( int id, const wxBitmap& bitmap )
1480 {
1481     wxToolBarTool* tool = static_cast<wxToolBarTool*>(FindById(id));
1482     if ( tool )
1483     {
1484         wxCHECK_RET( tool->IsButton(), wxT("Can only set bitmap on button tools."));
1485 
1486         tool->SetNormalBitmap(bitmap);
1487 
1488         // a side-effect of the UpdateToggleImage function is that it always changes the bitmap used on the button.
1489         tool->UpdateToggleImage( tool->CanBeToggled() && tool->IsToggled() );
1490     }
1491 }
1492 
SetToolDisabledBitmap(int id,const wxBitmap & bitmap)1493 void wxToolBar::SetToolDisabledBitmap( int id, const wxBitmap& bitmap )
1494 {
1495     wxToolBarTool* tool = static_cast<wxToolBarTool*>(FindById(id));
1496     if ( tool )
1497     {
1498         wxCHECK_RET( tool->IsButton(), wxT("Can only set bitmap on button tools."));
1499 
1500         tool->SetDisabledBitmap(bitmap);
1501 
1502         // TODO:  what to do for this one?
1503     }
1504 }
1505 
FindToolForPosition(wxCoord x,wxCoord y) const1506 wxToolBarToolBase *wxToolBar::FindToolForPosition(wxCoord x, wxCoord y) const
1507 {
1508     wxToolBarTool *tool;
1509     wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst();
1510     while ( node )
1511     {
1512         tool = (wxToolBarTool *)node->GetData();
1513         if (tool != NULL)
1514         {
1515             wxRect2DInt r( tool->GetPosition(), tool->GetSize() );
1516             if ( r.Contains( wxPoint( x, y ) ) )
1517                 return tool;
1518         }
1519 
1520         node = node->GetNext();
1521     }
1522 
1523     return NULL;
1524 }
1525 
MacGetToolTipString(wxPoint & pt)1526 wxString wxToolBar::MacGetToolTipString( wxPoint &pt )
1527 {
1528     wxToolBarToolBase *tool = FindToolForPosition( pt.x, pt.y );
1529     if ( tool != NULL )
1530         return tool->GetShortHelp();
1531 
1532     return wxEmptyString;
1533 }
1534 
DoEnableTool(wxToolBarToolBase * WXUNUSED (t),bool WXUNUSED (enable))1535 void wxToolBar::DoEnableTool(wxToolBarToolBase *WXUNUSED(t), bool WXUNUSED(enable))
1536 {
1537     // everything already done in the tool's implementation
1538 }
1539 
DoToggleTool(wxToolBarToolBase * WXUNUSED (t),bool WXUNUSED (toggle))1540 void wxToolBar::DoToggleTool(wxToolBarToolBase *WXUNUSED(t), bool WXUNUSED(toggle))
1541 {
1542     // everything already done in the tool's implementation
1543 }
1544 
DoInsertTool(size_t WXUNUSED (pos),wxToolBarToolBase * toolBase)1545 bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos), wxToolBarToolBase *toolBase)
1546 {
1547     wxToolBarTool *tool = static_cast< wxToolBarTool*>(toolBase );
1548     if (tool == NULL)
1549         return false;
1550 
1551     WindowRef window = (WindowRef) MacGetTopLevelWindowRef();
1552     wxSize toolSize = GetToolSize();
1553     Rect toolrect = { 0, 0, toolSize.y, toolSize.x };
1554     ControlRef controlHandle = NULL;
1555     OSStatus err = 0;
1556 
1557 #if wxOSX_USE_NATIVE_TOOLBAR
1558     wxString label = tool->GetLabel();
1559     if (m_macToolbar && !label.empty() )
1560     {
1561         // strip mnemonics from the label for compatibility
1562         // with the usual labels in wxStaticText sense
1563         label = wxStripMenuCodes(label);
1564     }
1565 #endif // wxOSX_USE_NATIVE_TOOLBAR
1566 
1567     switch (tool->GetStyle())
1568     {
1569         case wxTOOL_STYLE_SEPARATOR:
1570             {
1571                 wxASSERT( tool->GetControlHandle() == NULL );
1572                 toolSize.x /= 4;
1573                 toolSize.y /= 4;
1574                 if ( GetWindowStyleFlag() & (wxTB_LEFT|wxTB_RIGHT) )
1575                     toolrect.bottom = toolSize.y;
1576                 else
1577                     toolrect.right = toolSize.x;
1578 
1579                 // in flat style we need a visual separator
1580 #if wxOSX_USE_NATIVE_TOOLBAR
1581                 if (m_macToolbar != NULL)
1582                 {
1583                     HIToolbarItemRef item;
1584                     err = HIToolbarItemCreate(
1585                         kHIToolbarSeparatorIdentifier,
1586                         kHIToolbarItemCantBeRemoved | kHIToolbarItemIsSeparator | kHIToolbarItemAllowDuplicates,
1587                         &item );
1588                     if (err == noErr)
1589                         tool->SetToolbarItemRef( item );
1590                 }
1591                 else
1592                     err = noErr;
1593 #endif // wxOSX_USE_NATIVE_TOOLBAR
1594 
1595                 CreateSeparatorControl( window, &toolrect, &controlHandle );
1596                 tool->SetControlHandle( controlHandle );
1597             }
1598             break;
1599 
1600         case wxTOOL_STYLE_BUTTON:
1601             {
1602                 wxASSERT( tool->GetControlHandle() == NULL );
1603 
1604                 // contrary to the docs this control only works with iconrefs
1605                 ControlButtonContentInfo info;
1606                 wxMacCreateBitmapButton( &info, tool->GetNormalBitmap(), kControlContentIconRef );
1607                 CreateIconControl( window, &toolrect, &info, false, &controlHandle );
1608                 wxMacReleaseBitmapButton( &info );
1609 
1610 #if wxOSX_USE_NATIVE_TOOLBAR
1611                 if (m_macToolbar != NULL)
1612                 {
1613                     HIToolbarItemRef item;
1614                     wxString labelStr = wxString::Format(wxT("%p"), tool);
1615                     err = HIToolbarItemCreate(
1616                         wxCFStringRef(labelStr, wxFont::GetDefaultEncoding()),
1617                         kHIToolbarItemCantBeRemoved | kHIToolbarItemAnchoredLeft | kHIToolbarItemAllowDuplicates, &item );
1618                     if (err  == noErr)
1619                     {
1620                         ControlButtonContentInfo info2;
1621                         wxMacCreateBitmapButton( &info2, tool->GetNormalBitmap(), kControlContentCGImageRef);
1622 
1623                         InstallEventHandler(
1624                             HIObjectGetEventTarget(item), GetwxMacToolBarEventHandlerUPP(),
1625                             GetEventTypeCount(toolBarEventList), toolBarEventList, tool, NULL );
1626                         HIToolbarItemSetLabel( item, wxCFStringRef(label, GetFont().GetEncoding()) );
1627                         HIToolbarItemSetImage( item, info2.u.imageRef );
1628                         HIToolbarItemSetCommandID( item, kHIToolbarCommandPressAction );
1629                         tool->SetToolbarItemRef( item );
1630 
1631                         wxMacReleaseBitmapButton( &info2 );
1632                     }
1633                 }
1634                 else
1635                     err = noErr;
1636 #endif // wxOSX_USE_NATIVE_TOOLBAR
1637 
1638                 wxMacReleaseBitmapButton( &info );
1639 
1640 #if 0
1641                 SetBevelButtonTextPlacement( m_controlHandle, kControlBevelButtonPlaceBelowGraphic );
1642                 SetControlTitleWithCFString( m_controlHandle , wxCFStringRef( label, wxFont::GetDefaultEncoding() );
1643 #endif
1644 
1645                 InstallControlEventHandler(
1646                     (ControlRef) controlHandle, GetwxMacToolBarToolEventHandlerUPP(),
1647                     GetEventTypeCount(eventList), eventList, tool, NULL );
1648 
1649                 tool->SetControlHandle( controlHandle );
1650             }
1651             break;
1652 
1653         case wxTOOL_STYLE_CONTROL:
1654 
1655 #if wxOSX_USE_NATIVE_TOOLBAR
1656             if (m_macToolbar != NULL)
1657             {
1658                 wxCHECK_MSG( tool->GetControl(), false, wxT("control must be non-NULL") );
1659                 HIToolbarItemRef    item;
1660                 HIViewRef viewRef = (HIViewRef) tool->GetControl()->GetHandle() ;
1661                 CFDataRef data = CFDataCreate( kCFAllocatorDefault , (UInt8*) &viewRef , sizeof(viewRef) ) ;
1662                 err = HIToolbarCreateItemWithIdentifier((HIToolbarRef) m_macToolbar,kControlToolbarItemClassID,
1663                     data , &item ) ;
1664 
1665                 if (err  == noErr)
1666                 {
1667                     tool->SetToolbarItemRef( item );
1668                 }
1669                 CFRelease( data ) ;
1670            }
1671            else
1672            {
1673                err = noErr;
1674                break;
1675            }
1676 #else
1677                 // right now there's nothing to do here
1678 #endif
1679                 break;
1680 
1681         default:
1682             break;
1683     }
1684 
1685     if ( err == noErr )
1686     {
1687         if ( controlHandle )
1688         {
1689             ControlRef container = (ControlRef) GetHandle();
1690             wxASSERT_MSG( container != NULL, wxT("No valid Mac container control") );
1691 
1692             SetControlVisibility( controlHandle, true, true );
1693             ::EmbedControl( controlHandle, container );
1694         }
1695 
1696         if ( tool->CanBeToggled() && tool->IsToggled() )
1697             tool->UpdateToggleImage( true );
1698 
1699         // nothing special to do here - we relayout in Realize() later
1700         InvalidateBestSize();
1701     }
1702     else
1703     {
1704         wxFAIL_MSG( wxString::Format( wxT("wxToolBar::DoInsertTool - failure [%ld]"), (long)err ) );
1705     }
1706 
1707     return (err == noErr);
1708 }
1709 
DoSetToggle(wxToolBarToolBase * WXUNUSED (tool),bool WXUNUSED (toggle))1710 void wxToolBar::DoSetToggle(wxToolBarToolBase *WXUNUSED(tool), bool WXUNUSED(toggle))
1711 {
1712     // nothing to do
1713 }
1714 
DoDeleteTool(size_t WXUNUSED (pos),wxToolBarToolBase * toolbase)1715 bool wxToolBar::DoDeleteTool(size_t WXUNUSED(pos), wxToolBarToolBase *toolbase)
1716 {
1717     wxToolBarTool* tool = static_cast< wxToolBarTool*>(toolbase );
1718     wxToolBarToolsList::compatibility_iterator node;
1719     for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
1720     {
1721         wxToolBarToolBase *tool2 = node->GetData();
1722         if ( tool2 == tool )
1723         {
1724             // let node point to the next node in the list
1725             node = node->GetNext();
1726 
1727             break;
1728         }
1729     }
1730 
1731     wxSize sz = ((wxToolBarTool*)tool)->GetSize();
1732 
1733 #if wxOSX_USE_NATIVE_TOOLBAR
1734     CFIndex removeIndex = tool->GetIndex();
1735 #endif
1736 
1737 #if wxOSX_USE_NATIVE_TOOLBAR
1738     if (m_macToolbar != NULL)
1739     {
1740         if ( removeIndex != -1 && m_macToolbar )
1741         {
1742             HIToolbarRemoveItemAtIndex( (HIToolbarRef) m_macToolbar, removeIndex );
1743             tool->SetIndex( -1 );
1744         }
1745     }
1746 #endif
1747 
1748     tool->ClearControl();
1749 
1750     // and finally reposition all the controls after this one
1751 
1752     for ( /* node -> first after deleted */; node; node = node->GetNext() )
1753     {
1754         wxToolBarTool *tool2 = (wxToolBarTool*) node->GetData();
1755         wxPoint pt = tool2->GetPosition();
1756 
1757         if ( GetWindowStyleFlag() & (wxTB_LEFT|wxTB_RIGHT) )
1758             pt.y -= sz.y;
1759         else
1760             pt.x -= sz.x;
1761 
1762         tool2->SetPosition( pt );
1763 
1764 #if wxOSX_USE_NATIVE_TOOLBAR
1765         if (m_macToolbar != NULL)
1766         {
1767             if ( removeIndex != -1 && tool2->GetIndex() > removeIndex )
1768                 tool2->SetIndex( tool2->GetIndex() - 1 );
1769         }
1770 #endif
1771     }
1772 
1773     InvalidateBestSize();
1774 
1775     return true;
1776 }
1777 
OnPaint(wxPaintEvent & event)1778 void wxToolBar::OnPaint(wxPaintEvent& event)
1779 {
1780 #if wxOSX_USE_NATIVE_TOOLBAR
1781     if ( m_macUsesNativeToolbar )
1782     {
1783         event.Skip(true);
1784         return;
1785     }
1786 #endif
1787 
1788     wxPaintDC dc(this);
1789 
1790     int w, h;
1791     GetSize( &w, &h );
1792 
1793     bool drawMetalTheme = MacGetTopLevelWindow()->GetExtraStyle() & wxFRAME_EX_METAL;
1794 
1795     if ( !drawMetalTheme  )
1796     {
1797         HIThemePlacardDrawInfo info;
1798         memset( &info, 0, sizeof(info) );
1799         info.version = 0;
1800         info.state = IsEnabled() ? kThemeStateActive : kThemeStateInactive;
1801 
1802         CGContextRef cgContext = (CGContextRef) MacGetCGContextRef();
1803         HIRect rect = CGRectMake( 0, 0, w, h );
1804         HIThemeDrawPlacard( &rect, &info, cgContext, kHIThemeOrientationNormal );
1805     }
1806     else
1807     {
1808         // leave the background as it is (striped or metal)
1809     }
1810 
1811     event.Skip();
1812 }
1813 
1814 #endif // wxUSE_TOOLBAR
1815