Gui.cs: Layout issue in the Label.

Created on 18 Jun 2020  Â·  12Comments  Â·  Source: migueldeicaza/gui.cs

In my opinion I think that the LayoutSubviews () method should not be virtual because it is essential for the redisposition of all views and any overriden may forget to call the base. But for now I just put the Label to call the base method. What is your opinion?

layout-issue

bug

All 12 comments

What will break if we do this? I think it sounds like a reasonable idea, but I don't know how much existing behavior depends on it.

What will break if we do this? I think it sounds like a reasonable idea, but I don't know how much existing behavior depends on it.

I did a search and just found it on Labeland Dialogbut this one he calls the baseas it should be.

It will break Dialog; The only way to remove it as a virtual and fix is to add another event to View (LayoutStarted). I just did this and will submit a PR for this issue. Ok?

Actually, I spoke too soon. Adding a new event lets classes do their thing without relying on overriding, but if I change Layout to non-virtual I get an OOM error. This will require more investigation.

In Dialog.cs

...
            LayoutStarted += (args) => {
                LayoutStartedHandler ();
            };

...


void LayoutStartedHandler ()
{
    int buttonsWidth = GetButtonsWidth ();

    int shiftLeft = Math.Max ((Bounds.Width - buttonsWidth) / 2 - 2, 0);
    for (int i = buttons.Count - 1; i >= 0; i--) {
        Button button = buttons [i];
        shiftLeft += button.Frame.Width + 1;
        button.X = Pos.AnchorEnd (shiftLeft);
        button.Y = Pos.AnchorEnd (1);
    }
}

In View.cs:

/// <summary>
/// Invoked when a view starts executing or when the dimensions of the view have changed, for example in
/// response to the container view or terminal resizing.
/// </summary>
/// <remarks>
/// Calls <see cref="OnLayoutComplete"/> (which raises the <see cref="LayoutComplete"/> event) before it returns.
/// </remarks>
public virtual void LayoutSubviews ()
{
    if (!layoutNeeded)
        return;

    Rect oldBounds = Bounds;
    OnLayoutStarted (new LayoutEventArgs () { OldBounds = oldBounds });

    viewText.Size = Bounds.Size;

    // Sort out the dependencies of the X, Y, Width, Height properties
    var nodes = new HashSet<View> ();
    var edges = new HashSet<(View, View)> ();

...

/// <summary>
/// Raises the <see cref="LayoutStarted"/> event. Called from  <see cref="LayoutSubviews"/> before any subviews have been laid out.
/// </summary>
internal virtual void OnLayoutStarted (LayoutEventArgs args)
{
    LayoutStarted?.Invoke (args);
}

/// <summary>
/// Fired after the Views's <see cref="LayoutSubviews"/> method has completed. 
/// </summary>
/// <remarks>
/// Subscribe to this event to perform tasks when the <see cref="View"/> has been resized or the layout has otherwise changed.
/// </remarks>
public Action<LayoutEventArgs> LayoutComplete;

/// <summary>
/// Raises the <see cref="LayoutComplete"/> event. Called from  <see cref="LayoutSubviews"/> before all sub-views have been laid out.
/// </summary>
internal virtual void OnLayoutComplete (LayoutEventArgs args)
{
    LayoutComplete?.Invoke (args);
}

@tig really think it is the best solution. Use an event and don't override. Do it please. Thanks.

I'll close my PR too.

@tig I already tested the code above and it seems working well.

Did you change it away from virtual? If I do it i get an out of memory error when starting. Don't have time to look at it right now...

Affirmative @tig. I don't get any errors after removing the virtual from LayoutSubviews (). Perhaps it is another change that you have made that may be affecting this and not exactly because of this situation.

This will be fixed in #702

Was this page helpful?
0 / 5 - 0 ratings