From 7aed0e547bff49b16e2754f465d8106115ed9b2f Mon Sep 17 00:00:00 2001 From: Max Maisel Date: Wed, 14 Mar 2018 16:55:58 +0100 Subject: [PATCH] wxRibbonButtonBarButton: Implemented mutable lables and minimum label width Added new function SetButtonText() which modifies labels of existing ribbon button bar buttons. The new function SetButtonTextMinWidth() is used to specify the label width in advance so that lables can be changed without recalculating the layout. wxRibbonArtProvider is modified to support these operation. --- include/wx/ribbon/art.h | 12 ++++++ include/wx/ribbon/buttonbar.h | 5 +++ interface/wx/ribbon/art.h | 31 ++++++++++++++++ interface/wx/ribbon/buttonbar.h | 65 +++++++++++++++++++++++++++++++++ src/ribbon/art_msw.cpp | 52 +++++++++++++++++++++++++- src/ribbon/buttonbar.cpp | 61 +++++++++++++++++++++++++++++-- 6 files changed, 221 insertions(+), 5 deletions(-) diff --git a/include/wx/ribbon/art.h b/include/wx/ribbon/art.h index 5dc3ebf2d6..ad3b3c6532 100644 --- a/include/wx/ribbon/art.h +++ b/include/wx/ribbon/art.h @@ -381,12 +381,18 @@ public: wxRibbonButtonKind kind, wxRibbonButtonBarButtonState size, const wxString& label, + wxCoord text_min_width, wxSize bitmap_size_large, wxSize bitmap_size_small, wxSize* button_size, wxRect* normal_region, wxRect* dropdown_region) = 0; + virtual wxCoord GetButtonBarButtonTextWidth( + wxDC& dc, const wxString& label, + wxRibbonButtonKind kind, + wxRibbonButtonBarButtonState size) = 0; + virtual wxSize GetMinimisedPanelMinimumSize( wxDC& dc, const wxRibbonPanel* wnd, @@ -584,12 +590,18 @@ public: wxRibbonButtonKind kind, wxRibbonButtonBarButtonState size, const wxString& label, + wxCoord text_min_width, wxSize bitmap_size_large, wxSize bitmap_size_small, wxSize* button_size, wxRect* normal_region, wxRect* dropdown_region) wxOVERRIDE; + wxCoord GetButtonBarButtonTextWidth( + wxDC& dc, const wxString& label, + wxRibbonButtonKind kind, + wxRibbonButtonBarButtonState size) wxOVERRIDE; + wxSize GetMinimisedPanelMinimumSize( wxDC& dc, const wxRibbonPanel* wnd, diff --git a/include/wx/ribbon/buttonbar.h b/include/wx/ribbon/buttonbar.h index ed21e55d09..8bc27d74ef 100644 --- a/include/wx/ribbon/buttonbar.h +++ b/include/wx/ribbon/buttonbar.h @@ -146,6 +146,11 @@ public: const wxBitmap& bitmap_disabled = wxNullBitmap, const wxBitmap& bitmap_small_disabled = wxNullBitmap); + virtual void SetButtonText(int button_id, const wxString& label); + virtual void SetButtonTextMinWidth(int button_id, + int min_width_medium, int min_width_large); + virtual void SetButtonTextMinWidth(int button_id, const wxString& label); + virtual wxRibbonButtonBarButtonBase *GetActiveItem() const; virtual wxRibbonButtonBarButtonBase *GetHoveredItem() const; diff --git a/interface/wx/ribbon/art.h b/interface/wx/ribbon/art.h index e22d092fea..b233eb403b 100644 --- a/interface/wx/ribbon/art.h +++ b/interface/wx/ribbon/art.h @@ -934,6 +934,9 @@ public: be returned. @param label The label of the button. + @param text_min_width + The minimum width of the button label. + Set this to 0 if it is not used. @param bitmap_size_large The size of all "large" bitmaps on the button bar. @param bitmap_size_small @@ -953,11 +956,38 @@ public: wxRibbonButtonKind kind, wxRibbonButtonBarButtonState size, const wxString& label, + wxCoord text_min_width, wxSize bitmap_size_large, wxSize bitmap_size_small, wxSize* button_size, wxRect* normal_region, wxRect* dropdown_region) = 0; + + /** + Gets the width of the string if it is used as + a wxRibbonButtonBar button label. + + @param dc + A device context to use when one is required for size calculations. + @param label + The string whose width shall be calculated. + @param kind + The kind of button. + @param size + The size-class to calculate the size for. Buttons on a button bar + can have three distinct sizes: wxRIBBON_BUTTONBAR_BUTTON_SMALL, + wxRIBBON_BUTTONBAR_BUTTON_MEDIUM, and wxRIBBON_BUTTONBAR_BUTTON_LARGE. + If the requested size-class is not applicable, then NULL should + be returned. + + @return Width of the given label text in pixel. + + @note This function only works with single-line strings. + */ + virtual wxCoord GetButtonBarButtonTextWidth( + wxDC& dc, const wxString& label, + wxRibbonButtonKind kind, + wxRibbonButtonBarButtonState size) = 0; /** Calculate the size of a minimised ribbon panel. @@ -1208,6 +1238,7 @@ public: wxRibbonButtonKind kind, wxRibbonButtonBarButtonState size, const wxString& label, + wxCoord text_min_width, wxSize bitmap_size_large, wxSize bitmap_size_small, wxSize* button_size, diff --git a/interface/wx/ribbon/buttonbar.h b/interface/wx/ribbon/buttonbar.h index b01a9af5f5..a0e95396af 100644 --- a/interface/wx/ribbon/buttonbar.h +++ b/interface/wx/ribbon/buttonbar.h @@ -503,6 +503,71 @@ public: const wxBitmap& bitmap_disabled = wxNullBitmap, const wxBitmap& bitmap_small_disabled = wxNullBitmap); + /** + Changes the label text of an existing button. + + @param button_id + ID of the button to manipulate. + @param label + New label of the button. + + @remarks + If text size has changed, Realize() must be called + on the top level wxRibbonBar object to recalculate panel sizes. + Use SetButtonTextMinWidth() to avoid calling Realize() + after every change. + + @see SetButtonTextMinWidth + */ + virtual void SetButtonText(int button_id, const wxString& label); + + /** + Sets the minimum width of the button label, to indicate to + the wxRibbonArtProvider layout mechanism that this is the + minimum required size. + + You have to call Realize() after calling this function to + apply the given minimum width. + + @param button_id + ID of the button to manipulate. + @param min_width_medium + Requested minimum width of the button text in pixel + if the button is medium size. + @param min_width_medium + Requested minimum width of the button text in pixel + if the button is large size. + + @remarks + This function is used together with SetButtonText() to change + button labels on the fly without modifying the button bar layout. + + @see SetButtonText() + */ + virtual void SetButtonTextMinWidth(int button_id, + int min_width_medium, int min_width_large); + + /** + Sets the minimum width of the button label, to indicate to + the wxRibbonArtProvider layout mechanism that this is the + minimum required size. + + You have to call Realize() after calling this function to + apply the given minimum width. + + @param button_id + ID of the button to manipulate. + @param label + The minimum width is set to the width of this label. + + @remarks + This function is used together with SetButtonText() to change + button labels on the fly without modifying the button bar layout. + + @see SetButtonText() + */ + virtual void SetButtonTextMinWidth(int button_id, const wxString& label); + /** Returns the active item of the button bar or NULL if there is none. The active button is the one being clicked. diff --git a/src/ribbon/art_msw.cpp b/src/ribbon/art_msw.cpp index 2baddeef67..f2a85811cd 100644 --- a/src/ribbon/art_msw.cpp +++ b/src/ribbon/art_msw.cpp @@ -3036,6 +3036,7 @@ bool wxRibbonMSWArtProvider::GetButtonBarButtonSize( wxRibbonButtonKind kind, wxRibbonButtonBarButtonState size, const wxString& label, + wxCoord text_min_width, wxSize bitmap_size_large, wxSize bitmap_size_small, wxSize* button_size, @@ -3074,9 +3075,11 @@ bool wxRibbonMSWArtProvider::GetButtonBarButtonSize( // Small bitmap, with label to the right { GetButtonBarButtonSize(dc, wnd, kind, wxRIBBON_BUTTONBAR_BUTTON_SMALL, - label, bitmap_size_large, bitmap_size_small, button_size, - normal_region, dropdown_region); + label, text_min_width, bitmap_size_large, bitmap_size_small, + button_size, normal_region, dropdown_region); int text_size = dc.GetTextExtent(label).GetWidth(); + if(text_size < text_min_width) + text_size = text_min_width; button_size->SetWidth(button_size->GetWidth() + text_size); switch(kind) { @@ -3101,6 +3104,8 @@ bool wxRibbonMSWArtProvider::GetButtonBarButtonSize( wxCoord label_height; wxCoord best_width; dc.GetTextExtent(label, &best_width, &label_height); + if(best_width < text_min_width) + best_width = text_min_width; int last_line_extra_width = 0; if(kind != wxRIBBON_BUTTON_NORMAL && kind != wxRIBBON_BUTTON_TOGGLE) { @@ -3114,6 +3119,8 @@ bool wxRibbonMSWArtProvider::GetButtonBarButtonSize( int width = wxMax( dc.GetTextExtent(label.Left(i)).GetWidth(), dc.GetTextExtent(label.Mid(i + 1)).GetWidth() + last_line_extra_width); + if(best_width < text_min_width) + best_width = text_min_width; if(width < best_width) { best_width = width; @@ -3149,6 +3156,47 @@ bool wxRibbonMSWArtProvider::GetButtonBarButtonSize( return true; } +wxCoord wxRibbonMSWArtProvider::GetButtonBarButtonTextWidth( + wxDC& dc, const wxString& label, + wxRibbonButtonKind kind, + wxRibbonButtonBarButtonState size) +{ + wxCoord best_width = 0; + dc.SetFont(m_button_bar_label_font); + + if((size & wxRIBBON_BUTTONBAR_BUTTON_SIZE_MASK) + == wxRIBBON_BUTTONBAR_BUTTON_LARGE) + { + best_width = dc.GetTextExtent(label).GetWidth(); + int last_line_extra_width = 0; + if(kind != wxRIBBON_BUTTON_NORMAL && kind != wxRIBBON_BUTTON_TOGGLE) + { + last_line_extra_width += 8; + } + size_t i; + for(i = 0; i < label.Len(); ++i) + { + if(wxRibbonCanLabelBreakAtPosition(label, i)) + { + int width = wxMax( + dc.GetTextExtent(label.Left(i)).GetWidth(), + dc.GetTextExtent(label.Mid(i + 1)).GetWidth() + last_line_extra_width); + if(width < best_width) + { + best_width = width; + } + } + } + } + else if((size & wxRIBBON_BUTTONBAR_BUTTON_SIZE_MASK) + == wxRIBBON_BUTTONBAR_BUTTON_MEDIUM) + { + best_width = dc.GetTextExtent(label).GetWidth(); + } + + return best_width; +} + wxSize wxRibbonMSWArtProvider::GetMinimisedPanelMinimumSize( wxDC& dc, const wxRibbonPanel* wnd, diff --git a/src/ribbon/buttonbar.cpp b/src/ribbon/buttonbar.cpp index 8e32d63cd2..5b18727d07 100644 --- a/src/ribbon/buttonbar.cpp +++ b/src/ribbon/buttonbar.cpp @@ -118,6 +118,7 @@ public: wxBitmap bitmap_large_disabled; wxBitmap bitmap_small; wxBitmap bitmap_small_disabled; + wxCoord text_min_width[3]; wxRibbonButtonBarButtonSizeInfo sizes[3]; wxClientDataContainer client_data; int id; @@ -328,6 +329,9 @@ wxRibbonButtonBarButtonBase* wxRibbonButtonBar::InsertButton( base->kind = kind; base->help_string = help_string; base->state = 0; + base->text_min_width[0] = 0; + base->text_min_width[1] = 0; + base->text_min_width[2] = 0; wxClientDC temp_dc(this); FetchButtonSizeInfo(base, wxRIBBON_BUTTONBAR_BUTTON_SMALL, temp_dc); @@ -427,9 +431,9 @@ void wxRibbonButtonBar::FetchButtonSizeInfo(wxRibbonButtonBarButtonBase* button, if(m_art) { info.is_supported = m_art->GetButtonBarButtonSize(dc, this, - button->kind, size, button->label, m_bitmap_size_large, - m_bitmap_size_small, &info.size, &info.normal_region, - &info.dropdown_region); + button->kind, size, button->label, button->text_min_width[size], + m_bitmap_size_large, m_bitmap_size_small, &info.size, + &info.normal_region, &info.dropdown_region); } else info.is_supported = false; @@ -580,6 +584,57 @@ void wxRibbonButtonBar::SetButtonIcon( Refresh(); } +void wxRibbonButtonBar::SetButtonText(int button_id, const wxString& label) +{ + wxRibbonButtonBarButtonBase* base = GetItemById(button_id); + if(base == NULL) + return; + base->label = label; + + wxClientDC temp_dc(this); + FetchButtonSizeInfo(base, wxRIBBON_BUTTONBAR_BUTTON_SMALL, temp_dc); + FetchButtonSizeInfo(base, wxRIBBON_BUTTONBAR_BUTTON_MEDIUM, temp_dc); + FetchButtonSizeInfo(base, wxRIBBON_BUTTONBAR_BUTTON_LARGE, temp_dc); + m_layouts_valid = false; + Refresh(); +} + +void wxRibbonButtonBar::SetButtonTextMinWidth(int button_id, + int min_width_medium, int min_width_large) +{ + wxRibbonButtonBarButtonBase* base = GetItemById(button_id); + if(base == NULL) + return; + base->text_min_width[0] = 0; + base->text_min_width[1] = min_width_medium; + base->text_min_width[2] = min_width_large; + wxClientDC temp_dc(this); + FetchButtonSizeInfo(base, wxRIBBON_BUTTONBAR_BUTTON_SMALL, temp_dc); + FetchButtonSizeInfo(base, wxRIBBON_BUTTONBAR_BUTTON_MEDIUM, temp_dc); + FetchButtonSizeInfo(base, wxRIBBON_BUTTONBAR_BUTTON_LARGE, temp_dc); + m_layouts_valid = false; +} + +void wxRibbonButtonBar::SetButtonTextMinWidth( + int button_id, const wxString& label) +{ + wxRibbonButtonBarButtonBase* base = GetItemById(button_id); + if(base == NULL) + return; + wxClientDC temp_dc(this); + base->text_min_width[wxRIBBON_BUTTONBAR_BUTTON_MEDIUM] = + m_art->GetButtonBarButtonTextWidth( + temp_dc, label, base->kind, wxRIBBON_BUTTONBAR_BUTTON_MEDIUM); + base->text_min_width[wxRIBBON_BUTTONBAR_BUTTON_LARGE] = + m_art->GetButtonBarButtonTextWidth( + temp_dc, label, base->kind, wxRIBBON_BUTTONBAR_BUTTON_LARGE); + + FetchButtonSizeInfo(base, wxRIBBON_BUTTONBAR_BUTTON_SMALL, temp_dc); + FetchButtonSizeInfo(base, wxRIBBON_BUTTONBAR_BUTTON_MEDIUM, temp_dc); + FetchButtonSizeInfo(base, wxRIBBON_BUTTONBAR_BUTTON_LARGE, temp_dc); + m_layouts_valid = false; +} + void wxRibbonButtonBar::SetArtProvider(wxRibbonArtProvider* art) { if(art == m_art)