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