]> git.saurik.com Git - wxWidgets.git/blobdiff - src/univ/toolbar.cpp
use wxIsSameDouble() and wxIsNullDouble() for warning-less double comparison of doubles
[wxWidgets.git] / src / univ / toolbar.cpp
index 83d4ad199af9cb54f0071691a99ea452066cc877..d07923834ebff398ef85daba5724861ff5640ff3 100644 (file)
@@ -1,8 +1,12 @@
 /////////////////////////////////////////////////////////////////////////////
 // Name:        src/univ/toolbar.cpp
-// Author:      Robert Roebling
+// Purpose:     implementation of wxToolBar for wxUniversal
+// Author:      Robert Roebling, Vadim Zeitlin (universalization)
+// Modified by:
+// Created:     20.02.02
 // Id:          $Id$
-// Copyright:   (c) 2001 Robert Roebling
+// Copyright:   (c) 2001 Robert Roebling,
+//              (c) 2002 SciTech Software, Inc. (www.scitechsoft.com)
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
 // headers
 // ----------------------------------------------------------------------------
 
-#ifdef __GNUG__
-    #pragma implementation "univtoolbar.h"
-#endif
-
 // For compilers that support precompilation, includes "wx.h".
 #include "wx/wxprec.h"
 
     #pragma hdrstop
 #endif
 
+#if wxUSE_TOOLBAR
+
 #ifndef WX_PRECOMP
     #include "wx/utils.h"
     #include "wx/app.h"
 #endif
 
+#include "wx/univ/renderer.h"
+
+#include "wx/frame.h"
 #include "wx/toolbar.h"
-#include "wx/validate.h"
+#include "wx/image.h"
+#include "wx/log.h"
+
+// ----------------------------------------------------------------------------
+// constants
+// ----------------------------------------------------------------------------
 
-//-----------------------------------------------------------------------------
-// wxToolBar
-//-----------------------------------------------------------------------------
+// value meaning that m_widthSeparator is not initialized
+static const wxCoord INVALID_WIDTH = wxDefaultCoord;
 
-BEGIN_EVENT_TABLE(wxToolBar,wxToolBarBase)
-    EVT_MOUSE_EVENTS( wxToolBar::OnMouse )
-    EVT_PAINT( wxToolBar::OnPaint )
-    EVT_SIZE( wxToolBar::OnSize )
-END_EVENT_TABLE()
+// ----------------------------------------------------------------------------
+// wxToolBarTool: our implementation of wxToolBarToolBase
+// ----------------------------------------------------------------------------
 
-bool wxToolBar::Create( wxWindow *parent, wxWindowID id,
-                 const wxPoint& pos, const wxSize& size,
-                 long style, const wxString& name )
+class WXDLLEXPORT wxToolBarTool : public wxToolBarToolBase
 {
-    bool ret = wxToolBarBase::Create( parent, id, pos, size, style, wxDefaultValidator, name );
-    
-    return ret;
-}
+public:
+    wxToolBarTool(wxToolBar *tbar,
+                  int id,
+                  const wxString& label,
+                  const wxBitmap& bmpNormal,
+                  const wxBitmap& bmpDisabled,
+                  wxItemKind kind,
+                  wxObject *clientData,
+                  const wxString& shortHelp,
+                  const wxString& longHelp)
+        : wxToolBarToolBase(tbar, id, label, bmpNormal, bmpDisabled, kind,
+                            clientData, shortHelp, longHelp)
+    {
+        // no position yet
+        m_x =
+        m_y = wxDefaultCoord;
+        m_width =
+        m_height = 0;
+
+        // not pressed yet
+        m_isInverted = false;
+
+        // mouse not here yet
+        m_underMouse = false;
+    }
+
+    wxToolBarTool(wxToolBar *tbar, wxControl *control)
+        : wxToolBarToolBase(tbar, control)
+    {
+        // no position yet
+        m_x =
+        m_y = wxDefaultCoord;
+        m_width =
+        m_height = 0;
+
+        // not pressed yet
+        m_isInverted = false;
+
+        // mouse not here yet
+        m_underMouse = false;
+    }
+
+    // is this tool pressed, even temporarily? (this is different from being
+    // permanently toggled which is what IsToggled() returns)
+    bool IsPressed() const
+        { return CanBeToggled() ? IsToggled() != m_isInverted : m_isInverted; }
+
+    // are we temporarily pressed/unpressed?
+    bool IsInverted() const { return m_isInverted; }
+
+    // press the tool temporarily by inverting its toggle state
+    void Invert() { m_isInverted = !m_isInverted; }
+
+    // Set underMouse
+    void SetUnderMouse( bool under = true ) { m_underMouse = under; }
+    bool IsUnderMouse() { return m_underMouse; }
+
+public:
+    // the tool position (for controls)
+    wxCoord m_x;
+    wxCoord m_y;
+    wxCoord m_width;
+    wxCoord m_height;
+
+private:
+    // true if the tool is pressed
+    bool m_isInverted;
+
+    // true if the tool is under the mouse
+    bool m_underMouse;
+};
+
+// ============================================================================
+// wxToolBar implementation
+// ============================================================================
+
+IMPLEMENT_DYNAMIC_CLASS(wxToolBar, wxControl);
+
+// ----------------------------------------------------------------------------
+// wxToolBar creation
+// ----------------------------------------------------------------------------
 
 void wxToolBar::Init()
 {
-    // TODO: this is from tbarbase.cpp, but should be in
-    // wxToolbarBase::Init
-    // the list owns the pointers
-    m_tools.DeleteContents(TRUE);
-    m_xMargin = m_yMargin = 0;
-    m_maxRows = m_maxCols = 0;
-    // End TODO
-
-    m_maxWidth = 0;
+    // no tools yet
+    m_needsLayout = false;
+
+    // unknown widths for the tools and separators
+    m_widthSeparator = INVALID_WIDTH;
+
+    m_maxWidth =
     m_maxHeight = 0;
 
-    m_captured = NULL;
-    SetToolBitmapSize( wxSize(16,15) );
+    wxRenderer *renderer = GetRenderer();
+
+    SetToolBitmapSize(renderer->GetToolBarButtonSize(&m_widthSeparator));
+    SetMargins(renderer->GetToolBarMargin());
 }
 
