]> git.saurik.com Git - wxWidgets.git/blobdiff - src/aui/auibar.cpp
Fix Tab navigation when focused control is disabled.
[wxWidgets.git] / src / aui / auibar.cpp
index 0497c3ced9a3e29ad441d87906e638db8378fa1c..e33ce817a091db98f4ed597a8fd7d3e8771135be 100644 (file)
@@ -38,8 +38,6 @@
 
 #ifdef __WXMAC__
 #include "wx/osx/private.h"
 
 #ifdef __WXMAC__
 #include "wx/osx/private.h"
-// for themeing support
-#include <Carbon/Carbon.h>
 #endif
 
 #include "wx/arrimpl.cpp"
 #endif
 
 #include "wx/arrimpl.cpp"
@@ -187,8 +185,8 @@ wxAuiDefaultToolBarArt::wxAuiDefaultToolBarArt()
     m_gripper_pen2 = wxPen(darker3_colour);
     m_gripper_pen3 = *wxWHITE_PEN;
 
     m_gripper_pen2 = wxPen(darker3_colour);
     m_gripper_pen3 = *wxWHITE_PEN;
 
-    static unsigned char button_dropdown_bits[] = { 0xe0, 0xf1, 0xfb };
-    static unsigned char overflow_bits[] = { 0x80, 0xff, 0x80, 0xc1, 0xe3, 0xf7 };
+    static const unsigned char button_dropdown_bits[] = { 0xe0, 0xf1, 0xfb };
+    static const unsigned char overflow_bits[] = { 0x80, 0xff, 0x80, 0xc1, 0xe3, 0xf7 };
 
     m_button_dropdown_bmp = wxAuiBitmapFromBits(button_dropdown_bits, 5, 3,
                                                 *wxBLACK);
 
     m_button_dropdown_bmp = wxAuiBitmapFromBits(button_dropdown_bits, 5, 3,
                                                 *wxBLACK);
@@ -555,6 +553,12 @@ wxSize wxAuiDefaultToolBarArt::GetLabelSize(
     // get item's width
     width = item.GetMinSize().GetWidth();
 
     // get item's width
     width = item.GetMinSize().GetWidth();
 
+    if (width == -1)
+    {
+        // no width specified, measure the text ourselves
+        width = dc.GetTextExtent(item.GetLabel()).GetX();
+    }
+
     return wxSize(width, height);
 }
 
     return wxSize(width, height);
 }
 
@@ -728,9 +732,9 @@ void wxAuiDefaultToolBarArt::SetElementSize(int element_id, int size)
 {
     switch (element_id)
     {
 {
     switch (element_id)
     {
-        case wxAUI_TBART_SEPARATOR_SIZE: m_separator_size = size;
-        case wxAUI_TBART_GRIPPER_SIZE:   m_gripper_size = size;
-        case wxAUI_TBART_OVERFLOW_SIZE:  m_overflow_size = size;
+        case wxAUI_TBART_SEPARATOR_SIZE: m_separator_size = size; break;
+        case wxAUI_TBART_GRIPPER_SIZE:   m_gripper_size = size; break;
+        case wxAUI_TBART_OVERFLOW_SIZE:  m_overflow_size = size; break;
     }
 }
 
     }
 }
 
