slint-ui / slint

Slint is a declarative GUI toolkit to build native user interfaces for Rust, C++, or JavaScript apps.
https://slint.dev
Other
17.55k stars 601 forks source link

[bug] min-width in window is interpreted as max-width, when max-width is not set #786

Closed Vollbrecht closed 9 months ago

Vollbrecht commented 2 years ago

Description

Creating and Window that only defines an min-width and no max-width will be shrinkable to 0px. Its happening when using an child with no defined width/height and an relative width parameter.

Expectation

min-width in the top tree element should always hold true.

Behavior

Not defining max-width in the following example sets min-width as an max-width. Because one cannot set min-width and width at the same time the default starting width maybe causes this error ? By setting max-width the following example works as expected.

Example

export AppWindow := Window {
    min-width: 320px;
    min-height: 240px;
    //max-width: 1920px;
    VerticalBox {
        Rectangle {
            width: parent.width * 80%;
        }
    }
}

Software version

sixtyfps master/ 75ba29c sixtyfps-vscode nightly v2021.12.2818

Graphic Backend

GL

Operating System

Linux 5.10.0-8-amd64 -- Debian11

Vollbrecht commented 2 years ago

it seams that preferred-width also gets ignored in the case. the window always spawns with min-width and only is shrinkable example :

min-width: 320px;
preferred-width: 640px;
ogoffart commented 2 years ago

This is caused by the fact that you set a explicit the size of the layout base on itself:

    VerticalBox {
        Rectangle {
            width: parent.width * 80%;
        }
    }

What you are saying is that the Rectangle should have a specific with based on its parent layout. But the layout's contraint is based on its children. In this case, the layout's width will be the width of the rectangle plus the paddings. You get some kind of a loop similar to issue #782 which causes the window sizes to be not properly defined.

Vollbrecht commented 2 years ago

Thank you for your analysis.Though I have a couple of questions. If i use width: root.width *80% instead of parent.width .. it shows the same behavior. Shouldn't this work then? It shows the same behavior. I also tried to declare min-width and preferred-width in the VerticalBox, and still the same behaviour. Only if i am setting a max-width it starts working. To clarify "working" : The root window is resizable between min-width and max-width , but as soon as i don't set max-width, i would expect that it still resizable between min-width and + infinity, but it flips and is now only resizable between 0 and min-width. My intention with the example is: I want to express an Layout which is constraint by its parents/root, but follows its parent/root size relative. Declarative it feels unambiguous to me if i reefer to the a width as its parent or root width(child depends on parent/root). Should it not work this way? I don't feel like i am abusing the syntax here :D Thanks !

ogoffart commented 2 years ago

you can use width: 80%; this is a special syntax which has a different meaning in the layout. And you should give an alignment to the layout otherwise it stretches item. By restricting the size of an element, you restrict the size of layout containing it, and so on. So if you don't override max-width, the default max-width is going to use the value from the layout.

Vollbrecht commented 2 years ago

ok so to give a concrete example i should use something like this

export AppWindow := Window {
    min-width: 320px;
    preferred-width: 640px;
    HorizontalBox {
        alignment: start;
        Rectangle {
            width:  80%;
        }
    }
}

or as an alternative

export AppWindow := Window {
    min-width: 320px;
    preferred-width: 640px;
    HorizontalBox {
        Rectangle {
            width:  80%;
        }
        Rectangle{}
    }
}

does this look right?

Vollbrecht commented 2 years ago

you can use width: 80%; this is a special syntax which has a different meaning in the layout.

I am now a bit conflicted in my understanding. I reread the "Relative Lengths" paragraph in langref.md and it states This pattern of expressing the width or height in percent of the parent's property with the same name is common. For convenience, a short-hand syntax exists for this scenario:

why it is a special syntax here and not just an short-hand for parent.width * 80% ? So if you don't override max-width, the default max-width is going to use the value from the layout.

I don't fully understand this. Why does it set a max-width if i don't want to set a max-width in that case? I only restricted the minimum. Does this imply it also always try to find a maximum? Next comment Do you mean by declaring a relative length in a child it uses some kind of max-width, min-width to evaluate its size and not the current width ? If an implicit max-width on min-width is set can the compiler maybe help here saying : "BAD BOY: Declared max-width < min-width in AppWindow element Tree ! " or something alike. I understand that sometimes you maybe want an childrens max-width that is bigger than an min-width of an parent. But i think the min-width of the parents should always hold. I am just a bit puzzled that width:parent.width* 80% is not the same as width:80%. It feels unambiguous.

Vollbrecht commented 2 years ago

I am rereading the Layout.md again. I see that it states there that

You can tune the automatic placement using different constraints, to accommodate the design of your user interface. For example each element has a minimum and a maximum size.

So this is true for all 4 basic Layouts (and its derivative widgets) its setting an min and max-width on all children?. But only for them and not an Rectangle's children for example ? This pitfall should maybe be mentioned in the Relative Lengths paragraf by linking the Layout.md paragraph for automatic layouting. (While reading this imagine a voice in a friendly nice tone, its merely a suggestion not a angry demanding voice ^^ ) Is there a way to have a look at all defined values for an element? Like a debug feature prints out every value of an specific element? Thank you !

ogoffart commented 9 months ago

This is a documentation issue. But there is another documentation issue for layout at https://github.com/slint-ui/slint/issues/143