rerun-io / egui_tiles Goto Github PK
View Code? Open in Web Editor NEWA tiling layout engine for egui with drag-and-drop and resizing
License: Apache License 2.0
A tiling layout engine for egui with drag-and-drop and resizing
License: Apache License 2.0
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:
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
Is there a way to have aspect ratios in grids? Perhaps this would be a good addition to egui_tiles.
It's a nice library but I really miss the close buttons for tab items. Is there any support planed for that?
Or am I missing something?
For the mean time I hacked close buttons into egui_tiles:
But I don't consider the approach good/general enough for making a PR. This needs some more thought/design IMO.
As the title says. This feels like a generally useful feature that would benefit many project.
This is needed for cases where data needs to prepared for every visible tile before getting the pane_ui
callback (potentially in parallel).
When inserting a new Pane
into Tiles
, it returns a new TileId
. The behavior I'd expect is for this TileId
to consistently refer to the same Pane
throughout the lifetime of the Tree
.
However, this seems this is not the case; when a e.g. Tabs
container with two Pane
s is changed into a Horizontal
Container
, my first Pane
's TileId
refers to the Horitonzal
Container
in which the Pane
's TileId
is stored.
Would it be possible to keep current TileId
s always refer to the same Tile
? Not only would this remove the need to manually keep track of which CustomId
belongs to which Pane
, it would also fit (atleast in my opinion) the mental model of a TileId
better.
I'm also fine with implementing it myself and saw the insert
function, but I'm unsure whether that's the correct place, so would like some small pointers for it.
Thanks!
AFAICT (apologies, I'm very new to the egui
ecosystem and feeling my way around and possibly missing things) if I have nested tabs eg.
let top_level_tab1: TileId = tiles.insert_tab_tile(tabs1);
let top_level_tab2: TileId = tiles.insert_tab_tile(tabs2);
let top_level_tabs = tiles.insert_tab_tile(vec![top_level_tab1, top_level_tab2])
Container::new_tabs(top_level_tabs)
There's no function to assign a name to top_level_tab1
and top_level_tab2
. They're both just labelled "Tabs"
Any function which has a tile_id: TileId
argument should also have a tiles: &Tiles<Pane>
argument, such as to be able to retrieve state.
Example use case: tab_bg_color()
. Having tiles
would enable retrieving the "selected" state of the space view and returning a proper background colour.
I recently found this crate and it is exactly what I needed and solves problems I was struggling with when using egui by itself. Thanks! However, I'm running into an issue and I can't figure out a way (I'm new to Rust, and that doesn't help):
What's the best way to implement multiple types of Pane, all in the same tree? I can see that the tree.ui(behavior, ui)
function takes in a single behavior at the root, and I assume the individual Panes can have their own types that implement the Behavior trait, but... as soon as I use tiles.insert_pane(PaneType)
with two different Pane types (both implementing Behavior) I get a "mismatched types" compiler error, even when I implementing the trait for Box<(dyn MyPaneType + 'static)>
types, hoping to get around the type error.
I also tried getting around it by using an enum and handling each pane type in a match statement, but I'm still running into issues when passing data from the app to the panes, since the pane_ui
function defined in the Behavior trait doesn't allow passing custom data. Or does it? I can't figure it out.
Long story short, would it be possible to add a tiny, very simple example that demonstrates using two different pane types that ideally display data from the main App, instead of creating multiple panes with the same Behavior as the examples currently do?
Thank you so much!
The move_tile_to_container()
function accepts a reflow_grid
parameter which, when set to true
, should trigger a behaviour that is meaningful in the context of a 1D representation of the grid, for example the rerun's blueprint tree.
Currently, when a tile is moved within the same grid, it's swapped with the destination tile instead of being properly "1D-reflowed". This leads to undesirable behaviour:
Is there a standard way doing that?
The active tile could be made more visible btw. atm it's really lacking in that department.
Or can you tell me which file is selected here:
For a library like that getting the selected document is vital.
ps. I can probably hack up a solution to that but this would be my 4th feature that's not going to be taken. I think that many users will run into that problem. Adding tiles should be easier as well.
Doing an application with documents & dockable tool windows should be as easy as possible.
Can't find a way to do this. The Shares struct is private.
egui recently got support for multi-viewports (many native windows).
I'd like to be able to drag out a tile from the root egui viewport, spawning a new viewport containing that tile. That is, something like how browser tabs can be detached from their parent window into their own windows, and then dragged back into the parent window again.
For this to work well we should support:
Detecting that one viewport is being dragged onto another is complicated without:
Line 16 in f835c4d
I believe it's a typo and should be "construct".
when I compile my code with the published version 0.7.2
of egui_tiles
these errors appeared
Compiling egui_tiles v0.7.2
error: expected identifier, found keyword `dyn`
--> C:\Users\9awcj\.cargo\registry\src\index.crates.io-6f17d22bba15001f\egui_tiles-0.7.2\src\behavior.rs:26:20
|
26 | pub trait Behavior<dyn Pane> {
| ^^^ expected identifier, found keyword
error: expected one of `,`, `:`, `=`, or `>`, found `Pane`
--> C:\Users\9awcj\.cargo\registry\src\index.crates.io-6f17d22bba15001f\egui_tiles-0.7.2\src\behavior.rs:26:24
|
26 | pub trait Behavior<dyn Pane> {
| ^^^^ expected one of `,`, `:`, `=`, or `>`
error[E0432]: unresolved import `crate::behavior::EditAction`
--> C:\Users\9awcj\.cargo\registry\src\index.crates.io-6f17d22bba15001f\egui_tiles-0.7.2\src\container\grid.rs:4:5
|
4 | use crate::behavior::EditAction;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `EditAction` in `behavior`
error[E0432]: unresolved import `crate::behavior::EditAction`
--> C:\Users\9awcj\.cargo\registry\src\index.crates.io-6f17d22bba15001f\egui_tiles-0.7.2\src\container\linear.rs:4:5
|
4 | use crate::behavior::EditAction;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `EditAction` in `behavior`
error[E0432]: unresolved import `crate::behavior::EditAction`
--> C:\Users\9awcj\.cargo\registry\src\index.crates.io-6f17d22bba15001f\egui_tiles-0.7.2\src\container\tabs.rs:3:5
|
3 | use crate::behavior::EditAction;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `EditAction` in `behavior`
error[E0432]: unresolved import `crate::behavior::EditAction`
--> C:\Users\9awcj\.cargo\registry\src\index.crates.io-6f17d22bba15001f\egui_tiles-0.7.2\src\tree.rs:3:5
|
3 | use crate::behavior::EditAction;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `EditAction` in `behavior`
error[E0432]: unresolved imports `behavior::Behavior`, `behavior::EditAction`
--> C:\Users\9awcj\.cargo\registry\src\index.crates.io-6f17d22bba15001f\egui_tiles-0.7.2\src\lib.rs:125:20
|
125 | pub use behavior::{Behavior, EditAction};
| ^^^^^^^^ ^^^^^^^^^^ no `EditAction` in `behavior`
| |
| no `Behavior` in `behavior`
For more information about this error, try `rustc --explain E0432`.
error: could not compile `egui_tiles` (lib) due to 7 previous errors
but if I use the commit c2dae1
that its technically the same version, the errors doesn't shows. I don't know if something went wrong in the packaging version..
egui_tiles = { git = "https://github.com/rerun-io/egui_tiles.git", rev="c2dae1eaa27ba1a4e92fa538b98b112b38db97e7" }
With the release of v0.2.0
, it is not longer possible to create multiple Tree
s within a single frame, as this results in id clashes. With v0.1.0
this wasn't an issue.
In the specific case I'm having, I have three Tabbed
containers, the id clash egui
gives me is on the first Tab
button of each Tree
Container
.
The biggest use case for that in many applications would be adding a context menu.
But this doesn't work:
fn on_tab_button(
&mut self,
tiles: &Tiles<Tab>,
tile_id: TileId,
button_response: &Response,
) {
button_response.context_menu(|ui| {
if ui
.button("close")
.clicked()
{
ui.close_menu();
}
// etc.
});
}
Changing that to would fix the problem.
fn on_tab_button(
&mut self,
tiles: &Tiles<Tab>,
tile_id: TileId,
button_response: Response,
) -> Response
{
button_response.context_menu(|ui| {
if ui
.button("close")
.clicked()
{
ui.close_menu();
}
// etc.
})
}
One proposed change would be:
#23
EDIT:
Thanks for making this library. I'm currently developing some sort of drawing/editing tool. This lib will make it shine :).
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.