@@ -788,6 +792,22 @@ int wxAuiDefaultToolBarArt::ShowDropDown(wxWindow* wnd,
 
 
 
 
 
 
+static wxOrientation GetOrientation(long& style)
+{
+    switch (style & wxAUI_ORIENTATION_MASK)
+    {
+        case wxAUI_TB_HORIZONTAL:
+            return wxHORIZONTAL;
+        case wxAUI_TB_VERTICAL:
+            return wxVERTICAL;
+        default:
+            wxFAIL_MSG("toolbar cannot be locked in both horizontal and vertical orientations (maybe no lock was intended?)");
+            // fall through
+        case 0:
+            return wxBOTH;
+    }
+}
+
 BEGIN_EVENT_TABLE(wxAuiToolBar, wxControl)
     EVT_SIZE(wxAuiToolBar::OnSize)
     EVT_IDLE(wxAuiToolBar::OnIdle)
 BEGIN_EVENT_TABLE(wxAuiToolBar, wxControl)
     EVT_SIZE(wxAuiToolBar::OnSize)
     EVT_IDLE(wxAuiToolBar::OnIdle)
@@ -833,16 +853,22 @@ wxAuiToolBar::wxAuiToolBar(wxWindow* parent,
     m_gripper_sizer_item = NULL;
     m_overflow_sizer_item = NULL;
     m_dragging = false;
     m_gripper_sizer_item = NULL;
     m_overflow_sizer_item = NULL;
     m_dragging = false;
+    m_orientation = GetOrientation(style);
+    if (m_orientation == wxBOTH)
+    {
+        m_orientation = wxHORIZONTAL;
+    }
     m_style = style | wxBORDER_NONE;
     m_gripper_visible = (m_style & wxAUI_TB_GRIPPER) ? true : false;
     m_overflow_visible = (m_style & wxAUI_TB_OVERFLOW) ? true : false;
     m_overflow_state = 0;
     SetMargins(5, 5, 2, 2);
     SetFont(*wxNORMAL_FONT);
     m_style = style | wxBORDER_NONE;
     m_gripper_visible = (m_style & wxAUI_TB_GRIPPER) ? true : false;
     m_overflow_visible = (m_style & wxAUI_TB_OVERFLOW) ? true : false;
     m_overflow_state = 0;
     SetMargins(5, 5, 2, 2);
     SetFont(*wxNORMAL_FONT);
-    m_art->SetFlags((unsigned int)m_style);
+    SetArtFlags();
     SetExtraStyle(wxWS_EX_PROCESS_IDLE);
     if (style & wxAUI_TB_HORZ_LAYOUT)
         SetToolTextOrientation(wxAUI_TBTOOL_TEXT_RIGHT);
     SetExtraStyle(wxWS_EX_PROCESS_IDLE);
     if (style & wxAUI_TB_HORZ_LAYOUT)
         SetToolTextOrientation(wxAUI_TBTOOL_TEXT_RIGHT);
+    SetBackgroundStyle(wxBG_STYLE_CUSTOM);
 }
 
 
 }
 
 
@@ -854,13 +880,17 @@ wxAuiToolBar::~wxAuiToolBar()
 
 void wxAuiToolBar::SetWindowStyleFlag(long style)
 {
 
 void wxAuiToolBar::SetWindowStyleFlag(long style)
 {
+    GetOrientation(style);      // assert if style is invalid
+    wxCHECK_RET(IsPaneValid(style),
+                "window settings and pane settings are incompatible");
+
     wxControl::SetWindowStyleFlag(style);
 
     m_style = style;
 
     if (m_art)
     {
     wxControl::SetWindowStyleFlag(style);
 
     m_style = style;
 
     if (m_art)
     {
-        m_art->SetFlags((unsigned int)m_style);
+        SetArtFlags();
     }
 
     if (m_style & wxAUI_TB_GRIPPER)
     }
 
     if (m_style & wxAUI_TB_GRIPPER)
@@ -893,7 +923,7 @@ void wxAuiToolBar::SetArtProvider(wxAuiToolBarArt* art)
 
     if (m_art)
     {
 
     if (m_art)
     {
-        m_art->SetFlags((unsigned int)m_style);
+        SetArtFlags();
         m_art->SetTextOrientation(m_tool_text_orientation);
     }
 }
         m_art->SetTextOrientation(m_tool_text_orientation);
     }
 }
@@ -950,9 +980,9 @@ wxAuiToolBarItem* wxAuiToolBar::AddTool(int tool_id,
     item.min_size = wxDefaultSize;
     item.user_data = 0;
     item.sticky = false;
     item.min_size = wxDefaultSize;
     item.user_data = 0;
     item.sticky = false;
-    
-    if (item.id == wxID_ANY) 
-        item.id = wxNewId(); 
+
+    if (item.id == wxID_ANY)
+        item.id = wxNewId();
 
     if (!item.disabled_bitmap.IsOk())
     {
 
     if (!item.disabled_bitmap.IsOk())
     {
@@ -1018,9 +1048,9 @@ wxAuiToolBarItem* wxAuiToolBar::AddLabel(int tool_id,
     item.user_data = 0;
     item.sticky = false;
 
     item.user_data = 0;
     item.sticky = false;
 
-    if (item.id == wxID_ANY) 
-        item.id = wxNewId(); 
-       
+    if (item.id == wxID_ANY)
+        item.id = wxNewId();
+
     m_items.Add(item);
     return &m_items.Last();
 }
     m_items.Add(item);
     return &m_items.Last();
 }
@@ -1337,8 +1367,16 @@ int wxAuiToolBar::GetToolPacking() const
 }
 
 
 }
 
 
