slint icon indicating copy to clipboard operation
slint copied to clipboard

Introduce undefined values for properties and struct fields

Open FloVanGH opened this issue 9 months ago • 3 comments

I have the following use case:

export struct Style {
    border-radius: length,
    border-top-left-radius: length,
    background: brush
}

component StyledRectangle {
      in property <Style> style;
      
      Rectangle {
            background: style.background;
            border-radius: style.border-radius;
            border-top-left-radius: style.border-top-left-radius;
      }
}

export component MyExample inherits Window {
      width: 600px;
      height: 400px;
      
      StyledRectangle {
            style: {
                  background: #000000;
                  border-top-left-radius: 8px;
            }
      }
}

The following example does not work as expected, because the top left border radius of inner Rectangle will not be rendered with 8px but instead with 0. The problem is, that if the border-radius field on Style is not explicit set it will defaults to 0 and it overwrites the setting of border-top-left-radius. What could help to solve this problem is to introduce undefined for values and use this as default e.g. for border-radius instead of 0, so that is handled like there is no value set on the property border-radius.

FloVanGH avatar May 02 '24 13:05 FloVanGH

We could have default value for struct like propose in https://github.com/slint-ui/slint/issues/2936 , you could do something like:

export struct Style {
    border-radius: length,
    border-top-left-radius: length = -1px,
    background: brush
}

component StyledRectangle {
      in property <Style> style;
      
      Rectangle {
            background: style.background;
            border-radius: style.border-radius;
            border-top-left-radius: style.border-top-left-radius >= 0 ? style.border-top-left-radius : style.border-radius;
      }
}

export component MyExample inherits Window {
      width: 600px;
      height: 400px;
      
      StyledRectangle {
            style: {
                  background: #000000;
                  border-top-left-radius: 8px;
            }
      }
}

But in general, we might want to have option<...> types.

ogoffart avatar May 08 '24 13:05 ogoffart

border-top-left-radius: style.border-top-left-radius >= 0 ? style.border-top-left-radius : style.border-radius;

I think from user perspective that looks more like a workaround. As user I want to do something like on the Rectangle directly, if I do not define a value for border-radius it should be ignored and it should not override values like border-top-left-radius.

FloVanGH avatar May 08 '24 14:05 FloVanGH

Right, for the general case, we would need to introduced a new type like option<length> or length? or something like that. Somehow related: https://github.com/slint-ui/slint/issues/615

ogoffart avatar May 08 '24 17:05 ogoffart

If we had say option like this:

property <option<length>> maybe-length;

We could either do it like typescript and say the compiler requires an earlier check:

clicked => {
    width = self.maybe-length; // ERROR
    if (self.maybe-length) {
        width = self.maybe-length; // OK, control-flow before reaching this checks if value is not none
    }
}

or we could have Rust like syntax:

clicked => {
    width = self.maybe-length; // ERROR
    if let Some(length) = self.maybe-length {
        width = length;
    }
}

but this requires the introduction of local variables....

tronical avatar Sep 16 '24 08:09 tronical

I think the typescript approach is fine.

We can also make it work with || so that self.maybe-length || 0 works. And other operators such as ?.

ogoffart avatar Sep 16 '24 10:09 ogoffart