+bool wxToolBar::Create(wxWindow *parent,
+                       wxWindowID id,
+                       const wxPoint& pos,
+                       const wxSize& size,
+                       long style,
+                       const wxString& name)
+{
+    if ( !wxToolBarBase::Create(parent, id, pos, size, style,
+                                wxDefaultValidator, name) )
+    {
+        return false;
+    }
+
+    CreateInputHandler(wxINP_HANDLER_TOOLBAR);
+
+    SetBestSize(size);
+
+    return true;
+}
+
+wxToolBar::~wxToolBar()
+{
+    // Make sure the toolbar is removed from the parent.
+    SetSize(0,0);
+}
+
+void wxToolBar::SetMargins(int x, int y)
+{
+    // This required for similar visual effects under
+    // native platforms and wxUniv.
+    wxToolBarBase::SetMargins( x + 3, y + 3 );
+}
+
+// ----------------------------------------------------------------------------
+// wxToolBar tool-related methods
+// ----------------------------------------------------------------------------
+
 wxToolBarToolBase *wxToolBar::FindToolForPosition(wxCoord x, wxCoord y) const
 {
+    // check the "other" direction first: it must be inside the toolbar or we
+    // don't risk finding anything
+    if ( IsVertical() )
+    {
+        if ( x < 0 || x > m_maxWidth )
+            return NULL;
+
+        // we always use x, even for a vertical toolbar, this makes the code
+        // below simpler
+        x = y;
+    }
+    else // horizontal
+    {
+        if ( y < 0 || y > m_maxHeight )
+            return NULL;
+    }
+
+    for ( wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst();
+          node;
+          node = node->GetNext() )
+    {
+        wxToolBarToolBase *tool =  node->GetData();
+        wxRect rectTool = GetToolRect(tool);
+
+        wxCoord startTool, endTool;
+        GetRectLimits(rectTool, &startTool, &endTool);
+
+        if ( x >= startTool && x <= endTool )
+        {
+            // don't return the separators from here, they don't accept any
+            // input anyhow
+            return tool->IsSeparator() ? NULL : tool;
+        }
+    }
+
     return NULL;
 }
 
-void wxToolBar::SetToolShortHelp(int id, const wxString& helpString)
+void wxToolBar::SetToolShortHelp(int id, const wxString& help)
 {
+    wxToolBarToolBase *tool = FindById(id);
+
+    wxCHECK_RET( tool, _T("SetToolShortHelp: no such tool") );
+
+    tool->SetShortHelp(help);
 }
 
-bool wxToolBar::DoInsertTool(size_t pos, wxToolBarToolBase *tool)
+bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos),
+                             wxToolBarToolBase * WXUNUSED(tool))
 {
-    return TRUE;
+    // recalculate the toolbar geometry before redrawing it the next time
+    m_needsLayout = true;
+
+    // and ensure that we indeed are going to redraw
+    Refresh();
+
+    return true;
 }
 