-void wxAuiToolBar::SetOrientation(int WXUNUSED(orientation))
+void wxAuiToolBar::SetOrientation(int orientation)
 {
 {
+    wxCHECK_RET(orientation == wxHORIZONTAL ||
+                orientation == wxVERTICAL,
+                "invalid orientation value");
+    if (orientation != m_orientation)
+    {
+        m_orientation = wxOrientation(orientation);
+        SetArtFlags();
+    }
 }
 
 void wxAuiToolBar::SetMargins(int left, int right, int top, int bottom)
 }
 
 void wxAuiToolBar::SetMargins(int left, int right, int top, int bottom)
@@ -1469,7 +1507,7 @@ void wxAuiToolBar::RefreshOverflowState()
     // find out if the mouse cursor is inside the dropdown rectangle
     if (overflow_rect.Contains(pt.x, pt.y))
     {
     // find out if the mouse cursor is inside the dropdown rectangle
     if (overflow_rect.Contains(pt.x, pt.y))
     {
-        if (::wxGetMouseState().LeftDown())
+        if (::wxGetMouseState().LeftIsDown())
             overflow_state = wxAUI_BUTTON_STATE_PRESSED;
         else
             overflow_state = wxAUI_BUTTON_STATE_HOVER;
             overflow_state = wxAUI_BUTTON_STATE_PRESSED;
         else
             overflow_state = wxAUI_BUTTON_STATE_HOVER;
@@ -1496,7 +1534,7 @@ void wxAuiToolBar::ToggleTool(int tool_id, bool state)
             int i, idx, count;
             idx = GetToolIndex(tool_id);
             count = (int)m_items.GetCount();
             int i, idx, count;
             idx = GetToolIndex(tool_id);
             count = (int)m_items.GetCount();
-            
+
             if (idx >= 0 && idx < count)
             {
                 for (i = idx; i < count; ++i)
             if (idx >= 0 && idx < count)
             {
                 for (i = idx; i < count; ++i)
@@ -1512,7 +1550,7 @@ void wxAuiToolBar::ToggleTool(int tool_id, bool state)
                     m_items[i].state &= ~wxAUI_BUTTON_STATE_CHECKED;
                 }
             }
                     m_items[i].state &= ~wxAUI_BUTTON_STATE_CHECKED;
                 }
             }
-            
+
             tool->state |= wxAUI_BUTTON_STATE_CHECKED;
         }
          else if (tool->kind == wxITEM_CHECK)
             tool->state |= wxAUI_BUTTON_STATE_CHECKED;
         }
          else if (tool->kind == wxITEM_CHECK)
@@ -1646,6 +1684,65 @@ void wxAuiToolBar::SetCustomOverflowItems(const wxAuiToolBarItemArray& prepend,
     m_custom_overflow_append = append;
 }
 
     m_custom_overflow_append = append;
 }
 
