]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/toolbar.cpp
having fixed size icons, scaling from other common formats, otherwise the icons don...
[wxWidgets.git] / src / mac / carbon / toolbar.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: 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: The wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
13 #pragma implementation "toolbar.h"
14 #endif
15
16 #include "wx/wxprec.h"
17
18 #if wxUSE_TOOLBAR
19
20 #include "wx/wx.h"
21 #include "wx/toolbar.h"
22 #include "wx/notebook.h"
23 #include "wx/tabctrl.h"
24 #include "wx/bitmap.h"
25
26 #if !USE_SHARED_LIBRARY
27 IMPLEMENT_DYNAMIC_CLASS(wxToolBar, wxControl)
28
29 BEGIN_EVENT_TABLE(wxToolBar, wxToolBarBase)
30 EVT_PAINT( wxToolBar::OnPaint )
31 END_EVENT_TABLE()
32 #endif
33
34 #include "wx/mac/uma.h"
35 #include "wx/geometry.h"
36
37 #ifdef __WXMAC_OSX__
38 const short kwxMacToolBarToolDefaultWidth = 24 ;
39 const short kwxMacToolBarToolDefaultHeight = 24 ;
40 const short kwxMacToolBarTopMargin = 4 ;
41 const short kwxMacToolBarLeftMargin = 4 ;
42 const short kwxMacToolBorder = 0 ;
43 const short kwxMacToolSpacing = 6 ;
44 #else
45 const short kwxMacToolBarToolDefaultWidth = 24 ;
46 const short kwxMacToolBarToolDefaultHeight = 22 ;
47 const short kwxMacToolBarTopMargin = 2 ;
48 const short kwxMacToolBarLeftMargin = 2 ;
49 const short kwxMacToolBorder = 4 ;
50 const short kwxMacToolSpacing = 0 ;
51 #endif
52
53 // ----------------------------------------------------------------------------
54 // private classes
55 // ----------------------------------------------------------------------------
56
57 class wxToolBarTool : public wxToolBarToolBase
58 {
59 public:
60 wxToolBarTool(wxToolBar *tbar,
61 int id,
62 const wxString& label,
63 const wxBitmap& bmpNormal,
64 const wxBitmap& bmpDisabled,
65 wxItemKind kind,
66 wxObject *clientData,
67 const wxString& shortHelp,
68 const wxString& longHelp) ;
69
70 wxToolBarTool(wxToolBar *tbar, wxControl *control)
71 : wxToolBarToolBase(tbar, control)
72 {
73 Init() ;
74 }
75
76 ~wxToolBarTool()
77 {
78 if ( m_controlHandle )
79 DisposeControl( m_controlHandle ) ;
80 }
81
82 WXWidget GetControlHandle() { return (WXWidget) m_controlHandle ; }
83 void SetControlHandle( ControlRef handle ) { m_controlHandle = handle ; }
84
85 void SetSize(const wxSize& size) ;
86 void SetPosition( const wxPoint& position ) ;
87
88 wxSize GetSize() const
89 {
90 if ( IsControl() )
91 {
92 return GetControl()->GetSize() ;
93 }
94 else if ( IsButton() )
95 {
96 return GetToolBar()->GetToolSize() ;
97 }
98 else
99 {
100 // separator size
101 wxSize sz = GetToolBar()->GetToolSize() ;
102 sz.x /= 4 ;
103 sz.y /= 4 ;
104 return sz ;
105 }
106 }
107 wxPoint GetPosition() const
108 {
109 return wxPoint(m_x, m_y);
110 }
111 bool DoEnable( bool enable ) ;
112 private :
113 void Init()
114 {
115 m_controlHandle = NULL ;
116 }
117 ControlRef m_controlHandle ;
118
119 wxCoord m_x;
120 wxCoord m_y;
121 };
122
123 static const EventTypeSpec eventList[] =
124 {
125 { kEventClassControl , kEventControlHit } ,
126 } ;
127
128 static pascal OSStatus wxMacToolBarToolControlEventHandler( EventHandlerCallRef handler , EventRef event , void *data )
129 {
130 OSStatus result = eventNotHandledErr ;
131
132 wxMacCarbonEvent cEvent( event ) ;
133
134 ControlRef controlRef ;
135
136 cEvent.GetParameter( kEventParamDirectObject , &controlRef ) ;
137
138 switch( GetEventKind( event ) )
139 {
140 case kEventControlHit :
141 {
142 wxToolBarTool* tbartool = (wxToolBarTool*)data ;
143 if ( tbartool->CanBeToggled() )
144 {
145 ((wxToolBar*)tbartool->GetToolBar())->ToggleTool(tbartool->GetId(), GetControl32BitValue((ControlRef)tbartool->GetControlHandle()));
146 }
147 ((wxToolBar*)tbartool->GetToolBar())->OnLeftClick( tbartool->GetId() , tbartool -> IsToggled() ) ;
148 result = noErr;
149 }
150 break ;
151 default :
152 break ;
153 }
154 return result ;
155 }
156
157 pascal OSStatus wxMacToolBarToolEventHandler( EventHandlerCallRef handler , EventRef event , void *data )
158 {
159 OSStatus result = eventNotHandledErr ;
160
161 switch ( GetEventClass( event ) )
162 {
163 case kEventClassControl :
164 result = wxMacToolBarToolControlEventHandler( handler, event, data ) ;
165 break ;
166 default :
167 break ;
168 }
169 return result ;
170 }
171
172 DEFINE_ONE_SHOT_HANDLER_GETTER( wxMacToolBarToolEventHandler )
173
174 // ============================================================================
175 // implementation
176 // ============================================================================
177
178 // ----------------------------------------------------------------------------
179 // wxToolBarTool
180 // ----------------------------------------------------------------------------
181
182 bool wxToolBarTool::DoEnable(bool enable)
183 {
184 if ( IsControl() )
185 {
186 GetControl()->Enable( enable ) ;
187 }
188 else if ( IsButton() )
189 {
190 #if TARGET_API_MAC_OSX
191 if ( enable )
192 EnableControl( m_controlHandle ) ;
193 else
194 DisableControl( m_controlHandle ) ;
195 #else
196 if ( enable )
197 ActivateControl( m_controlHandle ) ;
198 else
199 DeactivateControl( m_controlHandle ) ;
200 #endif
201 }
202 return true ;
203 }
204 void wxToolBarTool::SetSize(const wxSize& size)
205 {
206 if ( IsControl() )
207 {
208 GetControl()->SetSize( size ) ;
209 }
210 }
211
212 void wxToolBarTool::SetPosition(const wxPoint& position)
213 {
214 m_x = position.x;
215 m_y = position.y;
216
217 if ( IsButton() )
218 {
219 int x , y ;
220 x = y = 0 ;
221 int mac_x = position.x ;
222 int mac_y = position.y ;
223 #ifdef __WXMAC_OSX__
224 wxSize toolSize = m_tbar->GetToolSize() ;
225 int iconsize = 16 ;
226 if ( toolSize.x >= 24 && toolSize.y >= 24)
227 {
228 iconsize = 24 ;
229 }
230 mac_x += ( toolSize.x - iconsize ) / 2 ;
231 mac_y += ( toolSize.y - iconsize ) / 2 ;
232 #else
233 WindowRef rootwindow = (WindowRef) GetToolBar()->MacGetTopLevelWindowRef() ;
234 GetToolBar()->MacWindowToRootWindow( &x , &y ) ;
235 mac_x += x;
236 mac_y += y;
237 #endif
238 Rect contrlRect ;
239 GetControlBounds( m_controlHandle , &contrlRect ) ;
240 int former_mac_x = contrlRect.left ;
241 int former_mac_y = contrlRect.top ;
242 GetToolBar()->GetToolSize() ;
243
244 if ( mac_x != former_mac_x || mac_y != former_mac_y )
245 {
246 UMAMoveControl( m_controlHandle , mac_x , mac_y ) ;
247 }
248 }
249 else if ( IsControl() )
250 {
251 GetControl()->Move( position ) ;
252 }
253 else
254 {
255 // separator
256 #ifdef __WXMAC_OSX__
257 int x , y ;
258 x = y = 0 ;
259 int mac_x = position.x ;
260 int mac_y = position.y ;
261
262 Rect contrlRect ;
263 GetControlBounds( m_controlHandle , &contrlRect ) ;
264 int former_mac_x = contrlRect.left ;
265 int former_mac_y = contrlRect.top ;
266
267 if ( mac_x != former_mac_x || mac_y != former_mac_y )
268 {
269 UMAMoveControl( m_controlHandle , mac_x , mac_y ) ;
270 }
271 #endif
272 }
273 }
274
275 wxToolBarTool::wxToolBarTool(wxToolBar *tbar,
276 int id,
277 const wxString& label,
278 const wxBitmap& bmpNormal,
279 const wxBitmap& bmpDisabled,
280 wxItemKind kind,
281 wxObject *clientData,
282 const wxString& shortHelp,
283 const wxString& longHelp)
284 : wxToolBarToolBase(tbar, id, label, bmpNormal, bmpDisabled, kind,
285 clientData, shortHelp, longHelp)
286 {
287 Init();
288
289 WindowRef window = (WindowRef) tbar->MacGetTopLevelWindowRef() ;
290 wxSize toolSize = tbar->GetToolSize() ;
291 Rect toolrect = { 0, 0 , toolSize.y , toolSize.x } ;
292
293 if ( id == wxID_SEPARATOR )
294 {
295 toolSize.x /= 4 ;
296 toolSize.y /= 4 ;
297 if ( GetToolBar()->GetWindowStyleFlag() & wxTB_VERTICAL )
298 {
299 toolrect.bottom = toolSize.y ;
300 }
301 else
302 {
303 toolrect.right = toolSize.x ;
304 }
305 #ifdef __WXMAC_OSX__
306 // in flat style we need a visual separator
307 CreateSeparatorControl( window , &toolrect , &m_controlHandle ) ;
308 #endif
309 }
310 else
311 {
312 ControlButtonContentInfo info ;
313 wxMacCreateBitmapButton( &info , GetNormalBitmap() ) ;
314
315 #ifdef __WXMAC_OSX__
316 int iconsize = 16 ;
317 if ( toolSize.x >= 24 && toolSize.y >= 24)
318 {
319 iconsize = 24 ;
320 }
321 toolrect.left += ( toolSize.x - iconsize ) / 2 ;
322 toolrect.right = toolrect.left + iconsize ;
323 toolrect.top += ( toolSize.y - iconsize ) / 2 ;
324 toolrect.bottom = toolrect.top + iconsize ;
325 CreateIconControl( window , &toolrect , &info , false , &m_controlHandle ) ;
326 #else
327 SInt16 behaviour = kControlBehaviorOffsetContents ;
328 if ( CanBeToggled() )
329 behaviour += kControlBehaviorToggles ;
330 CreateBevelButtonControl( window , &toolrect , CFSTR("") , kControlBevelButtonNormalBevel , behaviour , &info ,
331 0 , 0 , 0 , &m_controlHandle ) ;
332 #endif
333
334 wxMacReleaseBitmapButton( &info ) ;
335 /*
336 SetBevelButtonTextPlacement( m_controlHandle , kControlBevelButtonPlaceBelowGraphic ) ;
337 UMASetControlTitle( m_controlHandle , label , wxFont::GetDefaultEncoding() ) ;
338 */
339
340 InstallControlEventHandler( (ControlRef) m_controlHandle, GetwxMacToolBarToolEventHandlerUPP(),
341 GetEventTypeCount(eventList), eventList, this,NULL);
342
343 if ( CanBeToggled() && IsToggled() )
344 {
345 #ifdef __WXMAC_OSX__
346 // overlay with rounded white rect and set selected to 1
347 #else
348 ::SetControl32BitValue( m_controlHandle , 1 ) ;
349 #endif
350 }
351 }
352 ControlRef container = (ControlRef) tbar->GetHandle() ;
353 wxASSERT_MSG( container != NULL , wxT("No valid mac container control") ) ;
354 if ( m_controlHandle )
355 {
356 UMAShowControl( m_controlHandle ) ;
357 ::EmbedControl( m_controlHandle , container ) ;
358 }
359 }
360
361
362 wxToolBarToolBase *wxToolBar::CreateTool(int id,
363 const wxString& label,
364 const wxBitmap& bmpNormal,
365 const wxBitmap& bmpDisabled,
366 wxItemKind kind,
367 wxObject *clientData,
368 const wxString& shortHelp,
369 const wxString& longHelp)
370 {
371 return new wxToolBarTool(this, id, label, bmpNormal, bmpDisabled, kind,
372 clientData, shortHelp, longHelp);
373 }
374
375 wxToolBarToolBase *wxToolBar::CreateTool(wxControl *control)
376 {
377 return new wxToolBarTool(this, control);
378 }
379
380 void wxToolBar::Init()
381 {
382 m_maxWidth = -1;
383 m_maxHeight = -1;
384 m_defaultWidth = kwxMacToolBarToolDefaultWidth;
385 m_defaultHeight = kwxMacToolBarToolDefaultHeight;
386 }
387
388 bool wxToolBar::Create(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size,
389 long style, const wxString& name)
390 {
391
392 if ( !wxToolBarBase::Create( parent , id , pos , size , style ) )
393 return FALSE ;
394
395 return TRUE;
396 }
397
398 wxToolBar::~wxToolBar()
399 {
400 // we must refresh the frame size when the toolbar is deleted but the frame
401 // is not - otherwise toolbar leaves a hole in the place it used to occupy
402 }
403
404 bool wxToolBar::Realize()
405 {
406 if (m_tools.GetCount() == 0)
407 return FALSE;
408
409 int x = m_xMargin + kwxMacToolBarLeftMargin ;
410 int y = m_yMargin + kwxMacToolBarTopMargin ;
411
412 int tw, th;
413 GetSize(& tw, & th);
414
415 int maxWidth = 0 ;
416 int maxHeight = 0 ;
417
418 int maxToolWidth = 0;
419 int maxToolHeight = 0;
420
421 // Find the maximum tool width and height
422 wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst();
423 while ( node )
424 {
425 wxToolBarTool *tool = (wxToolBarTool *)node->GetData();
426 wxSize sz = tool->GetSize() ;
427
428 if ( sz.x > maxToolWidth )
429 maxToolWidth = sz.x ;
430 if (sz.y> maxToolHeight)
431 maxToolHeight = sz.y;
432
433 node = node->GetNext();
434 }
435
436 bool lastWasRadio = FALSE;
437 node = m_tools.GetFirst();
438 while (node)
439 {
440 wxToolBarTool *tool = (wxToolBarTool *)node->GetData();
441 wxSize cursize = tool->GetSize() ;
442
443 bool isRadio = FALSE;
444
445 if ( tool->IsButton() && tool->GetKind() == wxITEM_RADIO )
446 {
447 if ( !lastWasRadio )
448 {
449 if (tool->Toggle(true))
450 {
451 DoToggleTool(tool, true);
452 }
453 }
454 isRadio = TRUE;
455 }
456 else
457 {
458 isRadio = FALSE;
459 }
460 lastWasRadio = isRadio;
461
462 // for the moment we just do a single row/column alignement
463 if ( x + cursize.x > maxWidth )
464 maxWidth = x + cursize.x ;
465 if ( y + cursize.y > maxHeight )
466 maxHeight = y + cursize.y ;
467
468 tool->SetPosition( wxPoint( x , y ) ) ;
469
470 if ( GetWindowStyleFlag() & wxTB_VERTICAL )
471 {
472 y += cursize.y ;
473 y += kwxMacToolSpacing ;
474 }
475 else
476 {
477 x += cursize.x ;
478 x += kwxMacToolSpacing ;
479 }
480
481 node = node->GetNext();
482 }
483
484 if ( GetWindowStyleFlag() & wxTB_HORIZONTAL )
485 {
486 if ( m_maxRows == 0 )
487 {
488 // if not set yet, only one row
489 SetRows(1);
490 }
491 m_minWidth = maxWidth;
492 maxWidth = tw ;
493 maxHeight += m_yMargin + kwxMacToolBarTopMargin;
494 m_minHeight = m_maxHeight = maxHeight ;
495 }
496 else
497 {
498 if ( GetToolsCount() > 0 && m_maxRows == 0 )
499 {
500 // if not set yet, have one column
501 SetRows(GetToolsCount());
502 }
503 m_minHeight = maxHeight;
504 maxHeight = th ;
505 maxWidth += m_xMargin + kwxMacToolBarLeftMargin;
506 m_minWidth = m_maxWidth = maxWidth ;
507 }
508
509 SetSize( maxWidth, maxHeight );
510 InvalidateBestSize();
511
512 return TRUE;
513 }
514
515 void wxToolBar::SetToolBitmapSize(const wxSize& size)
516 {
517 m_defaultWidth = size.x+kwxMacToolBorder; m_defaultHeight = size.y+kwxMacToolBorder;
518 }
519
520 // The button size is bigger than the bitmap size
521 wxSize wxToolBar::GetToolSize() const
522 {
523 return wxSize(m_defaultWidth + kwxMacToolBorder, m_defaultHeight + kwxMacToolBorder);
524 }
525
526 void wxToolBar::SetRows(int nRows)
527 {
528 if ( nRows == m_maxRows )
529 {
530 // avoid resizing the frame uselessly
531 return;
532 }
533
534 m_maxRows = nRows;
535 }
536
537 void wxToolBar::MacSuperChangedPosition()
538 {
539 wxWindow::MacSuperChangedPosition() ;
540 Realize() ;
541 }
542
543 wxToolBarToolBase *wxToolBar::FindToolForPosition(wxCoord x, wxCoord y) const
544 {
545 wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst();
546 while (node)
547 {
548 wxToolBarTool *tool = (wxToolBarTool *)node->GetData() ;
549 wxRect2DInt r( tool->GetPosition() , tool->GetSize() ) ;
550 if ( r.Contains( wxPoint( x , y ) ) )
551 {
552 return tool;
553 }
554
555 node = node->GetNext();
556 }
557
558 return (wxToolBarToolBase *)NULL;
559 }
560
561 wxString wxToolBar::MacGetToolTipString( wxPoint &pt )
562 {
563 wxToolBarToolBase* tool = FindToolForPosition( pt.x , pt.y ) ;
564 if ( tool )
565 {
566 return tool->GetShortHelp() ;
567 }
568 return wxEmptyString ;
569 }
570
571 void wxToolBar::DoEnableTool(wxToolBarToolBase *t, bool enable)
572 {
573 ((wxToolBarTool*)t)->DoEnable( enable ) ;
574 }
575
576 void wxToolBar::DoToggleTool(wxToolBarToolBase *t, bool toggle)
577 {
578 wxToolBarTool *tool = (wxToolBarTool *)t;
579 if ( tool->IsButton() )
580 {
581 #ifdef __WXMAC_OSX__
582 IconTransformType transform = toggle ? kTransformSelected : kTransformNone ;
583 SetControlData( (ControlRef) tool->GetControlHandle(), 0, kControlIconTransformTag, sizeof( transform ),
584 (Ptr)&transform );
585 #else
586 ::SetControl32BitValue( (ControlRef) tool->GetControlHandle() , toggle ) ;
587 #endif
588 }
589 }
590
591 bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos),
592 wxToolBarToolBase *tool)
593 {
594 // nothing special to do here - we relayout in Realize() later
595 tool->Attach(this);
596 InvalidateBestSize();
597
598 return TRUE;
599 }
600
601 void wxToolBar::DoSetToggle(wxToolBarToolBase *WXUNUSED(tool), bool WXUNUSED(toggle))
602 {
603 wxFAIL_MSG( _T("not implemented") );
604 }
605
606 bool wxToolBar::DoDeleteTool(size_t WXUNUSED(pos), wxToolBarToolBase *tool)
607 {
608 wxToolBarToolsList::compatibility_iterator node;
609 for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
610 {
611 wxToolBarToolBase *tool2 = node->GetData();
612 if ( tool2 == tool )
613 {
614 // let node point to the next node in the list
615 node = node->GetNext();
616
617 break;
618 }
619 }
620
621 wxSize sz = ((wxToolBarTool*)tool)->GetSize() ;
622
623 tool->Detach();
624
625 // and finally reposition all the controls after this one
626
627 for ( /* node -> first after deleted */ ; node; node = node->GetNext() )
628 {
629 wxToolBarTool *tool2 = (wxToolBarTool*) node->GetData();
630 wxPoint pt = tool2->GetPosition() ;
631
632 if ( GetWindowStyleFlag() & wxTB_VERTICAL )
633 {
634 pt.y -= sz.y ;
635 }
636 else
637 {
638 pt.x -= sz.x ;
639 }
640 tool2->SetPosition( pt ) ;
641 }
642
643 InvalidateBestSize();
644 return TRUE ;
645 }
646
647 void wxToolBar::OnPaint(wxPaintEvent& event)
648 {
649 wxPaintDC dc(this) ;
650 #if wxMAC_USE_CORE_GRAPHICS
651 // leave the background as it is (striped or metal)
652 #else
653 wxMacPortSetter helper(&dc) ;
654 int w, h ;
655 GetSize( &w , &h ) ;
656
657 Rect toolbarrect = { dc.YLOG2DEVMAC(0) , dc.XLOG2DEVMAC(0) ,
658 dc.YLOG2DEVMAC(h) , dc.XLOG2DEVMAC(w) } ;
659 /*
660 if( toolbarrect.left < 0 )
661 toolbarrect.left = 0 ;
662 if ( toolbarrect.top < 0 )
663 toolbarrect.top = 0 ;
664 */
665 if ( !MacGetTopLevelWindow()->MacGetMetalAppearance() )
666 {
667 UMADrawThemePlacard( &toolbarrect , IsEnabled() ? kThemeStateActive : kThemeStateInactive) ;
668 }
669 else
670 {
671 #if TARGET_API_MAC_OSX
672 #if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_2
673 if ( UMAGetSystemVersion() >= 0x1030 )
674 {
675 HIRect hiToolbarrect = CGRectMake( dc.YLOG2DEVMAC(0) , dc.XLOG2DEVMAC(0) ,
676 dc.YLOG2DEVREL(h) , dc.XLOG2DEVREL(w) );
677 CGContextRef cgContext ;
678 Rect bounds ;
679 GetPortBounds( (CGrafPtr) dc.m_macPort , &bounds ) ;
680 QDBeginCGContext( (CGrafPtr) dc.m_macPort , &cgContext ) ;
681 CGContextTranslateCTM( cgContext , 0 , bounds.bottom - bounds.top ) ;
682 CGContextScaleCTM( cgContext , 1 , -1 ) ;
683
684 {
685 HIThemeBackgroundDrawInfo drawInfo ;
686 drawInfo.version = 0 ;
687 drawInfo.state = kThemeStateActive ;
688 drawInfo.kind = kThemeBackgroundMetal ;
689 HIThemeApplyBackground( &hiToolbarrect, &drawInfo , cgContext,kHIThemeOrientationNormal) ;
690 }
691 QDEndCGContext( (CGrafPtr) dc.m_macPort , &cgContext ) ;
692 }
693 else
694 #endif
695 {
696 UMADrawThemePlacard( &toolbarrect , IsEnabled() ? kThemeStateActive : kThemeStateInactive) ;
697 }
698 #endif
699 }
700 #endif
701
702 event.Skip() ;
703 }
704
705 #endif // wxUSE_TOOLBAR
706