Changed the wxWrapSizer code from using a variable "m_usedLast" to two different functions
CalcMinFirstPass() and CalcMin() for the two step min size calculation.
Added the same logic and naming to controls using GetEffectiveMinSizeFirstPass()
Implemented this for the generic code in wxStaticTextBase.
Added test to wrapsizer sample.
https://github.com/wxWidgets/wxWidgets/pull/25753
(9 files)
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.
So far only tested on GTK+. Will test on OSX later the week. I would appreciate testing on MSW.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.
Before looking at it, could you please explain the relationship between this and wxWrapSizer
? I mean, they do conceptually similar things, but other than that, there is none, right?
Also, I don't know if we want to do this unconditionally or if some flag is specified. While people probably don't want their labels being truncated, they may not want them to take more than one line too... And the interaction of this with ellipsize flags is not clear at all.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.
@vadz commented on this pull request.
Sorry, there are a number of things to fix here, but more importantly I see 2 changes here that should ideally correspond to 2 commits:
GetEffectiveMinSizeFirstPass()
and changing wxWrapSizer
to use it.wxStaticText
.(1) is probably fine, but it really needs to be documented.
For (2) I'm still not sure if we want to do it unconditionally or depending on a flag. If nothing else, this almost certainly shouldn't override explicit calls to Wrap()
in the user code as it, I believe, does now.
> + // Can be overidden for two step process, e.g. by wxWrapSizer + virtual wxSize CalcMinFirstPass() { return CalcMin(); }
It would be nice to explain what the two step process is, because this is really not obvious.
Also, wxWrapSizer
doesn't really need it, as it worked before adding it, so this makes things even more confusing.
> @@ -411,6 +411,7 @@ class WXDLLIMPEXP_CORE wxWindowBase : public wxEvtHandler // minimum size, giving priority to the min size components, and // returns the results. virtual wxSize GetEffectiveMinSize() const; + virtual wxSize GetEffectiveMinSizeFirstPass() const { return GetEffectiveMinSize(); }
This should really be documented (in a comment here and in interface/wx/window.h
) because I just have no idea how to use it right now.
> @@ -72,6 +77,12 @@ class WXDLLIMPEXP_CORE wxStaticTextBase : public wxControl // display. void UpdateLabel(); + // save unwrapped label to allow to call Wrap() several times and + // always starting from the original, unwrapped label + wxString m_unwrappedLabel;
Is this different from wxControl::m_labelOrig
?
> @@ -72,6 +77,12 @@ class WXDLLIMPEXP_CORE wxStaticTextBase : public wxControl // display. void UpdateLabel(); + // save unwrapped label to allow to call Wrap() several times and + // always starting from the original, unwrapped label + wxString m_unwrappedLabel; + int m_currentWrap = 0;
What is the value of this? Wrap width? With 0
meaning "none"? Please comment it too.
In samples/wrapsizer/wrapsizer.cpp:
> @@ -118,10 +118,13 @@ WrapSizerFrame::WrapSizerFrame() sizerMidWrap->Add(chk, wxSizerFlags().Centre().Border()); } -
Please avoid mixing whitespace-only changes with significant ones if possible.
In samples/wrapsizer/wrapsizer.cpp:
> sizerMid->Add(sizerMidWrap, wxSizerFlags(100).Expand()); sizerRoot->Add(sizerMid, wxSizerFlags(100).Expand().Border()); + // A long wxStaticText that wraps like a wxWrapSizer
Really not sure this belongs to this sample anyhow. I'd rather add a button setting a long label to the "widgets" sample.
In src/common/stattextcmn.cpp:
> @@ -213,8 +213,46 @@ class wxLabelWrapper : public wxTextWrapper void wxStaticTextBase::Wrap(int width) { + if (width == m_currentWrap) return;
Please don't do this:
⬇️ Suggested change- if (width == m_currentWrap) return; + if (width == m_currentWrap) + return;
In src/common/stattextcmn.cpp:
> @@ -213,8 +213,46 @@ class wxLabelWrapper : public wxTextWrapper void wxStaticTextBase::Wrap(int width) { + if (width == m_currentWrap) return; + m_currentWrap = width; + + // Allow for repeated calls to Wrap with different values + if (m_unwrappedLabel.IsNull())
Please use standard functions instead of wx 1.x ones
⬇️ Suggested change- if (m_unwrappedLabel.IsNull()) + if (m_unwrappedLabel.empty())
In src/common/stattextcmn.cpp:
> wxLabelWrapper wrapper; wrapper.WrapLabel(this, width); + InvalidateBestSize(); +} + +wxSize wxStaticTextBase::GetEffectiveMinSizeFirstPass() const +{ + // While wxWrapSizer can only wrap entire controls, a text paragraph + // could theoretically wrap at a few letters, so we start with + // requesting very little space in the first pass + return wxSize( 10, 10 );
Could we avoid hardcoding magic numbers please? It would make sense to use GetCharWidth()
or something else based it.
In src/common/stattextcmn.cpp:
> + +wxSize wxStaticTextBase::GetEffectiveMinSizeFirstPass() const +{ + // While wxWrapSizer can only wrap entire controls, a text paragraph + // could theoretically wrap at a few letters, so we start with + // requesting very little space in the first pass + return wxSize( 10, 10 ); +} + +bool wxStaticTextBase::InformFirstDirection(int direction, int size, int WXUNUSED(availableOtherDir)) +{ + // In the second pass, this control has been given "size" amount of + // space in the horizontal direction. Wrap there and report a new + // GetEffectiveMinSize() from then on. + + if (direction != wxHORIZONTAL) return false;⬇️ Suggested change
- if (direction != wxHORIZONTAL) return false; + if (direction != wxHORIZONTAL) + return false;
In src/common/stattextcmn.cpp:
> + // While wxWrapSizer can only wrap entire controls, a text paragraph + // could theoretically wrap at a few letters, so we start with + // requesting very little space in the first pass + return wxSize( 10, 10 ); +} + +bool wxStaticTextBase::InformFirstDirection(int direction, int size, int WXUNUSED(availableOtherDir)) +{ + // In the second pass, this control has been given "size" amount of + // space in the horizontal direction. Wrap there and report a new + // GetEffectiveMinSize() from then on. + + if (direction != wxHORIZONTAL) return false; + + int style = GetWindowStyleFlag(); + SetWindowStyleFlag( style | wxST_NO_AUTORESIZE );
It looks like we could avoid calling it unnecessarily (and also below):
⬇️ Suggested change- SetWindowStyleFlag( style | wxST_NO_AUTORESIZE ); + if ( !(style & wxST_NO_AUTORESIZE) ) + SetWindowStyleFlag( style | wxST_NO_AUTORESIZE );
> @@ -859,21 +859,39 @@ wxSize wxWindowBase::GetEffectiveMinSize() const // merge the best size with the min size, giving priority to the min size wxSize min = GetMinSize(); + const wxStaticText *text = dynamic_cast<const wxStaticText*>(this);
Please remove this and all the other changes to this file.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.
@RobertRoeb commented on this pull request.
> + // Can be overidden for two step process, e.g. by wxWrapSizer + virtual wxSize CalcMinFirstPass() { return CalcMin(); }
wxWrapSizer called CalcMin() several times, but with different behaviour, but instead of using either a flag or two different calls, it set a flag in wxSizer::InformFirstDirection() which altered the behaviour of CalcMin(). I tried to use CalcMinFirstPass() or CalcMin( bool firstpass = false ); for both wrapsizer and a wrapped control, but there sizers and controls are handled differently in wxSizer::Layout()
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.
Before looking at it, could you please explain the relationship between this and
wxWrapSizer
?
I mean, they do conceptually similar things, but other than that, there is none, right?
The code in wxSizer() always assumed this behaviour for wxWrapSizer and wxStaticText. It just
didn't work until now. This is even documented for probably 10 years:
https://docs.wxwidgets.org/3.2/classwx_window.html#a9fd5b6520c1b30eb8e82bb5d56bc24c0
Also, I don't know if we want to do this unconditionally or if some flag is specified. While
people probably don't want their labels being truncated, they may not want them to take
more than one line too... And the interaction of this with ellipsize flags is not clear at all.
This only happens inside of a vertical sizer, which calls InformsFirstDirection() to for the sole
purpose of wrapping the text. This change makes multiline text usable in sizers and should
not have an effect otherwise.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.
@RobertRoeb pushed 1 commit.
—
View it on GitHub or unsubscribe.
You are receiving this because you are subscribed to this thread.
@RobertRoeb commented on this pull request.
> @@ -411,6 +411,7 @@ class WXDLLIMPEXP_CORE wxWindowBase : public wxEvtHandler // minimum size, giving priority to the min size components, and // returns the results. virtual wxSize GetEffectiveMinSize() const; + virtual wxSize GetEffectiveMinSizeFirstPass() const { return GetEffectiveMinSize(); }
Right, will do
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.
@RobertRoeb commented on this pull request.
> @@ -72,6 +77,12 @@ class WXDLLIMPEXP_CORE wxStaticTextBase : public wxControl // display. void UpdateLabel(); + // save unwrapped label to allow to call Wrap() several times and + // always starting from the original, unwrapped label + wxString m_unwrappedLabel;
I could not figure out of the stripping of markup and/or mnemonics and/or the ellipsis code would alter m_labelOrig. I think m_labelOrig is the before any change, and m_unwrappedLabel is after the other changes, but before wrapping.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.
> @@ -72,6 +77,12 @@ class WXDLLIMPEXP_CORE wxStaticTextBase : public wxControl // display. void UpdateLabel(); + // save unwrapped label to allow to call Wrap() several times and + // always starting from the original, unwrapped label + wxString m_unwrappedLabel; + int m_currentWrap = 0;
0 means no wrapping (will add comment). The current value needs to be saved to prevent uncountable recalculations of the wrapping code during the wxSizer Layout() process (as you probably guessed).
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.
@RobertRoeb pushed 1 commit.
—
View it on GitHub or unsubscribe.
You are receiving this because you are subscribed to this thread.
@RobertRoeb pushed 1 commit.
—
View it on GitHub or unsubscribe.
You are receiving this because you are subscribed to this thread.
@vadz commented on this pull request.
> + // Can be overidden for two step process, e.g. by wxWrapSizer + virtual wxSize CalcMinFirstPass() { return CalcMin(); }
wxWrapSizer
was, AFAIR, somewhat of a hack and it's great to replace it with something better but this something should be documented/explained.
Maybe documenting it would also give some idea for a better name because, frankly, "first pass" is not great: it doesn't mean anything per se and implies the existence of "second pass" which doesn't actually exist.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.
@vadz commented on this pull request.
> @@ -72,6 +77,12 @@ class WXDLLIMPEXP_CORE wxStaticTextBase : public wxControl // display. void UpdateLabel(); + // save unwrapped label to allow to call Wrap() several times and + // always starting from the original, unwrapped label + wxString m_unwrappedLabel;
I think you're right, but is it really worth storing it separately instead of just stripping the other stuff from m_labelOrig
?
It's not just about optimizing memory usage but also, in more places we store redundant information, more places we need to remember to update later.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.
This only happens inside of a vertical sizer, which calls InformsFirstDirection() to for the sole purpose of wrapping the text.
Wait, does this mean that wrapping still won't work in a wxFlexGridSizer
? This makes it significantly less useful and potentially very, very confusing: there are no other examples of controls (AFAIK) that appear differently depending on the sizer they're placed in.
Can we make it work for 2D sizers too?
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.
Wait, does this mean that wrapping still won't work
in awxFlexGridSizer
?
It should work there as well. I meant any vertical compartment in any sizer. And with my code it works for controls as well, although I cannot think of any apart from display of text. Well, a text editor or a HTML window, maybe.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.
@RobertRoeb pushed 2 commits.
—
View it on GitHub or unsubscribe.
You are receiving this because you are subscribed to this thread.