+// get size of hint rectangle for a particular dock location
+wxSize wxAuiToolBar::GetHintSize(int dock_direction) const
+{
+    switch (dock_direction)
+    {
+        case wxAUI_DOCK_TOP:
+        case wxAUI_DOCK_BOTTOM:
+            return m_horzHintSize;
+        case wxAUI_DOCK_RIGHT:
+        case wxAUI_DOCK_LEFT:
+            return m_vertHintSize;
+        default:
+            wxCHECK_MSG(false, wxDefaultSize, "invalid dock location value");
+    }
+}
+
+bool wxAuiToolBar::IsPaneValid(const wxAuiPaneInfo& pane) const
+{
+    return IsPaneValid(m_style, pane);
+}
+
+bool wxAuiToolBar::IsPaneValid(long style, const wxAuiPaneInfo& pane)
+{
+    if (style & wxAUI_TB_HORIZONTAL)
+    {
+        if (pane.IsLeftDockable() || pane.IsRightDockable())
+        {
+            return false;
+        }
+    }
+    else if (style & wxAUI_TB_VERTICAL)
+    {
+        if (pane.IsTopDockable() || pane.IsBottomDockable())
+        {
+            return false;
+        }
+    }
+    return true;
+}
+
+bool wxAuiToolBar::IsPaneValid(long style) const
+{
+    wxAuiManager* manager = wxAuiManager::GetManager(const_cast<wxAuiToolBar*>(this));
+    if (manager)
+    {
+        return IsPaneValid(style, manager->GetPane(const_cast<wxAuiToolBar*>(this)));
+    }
+    return true;
+}
+
+void wxAuiToolBar::SetArtFlags() const
+{
+    unsigned int artflags = m_style & ~wxAUI_ORIENTATION_MASK;
+    if (m_orientation == wxVERTICAL)
+    {
+        artflags |= wxAUI_TB_VERTICAL;
+    }
+    m_art->SetFlags(artflags);
+}
 
 size_t wxAuiToolBar::GetToolCount() const
 {
 
 size_t wxAuiToolBar::GetToolCount() const
 {
@@ -1683,7 +1780,7 @@ bool wxAuiToolBar::GetToolFitsByIndex(int tool_idx) const
 
     wxRect rect = m_items[tool_idx].sizer_item->GetRect();
 
 
     wxRect rect = m_items[tool_idx].sizer_item->GetRect();
 
-    if (m_style & wxAUI_TB_VERTICAL)
+    if (m_orientation == wxVERTICAL)
     {
         // take the dropdown size into account
         if (m_overflow_visible)
     {
         // take the dropdown size into account
         if (m_overflow_visible)
@@ -1740,11 +1837,40 @@ bool wxAuiToolBar::Realize()
     if (!dc.IsOk())
         return false;
 
     if (!dc.IsOk())
         return false;
 
-    bool horizontal = true;
-    if (m_style & wxAUI_TB_VERTICAL)
-        horizontal = false;
+    // calculate hint sizes for both horizontal and vertical
+    // in the order that leaves toolbar in correct final state
+    bool retval = false;
+    if (m_orientation == wxHORIZONTAL)
+    {
+        if (RealizeHelper(dc, false))
+        {
+            m_vertHintSize = GetSize();
+            if (RealizeHelper(dc, true))
+            {
+                m_horzHintSize = GetSize();
+                retval = true;
+            }
+        }
+    }
+    else
+    {
+        if (RealizeHelper(dc, true))
+        {
+            m_horzHintSize = GetSize();
+            if (RealizeHelper(dc, false))
+            {
+                m_vertHintSize = GetSize();
+                retval = true;
+            }
+        }
+    }
 
 
+    Refresh(false);
+    return retval;
+}
 
 
+bool wxAuiToolBar::RealizeHelper(wxClientDC& dc, bool horizontal)
+{
     // create the new sizer to add toolbar elements to
     wxBoxSizer* sizer = new wxBoxSizer(horizontal ? wxHORIZONTAL : wxVERTICAL);
 
     // create the new sizer to add toolbar elements to
     wxBoxSizer* sizer = new wxBoxSizer(horizontal ? wxHORIZONTAL : wxVERTICAL);
 
@@ -1981,7 +2107,6 @@ bool wxAuiToolBar::Realize()
         m_sizer->SetDimension(0, 0, cur_size.x, cur_size.y);
     }
 
         m_sizer->SetDimension(0, 0, cur_size.x, cur_size.y);
     }
 
-    Refresh(false);
     return true;
 }
 
     return true;
 }
 
@@ -1996,7 +2121,7 @@ wxRect wxAuiToolBar::GetOverflowRect() const
     wxRect overflow_rect = m_overflow_sizer_item->GetRect();
     int overflow_size = m_art->GetElementSize(wxAUI_TBART_OVERFLOW_SIZE);
 
     wxRect overflow_rect = m_overflow_sizer_item->GetRect();
     int overflow_size = m_art->GetElementSize(wxAUI_TBART_OVERFLOW_SIZE);
 
