rerun-io / egui_tiles

A tiling layout engine for egui with drag-and-drop and resizing
Apache License 2.0
302 stars 25 forks source link

An easier way to define the initial layout from code #46

Open EriKWDev opened 9 months ago

EriKWDev commented 9 months ago

I really like this extension to egui! I've written several apps at my previous work using egui_dock, but I am now switching to egui_tiles for my current company's game engine. Adding docking/tiles to egui really takes the gui to the next level.

The thing that was not so nice about egui_dock was the way in which you defined the initial layout of all the tabs and panes in code. If I really put my head to it, I was able to get the layout I wanted, but after coming back to the code way later it was always a pain.

Sadly, I felt the same now that I came back to my layout code for egui_tiles. I feel like there should be a way to describe the layout I want in a more expressive and editable way rather than a bunch of calls to set_share and needing to have good names for panes/tiles/tabs and manually inserting them into the correct Container. Maybe it's just me, but not knowing the internals of egui_tiles there seem to be a lot of concepts to learn for the user.

I usually don't advocate for crazy macros, but I feel like there could be a use for one here just to make the initial creation of the Tree really ergonomic. Perhaps this can even be done with plain functions - implementation detail.

Here is my current layout:

image

And it would be lovely to be able to express it in a way like this:

// (all panes defined above) 

let initial_layout = egui_tiles::layout_helper! {
    horizontal(1.0, {
        tabs(0.7, [scene_pane, profiler_pane, game_pane]),
        vertical(0.3, {
            tabs(0.5, [inspector_pane]),
            tabs(0.3, [scene_settings_pane]),
            tabs(0.2, [assets_pane]),
        }),
    })
};
let root = tiles.insert_new(initial_layout);
let tree = Tree::new("application_tree", root, tiles);

rather than

// (all panes defined above)

let mut inner_right = Linear {
    children: vec![inspector, scene_settings, assets],
    dir: LinearDir::Vertical,
    ..Default::default()
};
inner_right.shares.set_share(inspector, 0.5);
inner_right.shares.set_share(scene_settings, 0.3);
inner_right.shares.set_share(assets, 0.2);
let right = tiles.insert_new(Tile::Container(Container::Linear(inner_right)));

let left_tabs = tiles.insert_tab_tile(vec![scene_view, profiler, game]);

let mut inner_left = Linear {
    children: vec![left_tabs],
    dir: LinearDir::Vertical,
    ..Default::default()
};
inner_left.shares.set_share(left_tabs , 1.0);
let left = tiles.insert_new(Tile::Container(Container::Linear(inner_left)));

let mut inner = Linear {
    children: vec![left, right],
    dir: LinearDir::Horizontal,
    ..Default::default()
};
inner.shares.set_share(left, 0.7);
inner.shares.set_share(right, 0.3);
let root = tiles.insert_new(Tile::Container(Container::Linear(inner)));

let tree = Tree::new("application_tree", root, tiles);

Maybe I'm just using egui_tiles poorly though and there are some hidden gems here that I've not discovered to make the layout cleaner/readable xP

Ben-Ku commented 7 months ago

Seems like a really nice idea, defining panes right now is really a pain atm.

GlitchlessCode commented 2 months ago

Out of interest to see if I could do it, I've been working on a macro that does pretty much what you asked (the syntax I decided on is slightly different, but otherwise does what you want). I'm done the macro and it works well, I'm just writing up documentation and some tests and then I'll send in a PR.