GithubHelp home page GithubHelp logo

rerun-io / egui_tiles Goto Github PK

View Code? Open in Web Editor NEW
257.0 7.0 20.0 271 KB

A tiling layout engine for egui with drag-and-drop and resizing

License: Apache License 2.0

Shell 0.45% Rust 91.80% Python 7.75%
egui gui

egui_tiles's Introduction

egui_tiles

github Latest version Documentation unsafe forbidden Build Status MIT Apache

Layouting and docking for egui.

Supports:

  • Horizontal and vertical layouts
  • Grid layouts
  • Tabs
  • Drag-and-drop docking

egui_tiles

Trying it

cargo r --example simple

Comparison with egui_dock

egui_dock is an excellent crate serving similar needs. egui_tiles aims to become a more flexible and feature-rich alternative to egui_dock.

egui_dock only supports binary splits (left/right or top/bottom), while egui_tiles support full horizontal and vertical layouts, as well as grid layouts. egui_tiles also strives to be more customizable, enabling users to override the default style and behavior by implementing methods on a Behavior trait.

egui_dock supports some features that egui_tiles does not yet support, such as close-buttons on each tab, and built-in scroll areas.


egui_tiles development is sponsored by Rerun, a startup doing
visualizations for computer vision and robotics.

egui_tiles's People

Contributors

abey79 avatar bennjii avatar emilk avatar gohla avatar guillaumeschmid avatar jleibs avatar liquidhelium avatar mcoroz avatar mkrueger avatar rydb avatar teh-cmc avatar tosti007 avatar voidburn avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

egui_tiles's Issues

Where are the close buttons?

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:

mkrueger@b8c5259

But I don't consider the approach good/general enough for making a PR. This needs some more thought/design IMO.

Ability to give names besides "tabs" to a container which holds sub-tabs

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"

Properly reflow grid with `move_tile_to_container()`

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:

Bug `v0.2.0`: Id clash when using multiple `Tree`s

With the release of v0.2.0, it is not longer possible to create multiple Trees 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.

Example with multiple Pane types?

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!

Make it easier to find the active 'tile'.

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:

grafik

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.

on_tab_button in behavior is mostly useless.

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 :).

Changed `TileId`s after drag

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 Panes 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 TileIds 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!

Duplicate Id when creating 2 pane trees in the same app.

I have 2 separate pane trees in 2 different areas of my user interface.
They have different behaviors and I don't want to mix the panes between the 2 trees.
I noticed that both trees when rendering creates same Ids for pane separator:
image
Is this a bug or is there a way to avoid this?

An easier way to define the initial layout from code

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

Docking of tiles

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:

  • Dragging out a tile into a new viewport
  • Dragging one viewport onto another viewport, merging the two
  • Dragging tiles between viewports

Detecting that one viewport is being dragged onto another is complicated without:

tree.ui sprawls outside of Window when not using CentralPanel.

I'd like to add egui_tiles to my app, but it seems Trees don't scale with the ui when they're not in a CentralPanel?

I tested with examples/simple.rs, but changed CentralPanel to Window, and the below is what I got.

#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release

use egui::Grid;

struct Pane {
    nr: usize,
}

struct TreeBehavior {}

impl egui_tiles::Behavior<Pane> for TreeBehavior {
    fn tab_title_for_pane(&mut self, pane: &Pane) -> egui::WidgetText {
        format!("Pane {}", pane.nr).into()
    }

    fn pane_ui(
        &mut self,
        ui: &mut egui::Ui,
        _tile_id: egui_tiles::TileId,
        pane: &mut Pane,
    ) -> egui_tiles::UiResponse {
        // Give each pane a unique color:
        let color = egui::epaint::Hsva::new(0.103 * pane.nr as f32, 0.5, 0.5, 1.0);
        ui.painter().rect_filled(ui.max_rect(), 0.0, color);

        ui.label(format!("The contents of pane {}.", pane.nr));

        // You can make your pane draggable like so:
        if ui
            .add(egui::Button::new("Drag me!").sense(egui::Sense::drag()))
            .drag_started()
        {
            egui_tiles::UiResponse::DragStarted
        } else {
            egui_tiles::UiResponse::None
        }
    }
}

fn main() -> Result<(), eframe::Error> {
    env_logger::init(); // Log to stderr (if you run with `RUST_LOG=debug`).

    let options = eframe::NativeOptions {
        viewport: egui::ViewportBuilder::default().with_inner_size([320.0, 240.0]),
        ..Default::default()
    };

    let mut tree = create_tree();

    eframe::run_simple_native("My egui App", options, move |ctx, _frame| {
        egui::Window::new("test window")
        //.min_size((250.0, 250.0))
        .show(ctx, |ui| {
            let mut behavior = TreeBehavior {};
            tree.ui(&mut behavior, ui);
        });
    })
}

fn create_tree() -> egui_tiles::Tree<Pane> {
    let mut next_view_nr = 0;
    let mut gen_pane = || {
        let pane = Pane { nr: next_view_nr };
        next_view_nr += 1;
        pane
    };

    let mut tiles = egui_tiles::Tiles::default();

    let mut tabs = vec![];
    tabs.push({
        let children = (0..7).map(|_| tiles.insert_pane(gen_pane())).collect();
        tiles.insert_horizontal_tile(children)
    });
    tabs.push({
        let cells = (0..11).map(|_| tiles.insert_pane(gen_pane())).collect();
        tiles.insert_grid_tile(cells)
    });
    tabs.push(tiles.insert_pane(gen_pane()));

    let root = tiles.insert_tab_tile(tabs);



    egui_tiles::Tree::new("my_tree", root, tiles)
}

ui_in_window

Aspect Ratios in grids?

Is there a way to have aspect ratios in grids? Perhaps this would be a good addition to egui_tiles.

Add `tiles` argument to `Behavior` functions

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.

Apparent dependency problem with crates.io package

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" }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.