-    if (m_style & wxAUI_TB_VERTICAL)
+    if (m_orientation == wxVERTICAL)
     {
         overflow_rect.y = cli_rect.height - overflow_size;
         overflow_rect.x = 0;
     {
         overflow_rect.y = cli_rect.height - overflow_size;
         overflow_rect.x = 0;
@@ -2114,11 +2239,6 @@ void wxAuiToolBar::OnSize(wxSizeEvent& WXUNUSED(evt))
     int x, y;
     GetClientSize(&x, &y);
 
     int x, y;
     GetClientSize(&x, &y);
 
-    if (x > y)
-        SetOrientation(wxHORIZONTAL);
-    else
-        SetOrientation(wxVERTICAL);
-
     if (((x >= y) && m_absolute_min_size.x > x) ||
         ((y > x) && m_absolute_min_size.y > y))
     {
     if (((x >= y) && m_absolute_min_size.x > x) ||
         ((y > x) && m_absolute_min_size.y > y))
     {
@@ -2153,6 +2273,11 @@ void wxAuiToolBar::OnSize(wxSizeEvent& WXUNUSED(evt))
 
     Refresh(false);
     Update();
 
     Refresh(false);
     Update();
+
+    // idle events aren't sent while user is resizing frame (why?),
+    // but resizing toolbar here causes havoc,
+    // so force idle handler to run after size handling complete
+    QueueEvent(new wxIdleEvent);
 }
 
 
 }
 
 
@@ -2175,19 +2300,87 @@ void wxAuiToolBar::DoSetSize(int x,
 
 void wxAuiToolBar::OnIdle(wxIdleEvent& evt)
 {
 
 void wxAuiToolBar::OnIdle(wxIdleEvent& evt)
 {
+    // if orientation doesn't match dock, fix it
+    wxAuiManager* manager = wxAuiManager::GetManager(this);
+    if (manager)
+    {
+        wxAuiPaneInfo& pane = manager->GetPane(this);
+        // pane state member is public, so it might have been changed
+        // without going through wxPaneInfo::SetFlag() check
+        bool ok = pane.IsOk();
+        wxCHECK2_MSG(!ok || IsPaneValid(m_style, pane), ok = false,
+                    "window settings and pane settings are incompatible");
+        if (ok)
+        {
+            wxOrientation newOrientation = m_orientation;
+            if (pane.IsDocked())
+            {
+                switch (pane.dock_direction)
+                {
+                    case wxAUI_DOCK_TOP:
+                    case wxAUI_DOCK_BOTTOM:
+                        newOrientation = wxHORIZONTAL;
+                        break;
+                    case wxAUI_DOCK_LEFT:
+                    case wxAUI_DOCK_RIGHT:
+                        newOrientation = wxVERTICAL;
+                        break;
+                    default:
+                        wxFAIL_MSG("invalid dock location value");
+                }
+            }
+            else if (pane.IsResizable() &&
+                    GetOrientation(m_style) == wxBOTH)
+            {
+                // changing orientation in OnSize causes havoc
+                int x, y;
+                GetClientSize(&x, &y);
+
+                if (x > y)
+                {
+                    newOrientation = wxHORIZONTAL;
+                }
+                else
+                {
+                    newOrientation = wxVERTICAL;
+                }
+            }
+            if (newOrientation != m_orientation)
+            {
+                SetOrientation(newOrientation);
+                Realize();
+                if (newOrientation == wxHORIZONTAL)
+                {
+                    pane.best_size = GetHintSize(wxAUI_DOCK_TOP);
+                }
+                else
+                {
+                    pane.best_size = GetHintSize(wxAUI_DOCK_LEFT);
+                }
+                if (pane.IsDocked())
+                {
+                    pane.floating_size = wxDefaultSize;
+                }
+                else
+                {
+                    SetSize(GetParent()->GetClientSize());
+                }
+                manager->Update();
+            }
+        }
+    }
+
     DoIdleUpdate();
     evt.Skip();
 }
 
 void wxAuiToolBar::OnPaint(wxPaintEvent& WXUNUSED(evt))
 {
     DoIdleUpdate();
     evt.Skip();
 }
 
 void wxAuiToolBar::OnPaint(wxPaintEvent& WXUNUSED(evt))
 {
-    wxBufferedPaintDC dc(this);
+    wxAutoBufferedPaintDC dc(this);
     wxRect cli_rect(wxPoint(0,0), GetClientSize());
 
 
     wxRect cli_rect(wxPoint(0,0), GetClientSize());
 
 
-    bool horizontal = true;
-    if (m_style & wxAUI_TB_VERTICAL)
-        horizontal = false;
+    bool horizontal = m_orientation == wxHORIZONTAL;
 
 
     m_art->DrawBackground(dc, this, cli_rect);
 
 
     m_art->DrawBackground(dc, this, cli_rect);
@@ -2440,13 +2633,14 @@ void wxAuiToolBar::OnLeftUp(wxMouseEvent& evt)
                     toggle = true;
 
                 ToggleTool(m_action_item->id, toggle);
                     toggle = true;
 
                 ToggleTool(m_action_item->id, toggle);
-                
+
                 // repaint immediately
                 Refresh(false);
                 Update();
                 // repaint immediately
                 Refresh(false);
                 Update();
-        
+
                 wxCommandEvent e(wxEVT_COMMAND_MENU_SELECTED, m_action_item->id);
                 e.SetEventObject(this);
                 wxCommandEvent e(wxEVT_COMMAND_MENU_SELECTED, m_action_item->id);
                 e.SetEventObject(this);
+                e.SetInt (toggle);
                 GetEventHandler()->ProcessEvent(e);
                 DoIdleUpdate();
             }
                 GetEventHandler()->ProcessEvent(e);
                 DoIdleUpdate();
             }