-bool wxToolBar::DoDeleteTool(size_t pos, wxToolBarToolBase *tool)
+bool wxToolBar::DoDeleteTool(size_t WXUNUSED(pos),
+                             wxToolBarToolBase * WXUNUSED(tool))
 {
-    return TRUE;
+    // as above
+    m_needsLayout = true;
+
+    Refresh();
+
+    return true;
 }
 
 void wxToolBar::DoEnableTool(wxToolBarToolBase *tool, bool enable)
 {
+    // created disabled-state bitmap on demand
+    if ( !enable && !tool->GetDisabledBitmap().Ok() )
+    {
+        wxImage image( tool->GetNormalBitmap().ConvertToImage() );
+
+        // TODO: don't hardcode 180
+        unsigned char bg_red = 180;
+        unsigned char bg_green = 180;
+        unsigned char bg_blue = 180;
+
+        unsigned char mask_red = image.GetMaskRed();
+        unsigned char mask_green = image.GetMaskGreen();
+        unsigned char mask_blue = image.GetMaskBlue();
+
+        bool has_mask = image.HasMask();
+
+        int x,y;
+        for (y = 0; y < image.GetHeight(); y++)
+        {
+            for (x = 0; x < image.GetWidth(); x++)
+            {
+                unsigned char red = image.GetRed(x,y);
+                unsigned char green = image.GetGreen(x,y);
+                unsigned char blue = image.GetBlue(x,y);
+                if (!has_mask || red != mask_red || green != mask_green || blue != mask_blue)
+                {
+                    red = (unsigned char)((((wxInt32) red  - bg_red) >> 1) + bg_red);
+                    green = (unsigned char)((((wxInt32) green  - bg_green) >> 1) + bg_green);
+                    blue = (unsigned char)((((wxInt32) blue  - bg_blue) >> 1) + bg_blue);
+                    image.SetRGB( x, y, red, green, blue );
+                }
+            }
+        }
+
+        for (y = 0; y < image.GetHeight(); y++)
+        {
+            for (x = y % 2; x < image.GetWidth(); x += 2)
+            {
+                unsigned char red = image.GetRed(x,y);
+                unsigned char green = image.GetGreen(x,y);
+                unsigned char blue = image.GetBlue(x,y);
+                if (!has_mask || red != mask_red || green != mask_green || blue != mask_blue)
+                {
+                    red = (unsigned char)((((wxInt32) red  - bg_red) >> 1) + bg_red);
+                    green = (unsigned char)((((wxInt32) green  - bg_green) >> 1) + bg_green);
+                    blue = (unsigned char)((((wxInt32) blue  - bg_blue) >> 1) + bg_blue);
+                    image.SetRGB( x, y, red, green, blue );
+                }
+            }
+        }
+
+        tool->SetDisabledBitmap(image);
+    }
+
+    RefreshTool(tool);
 }
 
-void wxToolBar::DoToggleTool(wxToolBarToolBase *tool, bool toggle)
+void wxToolBar::DoToggleTool(wxToolBarToolBase *tool, bool WXUNUSED(toggle))
 {
-    wxToolBarTool *my_tool = (wxToolBarTool*) tool;
-    
-    bool refresh = (my_tool->IsToggled() != toggle);
-    
-    my_tool->m_isDown = toggle;
-    
-    if (refresh)
-        RefreshTool( my_tool );
+    // note that if we're called the tool did change state (the base class
+    // checks for it), so it's not necessary to check for this again here
+    RefreshTool(tool);
 }
 
-void wxToolBar::DoSetToggle(wxToolBarToolBase *tool, bool toggle)
+void wxToolBar::DoSetToggle(wxToolBarToolBase *tool, bool WXUNUSED(toggle))
 {
+    RefreshTool(tool);
 }
 
 wxToolBarToolBase *wxToolBar::CreateTool(int id,
-                                          const wxBitmap& bitmap1,
-                                          const wxBitmap& bitmap2,
-                                          bool toggle,
-                                          wxObject *clientData,
-                                          const wxString& shortHelpString,
-                                          const wxString& longHelpString)
+                                         const wxString& label,
+                                         const wxBitmap& bmpNormal,
+                                         const wxBitmap& bmpDisabled,
+                                         wxItemKind kind,
+                                         wxObject *clientData,
+                                         const wxString& shortHelp,
+                                         const wxString& longHelp)
 {
-    return new wxToolBarTool( this, id, bitmap1, bitmap2, toggle,
-                              clientData, shortHelpString, longHelpString);
+    return new wxToolBarTool(this, id, label, bmpNormal, bmpDisabled, kind,
+                             clientData, shortHelp, longHelp);
 }
-                                          
+
 wxToolBarToolBase *wxToolBar::CreateTool(wxControl *control)
 {
-    wxFAIL_MSG( wxT("Toolbar doesn't support controls yet.") );
-    
-    return NULL;
+    return new wxToolBarTool(this, control);
 }
 
