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