rerun-io / egui_tiles

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

Optional close-buttons on tabs #70

Closed voidburn closed 5 months ago

voidburn commented 6 months ago

This is a proposal for close buttons on tabs. It should be backwards compatible (defaulting to no buttons).

Override Behavior::is_tab_closable to add a close-button to a tab.

Notes

voidburn commented 6 months ago

P.S. In my personal implementation I commented out all .on_hover_cursor(egui::CursorIcon::Grab) except for the one that changes the cursor while dragging, as they were overriding all my attempts to change the cursor to a pointer when over the close button. I don't know how that would've impacted existing implementations so I left them in this PR.

Cursor changes in question:

As a result, the mouse cursor remains the drag hand even when hovering the close button.

voidburn commented 5 months ago

Thanks for the comments, I'll get to it during the week or next weekend! Everything looks very reasonable!

emilk commented 5 months ago

P.S. In my personal implementation I commented out all .on_hover_cursor(egui::CursorIcon::Grab) except for the one that changes the cursor while dragging, as they were overriding all my attempts to change the cursor to a pointer when over the close button. I don't know how that would've impacted existing implementations so I left them in this PR.

Cursor changes in question:

As a result, the mouse cursor remains the drag hand even when hovering the close button.

If you want to have a normal cursor when hovering the close-button, try this:

--- a/src/behavior.rs
+++ b/src/behavior.rs
@@ -105,7 +105,9 @@ pub trait Behavior<Pane> {
             + f32::from(state.closable) * (close_btn_left_padding + close_btn_size.x);
         let (_, tab_rect) = ui.allocate_space(vec2(button_width, ui.available_height()));

-        let tab_response = ui.interact(tab_rect, id, Sense::click_and_drag());
+        let tab_response = ui
+            .interact(tab_rect, id, Sense::click_and_drag())
+            .on_hover_cursor(egui::CursorIcon::Grab);

         // Show a gap when dragged
         if ui.is_rect_visible(tab_rect) && !state.is_being_dragged {
@@ -139,7 +141,8 @@ pub trait Behavior<Pane> {

                 // Allocate
                 let close_btn_id = ui.auto_id_with("tab_close_btn");
-                let close_btn_response = ui.interact(close_btn_rect, close_btn_id, Sense::click());
+                let close_btn_response =
+                    ui.interact(close_btn_rect, close_btn_id, Sense::click_and_drag());

                 let visuals = ui.style().interact(&close_btn_response);

diff --git a/src/container/tabs.rs b/src/container/tabs.rs
index 13455fc..e88e49c 100644
--- a/src/container/tabs.rs
+++ b/src/container/tabs.rs
@@ -303,7 +303,6 @@ impl Tabs {

                             let response =
                                 behavior.tab_ui(&mut tree.tiles, ui, id, child_id, tab_state);
-                            let response = response.on_hover_cursor(egui::CursorIcon::Grab);
                             if response.clicked() {
                                 behavior.on_edit(EditAction::TabSelected);
                                 next_active = Some(child_id);

This also forbids dragging the close-button, for better or for worse

voidburn commented 5 months ago

P.S. In my personal implementation I commented out all .on_hover_cursor(egui::CursorIcon::Grab) except for the one that changes the cursor while dragging, as they were overriding all my attempts to change the cursor to a pointer when over the close button. I don't know how that would've impacted existing implementations so I left them in this PR. Cursor changes in question:

As a result, the mouse cursor remains the drag hand even when hovering the close button.

If you want to have a normal cursor when hovering the close-button, try this:

--- a/src/behavior.rs
+++ b/src/behavior.rs
@@ -105,7 +105,9 @@ pub trait Behavior<Pane> {
             + f32::from(state.closable) * (close_btn_left_padding + close_btn_size.x);
         let (_, tab_rect) = ui.allocate_space(vec2(button_width, ui.available_height()));

-        let tab_response = ui.interact(tab_rect, id, Sense::click_and_drag());
+        let tab_response = ui
+            .interact(tab_rect, id, Sense::click_and_drag())
+            .on_hover_cursor(egui::CursorIcon::Grab);

         // Show a gap when dragged
         if ui.is_rect_visible(tab_rect) && !state.is_being_dragged {
@@ -139,7 +141,8 @@ pub trait Behavior<Pane> {

                 // Allocate
                 let close_btn_id = ui.auto_id_with("tab_close_btn");
-                let close_btn_response = ui.interact(close_btn_rect, close_btn_id, Sense::click());
+                let close_btn_response =
+                    ui.interact(close_btn_rect, close_btn_id, Sense::click_and_drag());

                 let visuals = ui.style().interact(&close_btn_response);

diff --git a/src/container/tabs.rs b/src/container/tabs.rs
index 13455fc..e88e49c 100644
--- a/src/container/tabs.rs
+++ b/src/container/tabs.rs
@@ -303,7 +303,6 @@ impl Tabs {

                             let response =
                                 behavior.tab_ui(&mut tree.tiles, ui, id, child_id, tab_state);
-                            let response = response.on_hover_cursor(egui::CursorIcon::Grab);
                             if response.clicked() {
                                 behavior.on_edit(EditAction::TabSelected);
                                 next_active = Some(child_id);

This also forbids dragging the close-button, for better or for worse

I added a way to customize it, let me know if you want it to default to something different. I think everything looks good now!

emilk commented 5 months ago

I think everything looks good now!

The CI disagrees

emilk commented 5 months ago

Thanks!

voidburn commented 5 months ago

Thank you for Egui and all these goodies, happy to help!