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