slint icon indicating copy to clipboard operation
slint copied to clipboard

Add support for filtering and mapping models in `.slint` directly

Open dilawar opened this issue 2 years ago • 10 comments

I have a property<[FooMsg]> msgs that stores list messages I want to display in different tabs. I am not maintaining different properties for each tab. I can do that if the answer here is a No. Each message FooMsg has a field called tag that determines the Tab of the message.

Inside a Tab, Here is a psedo code that I use to filter the messages and display them.

for msg[i] in root.msgs {
   if msg.tag == root.tag { 
      Text {
         text : msg.text;
         row: i;
       }
   }
}

I was hoping for something like (pseudo code):

for msg in root.msg.filter( |x| x.tag == root.tag) {
   Text { text: msg.text, row : i };
}

Note that the value of i will be different in the second case. The second case is suitable for generating a grid-layout because i will take values that increase by 1 at each step and there won't be gaps.

In short, I am looking for a filter like function for the array before I can iterate over it. Suggestions?

dilawar avatar Jun 09 '22 06:06 dilawar

While this isn’t possible in pure Slint yet, you can do this if you provide your Mode from Rust and place it behind a FilterModel. Would that help?

tronical avatar Jun 09 '22 07:06 tronical

FWIW it would be nice to be able to write a filter like in your example in pure Slint as well.

tronical avatar Jun 09 '22 07:06 tronical

We just would need to find a good syntax for it.

// Like in rust
for xx in model.filter(|x| x.tag == root.tag) : Rectangle {
// like in JS
for xx in model.filter(x => x.tag == root.tag) : Rectangle {
// specialized syntax
for xx in model | #.tag == root.tag : Rectangle {

We also would probably need a map adapror syntax as well.
Maybe a sorting one too?

ogoffart avatar Jun 09 '22 07:06 ogoffart

Right, and we'd need the map/filter/sort in C++ as well. This sounds very well doable. My order of preference in syntax is JS > Rust > Special ;-)

tronical avatar Jun 09 '22 07:06 tronical

While this isn’t possible in pure Slint yet, you can do this if you provide your Mode from Rust and place it behind a FilterModel. Would that help?

Thanks! This might just work 🥳 .

dilawar avatar Jun 09 '22 09:06 dilawar

I also think the JS syntax is easier on the eyes than Rust syntax (especially when you are also supporting JS and C++).

dilawar avatar Jun 09 '22 09:06 dilawar

While this isn’t possible in pure Slint yet, you can do this if you provide your Mode from Rust and place it behind a FilterModel. Would that help?

Thanks again for the suggestion @tronical. It worked! Not sure if I am using it the most efficiently but for now it solves my problem.

        // Connect msglist to slint Window.
        let msglist_app = ModelRc::new(FilterModel::new(self.msglist.clone(), |s| s.code == "App"));
        self.window.unwrap().set_msglist(msglist_app);

dilawar avatar Jun 10 '22 05:06 dilawar

👍 We could leave this ticket open to track the ability to specify filters in .slint itself. If you're okay with that then I'll edit the title slightly to reflect the intent.

tronical avatar Jun 10 '22 07:06 tronical

@tronical Sounds good.

dilawar avatar Jun 10 '22 07:06 dilawar

Any other workarounds suggested for this? It seems like it makes maintaining the "one source of truth" that Slint seems to otherwise do pretty well break quickly without losing modularity.

jmgrosen avatar Jan 24 '24 18:01 jmgrosen