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.54k stars 600 forks source link

When will an item be rendered as a layer and when it will not ? #2407

Closed cppdev123 closed 1 year ago

cppdev123 commented 1 year ago

While trying to implement the material slider I encountered a problem in the disabled slider: the handle and track both have opacity less than 1 so they appear one on top the other which is undesirable. I looked how it is done in slint and from here: https://github.com/slint-ui/slint/blob/master/internal/compiler/widgets/material-base/widget-slider.slint the root.opacity is used instead and it gives the effect of qml layer. I see from the source of slint that it has support for layer rendering and has a hint property for this, but the root is used as a layer without any hint set.

ogoffart commented 1 year ago

the idea is that it is "as if" every element is its own layer. In practice, the layer are only done if required. This is the case for item that have opacity and have overlapping children. The hint is there to force layer in some renderer as it may be more optimal to cache it.

so to answer the question, there is a layer if:

cppdev123 commented 1 year ago

but this violates the "as if" rule because the expected behaviour is that without layering enabled the opacity should propagate to children. IMO layering is more of behaviour than an optimization!

ogoffart commented 1 year ago

the expected behaviour is that without layering enabled the opacity should propagate to children.

Is that really the expected behaviour? To me this is not obvious. When i say, for example: Button { opacity: 0.5; } I'm expecting the whole Button to be translucent. I do not expect to be able to see the Button's background through the Button's text. Why would anyone want that? (this is a serious question, do you have an use case were this is what you want? Because if that's the case we should indeed reconsider our choice)

cppdev123 commented 1 year ago

Is that really the expected behaviour? Yes at least in css and qml. Is this the desired behaviour? No, and this is why I wondered how slint did it. In css and qml the opacity is relative to the parent so if the parent has an opacity of 0.5 then each child will have opacity of 0.5 * child opacity so it will always be between 0 and 0.5! When multiple overlapping items are draw with opacity less than 1, they will appear on top of each other which is not desired. This is also why it is advised to use rgba with alpha channels instead of opacity in general when possible.

for css see here: https://stackoverflow.com/questions/21295478/css-overlapping-elements-opacity-issue https://stackoverflow.com/questions/8746860/how-to-handle-double-opacity-of-two-overlapping-divs

for qml see here: https://doc.qt.io/qt-6/qml-qtquick-item.html#item-layers

The docs describe the issue of opacity and how to solve it with explicit layer enabled.

ogoffart commented 1 year ago

I know what's the behavior in QML (and CSS), but IMHO, this is not what people really want. This is why we made a behavior which in our opinion is more right towards what people want.

Why would you like to see intermediate element trough the top elements?

cppdev123 commented 1 year ago

You got me wrong. I don't want the behaviour of QML and CSS, I was even surprised by their behaviour. But since slint is trying to take the CSS route as possible (I think) I thought that it will have the same opacity rules and I didn't understand in first how it achieved its behaviour. The docs should include this so that people are not confused while trying to port some code from qml or css