-void wxToolBar::RefreshTool( wxToolBarTool *tool )
-{
-    wxRect rect( tool->m_x, tool->m_y, m_defaultWidth+6, m_defaultHeight+6 );
-    Refresh( TRUE, &rect );
-}
+// ----------------------------------------------------------------------------
+// wxToolBar geometry
+// ----------------------------------------------------------------------------
 
-void wxToolBar::DrawToolBarTool( wxToolBarTool *tool, wxDC &dc, bool down )
+wxRect wxToolBar::GetToolRect(wxToolBarToolBase *toolBase) const
 {
-    if (down)
+    const wxToolBarTool *tool = (wxToolBarTool *)toolBase;
+
+    wxRect rect;
+
+    wxCHECK_MSG( tool, rect, _T("GetToolRect: NULL tool") );
+
+    // ensure that we always have the valid tool position
+    if ( m_needsLayout )
     {
-        dc.DrawBitmap( tool->GetBitmap1(), tool->m_x+4, tool->m_y+4, TRUE );
-        
-        dc.SetPen( *wxGREY_PEN );
-        dc.DrawLine( tool->m_x, tool->m_y, tool->m_x+m_defaultWidth+5, tool->m_y );
-        dc.DrawLine( tool->m_x, tool->m_y, tool->m_x, tool->m_y+m_defaultHeight+5 );
-        
-        dc.SetPen( *wxBLACK_PEN );
-        dc.DrawLine( tool->m_x+1, tool->m_y+1, tool->m_x+m_defaultWidth+4, tool->m_y+1 );
-        dc.DrawLine( tool->m_x+1, tool->m_y+1, tool->m_x+1, tool->m_y+m_defaultHeight+4 );
-        
-        dc.SetPen( *wxWHITE_PEN );
-        dc.DrawLine( tool->m_x, tool->m_y+m_defaultHeight+5, tool->m_x+m_defaultWidth+6, tool->m_y+m_defaultHeight+5 );
-        dc.DrawLine( tool->m_x+m_defaultWidth+5, tool->m_y, tool->m_x+m_defaultWidth+5, tool->m_y+m_defaultHeight+6 );
+        wxConstCast(this, wxToolBar)->DoLayout();
     }
-    else
+
+    rect.x = tool->m_x - m_xMargin;
+    rect.y = tool->m_y - m_yMargin;
+
+    if ( IsVertical() )
     {
-        dc.DrawBitmap( tool->GetBitmap1(), tool->m_x+3, tool->m_y+3, TRUE );
-        
-        dc.SetPen( *wxWHITE_PEN );
-        dc.DrawLine( tool->m_x, tool->m_y, tool->m_x+m_defaultWidth+5, tool->m_y );
-        dc.DrawLine( tool->m_x, tool->m_y, tool->m_x, tool->m_y+m_defaultHeight+5 );
-        dc.DrawLine( tool->m_x+m_defaultWidth+4, tool->m_y, tool->m_x+m_defaultWidth+4, tool->m_y+2 );
-        dc.DrawLine( tool->m_x, tool->m_y+m_defaultHeight+4, tool->m_x+2, tool->m_y+m_defaultHeight+4 );
-        
-        dc.SetPen( *wxBLACK_PEN );
-        dc.DrawLine( tool->m_x, tool->m_y+m_defaultHeight+5, tool->m_x+m_defaultWidth+6, tool->m_y+m_defaultHeight+5 );
-        dc.DrawLine( tool->m_x+m_defaultWidth+5, tool->m_y, tool->m_x+m_defaultWidth+5, tool->m_y+m_defaultHeight+6 );
-        
-        dc.SetPen( *wxGREY_PEN );
-        dc.DrawLine( tool->m_x+1, tool->m_y+m_defaultHeight+4, tool->m_x+m_defaultWidth+5, tool->m_y+m_defaultHeight+4 );
-        dc.DrawLine( tool->m_x+m_defaultWidth+4, tool->m_y+1, tool->m_x+m_defaultWidth+4, tool->m_y+m_defaultHeight+5 );
+        if (tool->IsButton())
+        {
+            rect.width = m_defaultWidth;
+            rect.height = m_defaultHeight;
+        }
+        else if (tool->IsSeparator())
+        {
+            rect.width = m_defaultWidth;
+            rect.height = m_widthSeparator;
+        }
+        else // control
+        {
+            rect.width = tool->m_width;
+            rect.height = tool->m_height;
+        }
+    }
+    else // horizontal
+    {
+        if (tool->IsButton())
+        {
+            rect.width = m_defaultWidth;
+            rect.height = m_defaultHeight;
+        }
+        else if (tool->IsSeparator())
+        {
+            rect.width = m_widthSeparator;
+            rect.height = m_defaultHeight;
+        }
+        else // control
+        {
+            rect.width = tool->m_width;
+            rect.height = tool->m_height;
+        }
     }
+
+    rect.width += 2*m_xMargin;
+    rect.height += 2*m_yMargin;
+
+    return rect;
 }
 
