From eedc16bc89a8cdc5b186c27ef95ae8ba951d343c Mon Sep 17 00:00:00 2001 From: ryancog <170381220+ryancog@users.noreply.github.com> Date: Tue, 26 May 2026 09:56:39 -0400 Subject: [PATCH] Add wxSizer::DetachItem() Unlike the existing Detach(), this function doesn't delete wxSizerItem itself, allowing to add it back to this or another sizer later. Closes #26512. --- include/wx/sizer.h | 2 ++ interface/wx/sizer.h | 25 ++++++++++++++++++++++++- src/common/sizer.cpp | 17 +++++++++++++++++ tests/sizers/boxsizer.cpp | 34 ++++++++++++++++++++++++++++++++++ 4 files changed, 77 insertions(+), 1 deletion(-) diff --git a/include/wx/sizer.h b/include/wx/sizer.h index 80114a4abf..8837095bc2 100644 --- a/include/wx/sizer.h +++ b/include/wx/sizer.h @@ -617,6 +617,8 @@ public: virtual bool Detach( wxSizer *sizer ); virtual bool Detach( int index ); + wxNODISCARD virtual wxSizerItem *DetachItem(size_t index); + virtual bool Replace( wxWindow *oldwin, wxWindow *newwin, bool recursive = false ); virtual bool Replace( wxSizer *oldsz, wxSizer *newsz, bool recursive = false ); virtual bool Replace( size_t index, wxSizerItem *newitem ); diff --git a/interface/wx/sizer.h b/interface/wx/sizer.h index 255c784383..15149ceb58 100644 --- a/interface/wx/sizer.h +++ b/interface/wx/sizer.h @@ -440,16 +440,39 @@ public: virtual bool Detach(wxSizer* sizer); /** - Detach an item at position @a index from the sizer without destroying it. + Detach the child sizer or window in item at position @a index without + destroying the child object. This method does not cause any layout or resizing to take place, call Layout() to update the layout "on screen" after detaching a child from the sizer. + Returns @true if the child item was found and detached, @false otherwise. + Note that the sizer item containing the child sizer or window is + deleted by this function, see DetachItem() if you want to prevent this + from happening. + @see Remove() */ virtual bool Detach(int index); + /** + Detach the item at position @a index without destroying it. + + This method does not cause any layout or resizing to take place, call Layout() + to update the layout "on screen" after detaching a child from the sizer. + + Returns the item if it was found and detached, @nullptr otherwise. + + The caller takes ownership of the returned pointer, i.e. must either + delete it or add it back to this or another sizer later. + + @see Remove(), Add() + + @since 3.3.3 + */ + virtual wxSizerItem *DetachItem(size_t index); + /** Tell the sizer to resize the @a window so that its client area matches the sizer's minimal size (ComputeFittingClientSize() is called to determine it). diff --git a/src/common/sizer.cpp b/src/common/sizer.cpp index 7c367ee328..4668b9c319 100644 --- a/src/common/sizer.cpp +++ b/src/common/sizer.cpp @@ -1099,6 +1099,23 @@ bool wxSizer::Detach( int index ) return true; } +wxSizerItem *wxSizer::DetachItem(size_t index) +{ + const auto node = GetChildNode(index); + if ( !node ) + return nullptr; + + wxSizerItem *item = node->GetData(); + + wxWindow *window = item->GetWindow(); + if ( window != nullptr ) + window->SetContainingSizer(nullptr); + + m_children.Erase( node ); + + return item; +} + bool wxSizer::Replace( wxWindow *oldwin, wxWindow *newwin, bool recursive ) { wxASSERT_MSG( oldwin, wxT("Replacing null window") ); diff --git a/tests/sizers/boxsizer.cpp b/tests/sizers/boxsizer.cpp index 76a68910f0..4edb683230 100644 --- a/tests/sizers/boxsizer.cpp +++ b/tests/sizers/boxsizer.cpp @@ -448,6 +448,40 @@ TEST_CASE_METHOD(BoxSizerTestCase, "BoxSizer::Replace", "[sizer]") m_sizer->Replace(0, new wxSizerItem(new wxWindow(m_win, wxID_ANY))); } +TEST_CASE_METHOD(BoxSizerTestCase, "Sizer::DetachItem", "[sizer]") +{ + wxSizerItem *item = nullptr; + + SECTION("Spacer") + { + item = new wxSizerItem(0, 0); + } + + SECTION("Sizer") + { + item = new wxSizerItem(new wxBoxSizer(wxVERTICAL)); + } + + SECTION("Window") + { + item = new wxSizerItem(new wxWindow(m_win, wxID_ANY)); + } + + m_sizer->Add(item); + + // Test re-insertion + auto *detached = m_sizer->DetachItem(0); + CHECK( item == detached ); + + m_sizer->Insert(0, detached); + + // Test deletion after detach. + detached = m_sizer->DetachItem(0); + CHECK( item == detached ); + + delete detached; +} + TEST_CASE("Sizer::CombineFlags", "[sizer]") { // This is a compile-time test which simply verifies that we can combine