From 3241e7a850aa9e55a630e5f790d6a71fe0a83a59 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Thu, 22 Aug 2019 13:46:53 +0200 Subject: [PATCH 1/3] Make wxTopLevelWindow::Layout() do the expected thing It makes sense for explicit calls to Layout() to use the same logic as is implicitly used when a TLW is resized, so override it to use TLW-specific logic instead of using a separate DoLayout() for this. Note that DoLayout() still has to be preserved because Debian code search finds at least a couple of examples of its use outside the library, meaning that there are probably quite a few more of them in the wild. Also, wxTopLevelWindow still needs its own wxEVT_SIZE handler because the base class only calls Layout() if GetAutoLayout() is true, while we want it to be always called. This might be worked around by just calling SetAutoLayout(true) in wxTopLevelWindow ctor, but it seems safer, from compatibility point of view, to keep wxTopLevelWindow::OnSize() instead. See #18472. --- include/wx/toplevel.h | 11 +++++++---- src/common/toplvcmn.cpp | 12 ++++++++---- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/include/wx/toplevel.h b/include/wx/toplevel.h index 9927d67db1..0089481189 100644 --- a/include/wx/toplevel.h +++ b/include/wx/toplevel.h @@ -276,9 +276,13 @@ public: virtual bool IsTopNavigationDomain(NavigationKind kind) const wxOVERRIDE; virtual bool IsVisible() const { return IsShown(); } + // override to do TLW-specific layout: we resize our unique child to fill + // the entire client area + virtual bool Layout() wxOVERRIDE; + // event handlers void OnCloseWindow(wxCloseEvent& event); - void OnSize(wxSizeEvent& WXUNUSED(event)) { DoLayout(); } + void OnSize(wxSizeEvent& WXUNUSED(event)) { Layout(); } // Get rect to be used to center top-level children virtual void GetRectForTopLevelChildren(int *x, int *y, int *w, int *h); @@ -326,9 +330,8 @@ protected: // send the iconize event, return true if processed bool SendIconizeEvent(bool iconized = true); - // do TLW-specific layout: we resize our unique child to fill the entire - // client area - void DoLayout(); + // this method is only kept for compatibility, call Layout() instead. + void DoLayout() { Layout(); } static int WidthDefault(int w) { return w == wxDefaultCoord ? GetDefaultSize().x : w; } static int HeightDefault(int h) { return h == wxDefaultCoord ? GetDefaultSize().y : h; } diff --git a/src/common/toplvcmn.cpp b/src/common/toplvcmn.cpp index 7619328a18..01211ce7c0 100644 --- a/src/common/toplvcmn.cpp +++ b/src/common/toplvcmn.cpp @@ -411,20 +411,20 @@ bool wxTopLevelWindowBase::IsTopNavigationDomain(NavigationKind kind) const // default resizing behaviour - if only ONE subwindow, resize to fill the // whole client area -void wxTopLevelWindowBase::DoLayout() +bool wxTopLevelWindowBase::Layout() { // We are called during the window destruction several times, e.g. as // wxFrame tries to adjust to its tool/status bars disappearing. But // actually doing the layout is pretty useless in this case as the window // will disappear anyhow -- so just don't bother. if ( IsBeingDeleted() ) - return; + return false; // if we're using constraints or sizers - do use them if ( GetAutoLayout() ) { - Layout(); + return wxNonOwnedWindow::Layout(); } else { @@ -443,7 +443,7 @@ void wxTopLevelWindowBase::DoLayout() { if ( child ) { - return; // it's our second subwindow - nothing to do + return false; // it's our second subwindow - nothing to do } child = win; @@ -458,8 +458,12 @@ void wxTopLevelWindowBase::DoLayout() DoGetClientSize(&clientW, &clientH); child->SetSize(0, 0, clientW, clientH); + + return true; } } + + return false; } // The default implementation for the close window event. From c74a15eded18c72e475bc7840c6f45064fba5604 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Thu, 22 Aug 2019 13:48:07 +0200 Subject: [PATCH 2/3] Call wxTopLevelWindow::Layout() rather than DoLayout() Ideal would be to completely get rid of the DoLayout() method later, however this method seems to be used in the existing applications, so for now it needs to be kept. --- src/common/framecmn.cpp | 8 ++++---- src/generic/wizard.cpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/common/framecmn.cpp b/src/common/framecmn.cpp index fee0c1bfb4..93d2cfc716 100644 --- a/src/common/framecmn.cpp +++ b/src/common/framecmn.cpp @@ -465,7 +465,7 @@ void wxFrameBase::SetStatusBar(wxStatusBar *statBar) { PositionStatusBar(); - DoLayout(); + Layout(); } } @@ -597,19 +597,19 @@ void wxFrameBase::SetToolBar(wxToolBar *toolbar) m_frameToolBar = toolbar; PositionToolBar(); } - //else: tricky: do not reset m_frameToolBar yet as otherwise DoLayout() + //else: tricky: do not reset m_frameToolBar yet as otherwise Layout() // wouldn't recognize the (still existing) toolbar as one of our // bars and wouldn't layout the single child of the frame correctly - // and this is even more tricky: we want DoLayout() to recognize the + // and this is even more tricky: we want Layout() to recognize the // old toolbar for the purpose of not counting it among our non-bar // children but we don't want to reserve any more space for it so we // temporarily hide it if ( m_frameToolBar ) m_frameToolBar->Hide(); - DoLayout(); + Layout(); if ( m_frameToolBar ) m_frameToolBar->Show(); diff --git a/src/generic/wizard.cpp b/src/generic/wizard.cpp index ea60568b18..e77a506606 100644 --- a/src/generic/wizard.cpp +++ b/src/generic/wizard.cpp @@ -929,7 +929,7 @@ bool wxWizard::DoLayoutAdaptation() wxStandardDialogLayoutAdapter::DoFitWithScrolling(this, windows); // Size event doesn't get sent soon enough on wxGTK - DoLayout(); + Layout(); SetLayoutAdaptationDone(true); From 2a487ffe83f2d2b5ae21409d1e07f30b58bbee41 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Thu, 22 Aug 2019 13:56:32 +0200 Subject: [PATCH 3/3] Update wxWindow and wxTopLevelWindow::Layout() documentation Explain how these methods actually work, remove a very (from wx 1.x days?) outdated reference to wxPanel always calling Layout() and mention the special case of wxTopLevelWindow in the overview too. --- docs/doxygen/overviews/windowsizing.h | 5 +++++ interface/wx/toplevel.h | 16 ++++++++++++++-- interface/wx/window.h | 17 +++++++++++------ 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/docs/doxygen/overviews/windowsizing.h b/docs/doxygen/overviews/windowsizing.h index 9b75a36246..940e51b8da 100644 --- a/docs/doxygen/overviews/windowsizing.h +++ b/docs/doxygen/overviews/windowsizing.h @@ -116,4 +116,9 @@ some simple explanations of things. the constraints algorithm is run. The @c Layout() method is what is called by the default @c EVT_SIZE handler for container windows. +@li wxTopLevelWindow::Layout(): this overridden version does the same thing as + the base wxWindow::Layout() except, for convenience, it will also resize + the only child of the top-level window to cover its entire client area if + there is no sizer associated with the window. Note that this only happens + if there is exactly one child. */ diff --git a/interface/wx/toplevel.h b/interface/wx/toplevel.h index 361a5794c9..a24ea8dbc7 100644 --- a/interface/wx/toplevel.h +++ b/interface/wx/toplevel.h @@ -283,8 +283,20 @@ public: bool IsUsingNativeDecorations() const; /** - See wxWindow::SetAutoLayout(): when auto layout is on, this function gets - called automatically when the window is resized. + Lays out the children using the window sizer or resizes the only child + of the window to cover its entire area. + + This class overrides the base class Layout() method to check if this + window contains exactly one child -- which is commonly the case, with + wxPanel being often created as the only child of wxTopLevelWindow -- + and, if this is the case, resizes this child window to cover the entire + client area. + + Note that if you associate a sizer with this window, the sizer takes + precedence and the only-child-resizing is only used as fallback. + + @returns @false if nothing was done because the window doesn't have + neither a sizer nor a single child, @true otherwise. */ virtual bool Layout(); diff --git a/interface/wx/window.h b/interface/wx/window.h index 8628ce5d26..cd873f0d65 100644 --- a/interface/wx/window.h +++ b/interface/wx/window.h @@ -3445,15 +3445,20 @@ public: void SetConstraints(wxLayoutConstraints* constraints); /** - Invokes the constraint-based layout algorithm or the sizer-based algorithm - for this window. + Lays out the children of this window using the associated sizer. - This function does not get called automatically when the window is resized - because lots of windows deriving from wxWindow does not need this functionality. - If you want to have Layout() called automatically, you should derive - from wxPanel (see wxPanel::Layout). + If a sizer hadn't been associated with this window (see SetSizer()), + this function doesn't do anything, unless this is a top level window + (see wxTopLevelWindow::Layout()). + + Note that this method is called automatically when the window size + changes if it has the associated sizer (or if SetAutoLayout() with + @true argument had been explicitly called), ensuring that it is always + laid out correctly. @see @ref overview_windowsizing + + @returns Always returns @true, the return value is not useful. */ virtual bool Layout();