Make wxRibbonButtonBar buttons more customizable.

See https://github.com/wxWidgets/wxWidgets/pull/762
This commit is contained in:
Vadim Zeitlin
2018-06-04 23:01:50 +02:00
8 changed files with 641 additions and 87 deletions

View File

@@ -81,6 +81,7 @@ All (GUI):
- Improve stock items consistency and aesthetics (dhowland).
- Fix bug with missing items in overflowing AUI toolbar (Maarten Bent).
- Revert to left-aligning wxSpinCtrl contents by default.
- Make wxRibbonButtonBar buttons more customizable (Max Maisel).
wxGTK:

View File

@@ -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,

View File

@@ -139,6 +139,22 @@ public:
virtual void EnableButton(int button_id, bool enable = true);
virtual void ToggleButton(int button_id, bool checked);
virtual void SetButtonIcon(
int button_id,
const wxBitmap& bitmap,
const wxBitmap& bitmap_small = wxNullBitmap,
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 void SetButtonMinSizeClass(int button_id,
wxRibbonButtonBarButtonState min_size_class);
virtual void SetButtonMaxSizeClass(int button_id,
wxRibbonButtonBarButtonState max_size_class);
virtual wxRibbonButtonBarButtonBase *GetActiveItem() const;
virtual wxRibbonButtonBarButtonBase *GetHoveredItem() const;
@@ -171,7 +187,14 @@ protected:
void CommonInit(long style);
void MakeLayouts();
bool TryCollapseLayout(wxRibbonButtonBarLayout* original, size_t first_btn, size_t* last_button);
void TryCollapseLayout(wxRibbonButtonBarLayout* original,
size_t first_btn, size_t* last_button,
wxRibbonButtonBarButtonState target_size);
void MakeBitmaps(wxRibbonButtonBarButtonBase* base,
const wxBitmap& bitmap_large,
const wxBitmap& bitmap_large_disabled,
const wxBitmap& bitmap_small,
const wxBitmap& bitmap_small_disabled);
static wxBitmap MakeResizedBitmap(const wxBitmap& original, wxSize size);
static wxBitmap MakeDisabledBitmap(const wxBitmap& original);
void FetchButtonSizeInfo(wxRibbonButtonBarButtonBase* button,

View File

@@ -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,12 +956,41 @@ 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.
@since 3.1.2
*/
virtual wxCoord GetButtonBarButtonTextWidth(
wxDC& dc, const wxString& label,
wxRibbonButtonKind kind,
wxRibbonButtonBarButtonState size) = 0;
/**
Calculate the size of a minimised ribbon panel.
@@ -1208,6 +1240,7 @@ public:
wxRibbonButtonKind kind,
wxRibbonButtonBarButtonState size,
const wxString& label,
wxCoord text_min_width,
wxSize bitmap_size_large,
wxSize bitmap_size_small,
wxSize* button_size,

View File

@@ -476,6 +476,142 @@ public:
*/
virtual void ToggleButton(int button_id, bool checked);
/**
Changes the bitmap of an existing button.
@param button_id
ID of the button to manipulate.
@param bitmap
Large bitmap of the new button. Must be the same size as all other
large bitmaps used on the button bar.
@param bitmap_small
Small bitmap of the new button. If left as null, then a small
bitmap will be automatically generated. Must be the same size as
all other small bitmaps used on the button bar.
@param bitmap_disabled
Large bitmap of the new button when it is disabled. If left as
null, then a bitmap will be automatically generated from @a bitmap.
@param bitmap_small_disabled
Small bitmap of the new button when it is disabled. If left as
null, then a bitmap will be automatically generated from @a
bitmap_small.
@since 3.1.2
*/
virtual void SetButtonIcon(
int button_id,
const wxBitmap& bitmap,
const wxBitmap& bitmap_small = wxNullBitmap,
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
@since 3.1.2
*/
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()
@since 3.1.2
*/
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()
@since 3.1.2
*/
virtual void SetButtonTextMinWidth(int button_id, const wxString& label);
/**
Sets the minimum size class of a ribbon button.
You have to call Realize() after calling this function to
apply the given minimum size.
@param button_id
ID of the button to manipulate.
@param min_size_class
The minimum size-class of the button. Buttons on a button bar
can have three distinct sizes: wxRIBBON_BUTTONBAR_BUTTON_SMALL,
wxRIBBON_BUTTONBAR_BUTTON_MEDIUM, and wxRIBBON_BUTTONBAR_BUTTON_LARGE.
@since 3.1.2
*/
virtual void SetButtonMinSizeClass(int button_id,
wxRibbonButtonBarButtonState min_size_class);
/**
Sets the maximum size class of a ribbon button.
You have to call Realize() after calling this function to
apply the given maximum size.
@param button_id
ID of the button to manipulate.
@param max_size_class
The maximum size-class of the button. Buttons on a button bar
can have three distinct sizes: wxRIBBON_BUTTONBAR_BUTTON_SMALL,
wxRIBBON_BUTTONBAR_BUTTON_MEDIUM, and wxRIBBON_BUTTONBAR_BUTTON_LARGE.
@since 3.1.2
*/
virtual void SetButtonMaxSizeClass(int button_id,
wxRibbonButtonBarButtonState max_size_class);
/**
Returns the active item of the button bar or NULL if there is none.
The active button is the one being clicked.

View File

@@ -60,6 +60,8 @@ public:
ID_SELECTION_EXPAND_H,
ID_SELECTION_EXPAND_V,
ID_SELECTION_CONTRACT,
ID_BUTTON_XX,
ID_BUTTON_XY,
ID_PRIMARY_COLOUR,
ID_SECONDARY_COLOUR,
ID_DEFAULT_PROVIDER,
@@ -84,7 +86,15 @@ public:
ID_UI_CHANGE_TEXT_UPDATED,
ID_REMOVE_PAGE,
ID_HIDE_PAGES,
ID_SHOW_PAGES
ID_SHOW_PAGES,
ID_PLUS_MINUS,
ID_CHANGE_LABEL,
ID_SMALL_BUTTON_1,
ID_SMALL_BUTTON_2,
ID_SMALL_BUTTON_3,
ID_SMALL_BUTTON_4,
ID_SMALL_BUTTON_5,
ID_SMALL_BUTTON_6
};
void OnEnableUpdateUI(wxUpdateUIEvent& evt);
@@ -134,6 +144,8 @@ public:
void OnRemovePage(wxRibbonButtonBarEvent& evt);
void OnHidePages(wxRibbonButtonBarEvent& evt);
void OnShowPages(wxRibbonButtonBarEvent& evt);
void OnPlusMinus(wxRibbonButtonBarEvent& evt);
void OnChangeLabel(wxRibbonButtonBarEvent& evt);
void OnTogglePanels(wxCommandEvent& evt);
void OnRibbonBarToggled(wxRibbonBarEvent& evt);
void OnRibbonBarHelpClicked(wxRibbonBarEvent& evt);
@@ -169,6 +181,10 @@ protected:
bool m_bChecked;
wxString m_new_text;
wxRibbonButtonBar* m_mutable_button_bar;
bool m_plus_minus_state;
bool m_change_label_state;
wxDECLARE_EVENT_TABLE();
};
@@ -241,6 +257,8 @@ EVT_RIBBONPANEL_EXTBUTTON_ACTIVATED(wxID_ANY, MyFrame::OnExtButton)
EVT_RIBBONBUTTONBAR_CLICKED(ID_REMOVE_PAGE, MyFrame::OnRemovePage)
EVT_RIBBONBUTTONBAR_CLICKED(ID_HIDE_PAGES, MyFrame::OnHidePages)
EVT_RIBBONBUTTONBAR_CLICKED(ID_SHOW_PAGES, MyFrame::OnShowPages)
EVT_RIBBONBUTTONBAR_CLICKED(ID_PLUS_MINUS, MyFrame::OnPlusMinus)
EVT_RIBBONBUTTONBAR_CLICKED(ID_CHANGE_LABEL, MyFrame::OnChangeLabel)
EVT_RIBBONBAR_TOGGLED(wxID_ANY, MyFrame::OnRibbonBarToggled)
EVT_RIBBONBAR_HELP_CLICK(wxID_ANY, MyFrame::OnRibbonBarHelpClicked)
EVT_SIZE(MyFrame::OnSizeEvent)
@@ -352,13 +370,22 @@ MyFrame::MyFrame()
sizer_panelcombo->SetMinSize(wxSize(150, -1));
sizer_panelcombo2->SetMinSize(wxSize(150, -1));
//not using wxWrapSizer(wxHORIZONTAL) as it reports an incorrect min height
wxSizer* sizer_panelsizer = new wxBoxSizer(wxVERTICAL);
sizer_panelsizer->AddStretchSpacer(1);
sizer_panelsizer->Add(sizer_panelcombo, 0, wxALL|wxEXPAND, 2);
sizer_panelsizer->Add(sizer_panelcombo2, 0, wxALL|wxEXPAND, 2);
sizer_panelsizer->AddStretchSpacer(1);
sizer_panel->SetSizer(sizer_panelsizer);
wxRibbonButtonBar* bar = new wxRibbonButtonBar(sizer_panel, wxID_ANY);
bar->AddButton(ID_BUTTON_XX, wxT("xx"), ribbon_xpm);
bar->AddButton(ID_BUTTON_XY, wxT("xy"), ribbon_xpm);
// This prevents ribbon buttons in panels with sizer from collapsing.
bar->SetButtonMinSizeClass(ID_BUTTON_XX, wxRIBBON_BUTTONBAR_BUTTON_LARGE);
bar->SetButtonMinSizeClass(ID_BUTTON_XY, wxRIBBON_BUTTONBAR_BUTTON_LARGE);
wxSizer* sizer_panelsizer_h = new wxBoxSizer(wxHORIZONTAL);
wxSizer* sizer_panelsizer_v = new wxBoxSizer(wxVERTICAL);
sizer_panelsizer_v->AddStretchSpacer(1);
sizer_panelsizer_v->Add(sizer_panelcombo, 0, wxALL|wxEXPAND, 2);
sizer_panelsizer_v->Add(sizer_panelcombo2, 0, wxALL|wxEXPAND, 2);
sizer_panelsizer_v->AddStretchSpacer(1);
sizer_panelsizer_h->Add(bar, 0, wxEXPAND);
sizer_panelsizer_h->Add(sizer_panelsizer_v, 0);
sizer_panel->SetSizer(sizer_panelsizer_h);
wxFont label_font(8, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_LIGHT);
m_bitmap_creation_dc.SetFont(label_font);
@@ -418,10 +445,57 @@ MyFrame::MyFrame()
bar->AddButton(ID_REMOVE_PAGE, wxT("Remove"), wxArtProvider::GetBitmap(wxART_DELETE, wxART_OTHER, wxSize(24, 24)));
bar->AddButton(ID_HIDE_PAGES, wxT("Hide Pages"), ribbon_xpm);
bar->AddButton(ID_SHOW_PAGES, wxT("Show Pages"), ribbon_xpm);
panel = new wxRibbonPanel(page, wxID_ANY, wxT("Button bar manipulation"), ribbon_xpm);
m_mutable_button_bar = new wxRibbonButtonBar(panel, wxID_ANY);
m_mutable_button_bar->AddButton(ID_PLUS_MINUS, wxT("+/-"),
wxArtProvider::GetBitmap(wxART_PLUS, wxART_OTHER, wxSize(24, 24)));
m_plus_minus_state = false;
m_mutable_button_bar->AddButton(ID_CHANGE_LABEL, wxT("short"), ribbon_xpm);
m_mutable_button_bar->SetButtonTextMinWidth(ID_CHANGE_LABEL, wxT("some long text"));
m_change_label_state = false;
panel = new wxRibbonPanel(page, wxID_ANY, wxT("Always medium buttons"), ribbon_xpm);
bar = new wxRibbonButtonBar(panel, wxID_ANY);
bar->AddButton(ID_SMALL_BUTTON_1, wxT("Button 1"), ribbon_xpm);
bar->SetButtonMaxSizeClass(ID_SMALL_BUTTON_1, wxRIBBON_BUTTONBAR_BUTTON_MEDIUM);
bar->AddButton(ID_SMALL_BUTTON_2, wxT("Button 2"), ribbon_xpm);
bar->SetButtonMaxSizeClass(ID_SMALL_BUTTON_2, wxRIBBON_BUTTONBAR_BUTTON_MEDIUM);
bar->AddButton(ID_SMALL_BUTTON_3, wxT("Button 3"), ribbon_xpm);
bar->AddButton(ID_SMALL_BUTTON_4, wxT("Button 4"), ribbon_xpm);
bar->AddButton(ID_SMALL_BUTTON_5, wxT("Button 5"), ribbon_xpm);
bar->SetButtonMaxSizeClass(ID_SMALL_BUTTON_5, wxRIBBON_BUTTONBAR_BUTTON_MEDIUM);
bar->AddButton(ID_SMALL_BUTTON_6, wxT("Button 6"), ribbon_xpm);
bar->SetButtonMaxSizeClass(ID_SMALL_BUTTON_6, wxRIBBON_BUTTONBAR_BUTTON_MEDIUM);
}
new wxRibbonPage(m_ribbon, wxID_ANY, wxT("Highlight Page"), empty_xpm);
m_ribbon->AddPageHighlight(m_ribbon->GetPageCount()-1);
{
wxRibbonPage* page = new wxRibbonPage(m_ribbon, wxID_ANY, wxT("Advanced"), empty_xpm);
wxRibbonPanel* panel = new wxRibbonPanel(page, wxID_ANY, wxT("Button bar manipulation"), ribbon_xpm);
m_mutable_button_bar = new wxRibbonButtonBar(panel, wxID_ANY);
m_mutable_button_bar->AddButton(ID_PLUS_MINUS, wxT("+/-"),
wxArtProvider::GetBitmap(wxART_PLUS, wxART_OTHER, wxSize(24, 24)));
m_plus_minus_state = false;
m_mutable_button_bar->AddButton(ID_CHANGE_LABEL, wxT("short"), ribbon_xpm);
m_mutable_button_bar->SetButtonTextMinWidth(ID_CHANGE_LABEL, wxT("some long text"));
m_change_label_state = false;
panel = new wxRibbonPanel(page, wxID_ANY, wxT("Always medium buttons"), ribbon_xpm);
wxRibbonButtonBar* bar = new wxRibbonButtonBar(panel, wxID_ANY);
bar->AddButton(ID_SMALL_BUTTON_1, wxT("Button 1"), ribbon_xpm);
bar->SetButtonMaxSizeClass(ID_SMALL_BUTTON_1, wxRIBBON_BUTTONBAR_BUTTON_MEDIUM);
bar->AddButton(ID_SMALL_BUTTON_2, wxT("Button 2"), ribbon_xpm);
bar->SetButtonMaxSizeClass(ID_SMALL_BUTTON_2, wxRIBBON_BUTTONBAR_BUTTON_MEDIUM);
bar->AddButton(ID_SMALL_BUTTON_3, wxT("Button 3"), ribbon_xpm);
bar->AddButton(ID_SMALL_BUTTON_4, wxT("Button 4"), ribbon_xpm);
bar->AddButton(ID_SMALL_BUTTON_5, wxT("Button 5"), ribbon_xpm);
bar->SetButtonMaxSizeClass(ID_SMALL_BUTTON_5, wxRIBBON_BUTTONBAR_BUTTON_MEDIUM);
bar->AddButton(ID_SMALL_BUTTON_6, wxT("Button 6"), ribbon_xpm);
bar->SetButtonMaxSizeClass(ID_SMALL_BUTTON_6, wxRIBBON_BUTTONBAR_BUTTON_MEDIUM);
}
m_ribbon->Realize();
m_logwindow = new wxTextCtrl(this, wxID_ANY, wxEmptyString,
@@ -1038,6 +1112,36 @@ void MyFrame::OnShowPages(wxRibbonButtonBarEvent& WXUNUSED(evt))
m_ribbon->Realize();
}
void MyFrame::OnPlusMinus(wxRibbonButtonBarEvent& WXUNUSED(evt))
{
if(m_plus_minus_state)
{
m_mutable_button_bar->SetButtonIcon(ID_PLUS_MINUS,
wxArtProvider::GetBitmap(wxART_PLUS, wxART_OTHER, wxSize(24, 24)));
m_plus_minus_state = false;
}
else
{
m_mutable_button_bar->SetButtonIcon(ID_PLUS_MINUS,
wxArtProvider::GetBitmap(wxART_MINUS, wxART_OTHER, wxSize(24, 24)));
m_plus_minus_state = true;
}
}
void MyFrame::OnChangeLabel(wxRibbonButtonBarEvent& WXUNUSED(evt))
{
if(m_change_label_state)
{
m_mutable_button_bar->SetButtonText(ID_CHANGE_LABEL, wxT("short"));
m_change_label_state = false;
}
else
{
m_mutable_button_bar->SetButtonText(ID_CHANGE_LABEL, wxT("some long text"));
m_change_label_state = true;
}
}
void MyFrame::OnRibbonBarToggled(wxRibbonBarEvent& WXUNUSED(evt))
{
AddText(wxString::Format("Ribbon bar %s.",

View File

@@ -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,

View File

@@ -75,10 +75,16 @@ public:
wxRibbonButtonBarButtonState GetLargestSize()
{
if(sizes[wxRIBBON_BUTTONBAR_BUTTON_LARGE].is_supported)
if(sizes[wxRIBBON_BUTTONBAR_BUTTON_LARGE].is_supported
&& max_size_class >= wxRIBBON_BUTTONBAR_BUTTON_LARGE)
{
return wxRIBBON_BUTTONBAR_BUTTON_LARGE;
if(sizes[wxRIBBON_BUTTONBAR_BUTTON_MEDIUM].is_supported)
}
if(sizes[wxRIBBON_BUTTONBAR_BUTTON_MEDIUM].is_supported
&& max_size_class >= wxRIBBON_BUTTONBAR_BUTTON_MEDIUM)
{
return wxRIBBON_BUTTONBAR_BUTTON_MEDIUM;
}
wxASSERT(sizes[wxRIBBON_BUTTONBAR_BUTTON_SMALL].is_supported);
return wxRIBBON_BUTTONBAR_BUTTON_SMALL;
}
@@ -91,14 +97,16 @@ public:
switch(*size)
{
case wxRIBBON_BUTTONBAR_BUTTON_LARGE:
if(sizes[wxRIBBON_BUTTONBAR_BUTTON_MEDIUM].is_supported)
if(sizes[wxRIBBON_BUTTONBAR_BUTTON_MEDIUM].is_supported
&& min_size_class <= wxRIBBON_BUTTONBAR_BUTTON_MEDIUM)
{
*size = wxRIBBON_BUTTONBAR_BUTTON_MEDIUM;
break;
}
wxFALLTHROUGH;
case wxRIBBON_BUTTONBAR_BUTTON_MEDIUM:
if(sizes[wxRIBBON_BUTTONBAR_BUTTON_SMALL].is_supported)
if(sizes[wxRIBBON_BUTTONBAR_BUTTON_SMALL].is_supported
&& min_size_class <= wxRIBBON_BUTTONBAR_BUTTON_SMALL)
{
*size = wxRIBBON_BUTTONBAR_BUTTON_SMALL;
break;
@@ -118,7 +126,10 @@ public:
wxBitmap bitmap_large_disabled;
wxBitmap bitmap_small;
wxBitmap bitmap_small_disabled;
wxCoord text_min_width[3];
wxRibbonButtonBarButtonSizeInfo sizes[3];
wxRibbonButtonBarButtonState min_size_class;
wxRibbonButtonBarButtonState max_size_class;
wxClientDataContainer client_data;
int id;
wxRibbonButtonKind kind;
@@ -323,41 +334,16 @@ wxRibbonButtonBarButtonBase* wxRibbonButtonBar::InsertButton(
wxRibbonButtonBarButtonBase* base = new wxRibbonButtonBarButtonBase;
base->id = button_id;
base->label = label;
base->bitmap_large = bitmap;
if(!base->bitmap_large.IsOk())
{
base->bitmap_large = MakeResizedBitmap(base->bitmap_small,
m_bitmap_size_large);
}
else if(base->bitmap_large.GetScaledSize() != m_bitmap_size_large)
{
base->bitmap_large = MakeResizedBitmap(base->bitmap_large,
m_bitmap_size_large);
}
base->bitmap_small = bitmap_small;
if(!base->bitmap_small.IsOk())
{
base->bitmap_small = MakeResizedBitmap(base->bitmap_large,
m_bitmap_size_small);
}
else if(base->bitmap_small.GetScaledSize() != m_bitmap_size_small)
{
base->bitmap_small = MakeResizedBitmap(base->bitmap_small,
m_bitmap_size_small);
}
base->bitmap_large_disabled = bitmap_disabled;
if(!base->bitmap_large_disabled.IsOk())
{
base->bitmap_large_disabled = MakeDisabledBitmap(base->bitmap_large);
}
base->bitmap_small_disabled = bitmap_small_disabled;
if(!base->bitmap_small_disabled.IsOk())
{
base->bitmap_small_disabled = MakeDisabledBitmap(base->bitmap_small);
}
MakeBitmaps(base, bitmap, bitmap_disabled,
bitmap_small, bitmap_small_disabled);
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;
base->min_size_class = wxRIBBON_BUTTONBAR_BUTTON_SMALL;
base->max_size_class = wxRIBBON_BUTTONBAR_BUTTON_LARGE;
wxClientDC temp_dc(this);
FetchButtonSizeInfo(base, wxRIBBON_BUTTONBAR_BUTTON_SMALL, temp_dc);
@@ -457,9 +443,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;
@@ -595,6 +581,102 @@ void wxRibbonButtonBar::ToggleButton(int button_id, bool checked)
}
}
void wxRibbonButtonBar::SetButtonIcon(
int button_id,
const wxBitmap& bitmap,
const wxBitmap& bitmap_small,
const wxBitmap& bitmap_disabled,
const wxBitmap& bitmap_small_disabled)
{
wxRibbonButtonBarButtonBase* base = GetItemById(button_id);
if(base == NULL)
return;
MakeBitmaps(base, bitmap, bitmap_small,
bitmap_disabled, bitmap_small_disabled);
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::SetButtonMinSizeClass(int button_id,
wxRibbonButtonBarButtonState min_size_class)
{
wxRibbonButtonBarButtonBase* base = GetItemById(button_id);
if(base == NULL)
return;
if(base->max_size_class < min_size_class)
{
wxFAIL_MSG("Button minimum size is larger than maximum size");
return;
}
base->min_size_class = min_size_class;
m_layouts_valid = false;
}
void wxRibbonButtonBar::SetButtonMaxSizeClass(int button_id,
wxRibbonButtonBarButtonState max_size_class)
{
wxRibbonButtonBarButtonBase* base = GetItemById(button_id);
if(base == NULL)
return;
if(base->min_size_class > max_size_class)
{
wxFAIL_MSG("Button maximum size is smaller than minimum size");
return;
}
base->max_size_class = max_size_class;
m_layouts_valid = false;
}
void wxRibbonButtonBar::SetArtProvider(wxRibbonArtProvider* art)
{
if(art == m_art)
@@ -865,8 +947,27 @@ void wxRibbonButtonBar::MakeLayouts()
}
size_t btn_count = m_buttons.Count();
size_t btn_i;
// Determine available height:
// 1 large button or, if not found, 3 medium or small buttons
int available_height = 0;
bool large_button_found = false;
for(btn_i = 0; btn_i < btn_count; ++btn_i)
{
// Best layout : all buttons large, stacking horizontally
wxRibbonButtonBarButtonBase* button = m_buttons.Item(btn_i);
wxRibbonButtonBarButtonState size_class = button->GetLargestSize();
available_height = wxMax(available_height,
button->sizes[size_class].size.GetHeight());
if(size_class == wxRIBBON_BUTTONBAR_BUTTON_LARGE)
large_button_found = true;
}
if(!large_button_found)
available_height *= 3;
int stacked_width = 0;
{
// Best layout : all buttons large, stacking horizontally,
// small buttons small, stacked vertically
wxRibbonButtonBarLayout* layout = new wxRibbonButtonBarLayout;
wxPoint cursor(0, 0);
layout->overall_size.SetHeight(0);
@@ -877,54 +978,111 @@ void wxRibbonButtonBar::MakeLayouts()
instance.position = cursor;
instance.size = button->GetLargestSize();
wxSize& size = button->sizes[instance.size].size;
cursor.x += size.GetWidth();
layout->overall_size.SetHeight(wxMax(layout->overall_size.GetHeight(),
size.GetHeight()));
if(instance.size < wxRIBBON_BUTTONBAR_BUTTON_LARGE)
{
stacked_width = wxMax(stacked_width, size.GetWidth());
if(cursor.y + size.GetHeight() >= available_height)
{
cursor.y = 0;
cursor.x += stacked_width;
stacked_width = 0;
}
else
{
cursor.y += size.GetHeight();
}
}
else
{
if(cursor.y != 0)
{
cursor.y = 0;
cursor.x += stacked_width;
stacked_width = 0;
instance.position = cursor;
}
cursor.x += size.GetWidth();
}
layout->buttons.Add(instance);
}
layout->overall_size.SetWidth(cursor.x);
layout->overall_size.SetHeight(available_height);
layout->overall_size.SetWidth(cursor.x + stacked_width);
m_layouts.Add(layout);
}
if(btn_count >= 2)
{
// Collapse the rightmost buttons and stack them vertically
size_t iLast = btn_count - 1;
while(TryCollapseLayout(m_layouts.Last(), iLast, &iLast) && iLast > 0)
// if they are not already small. If rightmost buttons can't
// be collapsed because "min_size_class" is set, try it again
// starting from second rightmost button and so on.
size_t iLast = btn_count;
while(iLast-- > 0)
{
--iLast;
TryCollapseLayout(m_layouts.Last(), iLast, &iLast,
wxRIBBON_BUTTONBAR_BUTTON_MEDIUM);
}
// TODO: small buttons are not implemented yet in
// art_msw.cpp:2581 and will be invisible
/*iLast = btn_count;
while(iLast-- > 0)
{
TryCollapseLayout(m_layouts.Last(), iLast, &iLast,
wxRIBBON_BUTTONBAR_BUTTON_SMALL);
}*/
}
}
bool wxRibbonButtonBar::TryCollapseLayout(wxRibbonButtonBarLayout* original,
size_t first_btn, size_t* last_button)
void wxRibbonButtonBar::TryCollapseLayout(wxRibbonButtonBarLayout* original,
size_t first_btn, size_t* last_button,
wxRibbonButtonBarButtonState target_size)
{
size_t btn_count = m_buttons.Count();
size_t btn_i;
int used_height = 0;
int used_width = 0;
int original_column_width = 0;
int available_width = 0;
int available_height = 0;
int available_height = original->overall_size.GetHeight();
// Search for button range from right which should be
// collapsed into a column of small buttons.
for(btn_i = first_btn + 1; btn_i > 0; /* decrement is inside loop */)
{
--btn_i;
wxRibbonButtonBarButtonBase* button = m_buttons.Item(btn_i);
wxRibbonButtonBarButtonState large_size_class = button->GetLargestSize();
wxSize large_size = button->sizes[large_size_class].size;
int t_available_height = wxMax(available_height,
large_size.GetHeight());
int t_available_width = available_width + large_size.GetWidth();
wxRibbonButtonBarButtonState small_size_class = large_size_class;
if(!button->GetSmallerSize(&small_size_class))
int t_available_width = available_width;
original_column_width = wxMax(original_column_width,
large_size.GetWidth());
// Top button in column: add column width to available width
if(original->buttons.Item(btn_i).position.y == 0)
{
return false;
t_available_width += original_column_width;
original_column_width = 0;
}
wxRibbonButtonBarButtonState small_size_class = large_size_class;
if(large_size_class > target_size)
{
if(!button->GetSmallerSize(&small_size_class,
small_size_class - target_size))
{
// Large button that cannot shrink: stop search
++btn_i;
break;
}
}
wxSize small_size = button->sizes[small_size_class].size;
int t_used_height = used_height + small_size.GetHeight();
int t_used_width = wxMax(used_width, small_size.GetWidth());
if(t_used_height > t_available_height)
// Height is full: stop search
if(t_used_height > available_height)
{
++btn_i;
break;
@@ -934,13 +1092,13 @@ bool wxRibbonButtonBar::TryCollapseLayout(wxRibbonButtonBarLayout* original,
used_height = t_used_height;
used_width = t_used_width;
available_width = t_available_width;
available_height = t_available_height;
}
}
// Layout got wider than before or no suitable button found: abort
if(btn_i >= first_btn || used_width >= available_width)
{
return false;
return;
}
if(last_button != NULL)
{
@@ -950,27 +1108,23 @@ bool wxRibbonButtonBar::TryCollapseLayout(wxRibbonButtonBarLayout* original,
wxRibbonButtonBarLayout* layout = new wxRibbonButtonBarLayout;
WX_APPEND_ARRAY(layout->buttons, original->buttons);
wxPoint cursor(layout->buttons.Item(btn_i).position);
bool preserve_height = false;
if(btn_i == 0)
{
// If height isn't preserved (i.e. it is reduced), then the minimum
// size for the button bar will decrease, preventing the original
// layout from being used (in some cases).
// It may be a good idea to always preserve the height, but for now
// it is only done when the first button is involved in a collapse.
preserve_height = true;
}
cursor.y = 0;
for(; btn_i <= first_btn; ++btn_i)
{
wxRibbonButtonBarButtonInstance& instance = layout->buttons.Item(btn_i);
instance.base->GetSmallerSize(&instance.size);
if(instance.size > target_size)
{
instance.base->GetSmallerSize(&instance.size,
instance.size - target_size);
}
instance.position = cursor;
cursor.y += instance.base->sizes[instance.size].size.GetHeight();
}
int x_adjust = available_width - used_width;
// Adjust x coords of buttons right of shrinked column
for(; btn_i < btn_count; ++btn_i)
{
wxRibbonButtonBarButtonInstance& instance = layout->buttons.Item(btn_i);
@@ -985,16 +1139,59 @@ bool wxRibbonButtonBar::TryCollapseLayout(wxRibbonButtonBarLayout* original,
{
delete layout;
wxFAIL_MSG("Layout collapse resulted in increased size");
return false;
return;
}
if(preserve_height)
{
layout->overall_size.SetHeight(original->overall_size.GetHeight());
}
// If height isn't preserved (i.e. it is reduced), then the minimum
// size for the button bar will decrease, preventing the original
// layout from being used (in some cases).
// If neither "min_size_class" nor "max_size_class" is set, this is
// only required when the first button is involved in a collapse but
// if small, medium and large buttons as well as min/max size classes
// are involved this is always a good idea.
layout->overall_size.SetHeight(original->overall_size.GetHeight());
m_layouts.Add(layout);
return true;
}
void wxRibbonButtonBar::MakeBitmaps(wxRibbonButtonBarButtonBase* base,
const wxBitmap& bitmap_large,
const wxBitmap& bitmap_large_disabled,
const wxBitmap& bitmap_small,
const wxBitmap& bitmap_small_disabled)
{
base->bitmap_large = bitmap_large;
if(!base->bitmap_large.IsOk())
{
base->bitmap_large = MakeResizedBitmap(base->bitmap_small,
m_bitmap_size_large);
}
else if(base->bitmap_large.GetScaledSize() != m_bitmap_size_large)
{
base->bitmap_large = MakeResizedBitmap(base->bitmap_large,
m_bitmap_size_large);
}
base->bitmap_small = bitmap_small;
if(!base->bitmap_small.IsOk())
{
base->bitmap_small = MakeResizedBitmap(base->bitmap_large,
m_bitmap_size_small);
}
else if(base->bitmap_small.GetScaledSize() != m_bitmap_size_small)
{
base->bitmap_small = MakeResizedBitmap(base->bitmap_small,
m_bitmap_size_small);
}
base->bitmap_large_disabled = bitmap_large_disabled;
if(!base->bitmap_large_disabled.IsOk())
{
base->bitmap_large_disabled = MakeDisabledBitmap(base->bitmap_large);
}
base->bitmap_small_disabled = bitmap_small_disabled;
if(!base->bitmap_small_disabled.IsOk())
{
base->bitmap_small_disabled = MakeDisabledBitmap(base->bitmap_small);
}
}
void wxRibbonButtonBar::OnMouseMove(wxMouseEvent& evt)