1/////////////////////////////////////////////////////////////////////////////
2// Name:        src/mac/classic/toolbar.cpp
3// Purpose:     wxToolBar
4// Author:      Stefan Csomor
5// Modified by:
6// Created:     04/01/98
7// RCS-ID:      $Id: toolbar.cpp 41020 2006-09-05 20:47:48Z VZ $
8// Copyright:   (c) Stefan Csomor
9// Licence:     The 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/notebook.h"
23#include "wx/tabctrl.h"
24
25IMPLEMENT_DYNAMIC_CLASS(wxToolBar, wxControl)
26
27BEGIN_EVENT_TABLE(wxToolBar, wxToolBarBase)
28    EVT_MOUSE_EVENTS( wxToolBar::OnMouse )
29    EVT_PAINT( wxToolBar::OnPaint )
30END_EVENT_TABLE()
31
32#include "wx/mac/uma.h"
33#include "wx/geometry.h"
34// ----------------------------------------------------------------------------
35// private classes
36// ----------------------------------------------------------------------------
37
38class wxToolBarTool : public wxToolBarToolBase
39{
40public:
41    wxToolBarTool(wxToolBar *tbar,
42                  int id,
43                  const wxString& label,
44                  const wxBitmap& bmpNormal,
45                  const wxBitmap& bmpDisabled,
46                  wxItemKind kind,
47                  wxObject *clientData,
48                  const wxString& shortHelp,
49                  const wxString& longHelp) ;
50
51    wxToolBarTool(wxToolBar *tbar, wxControl *control)
52        : wxToolBarToolBase(tbar, control)
53    {
54        Init() ;
55    }
56
57    virtual ~wxToolBarTool()
58    {
59        if ( m_controlHandle )
60            DisposeControl( m_controlHandle ) ;
61    }
62
63    ControlHandle   GetControlHandle() { return m_controlHandle ; }
64    void SetControlHandle( ControlHandle handle ) { m_controlHandle = handle ; }
65
66    void SetSize(const wxSize& size) ;
67    void SetPosition( const wxPoint& position ) ;
68    wxSize GetSize() const
69    {
70        if ( IsControl() )
71        {
72            return GetControl()->GetSize() ;
73        }
74        else if ( IsButton() )
75        {
76            return GetToolBar()->GetToolSize() ;
77        }
78        else
79        {
80            wxSize sz = GetToolBar()->GetToolSize() ;
81            sz.x /= 4 ;
82            sz.y /= 4 ;
83            return sz ;
84        }
85    }
86    wxPoint GetPosition() const
87    {
88        return wxPoint(m_x, m_y);
89    }
90private :
91    void Init()
92    {
93        m_controlHandle = NULL ;
94    }
95    ControlHandle m_controlHandle ;
96
97    wxCoord     m_x;
98    wxCoord     m_y;
99};
100
101// ============================================================================
102// implementation
103// ============================================================================
104
105// ----------------------------------------------------------------------------
106// wxToolBarTool
107// ----------------------------------------------------------------------------
108
109void wxToolBarTool::SetSize(const wxSize& size)
110{
111    if ( IsControl() )
112    {
113        GetControl()->SetSize( size ) ;
114    }
115}
116
117void wxToolBarTool::SetPosition(const wxPoint& position)
118{
119    m_x = position.x;
120    m_y = position.y;
121
122    if ( IsButton() )
123    {
124        int x , y ;
125        x = y = 0 ;
126        WindowRef rootwindow = (WindowRef) GetToolBar()->MacGetRootWindow() ;
127        GetToolBar()->MacWindowToRootWindow( &x , &y ) ;
128        int mac_x = x + position.x ;
129        int mac_y = y + position.y ;
130
131
132        Rect contrlRect ;
133        GetControlBounds( m_controlHandle , &contrlRect ) ;
134        int former_mac_x = contrlRect.left ;
135        int former_mac_y = contrlRect.top ;
136        wxSize sz = GetToolBar()->GetToolSize() ;
137
138        if ( mac_x != former_mac_x || mac_y != former_mac_y )
139        {
140            {
141                Rect inval = { former_mac_y , former_mac_x , former_mac_y + sz.y , former_mac_x + sz.x } ;
142                InvalWindowRect( rootwindow , &inval ) ;
143            }
144            UMAMoveControl( m_controlHandle , mac_x , mac_y ) ;
145            {
146                Rect inval = { mac_y , mac_x , mac_y + sz.y , mac_x + sz.x } ;
147                InvalWindowRect( rootwindow , &inval ) ;
148            }
149        }
150    }
151    else if ( IsControl() )
152    {
153        GetControl()->Move( position ) ;
154    }
155}
156
157const short kwxMacToolBarToolDefaultWidth = 24 ;
158const short kwxMacToolBarToolDefaultHeight = 22 ;
159const short kwxMacToolBarTopMargin = 2 ;
160const short kwxMacToolBarLeftMargin = 2 ;
161
162wxToolBarTool::wxToolBarTool(wxToolBar *tbar,
163                             int id,
164                             const wxString& label,
165                             const wxBitmap& bmpNormal,
166                             const wxBitmap& bmpDisabled,
167                             wxItemKind kind,
168                             wxObject *clientData,
169                             const wxString& shortHelp,
170                             const wxString& longHelp)
171        : wxToolBarToolBase(tbar, id, label, bmpNormal, bmpDisabled, kind,
172                            clientData, shortHelp, longHelp)
173{
174    Init();
175
176    if (id == wxID_SEPARATOR) return;
177
178    WindowRef window = (WindowRef) tbar->MacGetRootWindow() ;
179    wxSize toolSize = tbar->GetToolSize() ;
180    Rect toolrect = { 0, 0 , toolSize.y , toolSize.x } ;
181
182    ControlButtonContentInfo info ;
183    wxMacCreateBitmapButton( &info , GetNormalBitmap() ) ;
184
185    SInt16 behaviour = kControlBehaviorOffsetContents ;
186    if ( CanBeToggled() )
187        behaviour += kControlBehaviorToggles ;
188
189    if ( info.contentType != kControlNoContent )
190    {
191        m_controlHandle = ::NewControl( window , &toolrect , "\p" , false , 0 ,
192                                        behaviour + info.contentType , 0 , kControlBevelButtonNormalBevelProc , (long) this ) ;
193
194        ::SetControlData( m_controlHandle , kControlButtonPart , kControlBevelButtonContentTag , sizeof(info) , (char*) &info ) ;
195    }
196    else
197    {
198        m_controlHandle = ::NewControl( window , &toolrect , "\p" , false , 0 ,
199                                        behaviour  , 0 , kControlBevelButtonNormalBevelProc , (long) this ) ;
200    }
201    UMAShowControl( m_controlHandle ) ;
202    if ( !IsEnabled() )
203    {
204        UMADeactivateControl( m_controlHandle ) ;
205    }
206    if ( CanBeToggled() && IsToggled() )
207    {
208        ::SetControl32BitValue( m_controlHandle , 1 ) ;
209    }
210    else
211    {
212        ::SetControl32BitValue( m_controlHandle , 0 ) ;
213    }
214
215    ControlHandle container = (ControlHandle) tbar->MacGetContainerForEmbedding() ;
216    wxASSERT_MSG( container != NULL , wxT("No valid mac container control") ) ;
217    ::EmbedControl( m_controlHandle , container ) ;
218}
219
220
221wxToolBarToolBase *wxToolBar::CreateTool(int id,
222                                         const wxString& label,
223                                         const wxBitmap& bmpNormal,
224                                         const wxBitmap& bmpDisabled,
225                                         wxItemKind kind,
226                                         wxObject *clientData,
227                                         const wxString& shortHelp,
228                                         const wxString& longHelp)
229{
230    return new wxToolBarTool(this, id, label, bmpNormal, bmpDisabled, kind,
231                             clientData, shortHelp, longHelp);
232}
233
234wxToolBarToolBase *wxToolBar::CreateTool(wxControl *control)
235{
236    return new wxToolBarTool(this, control);
237}
238
239void wxToolBar::Init()
240{
241    m_maxWidth = -1;
242    m_maxHeight = -1;
243    m_defaultWidth = kwxMacToolBarToolDefaultWidth;
244    m_defaultHeight = kwxMacToolBarToolDefaultHeight;
245}
246
247bool wxToolBar::Create(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size,
248            long style, const wxString& name)
249{
250    int x = pos.x;
251    int y = pos.y;
252    int width = size.x;
253    int height = size.y;
254
255    if (width <= 0)
256        width = 100;
257    if (height <= 0)
258        height = 30;
259    if (x < 0)
260        x = 0;
261    if (y < 0)
262        y = 0;
263
264    SetName(name);
265
266    m_windowStyle = style;
267    parent->AddChild(this);
268
269    m_backgroundColour = parent->GetBackgroundColour() ;
270    m_foregroundColour = parent->GetForegroundColour() ;
271
272    if (id == wxID_ANY)
273        m_windowId = NewControlId();
274    else
275        m_windowId = id;
276
277    {
278        m_width = size.x ;
279        m_height = size.y ;
280        int x = pos.x ;
281        int y = pos.y ;
282        AdjustForParentClientOrigin(x, y, wxSIZE_USE_EXISTING);
283        m_x = x ;
284        m_y = y ;
285    }
286
287    return true;
288}
289
290wxToolBar::~wxToolBar()
291{
292    // we must refresh the frame size when the toolbar is deleted but the frame
293    // is not - otherwise toolbar leaves a hole in the place it used to occupy
294}
295
296bool wxToolBar::Realize()
297{
298    if (m_tools.GetCount() == 0)
299        return false;
300
301    int x = m_xMargin + kwxMacToolBarLeftMargin ;
302    int y = m_yMargin + kwxMacToolBarTopMargin ;
303
304    int tw, th;
305    GetSize(& tw, & th);
306
307    int maxWidth = 0 ;
308    int maxHeight = 0 ;
309
310    int maxToolWidth = 0;
311    int maxToolHeight = 0;
312
313    // Find the maximum tool width and height
314    wxToolBarToolsList::Node *node = m_tools.GetFirst();
315    while ( node )
316    {
317        wxToolBarTool *tool = (wxToolBarTool *)node->GetData();
318        wxSize sz = tool->GetSize() ;
319
320        if ( sz.x > maxToolWidth )
321            maxToolWidth = sz.x ;
322        if (sz.y> maxToolHeight)
323            maxToolHeight = sz.y;
324
325        node = node->GetNext();
326    }
327
328    node = m_tools.GetFirst();
329    while (node)
330    {
331        wxToolBarTool *tool = (wxToolBarTool *)node->GetData();
332        wxSize cursize = tool->GetSize() ;
333
334        // for the moment we just do a single row/column alignement
335        if ( x + cursize.x > maxWidth )
336            maxWidth = x + cursize.x ;
337        if ( y + cursize.y > maxHeight )
338            maxHeight = y + cursize.y ;
339
340        tool->SetPosition( wxPoint( x , y ) ) ;
341
342        if ( GetWindowStyleFlag() & wxTB_VERTICAL )
343        {
344            y += cursize.y ;
345        }
346        else
347        {
348            x += cursize.x ;
349        }
350
351        node = node->GetNext();
352    }
353
354    if ( GetWindowStyleFlag() & wxTB_HORIZONTAL )
355    {
356        if ( m_maxRows == 0 )
357        {
358            // if not set yet, only one row
359            SetRows(1);
360        }
361        maxWidth = tw ;
362        maxHeight += m_yMargin + kwxMacToolBarTopMargin;
363        m_maxHeight = maxHeight ;
364    }
365    else
366    {
367        if ( GetToolsCount() > 0 && m_maxRows == 0 )
368        {
369            // if not set yet, have one column
370            SetRows(GetToolsCount());
371        }
372        maxHeight = th ;
373        maxWidth += m_xMargin + kwxMacToolBarLeftMargin;
374        m_maxWidth = maxWidth ;
375    }
376
377    SetSize(maxWidth, maxHeight);
378    InvalidateBestSize();
379
380    return true;
381}
382
383void wxToolBar::SetToolBitmapSize(const wxSize& size)
384{
385    m_defaultWidth = size.x+4; m_defaultHeight = size.y+4;
386}
387
388// The button size is bigger than the bitmap size
389wxSize wxToolBar::GetToolSize() const
390{
391    return wxSize(m_defaultWidth + 4, m_defaultHeight + 4);
392}
393
394void wxToolBar::MacHandleControlClick( WXWidget control , wxInt16 controlpart , bool WXUNUSED( mouseStillDown ) )
395{
396    wxToolBarToolsList::Node *node;
397    for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
398    {
399        wxToolBarTool* tool = (wxToolBarTool*) node->GetData() ;
400        if ( tool->IsButton() )
401        {
402           if( (WXWidget) tool->GetControlHandle() == control )
403           {
404                if ( tool->CanBeToggled() )
405                {
406                    tool->Toggle( GetControl32BitValue( (ControlHandle) control ) ) ;
407                }
408                OnLeftClick( tool->GetId() , tool -> IsToggled() ) ;
409                break ;
410           }
411        }
412    }
413}
414
415void wxToolBar::SetRows(int nRows)
416{
417    if ( nRows == m_maxRows )
418    {
419        // avoid resizing the frame uselessly
420        return;
421    }
422
423    m_maxRows = nRows;
424}
425
426void wxToolBar::MacSuperChangedPosition()
427{
428    wxWindow::MacSuperChangedPosition() ;
429    Realize() ;
430}
431
432wxToolBarToolBase *wxToolBar::FindToolForPosition(wxCoord x, wxCoord y) const
433{
434    wxToolBarToolsList::Node *node = m_tools.GetFirst();
435    while (node)
436    {
437        wxToolBarTool *tool = (wxToolBarTool *)node->GetData() ;
438        wxRect2DInt r( tool->GetPosition() , tool->GetSize() ) ;
439        if ( r.Contains( wxPoint( x , y ) ) )
440        {
441            return tool;
442        }
443
444        node = node->GetNext();
445    }
446
447    return (wxToolBarToolBase *)NULL;
448}
449
450wxString wxToolBar::MacGetToolTipString( wxPoint &pt )
451{
452    wxToolBarToolBase* tool = FindToolForPosition( pt.x , pt.y ) ;
453    if ( tool )
454    {
455        return tool->GetShortHelp() ;
456    }
457    return wxEmptyString ;
458}
459
460void wxToolBar::DoEnableTool(wxToolBarToolBase *t, bool enable)
461{
462    if (!IsShown())
463        return ;
464
465    wxToolBarTool *tool = (wxToolBarTool *)t;
466    if ( tool->IsControl() )
467    {
468        tool->GetControl()->Enable( enable ) ;
469    }
470    else if ( tool->IsButton() )
471    {
472        if ( enable )
473            UMAActivateControl( tool->GetControlHandle() ) ;
474        else
475            UMADeactivateControl( tool->GetControlHandle() ) ;
476    }
477}
478
479void wxToolBar::DoToggleTool(wxToolBarToolBase *t, bool toggle)
480{
481    if (!IsShown())
482        return ;
483
484    wxToolBarTool *tool = (wxToolBarTool *)t;
485    if ( tool->IsButton() )
486    {
487        ::SetControl32BitValue( tool->GetControlHandle() , toggle ) ;
488    }
489}
490
491bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos),
492                             wxToolBarToolBase *tool)
493{
494    // nothing special to do here - we relayout in Realize() later
495    tool->Attach(this);
496    InvalidateBestSize();
497
498    return true;
499}
500
501void wxToolBar::DoSetToggle(wxToolBarToolBase *WXUNUSED(tool), bool WXUNUSED(toggle))
502{
503    wxFAIL_MSG( _T("not implemented") );
504}
505
506bool wxToolBar::DoDeleteTool(size_t WXUNUSED(pos), wxToolBarToolBase *tool)
507{
508    wxToolBarToolsList::Node *node;
509    for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
510    {
511        wxToolBarToolBase *tool2 = node->GetData();
512        if ( tool2 == tool )
513        {
514            // let node point to the next node in the list
515            node = node->GetNext();
516
517            break;
518        }
519    }
520
521    wxSize sz = ((wxToolBarTool*)tool)->GetSize() ;
522
523    tool->Detach();
524
525    // and finally reposition all the controls after this one
526
527    for ( /* node -> first after deleted */ ; node; node = node->GetNext() )
528    {
529        wxToolBarTool *tool2 = (wxToolBarTool*) node->GetData();
530        wxPoint pt = tool2->GetPosition() ;
531
532        if ( GetWindowStyleFlag() & wxTB_VERTICAL )
533        {
534            pt.y -= sz.y ;
535        }
536        else
537        {
538            pt.x -= sz.x ;
539        }
540        tool2->SetPosition( pt ) ;
541    }
542
543    InvalidateBestSize();
544    return true ;
545}
546
547void wxToolBar::OnPaint(wxPaintEvent& event)
548{
549    wxPaintDC dc(this) ;
550    wxMacPortSetter helper(&dc) ;
551
552    Rect toolbarrect = { dc.YLOG2DEVMAC(0) , dc.XLOG2DEVMAC(0) ,
553        dc.YLOG2DEVMAC(m_height) , dc.XLOG2DEVMAC(m_width) } ;
554    UMADrawThemePlacard( &toolbarrect , IsEnabled() ? kThemeStateActive : kThemeStateInactive) ;
555    {
556        wxToolBarToolsList::Node *node;
557        for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
558        {
559            wxToolBarTool* tool = (wxToolBarTool*) node->GetData() ;
560            if ( tool->IsButton() )
561            {
562               UMADrawControl( tool->GetControlHandle() ) ;
563            }
564        }
565    }
566}
567
568void  wxToolBar::OnMouse( wxMouseEvent &event )
569{
570    if (event.GetEventType() == wxEVT_LEFT_DOWN || event.GetEventType() == wxEVT_LEFT_DCLICK )
571    {
572
573        int x = event.m_x ;
574        int y = event.m_y ;
575
576        MacClientToRootWindow( &x , &y ) ;
577
578        ControlHandle   control ;
579        Point       localwhere ;
580        SInt16      controlpart ;
581        WindowRef   window = (WindowRef) MacGetRootWindow() ;
582
583        localwhere.h = x ;
584        localwhere.v = y ;
585
586        short modifiers = 0;
587
588        if ( !event.m_leftDown && !event.m_rightDown )
589            modifiers  |= btnState ;
590
591        if ( event.m_shiftDown )
592            modifiers |= shiftKey ;
593
594        if ( event.m_controlDown )
595            modifiers |= controlKey ;
596
597        if ( event.m_altDown )
598            modifiers |= optionKey ;
599
600        if ( event.m_metaDown )
601            modifiers |= cmdKey ;
602
603        controlpart = ::FindControl( localwhere , window , &control ) ;
604        {
605            if ( control && ::IsControlActive( control ) )
606            {
607                {
608                    controlpart = ::HandleControlClick( control , localwhere , modifiers , (ControlActionUPP) -1 ) ;
609                    wxTheApp->s_lastMouseDown = 0 ;
610                    if ( control && controlpart != kControlNoPart ) // otherwise we will get the event twice
611                    {
612                        MacHandleControlClick( (WXWidget) control , controlpart , false /* not down anymore */ ) ;
613                    }
614                }
615            }
616        }
617    }
618}
619
620#endif // wxUSE_TOOLBAR
621