Conditional item gets re-instantiated even if the result is the same
Platform: Linux / winit / FemtoVG / X11, Language: Rust
Consider the following code:
if (Facade.portfolio.file-name != ""): MainContent {}
When I call facade.set_portfolio, the MainContent appears to be always re-instantiated (judging by the loss of its state), even if the result of the condition stays true. This is undesirable.
I'm working it around in my application by instead doing:
MainContent {
visible: Facade.portfolio.file-name != "";
}
But this of course keeps the instance around, even when it is not needed.
The thing is that we have to reset the whole thing if the model is dirty in https://github.com/slint-ui/slint/blob/c695869344bc297e66463db963810ce420c9c7b9/internal/core/model.rs#L871-L872
But we could actually check if the model has changed before doing that.
Now the problem is how to compare two model. Because the generated expression in rust is sp::ModelRc::new(#model as bool), so it's always a different model. So we need to find a trick to make it work. Maybe instead of using a ModelRc for bool model, we could use something else.
So we need to find a trick to make it work. Maybe instead of using a ModelRc for bool model, we could use something else.
Or maybe it is possible to do a special case check for comparing bool models? Using as_any / downcast_ref, maybe?
I just came across this issue after updating an older private project; this seems to be a recession from 1.2.2 to 1.3.0. In my case, I had a conditional button in a video-player-like application, which is almost impossible to click because the player state is updated 60 times a second:
if (!state.playing): Button {
icon: @image-url("icons/play-fill.svg");
enabled: state.ready && !state.fastforward;
clicked => {
play();
focus.focus();
}
}
if (state.playing): Button {
icon: @image-url("icons/pause-fill.svg");
enabled: !state.fastforward;
clicked => {
pause();
focus.focus();
}
}
I could workaround this issue by "pulling the ifs inside":
Button {
icon: !state.playing ? @image-url("icons/play-fill.svg") : @image-url("icons/pause-fill.svg");
enabled: state.ready && !state.fastforward;
clicked => {
if (!state.playing) {
play();
focus.focus();
} else {
pause();
focus.focus();
}
}
}
FYI, I experienced a similar problem here: https://github.com/slint-ui/slint/discussions/7764
As you're discussing about comparing two models: I think for my use-case this wouldn't work unfortunately. As described in https://github.com/slint-ui/slint/discussions/7764, my model contains struct items, where one of the struct members (an enum) is used for the conditional components. So when other members of the struct are modified, the models will differ, but the conditional component shall still keep its state if the condition still evaluates to true after the modification.