slint icon indicating copy to clipboard operation
slint copied to clipboard

Datastructure that represents a tree (recursive datastructures)

Open codecat opened this issue 2 years ago • 4 comments

This is not possible (which makes perfect sense):

struct Foo {
  foo: Foo,
}

But I think this should be possible, as it would allow us to create tree structures:

struct Foo {
  children: [Foo],
}

codecat avatar Dec 26 '23 12:12 codecat

True, it should be possible to have recursive datastructure. We would need that for recursive sub-menus ( https://github.com/slint-ui/slint/issues/38 ) and maybe treeview kind.

This should be made possible:

struct Foo {
  children: [Foo],
}

But also

struct Foo {
  children: [{ id: string, node: Foo }] 
}

But unfortunately this is not possible:

struct Bar { id: string, node: Foo } 
struct Foo { children: [Bar] } 

Because there is no concept of forward declaration.

Also: this is currently valid code:

struct Foo { xxx: int }
struct Foo { children: [Foo] }

And changing this to take another meaning of Foo would be a breaking change. Although I guess no-one would do that. We could make this a warning a few version before.

ogoffart avatar Dec 27 '23 08:12 ogoffart

Just to add a voice to this issue, I've spent the past few weeks assessing slint and creating sample controls and apps. I think this is a really good framework.

I also think that this feature (the ability for a struct to self-reference/express a tree) is a make-or-break feature for this framework. If there were some kind of parallel to a Turing-completeness test for a UI framework, tree expression would be a part of the test.

Personally, I cannot build apps without this. The types of apps I build depend too much on logic-generated and recusrive visual elements. Even something as simple as creating a rich text control cannot be reasonably done without this feature.

I've never contributed to a project like slint before, but I would be happy to do so if it would get this feature rolling. I think this framework deserves it!

Sullux avatar May 25 '24 21:05 Sullux

Depending what you're trying to do, a tree can be represented as a flatten list. (For example to build a treeview, like in cargo-ui ), or use id-like things to get the value in native code.

For example, in Slint

struct MenuItem {
   text: string,
   icon: image,
   id: int, // could also be a string.
}

global MenuLogic {
   // Given a menu's id, fetch the children for that submenu
   pure callback fetch-children(int) -> [MenuItem];
}

And then the tree is held in native code and there you can have tree structure, without the need to declare a tree structure in Slint.

What is really your usecase for this feature?

ogoffart avatar Jun 05 '24 07:06 ogoffart

@ogoffart Thanks for your response!

I actually tried exactly what you describe. What you've posted is a good way to use logic to dictate UI in slint.

The shortcoming of your example is in turning it from a flat list into a tree. I'll simplify this example for brevity:

struct MenuData {
   text: string,
   id: int, // could also be a string.
   children: [int],
}

global MenuLogic {
    // Given a menu's id, fetch the children for that submenu
   pure callback fetch-children(int) -> [MenuData];
}

export component MenuItem {
    in-out property <MenuData> data;
    in property <int> indent: 0;
    VerticalLayout {
        Text {
            text: data.text;
            x: 10px * indent;
        }
        for child in data.children: MenuItem {
            data: MenuLogic.fetch-children(child);
            indent: root.indent + 1;
        }
    }
}

The above produces a compile error: unknown type MenuItem. It's the MenuItem referenced in the for loop. That is what we need to work before slint can be used for complex UI development. That feature is needed for trees, nested menus, rich text editing and a host of other use cases.

Sullux avatar Jun 05 '24 17:06 Sullux