From b08a0cc99eff1a1a8fd5ed7176c83a03b02a1fc8 Mon Sep 17 00:00:00 2001 From: Blake-Madden <66873089+Blake-Madden@users.noreply.github.com> Date: Sun, 16 Aug 2026 09:13:31 -0400 Subject: [PATCH 01/10] Null out button pointers after clearing button collection --- src/ribbon/buttonbar.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ribbon/buttonbar.cpp b/src/ribbon/buttonbar.cpp index 5a01aebc41..4e725f83f7 100644 --- a/src/ribbon/buttonbar.cpp +++ b/src/ribbon/buttonbar.cpp @@ -563,6 +563,8 @@ void wxRibbonButtonBar::ClearButtons() delete button; } m_buttons.Clear(); + m_hovered_button = nullptr; + m_active_button = nullptr; Realize(); } From a339b9fb02119c97d6a3739b849d8aee870002d1 Mon Sep 17 00:00:00 2001 From: Blake-Madden <66873089+Blake-Madden@users.noreply.github.com> Date: Sun, 16 Aug 2026 09:21:44 -0400 Subject: [PATCH 02/10] Clamp current layout index after rebuilding buttonbar layout --- src/ribbon/buttonbar.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/ribbon/buttonbar.cpp b/src/ribbon/buttonbar.cpp index 4e725f83f7..fc471d7c23 100644 --- a/src/ribbon/buttonbar.cpp +++ b/src/ribbon/buttonbar.cpp @@ -1175,6 +1175,11 @@ void wxRibbonButtonBar::MakeLayouts() wxRIBBON_BUTTONBAR_BUTTON_SMALL); } } + + // Removing buttons can result in fewer layouts from before, + // so clamp if necessary. + if ( m_current_layout >= (int)m_layouts.GetCount() ) + m_current_layout = (int)m_layouts.GetCount() - 1; } void wxRibbonButtonBar::TryCollapseLayout(wxRibbonButtonBarLayout* original, From 39e2be888daa0cbef865a02d0c5cc189a272f053 Mon Sep 17 00:00:00 2001 From: Blake-Madden <66873089+Blake-Madden@users.noreply.github.com> Date: Sun, 16 Aug 2026 09:26:09 -0400 Subject: [PATCH 03/10] Use page height, not width, when scrolling vertical ribbon pages --- src/ribbon/page.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ribbon/page.cpp b/src/ribbon/page.cpp index 62adae3eef..983d8d8767 100644 --- a/src/ribbon/page.cpp +++ b/src/ribbon/page.cpp @@ -391,7 +391,7 @@ bool wxRibbonPage::ScrollSections(int sections) gap = m_art->GetMetric(wxRIBBON_ART_PANEL_Y_SEPARATION_SIZE); if (scrollForward) { - scrollpos = width - m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_BOTTOM_SIZE); + scrollpos = height - m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_BOTTOM_SIZE); } else { From 08b63a474fc86bd9f516dc3bd455e0af320cdd61 Mon Sep 17 00:00:00 2001 From: Blake-Madden <66873089+Blake-Madden@users.noreply.github.com> Date: Sun, 16 Aug 2026 09:31:49 -0400 Subject: [PATCH 04/10] Fix stale hovered page index in buttonbar after page removal --- src/ribbon/bar.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/ribbon/bar.cpp b/src/ribbon/bar.cpp index c55437fb10..49a67c645c 100644 --- a/src/ribbon/bar.cpp +++ b/src/ribbon/bar.cpp @@ -389,6 +389,15 @@ void wxRibbonBar::DeletePage(size_t n) { m_current_page--; } + + if ( m_current_hovered_page == static_cast(n) ) + { + m_current_hovered_page = wxNOT_FOUND; + } + else if ( m_current_hovered_page > static_cast(n) ) + { + m_current_hovered_page--; + } } } @@ -410,6 +419,7 @@ void wxRibbonBar::ClearPages() m_pages.Empty(); Realize(); m_current_page = wxNOT_FOUND; + m_current_hovered_page = wxNOT_FOUND; Refresh(); } From e93a4906b5e2aca3cf02730752f046a1d0e18c68 Mon Sep 17 00:00:00 2001 From: Blake-Madden <66873089+Blake-Madden@users.noreply.github.com> Date: Sun, 16 Aug 2026 09:42:45 -0400 Subject: [PATCH 05/10] Make art provider buttons in ribbon sample toggle buttons Will show which art provider is in use. --- samples/ribbon/ribbondemo.cpp | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/samples/ribbon/ribbondemo.cpp b/samples/ribbon/ribbondemo.cpp index ba16885fcc..5ee2888de5 100644 --- a/samples/ribbon/ribbondemo.cpp +++ b/samples/ribbon/ribbondemo.cpp @@ -163,10 +163,11 @@ protected: wxColour GetGalleryColour(wxRibbonGallery *gallery, wxRibbonGalleryItem* item, wxString* name); void ResetGalleryArtProviders(); - void SetArtProvider(wxRibbonArtProvider* prov); + void SetArtProvider(int button_id, wxRibbonArtProvider* prov); void SetBarStyle(long style); wxRibbonBar* m_ribbon; + wxRibbonButtonBar* m_provider_bar; wxRibbonGallery* m_primary_gallery; wxRibbonGallery* m_secondary_gallery; wxTextCtrl* m_logwindow; @@ -604,15 +605,17 @@ MyFrame::MyFrame() wxRibbonPanel *provider_panel = new wxRibbonPanel(scheme, wxID_ANY, "Art", wxBitmapBundle(), wxDefaultPosition, wxDefaultSize, wxRIBBON_PANEL_NO_AUTO_MINIMISE); - wxRibbonButtonBar *provider_bar = new wxRibbonButtonBar(provider_panel, wxID_ANY); - provider_bar->AddButton(ID_DEFAULT_PROVIDER, "Default Provider", + m_provider_bar = new wxRibbonButtonBar(provider_panel, wxID_ANY); + m_provider_bar->AddToggleButton(ID_DEFAULT_PROVIDER, "Default Provider", wxArtProvider::GetBitmap(wxART_QUESTION, wxART_OTHER, wxSize(32, 32))); - provider_bar->AddButton(ID_AUI_PROVIDER, "AUI Provider", + m_provider_bar->AddToggleButton(ID_AUI_PROVIDER, "AUI Provider", MakeSvgBundle(aui_style_svg, wxSize(32, 32))); - provider_bar->AddButton(ID_MSW_PROVIDER, "MSW Provider", + m_provider_bar->AddToggleButton(ID_MSW_PROVIDER, "MSW Provider", MakeSvgBundle(msw_style_svg, wxSize(32, 32))); - provider_bar->AddButton(ID_MSW_FLAT_PROVIDER, "MSW Flat Provider", + m_provider_bar->AddToggleButton(ID_MSW_FLAT_PROVIDER, "MSW Flat Provider", MakeSvgBundle(msw_flat_style_svg, wxSize(32, 32))); + + m_provider_bar->ToggleButton(ID_DEFAULT_PROVIDER, true); wxRibbonPanel *primary_panel = new wxRibbonPanel(scheme, wxID_ANY, "Primary Colour", MakeSvgBundle(colours_svg, wxSize(16, 16))); m_primary_gallery = PopulateColoursPanel(primary_panel, @@ -1275,28 +1278,28 @@ void MyFrame::OnColourGalleryButton(wxCommandEvent& evt) void MyFrame::OnDefaultProvider(wxRibbonButtonBarEvent& WXUNUSED(evt)) { m_ribbon->DismissExpandedPanel(); - SetArtProvider(new wxRibbonDefaultArtProvider); + SetArtProvider(ID_DEFAULT_PROVIDER, new wxRibbonDefaultArtProvider); } void MyFrame::OnAUIProvider(wxRibbonButtonBarEvent& WXUNUSED(evt)) { m_ribbon->DismissExpandedPanel(); - SetArtProvider(new wxRibbonAUIArtProvider); + SetArtProvider(ID_AUI_PROVIDER, new wxRibbonAUIArtProvider); } void MyFrame::OnMSWProvider(wxRibbonButtonBarEvent& WXUNUSED(evt)) { m_ribbon->DismissExpandedPanel(); - SetArtProvider(new wxRibbonMSWArtProvider); + SetArtProvider(ID_MSW_PROVIDER, new wxRibbonMSWArtProvider); } void MyFrame::OnMSWFlatProvider(wxRibbonButtonBarEvent& WXUNUSED(evt)) { m_ribbon->DismissExpandedPanel(); - SetArtProvider(new wxRibbonMSWFlatArtProvider); + SetArtProvider(ID_MSW_FLAT_PROVIDER, new wxRibbonMSWFlatArtProvider); } -void MyFrame::SetArtProvider(wxRibbonArtProvider *prov) +void MyFrame::SetArtProvider(int button_id, wxRibbonArtProvider *prov) { m_ribbon->Freeze(); m_ribbon->SetArtProvider(prov); @@ -1308,6 +1311,15 @@ void MyFrame::SetArtProvider(wxRibbonArtProvider *prov) PopulateColoursPanel(m_secondary_gallery->GetParent(), m_default_secondary, ID_SECONDARY_COLOUR); + m_provider_bar->ToggleButton(ID_DEFAULT_PROVIDER, + button_id == ID_DEFAULT_PROVIDER); + m_provider_bar->ToggleButton(ID_AUI_PROVIDER, + button_id == ID_AUI_PROVIDER); + m_provider_bar->ToggleButton(ID_MSW_PROVIDER, + button_id == ID_MSW_PROVIDER); + m_provider_bar->ToggleButton(ID_MSW_FLAT_PROVIDER, + button_id == ID_MSW_FLAT_PROVIDER); + m_ribbon->Realize(); m_ribbon->Thaw(); GetSizer()->Layout(); From d5eccea262312845203dfb2a74b0e076b7302a75 Mon Sep 17 00:00:00 2001 From: Blake-Madden <66873089+Blake-Madden@users.noreply.github.com> Date: Sun, 16 Aug 2026 09:53:19 -0400 Subject: [PATCH 06/10] Add pointer checks --- src/ribbon/bar.cpp | 6 +++++- src/ribbon/buttonbar.cpp | 3 ++- src/ribbon/gallery.cpp | 3 ++- src/ribbon/page.cpp | 3 ++- src/ribbon/panel.cpp | 3 ++- src/ribbon/toolbar.cpp | 3 ++- 6 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/ribbon/bar.cpp b/src/ribbon/bar.cpp index 49a67c645c..3d1bdee1f3 100644 --- a/src/ribbon/bar.cpp +++ b/src/ribbon/bar.cpp @@ -799,6 +799,9 @@ wxImageList* wxRibbonBar::GetButtonImageList(wxSize size, int initialCount) void wxRibbonBar::SetArtProvider(wxRibbonArtProvider* art) { + if ( art == m_art ) + return; + wxRibbonArtProvider *old = m_art; m_art = art; @@ -970,7 +973,8 @@ void wxRibbonBar::OnDPIChanged(wxDPIChangedEvent& event) void wxRibbonBar::OnSysColourChanged(wxSysColourChangedEvent& event) { event.Skip(); - m_art->UpdateColoursFromSystem(); + if ( m_art ) + m_art->UpdateColoursFromSystem(); } void wxRibbonBar::RepositionPage(wxRibbonPage *page) diff --git a/src/ribbon/buttonbar.cpp b/src/ribbon/buttonbar.cpp index fc471d7c23..3604aed67e 100644 --- a/src/ribbon/buttonbar.cpp +++ b/src/ribbon/buttonbar.cpp @@ -1614,7 +1614,8 @@ void wxRibbonButtonBar::OnDPIChanged(wxDPIChangedEvent& event) void wxRibbonButtonBar::OnSysColourChanged(wxSysColourChangedEvent& event) { event.Skip(); - m_art->UpdateColoursFromSystem(); + if ( m_art ) + m_art->UpdateColoursFromSystem(); } #endif // wxUSE_RIBBON diff --git a/src/ribbon/gallery.cpp b/src/ribbon/gallery.cpp index ffe8084bbd..7690d8c959 100644 --- a/src/ribbon/gallery.cpp +++ b/src/ribbon/gallery.cpp @@ -543,7 +543,8 @@ void wxRibbonGallery::OnDPIChanged(wxDPIChangedEvent& event) void wxRibbonGallery::OnSysColourChanged(wxSysColourChangedEvent& event) { event.Skip(); - m_art->UpdateColoursFromSystem(); + if ( m_art ) + m_art->UpdateColoursFromSystem(); } wxRibbonGalleryItem* wxRibbonGallery::Append(const wxBitmapBundle& bitmap, int id) diff --git a/src/ribbon/page.cpp b/src/ribbon/page.cpp index 983d8d8767..503a905372 100644 --- a/src/ribbon/page.cpp +++ b/src/ribbon/page.cpp @@ -574,7 +574,8 @@ void wxRibbonPage::OnDPIChanged(wxDPIChangedEvent& event) void wxRibbonPage::OnSysColourChanged(wxSysColourChangedEvent& event) { event.Skip(); - m_art->UpdateColoursFromSystem(); + if ( m_art ) + m_art->UpdateColoursFromSystem(); } void wxRibbonPage::RemoveChild(wxWindowBase *child) diff --git a/src/ribbon/panel.cpp b/src/ribbon/panel.cpp index c41a144f32..a224c96301 100644 --- a/src/ribbon/panel.cpp +++ b/src/ribbon/panel.cpp @@ -263,7 +263,8 @@ void wxRibbonPanel::OnDPIChanged(wxDPIChangedEvent& event) void wxRibbonPanel::OnSysColourChanged(wxSysColourChangedEvent& event) { event.Skip(); - m_art->UpdateColoursFromSystem(); + if ( m_art ) + m_art->UpdateColoursFromSystem(); } void wxRibbonPanel::DoSetSize(int x, int y, int width, int height, int sizeFlags) diff --git a/src/ribbon/toolbar.cpp b/src/ribbon/toolbar.cpp index b04bafc42c..185a808589 100644 --- a/src/ribbon/toolbar.cpp +++ b/src/ribbon/toolbar.cpp @@ -990,7 +990,8 @@ void wxRibbonToolBar::OnDPIChanged(wxDPIChangedEvent& event) void wxRibbonToolBar::OnSysColourChanged(wxSysColourChangedEvent& event) { event.Skip(); - m_art->UpdateColoursFromSystem(); + if ( m_art ) + m_art->UpdateColoursFromSystem(); } // Finds the best width and height given the parents' width and height From b4d93a62c4ce2fa37f85bc490ff73a527660b42d Mon Sep 17 00:00:00 2001 From: Blake-Madden <66873089+Blake-Madden@users.noreply.github.com> Date: Sun, 16 Aug 2026 09:56:06 -0400 Subject: [PATCH 07/10] Fix wxRibbonToolBar default CTOR to call init helper --- src/ribbon/toolbar.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ribbon/toolbar.cpp b/src/ribbon/toolbar.cpp index 185a808589..c1564a246e 100644 --- a/src/ribbon/toolbar.cpp +++ b/src/ribbon/toolbar.cpp @@ -76,6 +76,7 @@ wxEND_EVENT_TABLE() wxRibbonToolBar::wxRibbonToolBar() { + CommonInit(0); } wxRibbonToolBar::wxRibbonToolBar(wxWindow* parent, From 486948ced5f84af8b1510634db5c23f316f723e7 Mon Sep 17 00:00:00 2001 From: Blake-Madden <66873089+Blake-Madden@users.noreply.github.com> Date: Sun, 16 Aug 2026 10:04:21 -0400 Subject: [PATCH 08/10] Fix dangling tool pointers in ribbon toolbar clear/delete --- src/ribbon/toolbar.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/ribbon/toolbar.cpp b/src/ribbon/toolbar.cpp index c1564a246e..b1e7e66cae 100644 --- a/src/ribbon/toolbar.cpp +++ b/src/ribbon/toolbar.cpp @@ -339,6 +339,12 @@ void wxRibbonToolBar::ClearTools() delete group; } m_groups.Clear(); + + m_hover_tool = nullptr; + m_active_tool = nullptr; + + // at least one group should be available + AppendGroup(); } bool wxRibbonToolBar::DeleteTool(int tool_id) @@ -355,6 +361,10 @@ bool wxRibbonToolBar::DeleteTool(int tool_id) if(tool->id == tool_id) { group->tools.RemoveAt(t); + if ( tool == m_hover_tool ) + m_hover_tool = nullptr; + if ( tool == m_active_tool ) + m_active_tool = nullptr; delete tool; return true; } @@ -376,6 +386,10 @@ bool wxRibbonToolBar::DeleteToolByPos(size_t pos) // Remove tool wxRibbonToolBarToolBase* tool = group->tools.Item(pos); group->tools.RemoveAt(pos); + if (tool == m_hover_tool ) + m_hover_tool = nullptr; + if ( tool == m_active_tool ) + m_active_tool = nullptr; delete tool; return true; } From db57e36a670835e54551275f62a7ada8462d4f74 Mon Sep 17 00:00:00 2001 From: Blake-Madden <66873089+Blake-Madden@users.noreply.github.com> Date: Sun, 16 Aug 2026 10:35:46 -0400 Subject: [PATCH 09/10] Smarter way to init wxRibbonToolBar --- include/wx/ribbon/toolbar.h | 10 +++++----- src/ribbon/toolbar.cpp | 1 - 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/include/wx/ribbon/toolbar.h b/include/wx/ribbon/toolbar.h index c162e6bf55..872ccd4502 100644 --- a/include/wx/ribbon/toolbar.h +++ b/include/wx/ribbon/toolbar.h @@ -190,11 +190,11 @@ protected: static wxBitmap MakeDisabledBitmap(const wxBitmap& original); wxArrayRibbonToolBarToolGroup m_groups; - wxRibbonToolBarToolBase* m_hover_tool; - wxRibbonToolBarToolBase* m_active_tool; - wxSize* m_sizes; - int m_nrows_min; - int m_nrows_max; + wxRibbonToolBarToolBase* m_hover_tool = nullptr; + wxRibbonToolBarToolBase* m_active_tool = nullptr; + wxSize* m_sizes = nullptr; + int m_nrows_min = 0; + int m_nrows_max = 0; #ifndef SWIG wxDECLARE_CLASS(wxRibbonToolBar); diff --git a/src/ribbon/toolbar.cpp b/src/ribbon/toolbar.cpp index b1e7e66cae..0fd8326dd2 100644 --- a/src/ribbon/toolbar.cpp +++ b/src/ribbon/toolbar.cpp @@ -76,7 +76,6 @@ wxEND_EVENT_TABLE() wxRibbonToolBar::wxRibbonToolBar() { - CommonInit(0); } wxRibbonToolBar::wxRibbonToolBar(wxWindow* parent, From f1b668bd7e310dd7702e1dbf4959c30440842975 Mon Sep 17 00:00:00 2001 From: Blake-Madden <66873089+Blake-Madden@users.noreply.github.com> Date: Sun, 16 Aug 2026 11:01:44 -0400 Subject: [PATCH 10/10] Add comments about m_current_hovered_page logic --- src/ribbon/bar.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ribbon/bar.cpp b/src/ribbon/bar.cpp index 3d1bdee1f3..82b574c132 100644 --- a/src/ribbon/bar.cpp +++ b/src/ribbon/bar.cpp @@ -390,10 +390,14 @@ void wxRibbonBar::DeletePage(size_t n) m_current_page--; } + // If the current hovered page is the one getting deleted, then we + // don't have a hovered page anymore. if ( m_current_hovered_page == static_cast(n) ) { m_current_hovered_page = wxNOT_FOUND; } + // ...otherwise, the pages after it shifted down by one, + // so adjust the index to keep referring to the same (still hovered) page. else if ( m_current_hovered_page > static_cast(n) ) { m_current_hovered_page--;