X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/3c3ead1d1513a5eb79091a604f4e42b45d1bdf5d..e9d7a889634ee5cbe90bcc639c6197a29169be3a:/src/ribbon/toolbar.cpp diff --git a/src/ribbon/toolbar.cpp b/src/ribbon/toolbar.cpp index 945204f269..791da940ea 100644 --- a/src/ribbon/toolbar.cpp +++ b/src/ribbon/toolbar.cpp @@ -15,10 +15,9 @@ #pragma hdrstop #endif -#include "wx/ribbon/toolbar.h" - #if wxUSE_RIBBON +#include "wx/ribbon/toolbar.h" #include "wx/ribbon/art.h" #include "wx/ribbon/bar.h" #include "wx/dcbuffer.h" @@ -45,7 +44,7 @@ public: long state; }; -WX_DEFINE_ARRAY(wxRibbonToolBarToolBase*, wxArrayRibbonToolBarToolBase); +WX_DEFINE_ARRAY_PTR(wxRibbonToolBarToolBase*, wxArrayRibbonToolBarToolBase); class wxRibbonToolBarToolGroup { @@ -162,6 +161,15 @@ wxRibbonToolBarToolBase* wxRibbonToolBar::AddHybridTool( wxRIBBON_BUTTON_HYBRID, NULL); } +wxRibbonToolBarToolBase* wxRibbonToolBar::AddToggleTool( + int tool_id, + const wxBitmap& bitmap, + const wxString& help_string) +{ + return AddTool(tool_id, bitmap, wxNullBitmap, help_string, + wxRIBBON_BUTTON_TOGGLE, NULL); +} + wxRibbonToolBarToolBase* wxRibbonToolBar::AddTool( int tool_id, const wxBitmap& bitmap, @@ -169,9 +177,74 @@ wxRibbonToolBarToolBase* wxRibbonToolBar::AddTool( const wxString& help_string, wxRibbonButtonKind kind, wxObject* client_data) +{ + return InsertTool(GetToolCount(), tool_id, bitmap, bitmap_disabled, + help_string, kind, client_data); +} + +wxRibbonToolBarToolBase* wxRibbonToolBar::AddSeparator() +{ + if(m_groups.Last()->tools.IsEmpty()) + return NULL; + + AppendGroup(); + return &m_groups.Last()->dummy_tool; +} + + +wxRibbonToolBarToolBase* wxRibbonToolBar::InsertTool( + size_t pos, + int tool_id, + const wxBitmap& bitmap, + const wxString& help_string, + wxRibbonButtonKind kind) +{ + return InsertTool(pos, tool_id, bitmap, wxNullBitmap, help_string, kind, + NULL); +} + +wxRibbonToolBarToolBase* wxRibbonToolBar::InsertDropdownTool( + size_t pos, + int tool_id, + const wxBitmap& bitmap, + const wxString& help_string) +{ + return InsertTool(pos, tool_id, bitmap, wxNullBitmap, help_string, + wxRIBBON_BUTTON_DROPDOWN, NULL); +} + +wxRibbonToolBarToolBase* wxRibbonToolBar::InsertHybridTool( + size_t pos, + int tool_id, + const wxBitmap& bitmap, + const wxString& help_string) +{ + return InsertTool(pos, tool_id, bitmap, wxNullBitmap, help_string, + wxRIBBON_BUTTON_HYBRID, NULL); +} + +wxRibbonToolBarToolBase* wxRibbonToolBar::InsertToggleTool( + size_t pos, + int tool_id, + const wxBitmap& bitmap, + const wxString& help_string) +{ + return InsertTool(pos, tool_id, bitmap, wxNullBitmap, help_string, + wxRIBBON_BUTTON_TOGGLE, NULL); +} + +wxRibbonToolBarToolBase* wxRibbonToolBar::InsertTool( + size_t pos, + int tool_id, + const wxBitmap& bitmap, + const wxBitmap& bitmap_disabled, + const wxString& help_string, + wxRibbonButtonKind kind, + wxObject* client_data) { wxASSERT(bitmap.IsOk()); + // Create the wxRibbonToolBarToolBase with parameters wxRibbonToolBarToolBase* tool = new wxRibbonToolBarToolBase; tool->id = tool_id; tool->bitmap = bitmap; @@ -189,19 +262,257 @@ wxRibbonToolBarToolBase* wxRibbonToolBar::AddTool( tool->size = wxSize(0, 0); tool->state = 0; - m_groups.Last()->tools.Add(tool); - return tool; + // Find the position where insert tool + size_t group_count = m_groups.GetCount(); + size_t g; + for(g = 0; g < group_count; ++g) + { + wxRibbonToolBarToolGroup* group = m_groups.Item(g); + size_t tool_count = group->tools.GetCount(); + if(pos <= tool_count) + { + group->tools.Insert(tool, pos); + return tool; + } + pos -= tool_count + 1; + } + wxFAIL_MSG("Tool position out of toolbar bounds."); + return NULL; } -wxRibbonToolBarToolBase* wxRibbonToolBar::AddSeparator() +wxRibbonToolBarToolBase* wxRibbonToolBar::InsertSeparator(size_t pos) { + size_t group_count = m_groups.GetCount(); + size_t g; + for(g = 0; g < group_count; ++g) + { + if(pos==0) // Prepend group + return &InsertGroup(g)->dummy_tool; + if(pos==group_count) // Append group + return &InsertGroup(g+1)->dummy_tool; + + wxRibbonToolBarToolGroup* group = m_groups.Item(g); + size_t tool_count = group->tools.GetCount(); + if(pos < tool_count) + { + wxRibbonToolBarToolGroup* new_group = InsertGroup(g+1); + + for(size_t t = pos; t < tool_count; t++) + new_group->tools.Add(group->tools[t]); + group->tools.RemoveAt(pos, tool_count-pos); + + return &group->dummy_tool; + } + pos -= tool_count + 1; + } + // Add an empty group at the end of the bar. if(m_groups.Last()->tools.IsEmpty()) return NULL; - AppendGroup(); return &m_groups.Last()->dummy_tool; } +wxRibbonToolBarToolGroup* wxRibbonToolBar::InsertGroup(size_t pos) +{ + wxRibbonToolBarToolGroup* group = new wxRibbonToolBarToolGroup; + group->position = wxPoint(0, 0); + group->size = wxSize(0, 0); + m_groups.Insert(group, pos); + return group; +} + +void wxRibbonToolBar::ClearTools() +{ + size_t count = m_groups.GetCount(); + size_t i, t; + for(i = 0; i < count; ++i) + { + wxRibbonToolBarToolGroup* group = m_groups.Item(i); + size_t tool_count = group->tools.GetCount(); + for(t = 0; t < tool_count; ++t) + { + wxRibbonToolBarToolBase* tool = group->tools.Item(t); + delete tool; + } + delete group; + } + m_groups.Clear(); +} + +bool wxRibbonToolBar::DeleteTool(int tool_id) +{ + size_t group_count = m_groups.GetCount(); + size_t g, t; + for(g = 0; g < group_count; ++g) + { + wxRibbonToolBarToolGroup* group = m_groups.Item(g); + size_t tool_count = group->tools.GetCount(); + for(t = 0; t < tool_count; ++t) + { + wxRibbonToolBarToolBase* tool = group->tools.Item(t); + if(tool->id == tool_id) + { + group->tools.RemoveAt(t); + delete tool; + return true; + } + } + } + return false; +} + +bool wxRibbonToolBar::DeleteToolByPos(size_t pos) +{ + size_t group_count = m_groups.GetCount(); + size_t g, t; + for(g = 0; g < group_count; ++g) + { + wxRibbonToolBarToolGroup* group = m_groups.Item(g); + size_t tool_count = group->tools.GetCount(); + if(postools.Item(pos); + group->tools.RemoveAt(pos); + delete tool; + return true; + } + else if(pos==tool_count) + { + // Remove separator + if(g < group_count - 1) + { + wxRibbonToolBarToolGroup* next_group = m_groups.Item(g+1); + for(t = 0; t < next_group->tools.GetCount(); ++t) + group->tools.Add(next_group->tools[t]); + m_groups.RemoveAt(g+1); + delete next_group; + } + return true; + } + } + return false; +} + +wxRibbonToolBarToolBase* wxRibbonToolBar::FindById(int tool_id)const +{ + size_t group_count = m_groups.GetCount(); + size_t g, t; + for(g = 0; g < group_count; ++g) + { + wxRibbonToolBarToolGroup* group = m_groups.Item(g); + size_t tool_count = group->tools.GetCount(); + for(t = 0; t < tool_count; ++t) + { + wxRibbonToolBarToolBase* tool = group->tools.Item(t); + if(tool->id == tool_id) + { + return tool; + } + } + } + return NULL; +} + +wxRibbonToolBarToolBase* wxRibbonToolBar::GetToolByPos(size_t pos)const +{ + size_t group_count = m_groups.GetCount(); + size_t g; + for(g = 0; g < group_count; ++g) + { + wxRibbonToolBarToolGroup* group = m_groups.Item(g); + size_t tool_count = group->tools.GetCount(); + if(postools[pos]; + } + else if(pos==tool_count) + { + return NULL; + } + } + return NULL; +} + +size_t wxRibbonToolBar::GetToolCount() const +{ + size_t count = 0; + for(size_t g = 0; g < m_groups.GetCount(); ++g) + { + wxRibbonToolBarToolGroup* group = m_groups.Item(g); + count += group->tools.GetCount(); + } + // There is a splitter in front of every group except for the first + // If only one group, no separator. + if(m_groups.GetCount()>1) + count += m_groups.GetCount() - 1; + return count; +} + +int wxRibbonToolBar::GetToolId(const wxRibbonToolBarToolBase* tool)const +{ + wxCHECK_MSG(tool != NULL , wxNOT_FOUND, "The tool pointer must not be NULL"); + return tool->id; +} + +wxObject* wxRibbonToolBar::GetToolClientData(int tool_id)const +{ + wxRibbonToolBarToolBase* tool = FindById(tool_id); + wxCHECK_MSG(tool != NULL , NULL, "Invalid tool id"); + return tool->client_data; +} + +bool wxRibbonToolBar::GetToolEnabled(int tool_id)const +{ + wxRibbonToolBarToolBase* tool = FindById(tool_id); + wxCHECK_MSG(tool != NULL , false, "Invalid tool id"); + return (tool->state & wxRIBBON_TOOLBAR_TOOL_DISABLED) == 0; +} + +wxString wxRibbonToolBar::GetToolHelpString(int tool_id)const +{ + wxRibbonToolBarToolBase* tool = FindById(tool_id); + wxCHECK_MSG(tool != NULL , wxEmptyString, "Invalid tool id"); + return tool->help_string; +} + +wxRibbonButtonKind wxRibbonToolBar::GetToolKind(int tool_id)const +{ + wxRibbonToolBarToolBase* tool = FindById(tool_id); + wxCHECK_MSG(tool != NULL , wxRIBBON_BUTTON_NORMAL, "Invalid tool id"); + return tool->kind; +} + +int wxRibbonToolBar::GetToolPos(int tool_id)const +{ + size_t group_count = m_groups.GetCount(); + size_t g, t; + int pos = 0; + for(g = 0; g < group_count; ++g) + { + wxRibbonToolBarToolGroup* group = m_groups.Item(g); + size_t tool_count = group->tools.GetCount(); + for(t = 0; t < tool_count; ++t) + { + wxRibbonToolBarToolBase* tool = group->tools.Item(t); + if(tool->id == tool_id) + { + return pos; + } + ++pos; + } + ++pos; // Increment pos for group separator. + } + return wxNOT_FOUND; +} + +bool wxRibbonToolBar::GetToolState(int tool_id)const +{ + wxRibbonToolBarToolBase* tool = FindById(tool_id); + wxCHECK_MSG(tool != NULL , false, "Invalid tool id"); + return (tool->state & wxRIBBON_TOOLBAR_TOOL_TOGGLED) != 0; +} + wxBitmap wxRibbonToolBar::MakeDisabledBitmap(const wxBitmap& original) { wxImage img(original.ConvertToImage()); @@ -221,6 +532,78 @@ bool wxRibbonToolBar::IsSizingContinuous() const return false; } +void wxRibbonToolBar::SetToolClientData(int tool_id, wxObject* clientData) +{ + wxRibbonToolBarToolBase* tool = FindById(tool_id); + wxCHECK_RET(tool != NULL , "Invalid tool id"); + tool->client_data = clientData; +} + +void wxRibbonToolBar::SetToolDisabledBitmap(int tool_id, const wxBitmap &bitmap) +{ + wxRibbonToolBarToolBase* tool = FindById(tool_id); + wxCHECK_RET(tool != NULL , "Invalid tool id"); + tool->bitmap_disabled = bitmap; +} + +void wxRibbonToolBar::SetToolHelpString(int tool_id, const wxString& helpString) +{ + wxRibbonToolBarToolBase* tool = FindById(tool_id); + wxCHECK_RET(tool != NULL , "Invalid tool id"); + tool->help_string = helpString; +} + +void wxRibbonToolBar::SetToolNormalBitmap(int tool_id, const wxBitmap &bitmap) +{ + wxRibbonToolBarToolBase* tool = FindById(tool_id); + wxCHECK_RET(tool != NULL , "Invalid tool id"); + tool->bitmap = bitmap; +} + +void wxRibbonToolBar::EnableTool(int tool_id, bool enable) +{ + wxRibbonToolBarToolBase* tool = FindById(tool_id); + wxCHECK_RET(tool != NULL , "Invalid tool id"); + if(enable) + { + if(tool->state & wxRIBBON_TOOLBAR_TOOL_DISABLED) + { + tool->state &= ~wxRIBBON_TOOLBAR_TOOL_DISABLED; + Refresh(); + } + } + else + { + if((tool->state & wxRIBBON_TOOLBAR_TOOL_DISABLED)==0) + { + tool->state |= wxRIBBON_TOOLBAR_TOOL_DISABLED; + Refresh(); + } + } +} + +void wxRibbonToolBar::ToggleTool(int tool_id, bool checked) +{ + wxRibbonToolBarToolBase* tool = FindById(tool_id); + wxCHECK_RET(tool != NULL , "Invalid tool id"); + if(checked) + { + if((tool->state & wxRIBBON_TOOLBAR_TOOL_TOGGLED) == 0) + { + tool->state |= wxRIBBON_TOOLBAR_TOOL_TOGGLED; + Refresh(); + } + } + else + { + if(tool->state & wxRIBBON_TOOLBAR_TOOL_TOGGLED) + { + tool->state &= ~wxRIBBON_TOOLBAR_TOOL_TOGGLED; + Refresh(); + } + } +} + static int GetSizeInOrientation(wxSize size, wxOrientation orientation) { switch(orientation) @@ -364,7 +747,6 @@ bool wxRibbonToolBar::Realize() tool->size = m_art->GetToolSize(temp_dc, this, tool->bitmap.GetSize(), tool->kind, t == 0, t == (tool_count - 1), &tool->dropdown); - tool->state = tool->state & ~wxRIBBON_TOOLBAR_TOOL_DISABLED; if(t == 0) tool->state |= wxRIBBON_TOOLBAR_TOOL_FIRST; if(t == tool_count - 1) @@ -399,7 +781,21 @@ bool wxRibbonToolBar::Realize() wxSize* row_sizes = new wxSize[m_nrows_max]; wxOrientation major_axis = m_art->GetFlags() & wxRIBBON_BAR_FLOW_VERTICAL ? wxVERTICAL : wxHORIZONTAL; + SetMinSize(wxSize(0, 0)); + wxSize minSize(INT_MAX, INT_MAX); + + // See if we're sizing flexibly (i.e. wrapping), and set min size differently + bool sizingFlexibly = false; + wxRibbonPanel* panel = wxDynamicCast(GetParent(), wxRibbonPanel); + if (panel && (panel->GetFlags() & wxRIBBON_PANEL_FLEXIBLE)) + sizingFlexibly = true; + + // Without this, there will be redundant horizontal space because SetMinSize will + // use the smallest possible height (and therefore largest width). + if (sizingFlexibly) + major_axis = wxHORIZONTAL; + for(nrows = m_nrows_min; nrows <= m_nrows_max; ++nrows) { for(r = 0; r < nrows; ++r) @@ -427,13 +823,31 @@ bool wxRibbonToolBar::Realize() size.IncBy(0, row_sizes[r].y); } m_sizes[nrows - m_nrows_min] = size; + if(GetSizeInOrientation(size, major_axis) < smallest_area) { - SetMinSize(size); smallest_area = GetSizeInOrientation(size, major_axis); + SetMinSize(size); + } + + if (sizingFlexibly) + { + if (size.x < minSize.x) + minSize.x = size.x; + if (size.y < minSize.y) + minSize.y = size.y; } } + if (sizingFlexibly) + { + // Give it the min size in either direction regardless of row, + // so that we're able to vary the size of the panel according to + // the space the toolbar takes up. + SetMinSize(minSize); + } + delete[] row_sizes; + // Position the groups wxSizeEvent dummy_event(GetSize()); OnSize(dummy_event); @@ -451,6 +865,20 @@ void wxRibbonToolBar::OnSize(wxSizeEvent& evt) int row_count = m_nrows_max; wxOrientation major_axis = m_art->GetFlags() & wxRIBBON_BAR_FLOW_VERTICAL ? wxVERTICAL : wxHORIZONTAL; + + // See if we're sizing flexibly, and set min size differently + bool sizingFlexibly = false; + wxRibbonPanel* panel = wxDynamicCast(GetParent(), wxRibbonPanel); + if (panel && (panel->GetFlags() & wxRIBBON_PANEL_FLEXIBLE)) + sizingFlexibly = true; + + // Without this, there will be redundant horizontal space because SetMinSize will + // use the smallest possible height (and therefore largest width). + if (sizingFlexibly) + major_axis = wxHORIZONTAL; + + wxSize bestSize = m_sizes[0]; + if(m_nrows_max != m_nrows_min) { int area = 0; @@ -461,6 +889,7 @@ void wxRibbonToolBar::OnSize(wxSizeEvent& evt) { area = GetSizeInOrientation(m_sizes[i], major_axis); row_count = m_nrows_min + i; + bestSize = m_sizes[i]; } } } @@ -512,6 +941,39 @@ void wxRibbonToolBar::OnSize(wxSizeEvent& evt) delete[] row_sizes; } +// Finds the best width and height given the parents' width and height +wxSize wxRibbonToolBar::GetBestSizeForParentSize(const wxSize& parentSize) const +{ + if (!m_sizes) + return GetMinSize(); + + // Choose row count with largest possible area + wxSize size = parentSize; + wxOrientation major_axis = m_art->GetFlags() & wxRIBBON_BAR_FLOW_VERTICAL ? + wxVERTICAL : wxHORIZONTAL; + + // A toolbar should maximize its width whether vertical or horizontal, so + // force the major axis to be horizontal. Without this, there will be + // redundant horizontal space. + major_axis = wxHORIZONTAL; + wxSize bestSize = m_sizes[0]; + + if(m_nrows_max != m_nrows_min) + { + int area = 0; + for(int i = 0; i <= m_nrows_max - m_nrows_min; ++i) + { + if(m_sizes[i].x <= size.x && m_sizes[i].y <= size.y && + GetSizeInOrientation(m_sizes[i], major_axis) > area) + { + area = GetSizeInOrientation(m_sizes[i], major_axis); + bestSize = m_sizes[i]; + } + } + } + return bestSize; +} + wxSize wxRibbonToolBar::DoGetBestSize() const { return GetMinSize(); @@ -544,8 +1006,12 @@ void wxRibbonToolBar::OnPaint(wxPaintEvent& WXUNUSED(evt)) { wxRibbonToolBarToolBase* tool = group->tools.Item(t); wxRect rect(group->position + tool->position, tool->size); - m_art->DrawTool(dc, this, rect, tool->bitmap, tool->kind, - tool->state); + if(tool->state & wxRIBBON_TOOLBAR_TOOL_DISABLED) + m_art->DrawTool(dc, this, rect, tool->bitmap_disabled, + tool->kind, tool->state); + else + m_art->DrawTool(dc, this, rect, tool->bitmap, tool->kind, + tool->state); } } } @@ -581,6 +1047,22 @@ void wxRibbonToolBar::OnMouseMove(wxMouseEvent& evt) } } +#if wxUSE_TOOLTIPS + if(new_hover) + { + SetToolTip(new_hover->help_string); + } + else if(GetToolTip()) + { + UnsetToolTip(); + } +#endif + + if(new_hover && new_hover->state & wxRIBBON_TOOLBAR_TOOL_DISABLED) + { + new_hover = NULL; // A disabled tool can not be hilighted + } + if(new_hover != m_hover_tool) { if(m_hover_tool) @@ -596,7 +1078,7 @@ void wxRibbonToolBar::OnMouseMove(wxMouseEvent& evt) what = wxRIBBON_TOOLBAR_TOOL_DROPDOWN_HOVERED; new_hover->state |= what; - + if(new_hover == m_active_tool) { new_hover->state &= ~wxRIBBON_TOOLBAR_TOOL_ACTIVE_MASK; @@ -657,13 +1139,26 @@ void wxRibbonToolBar::OnMouseUp(wxMouseEvent& WXUNUSED(evt)) if(m_active_tool->state & wxRIBBON_TOOLBAR_TOOL_DROPDOWN_ACTIVE) evt_type = wxEVT_COMMAND_RIBBONTOOL_DROPDOWN_CLICKED; wxRibbonToolBarEvent notification(evt_type, m_active_tool->id); + if(m_active_tool->kind == wxRIBBON_BUTTON_TOGGLE) + { + m_active_tool->state ^= + wxRIBBON_BUTTONBAR_BUTTON_TOGGLED; + notification.SetInt(m_active_tool->state & + wxRIBBON_BUTTONBAR_BUTTON_TOGGLED); + } notification.SetEventObject(this); notification.SetBar(this); ProcessEvent(notification); } - m_active_tool->state &= ~wxRIBBON_TOOLBAR_TOOL_ACTIVE_MASK; - m_active_tool = NULL; - Refresh(false); + + // Notice that m_active_tool could have been reset by the event handler + // above so we need to test it again. + if (m_active_tool) + { + m_active_tool->state &= ~wxRIBBON_TOOLBAR_TOOL_ACTIVE_MASK; + m_active_tool = NULL; + Refresh(false); + } } } @@ -675,6 +1170,39 @@ void wxRibbonToolBar::OnMouseEnter(wxMouseEvent& evt) } } +void wxRibbonToolBar::UpdateWindowUI(long flags) +{ + wxWindowBase::UpdateWindowUI(flags); + + // don't waste time updating state of tools in a hidden toolbar + if ( !IsShown() ) + return; + + size_t group_count = m_groups.GetCount(); + size_t g, t; + for(g = 0; g < group_count; ++g) + { + wxRibbonToolBarToolGroup* group = m_groups.Item(g); + size_t tool_count = group->tools.GetCount(); + for(t = 0; t < tool_count; ++t) + { + wxRibbonToolBarToolBase* tool = group->tools.Item(t); + int id = tool->id; + + wxUpdateUIEvent event(id); + event.SetEventObject(this); + + if ( ProcessWindowEvent(event) ) + { + if ( event.GetSetEnabled() ) + EnableTool(id, event.GetEnabled()); + if ( event.GetSetChecked() ) + ToggleTool(id, event.GetChecked()); + } + } + } +} + bool wxRibbonToolBarEvent::PopupMenu(wxMenu* menu) { wxPoint pos = wxDefaultPosition;