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