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