-void wxToolBar::OnPaint(wxPaintEvent &event)
+bool wxToolBar::Realize()
 {
-    wxPaintDC dc(this);
-    
-    wxSize clientSize = GetClientSize();
-    dc.SetPen( *wxBLACK_PEN );
-    dc.DrawLine( 0,0, clientSize.x,0 );
-    
-    for ( wxToolBarToolsList::Node *node = m_tools.GetFirst();
+    if ( !wxToolBarBase::Realize() )
+        return false;
+
+    m_needsLayout = true;
+    DoLayout();
+
+    SetBestSize(wxDefaultSize);
+
+    return true;
+}
+
+void wxToolBar::DoLayout()
+{
+    wxASSERT_MSG( m_needsLayout, _T("why are we called?") );
+
+    m_needsLayout = false;
+
+    wxCoord x = m_xMargin,
+            y = m_yMargin;
+
+    const wxCoord widthTool = IsVertical() ? m_defaultHeight : m_defaultWidth;
+    wxCoord margin = IsVertical() ? m_xMargin : m_yMargin;
+    wxCoord *pCur = IsVertical() ? &y : &x;
+
+    // calculate the positions of all elements
+    for ( wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst();
           node;
           node = node->GetNext() )
     {
-        wxToolBarTool *tool = (wxToolBarTool*) node->Data();
-        
-        if (tool->GetId() == -1) continue;
-        
-        DrawToolBarTool( tool, dc, tool->m_isDown );
+        wxToolBarTool *tool = (wxToolBarTool *) node->GetData();
+
+        tool->m_x = x;
+        tool->m_y = y;
+
+        // TODO ugly number fiddling
+        if (tool->IsButton())
+        {
+            *pCur += widthTool;
+        }
+        else if (tool->IsSeparator())
+        {
+            *pCur += m_widthSeparator;
+        }
+        else if (!IsVertical()) // horizontal control
+        {
+            wxControl *control = tool->GetControl();
+            wxSize size = control->GetSize();
+            tool->m_y += (m_defaultHeight - size.y)/2;
+            tool->m_width = size.x;
+            tool->m_height = size.y;
+
+            *pCur += tool->m_width;
+        }
+        *pCur += margin;
     }
+
+    // calculate the total toolbar size
+    wxCoord xMin = m_defaultWidth + 2*m_xMargin,
+            yMin = m_defaultHeight + 2*m_yMargin;
+
+    m_maxWidth = x < xMin ? xMin : x;
+    m_maxHeight = y < yMin ? yMin : y;
 }
 
-bool wxToolBar::Realize()
+wxSize wxToolBar::DoGetBestClientSize() const
+{
+    return wxSize(m_maxWidth, m_maxHeight);
+}
+
+void wxToolBar::DoSetSize(int x, int y, int width, int height, int sizeFlags)
 {
-    if (!wxToolBarBase::Realize())
-        return FALSE;
+    int old_width, old_height;
+    GetSize(&old_width, &old_height);
 
-    int x;
-    int y;
+    wxToolBarBase::DoSetSize(x, y, width, height, sizeFlags);
 
-    if (GetWindowStyleFlag() & wxTB_VERTICAL)
+    // Correct width and height if needed.
+    if ( width == wxDefaultCoord || height == wxDefaultCoord )
     {
-        x = m_xMargin;
-        y = 5;
+        int tmp_width, tmp_height;
+        GetSize(&tmp_width, &tmp_height);
+
+        if ( width == wxDefaultCoord )
+            width = tmp_width;
+        if ( height == wxDefaultCoord )
+            height = tmp_height;
     }
-    else
+
+    // We must refresh the frame size when the toolbar changes size
+    // otherwise the toolbar can be shown incorrectly
+    if ( old_width != width || old_height != height )
     {
-        y = m_yMargin;
-        x = 5;
+        // But before we send the size event check it
+        // we have a frame that is not being deleted.
+        wxFrame *frame = wxDynamicCast(GetParent(), wxFrame);
+        if ( frame && !frame->IsBeingDeleted() )
+        {
+            frame->SendSizeEvent();
+        }
     }
+}
+
+// ----------------------------------------------------------------------------
+// wxToolBar drawing
+// ----------------------------------------------------------------------------
+
+void wxToolBar::RefreshTool(wxToolBarToolBase *tool)
+{
+    RefreshRect(GetToolRect(tool));
+}
+
+void wxToolBar::GetRectLimits(const wxRect& rect,
+                              wxCoord *start,
+                              wxCoord *end) const
+{
+    wxCHECK_RET( start && end, _T("NULL pointer in GetRectLimits") );
 
-    for ( wxToolBarToolsList::Node *node = m_tools.GetFirst();
+    if ( IsVertical() )
+    {
+        *start = rect.GetTop();
+        *end = rect.GetBottom();
+    }
+    else // horizontal
+    {
+        *start = rect.GetLeft();
+        *end = rect.GetRight();
+    }
+}
+
+void wxToolBar::DoDraw(wxControlRenderer *renderer)
+{
+    // prepare the variables used below
+    wxDC& dc = renderer->GetDC();
+    wxRenderer *rend = renderer->GetRenderer();
+    // dc.SetFont(GetFont()); -- uncomment when we support labels
+
+    // draw the border separating us from the menubar (if there is no menubar
+    // we probably shouldn't draw it?)
+    if ( !IsVertical() )
+    {
+        rend->DrawHorizontalLine(dc, 0, 0, GetClientSize().x);
+    }
+
+    // get the update rect and its limits depending on the orientation
+    wxRect rectUpdate = GetUpdateClientRect();
+    wxCoord start, end;
+    GetRectLimits(rectUpdate, &start, &end);
+
+    // and redraw all the tools intersecting it
+    for ( wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst();
           node;
           node = node->GetNext() )
     {
-        wxToolBarTool *tool = (wxToolBarTool*) node->Data();
-        
-        if (GetWindowStyleFlag() & wxTB_VERTICAL)
+        wxToolBarTool *tool = (wxToolBarTool*) node->GetData();
+        wxRect rectTool = GetToolRect(tool);
+        wxCoord startTool, endTool;
+        GetRectLimits(rectTool, &startTool, &endTool);
+
+        if ( endTool < start )
         {
-            if (tool->GetId() == -1)
-            {
-                y += 6;
-                continue;
-            }
-            tool->m_x = m_xMargin;
-            tool->m_y = y;
-            y += m_defaultHeight + 6;
-
-            // Calculate the maximum height or width (depending on style)
-            // so we know how to size the toolbar in Realize.
-            // We could get the size of the tool instead of the
-            // default bitmap size
-            if (m_maxWidth < (m_defaultWidth + 2*(m_xMargin + 2)))
-                m_maxWidth = (m_defaultWidth + 2*(m_xMargin + 2)) ;
+            // we're still to the left of the area to redraw
+            continue;
         }
-        else
+
+        if ( startTool > end )
         {
-            if (tool->GetId() == -1)
-            {
-                x += 6;
-                continue;
-            }
-            tool->m_x = x;
-            tool->m_y = m_yMargin;
-            x += m_defaultWidth + 6;
-
-            // Calculate the maximum height or width (depending on style)
-            // so we know how to size the toolbar in Realize.
-            // We could get the size of the tool instead of the
-            // default bitmap size
-            if (m_maxHeight < (m_defaultHeight + 2*(m_yMargin + 2)))
-                m_maxHeight = (m_defaultHeight + 2*(m_yMargin + 2)) ;
+            // we're beyond the area to redraw, nothing left to do
+            break;
+        }
+
+        if (tool->IsSeparator() && !HasFlag(wxTB_FLAT))
+        {
+            // Draw separators only in flat mode
+            continue;
+        }
+
+        // deal with the flags
+        int flags = 0;
+
+        if ( tool->IsEnabled() )
+        {
+            // The toolbars without wxTB_FLAT don't react to the mouse hovering
+            if ( !HasFlag(wxTB_FLAT) || tool->IsUnderMouse() )
+                flags |= wxCONTROL_CURRENT;
+        }
+        else // disabled tool
+        {
+            flags |= wxCONTROL_DISABLED;
+        }
+
+        //if ( tool == m_toolCaptured )
+        //    flags |= wxCONTROL_FOCUSED;
+
+        if ( tool->IsPressed() )
+            flags = wxCONTROL_PRESSED;
+
+        wxString label;
+        wxBitmap bitmap;
+        if ( !tool->IsSeparator() )
+        {
+            // label = tool->GetLabel();
+            bitmap = tool->GetBitmap();
+        }
+        //else: leave both the label and the bitmap invalid to draw a separator
+
+        if ( !tool->IsControl() )
+        {
+            rend->DrawToolBarButton(dc, label, bitmap, rectTool, flags, tool->GetStyle());
+        }
+        else // control
+        {
+            wxControl *control = tool->GetControl();
+            control->Move(tool->m_x, tool->m_y);
         }
-        
     }
+}
+
+// ----------------------------------------------------------------------------
+// wxToolBar actions
+// ----------------------------------------------------------------------------
 
-    wxSize sz = GetSize();
-    if (GetWindowStyleFlag() & wxTB_VERTICAL)
+bool wxToolBar::PerformAction(const wxControlAction& action,
+                              long numArg,
+                              const wxString& strArg)
+{
+    wxToolBarTool *tool = (wxToolBarTool*) FindById(numArg);
+    if (!tool)
+        return false;
+
+    if ( action == wxACTION_TOOLBAR_TOGGLE )
     {
-        SetSize(m_maxWidth, sz.y);
+        PerformAction( wxACTION_BUTTON_RELEASE, numArg );
+
+        PerformAction( wxACTION_BUTTON_CLICK, numArg );
     }
-    else
+    else if ( action == wxACTION_TOOLBAR_PRESS )
     {
-        SetSize(sz.x, m_maxHeight);
+        wxLogTrace(_T("toolbar"), _T("Button '%s' pressed."), tool->GetShortHelp().c_str());
+
+        tool->Invert();
+
+        RefreshTool( tool );
     }
+    else if ( action == wxACTION_TOOLBAR_RELEASE )
+    {
+        wxLogTrace(_T("toolbar"), _T("Button '%s' released."), tool->GetShortHelp().c_str());
 
-    // Commenting out Robert's fix since the above should be
-    // more general
-    //    SetSize( x+16, m_defaultHeight + 14 );
-    
-    return TRUE;
-}
+        wxASSERT_MSG( tool->IsInverted(), _T("release unpressed button?") );
 
-void wxToolBar::OnMouse(wxMouseEvent &event)
-{
-    wxToolBarTool *hit = NULL;
-    int x = event.GetX();
-    int y = event.GetY();
-    
-    for ( wxToolBarToolsList::Node *node = m_tools.GetFirst();
-          node;
-          node = node->GetNext() )
+        tool->Invert();
+
+        RefreshTool( tool );
+    }
+    else if ( action == wxACTION_TOOLBAR_CLICK )
     {
-        wxToolBarTool *tool = (wxToolBarTool*) node->Data();
-        
-        if ((x > tool->m_x) && (x < tool->m_x+m_defaultWidth+5)  &&
-            (y > tool->m_y) && (y < tool->m_y+m_defaultHeight+5))
+        bool isToggled;
+        if ( tool->CanBeToggled() )
         {
-            hit = tool;
-            break;
+            tool->Toggle();
+
+            RefreshTool( tool );
+
+            isToggled = tool->IsToggled();
+        }
+        else // simple non-checkable tool
+        {
+            isToggled = false;
+        }
+        OnLeftClick( tool->GetId(), isToggled );
+    }
+    else if ( action == wxACTION_TOOLBAR_ENTER )
+    {
+        wxCHECK_MSG( tool, false, _T("no tool to enter?") );
+
+        if ( HasFlag(wxTB_FLAT) && tool->IsEnabled() )
+        {
+            tool->SetUnderMouse( true );
+
+            if ( !tool->IsToggled() )
+                RefreshTool( tool );
         }
     }
-    
-    if (event.LeftDown() && (hit))
+    else if ( action == wxACTION_TOOLBAR_LEAVE )
     {
-        CaptureMouse();
-        m_captured = hit;
-        
-        m_captured->m_isDown = TRUE;
-        RefreshTool( m_captured );
-        
-        return;
+        wxCHECK_MSG( tool, false, _T("no tool to leave?") );
+
+        if ( HasFlag(wxTB_FLAT) && tool->IsEnabled() )
+        {
+            tool->SetUnderMouse( false );
+
+            if ( !tool->IsToggled() )
+                RefreshTool( tool );
+        }
     }
-    
-    if (event.Dragging() && (m_captured))
+    else
+        return wxControl::PerformAction(action, numArg, strArg);
+
+    return true;
+}
+
+// ============================================================================
+// wxStdToolbarInputHandler implementation
+// ============================================================================
+
+wxStdToolbarInputHandler::wxStdToolbarInputHandler(wxInputHandler *handler)
+                        : wxStdInputHandler(handler)
+{
+    m_winCapture = NULL;
+    m_toolCapture = NULL;
+    m_toolLast = NULL;
+}
+
+bool wxStdToolbarInputHandler::HandleKey(wxInputConsumer *consumer,
+                                         const wxKeyEvent& event,
+                                         bool pressed)
+{
+    // TODO: when we have a current button we should allow the arrow
+    //       keys to move it
+    return wxStdInputHandler::HandleKey(consumer, event, pressed);
+}
+
+bool wxStdToolbarInputHandler::HandleMouse(wxInputConsumer *consumer,
+                                           const wxMouseEvent& event)
+{
+    wxToolBar *tbar = wxStaticCast(consumer->GetInputWindow(), wxToolBar);
+    wxToolBarToolBase *tool = tbar->FindToolForPosition(event.GetX(), event.GetY());
+
+    if ( event.Button(1) )
     {
-        bool is_down = (hit == m_captured);
-        if (is_down != m_captured->m_isDown)
+
+        if ( event.LeftDown() || event.LeftDClick() )
+        {
+            if ( !tool || !tool->IsEnabled() )
+                return true;
+
+            m_winCapture = tbar;
+            m_winCapture->CaptureMouse();
+
+            m_toolCapture = tool;
+
+            consumer->PerformAction( wxACTION_BUTTON_PRESS, tool->GetId() );
+
+            return true;
+        }
+        else if ( event.LeftUp() )
         {
-            m_captured->m_isDown = is_down;
-            RefreshTool( m_captured );
+            if ( m_winCapture )
+            {
+                m_winCapture->ReleaseMouse();
+                m_winCapture = NULL;
+            }
+
+            if (m_toolCapture)
+            {
+                if ( tool == m_toolCapture )
+                    consumer->PerformAction( wxACTION_BUTTON_TOGGLE, m_toolCapture->GetId() );
+                else
+                    consumer->PerformAction( wxACTION_TOOLBAR_LEAVE, m_toolCapture->GetId() );
+            }
+
+            m_toolCapture = NULL;
+
+            return true;
         }
-        
-        return;
+        //else: don't do anything special about the double click
     }
-    
-    if (event.LeftUp() && (m_captured))
+
+    return wxStdInputHandler::HandleMouse(consumer, event);
+}
+
+bool wxStdToolbarInputHandler::HandleMouseMove(wxInputConsumer *consumer,
+                                               const wxMouseEvent& event)
+{
+    if ( !wxStdInputHandler::HandleMouseMove(consumer, event) )
     {
-        ReleaseMouse();
-        
-        m_captured->m_isDown = FALSE;
-        RefreshTool( m_captured );
-        
-        if (hit == m_captured)
+        wxToolBar *tbar = wxStaticCast(consumer->GetInputWindow(), wxToolBar);
+
+        wxToolBarTool *tool;
+        if ( event.Leaving() )
+        {
+            // We cannot possibly be over a tool when
+            // leaving the toolbar
+            tool = NULL;
+        }
+        else
         {
-            wxCommandEvent cevent( wxEVT_COMMAND_TOOL_CLICKED, m_captured->GetId() );
-            cevent.SetEventObject( this );
-            // cevent.SetExtraLong((long) toggleDown);
-            GetEventHandler()->ProcessEvent( cevent );
+            tool = (wxToolBarTool*) tbar->FindToolForPosition( event.GetX(), event.GetY() );
         }
-        
-        m_captured = NULL;
-        
-        return;
+
+        if (m_toolCapture)
+        {
+            // During capture we only care of the captured tool
+            if (tool && (tool != m_toolCapture))
+                tool = NULL;
+
+            if (tool == m_toolLast)
+                return true;
+
+            if (tool)
+                consumer->PerformAction( wxACTION_BUTTON_PRESS, m_toolCapture->GetId() );
+            else
+                consumer->PerformAction( wxACTION_BUTTON_RELEASE, m_toolCapture->GetId() );
+
+            m_toolLast = tool;
+        }
+        else
+        {
+            if (tool == m_toolLast)
+               return true;
+
+            if (m_toolLast)
+            {
+                // Leave old tool if any
+                consumer->PerformAction( wxACTION_TOOLBAR_LEAVE, m_toolLast->GetId() );
+            }
+
+            if (tool)
+            {
+                // Enter new tool if any
+                consumer->PerformAction( wxACTION_TOOLBAR_ENTER, tool->GetId() );
+            }
+
+            m_toolLast = tool;
+        }
+
+        return true;
+    }
+
+    return false;
+}
+
+bool wxStdToolbarInputHandler::HandleFocus(wxInputConsumer *consumer,
+                                           const wxFocusEvent& WXUNUSED(event))
+{
+    if ( m_toolCapture )
+    {
+        // We shouldn't be left with a highlighted button
+        consumer->PerformAction( wxACTION_TOOLBAR_LEAVE, m_toolCapture->GetId() );
     }
+
+    return true;
 }
 
+bool wxStdToolbarInputHandler::HandleActivation(wxInputConsumer *consumer,
+                                                bool activated)
+{
+    if (m_toolCapture && !activated)
+    {
+        // We shouldn't be left with a highlighted button
+        consumer->PerformAction( wxACTION_TOOLBAR_LEAVE, m_toolCapture->GetId() );
+    }
+
+    return true;
+}
+
+#endif // wxUSE_TOOLBAR
+