Skip to content

Commit

Permalink
Different design: more compact windows and collapsing/closing control…
Browse files Browse the repository at this point in the history
… on each tab bar (#237)

* Correct comment typos

* Add two buttons on tab bars

- Close all tabs: "×"
- Collapse all tabs: "▼"

* Add some utility for recursive node collapse checking

* Preliminary implementation of collapsing windows

* Handle tab collapsing layout

* Resize windows when subnodes collapsed

* Implements leaf close all button

* Update changelog

* Allow dragging to a collapsed leaf

* Fix collapsed state checking after dnd splits

* Update examples

* Update changelog

* Fix up changelog after rebase

* Fix failing test and rename `Translations::window` to `Translations::leaf`.

* Remove `Clone` bound on `map_tabs` and `filter_map_tabs` (#241)

* remove Clone bound on map_tabs and filter_map_tabs

* remove Clone bound from all functions with Clone + FnMut bounds

* Update changelog

* Add missing period in changelog

---------

Co-authored-by: Adanos020 <adanos020@gmail.com>

* Update crate version and add MSRV change to changelog

* Fix heading type in changelog

* Fix tab bar scroll bar width on window surfaces

* Add close window button in context menu

* Add minimize window button

* Update CHANGELOG.md

* Fix cargo test

* Add tooltips to right-clickable tab bar buttons

* Add minimization activation with modifiers

* Add close window with modifiers

* Correct tooltip display conditions

* Upgrade to egui 0.29

* Add secondary button feature toggle

* Cleanup code

* Update examples

* Fix cursor icon logic

* Update examples

* Update changelog

* Make Japanese translations in the example more consistent with each other

---------

Co-authored-by: Adanos020 <adanos020@gmail.com>
Co-authored-by: Ved_s <vedomir.samarin.03@gmail.com>
  • Loading branch information
3 people authored Oct 19, 2024
1 parent 179832d commit cb5f470
Show file tree
Hide file tree
Showing 15 changed files with 1,385 additions and 269 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/target
/Cargo.lock
/.idea
/.vscode
64 changes: 64 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,69 @@
# egui_dock changelog

## 0.15.0 - Unreleased

### Changed

- From ([#237](https://github.com/Adanos020/egui_dock/pull/237)):
- Each leaf can now be collapsed / closed individually. They are introduced as additional tab bar controls.
- Undocked windows are now more compact. The original undocked window controls are now accessible as "secondary buttons" from the tab bar.
- By default, the secondary buttons are activated from primary buttons either by holding the <kbd>Shift</kbd> key while clicking on them, or from a context menu by right-clicking them.
- A number of tooltip hints are on by default as guides to the new behavior, but they can be disabled.
- There has been an overhaul to the internal codebase to support the new features.

### Added

- From ([#237](https://github.com/Adanos020/egui_dock/pull/237)):
- `DockArea::show_leaf_close_all_buttons` – shows a close all button which closes all open tabs in a leaf.
- `DockArea::show_leaf_collapse_buttons` – shows a collapsing button which collapses a leaf (no longer collapsing a window).
- `DockArea::show_secondary_button_hint` – sets whether tooltip hints are shown for secondary buttons on tab bars.
- `DockArea::show_leaf_collapse_buttons` – shows a collapsing button which collapses a leaf (no longer collapsing a window).
- `DockArea::secondary_button_on_modifier` – sets whether the secondary buttons on tab bars are activated by the modifier key.
- `DockArea::secondary_button_context_menu` – sets whether the secondary buttons on tab bars are activated from a context value by right-clicking primary buttons.
- Added the following translations:
- `LeafTranslations::close_all_button`
- `LeafTranslations::close_all_button_menu_hint`
- `LeafTranslations::close_all_button_modifier_hint`
- `LeafTranslations::close_all_button_modifier_menu_hint`
- `LeafTranslations::close_all_button_disabled_tooltip`
- `LeafTranslations::minimize_button`
- `LeafTranslations::minimize_button_menu_hint`
- `LeafTranslations::minimize_button_modifier_hint`
- `LeafTranslations::minimize_button_modifier_menu_hint`
- `Node::is_collapsed` – returns whether the `Node` is collapsed.
- `Node::collapsed_leaf_count` – returns the number of collapsed layers of leaf subnodes.
- `Node::set_collapsed` – set the collapsing state of the `Node`.
- `Node::set_collapsed_leaf_count` – sets the number of collapsed layers of leaf subnodes.
- `WindowState::minimized` field – records whether a window is minimized.
- `WindowState::expanded_height` field – records the height of the window before it was fully collapsed.
- Added style configuration for the two buttons:
- `ButtonsStyle::{close_all_tabs, collapse_tabs, minimize_window}_color`
- `ButtonsStyle::{close_all_tabs, collapse_tabs, minimize_window}_active_color`
- `ButtonsStyle::{close_all_tabs, collapse_tabs, minimize_window}_bg_fill`
- `ButtonsStyle::{close_all_tabs, collapse_tabs, minimize_window}_border_color`
- `ButtonsStyle::close_all_tabs_disabled_color`
- `Style::TAB_CLOSE_ALL_BUTTON_SIZE`
- `Style::TAB_CLOSE_ALL_SIZE`
- `Style::TAB_COLLAPSE_BUTTON_SIZE`
- `Style::TAB_COLLAPSE_ARROW_SIZE`
- `Style::TAB_EXPAND_BUTTON_SIZE`
- `Style::TAB_EXPAND_ARROW_SIZE`

### Breaking changes

- From ([#237](https://github.com/Adanos020/egui_dock/pull/237)):
- Renamed `Translations::WindowTranslations` to `Translations::LeafTranslations`.
- Renamed `WindowTranslations::close_button_tooltip` to `LeafTranslations::close_button_disabled_tooltip`.
- `Translations::LeafTranslations` now requires more fields to be constructed (see **Added** section).

### Deprecated

- From ([#237](https://github.com/Adanos020/egui_dock/pull/237)):
- `DockArea::show_window_close_buttons` – no longer has any effect; consider using `DockArea::show_leaf_close_all_buttons`
instead.
- `DockArea::show_window_collapse_buttons` – no longer has any effect; consider using `DockArea::show_leaf_collapse_buttons`
instead.

## 0.14.0 - 2024-09-02

### Breaking changes
Expand Down
42 changes: 33 additions & 9 deletions examples/hello.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,11 @@ struct MyContext {
draggable_tabs: bool,
show_tab_name_on_hover: bool,
allowed_splits: AllowedSplits,
show_window_close: bool,
show_window_collapse: bool,
show_leaf_close_all: bool,
show_leaf_collapse: bool,
show_secondary_button_hint: bool,
secondary_button_on_modifier: bool,
secondary_button_context_menu: bool,
}

struct MyApp {
Expand Down Expand Up @@ -156,10 +159,25 @@ impl MyContext {
ui.checkbox(&mut self.show_add_buttons, "Show add buttons");
ui.checkbox(&mut self.draggable_tabs, "Draggable tabs");
ui.checkbox(&mut self.show_tab_name_on_hover, "Show tab name on hover");
ui.checkbox(&mut self.show_window_close, "Show close button on windows");
ui.checkbox(
&mut self.show_window_collapse,
"Show collaspse button on windows",
&mut self.show_leaf_close_all,
"Show close all button on tab bars",
);
ui.checkbox(
&mut self.show_leaf_collapse,
"Show collaspse button on tab bars",
);
ui.checkbox(
&mut self.secondary_button_on_modifier,
"Enable secondary buttons when modifiers (Shift by default) are pressed",
);
ui.checkbox(
&mut self.secondary_button_context_menu,
"Enable secondary buttons in right-click context menus",
);
ui.checkbox(
&mut self.show_secondary_button_hint,
"Show tooltip hints for secondary buttons",
);
ComboBox::new("cbox:allowed_splits", "Split direction(s)")
.selected_text(format!("{:?}", self.allowed_splits))
Expand Down Expand Up @@ -540,8 +558,11 @@ impl Default for MyApp {
style: None,
open_tabs,

show_window_close: true,
show_window_collapse: true,
show_leaf_close_all: true,
show_leaf_collapse: true,
show_secondary_button_hint: true,
secondary_button_on_modifier: true,
secondary_button_context_menu: true,
show_close_buttons: true,
show_add_buttons: false,
draggable_tabs: true,
Expand Down Expand Up @@ -599,8 +620,11 @@ impl eframe::App for MyApp {
.draggable_tabs(self.context.draggable_tabs)
.show_tab_name_on_hover(self.context.show_tab_name_on_hover)
.allowed_splits(self.context.allowed_splits)
.show_window_close_buttons(self.context.show_window_close)
.show_window_collapse_buttons(self.context.show_window_collapse)
.show_leaf_close_all_buttons(self.context.show_leaf_close_all)
.show_leaf_collapse_buttons(self.context.show_leaf_collapse)
.show_secondary_button_hint(self.context.show_secondary_button_hint)
.secondary_button_on_modifier(self.context.secondary_button_on_modifier)
.secondary_button_context_menu(self.context.secondary_button_context_menu)
.show_inside(ui, &mut self.context);
});
}
Expand Down
60 changes: 52 additions & 8 deletions src/dock_state/translations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pub struct Translations {
/// Text overrides for buttons in tab context menus.
pub tab_context_menu: TabContextMenuTranslations,
/// Text overrides for buttons in windows.
pub window: WindowTranslations,
pub leaf: LeafTranslations,
}

/// Specifies text in buttons displayed in the context menu displayed upon right-clicking on a tab.
Expand All @@ -18,21 +18,46 @@ pub struct TabContextMenuTranslations {
pub eject_button: String,
}

/// Specifies text in buttons displayed in the context menu displayed upon right-clicking on a tab.
/// Specifies text displayed in the primary buttons on a tab bar.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct WindowTranslations {
/// Message in the tooltip shown while hovering over a grayed out X button of a window
pub struct LeafTranslations {
/// Message in the tooltip shown while hovering over a grayed out X button of a leaf
/// containing non-closable tabs.
pub close_button_disabled_tooltip: String,
/// Button that closes the entire window.
pub close_all_button: String,
/// Message in the tooltip shown while hovering over an X button of a window.
/// Used when the secondary buttons are accessible from the context menu.
pub close_all_button_menu_hint: String,
/// Message in the tooltip shown while hovering over an X button of a window.
/// Used when the secondary buttons are accessible using modifiers.
pub close_all_button_modifier_hint: String,
/// Message in the tooltip shown while hovering over an X button of a window.
/// Used when the secondary buttons are accessible using modifiers and from the context menu.
pub close_all_button_modifier_menu_hint: String,
/// Message in the tooltip shown while hovering over a grayed out close window button of a window
/// containing non-closable tabs.
pub close_button_tooltip: String,
pub close_all_button_disabled_tooltip: String,
/// Button that minimizes the window.
pub minimize_button: String,
/// Message in the tooltip shown while hovering over a collapse button of a leaf.
/// Used when the secondary buttons are accessible from the context menu.
pub minimize_button_menu_hint: String,
/// Message in the tooltip shown while hovering over a collapse button of a leaf.
/// Used when the secondary buttons are accessible using modifiers.
pub minimize_button_modifier_hint: String,
/// Message in the tooltip shown while hovering over a collapse button of a leaf.
/// Used when the secondary buttons are accessible using modifiers and from the context menu.
pub minimize_button_modifier_menu_hint: String,
}

impl Translations {
/// Default English translations.
pub fn english() -> Self {
Self {
tab_context_menu: TabContextMenuTranslations::english(),
window: WindowTranslations::english(),
leaf: LeafTranslations::english(),
}
}
}
Expand All @@ -47,11 +72,30 @@ impl TabContextMenuTranslations {
}
}

impl WindowTranslations {
impl LeafTranslations {
/// Default English translations.
pub fn english() -> Self {
Self {
close_button_tooltip: String::from("This window contains non-closable tabs."),
close_button_disabled_tooltip: String::from("This leaf contains non-closable tabs."),
close_all_button: String::from("Close window"),
close_all_button_menu_hint: String::from("Right click to close this window."),
close_all_button_modifier_hint: String::from(
"Press modifier keys (Shift by default) to close this window.",
),
close_all_button_modifier_menu_hint: String::from(
"Press modifier keys (Shift by default) or right click to close this window.",
),
close_all_button_disabled_tooltip: String::from(
"This window contains non-closable tabs.",
),
minimize_button: String::from("Minimize window"),
minimize_button_menu_hint: String::from("Right click to minimize this window."),
minimize_button_modifier_hint: String::from(
"Press modifier keys (Shift by default) to minimize this window.",
),
minimize_button_modifier_menu_hint: String::from(
"Press modifier keys (Shift by default) or right click to minimize this window.",
),
}
}
}
86 changes: 86 additions & 0 deletions src/dock_state/tree/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ pub use tab_iter::TabIter;
use egui::ahash::HashSet;
use egui::Rect;
use std::{
cmp::max,
fmt,
ops::{Index, IndexMut},
slice::{Iter, IterMut},
Expand Down Expand Up @@ -125,6 +126,9 @@ pub struct Tree<Tab> {
// Binary tree vector
pub(super) nodes: Vec<Node<Tab>>,
focused_node: Option<NodeIndex>,
// Whether all subnodes of the tree is collapsed
collapsed: bool,
collapsed_leaf_count: i32,
}

impl<Tab> fmt::Debug for Tree<Tab> {
Expand All @@ -138,6 +142,8 @@ impl<Tab> Default for Tree<Tab> {
Self {
nodes: Vec::new(),
focused_node: None,
collapsed: false,
collapsed_leaf_count: 0,
}
}
}
Expand Down Expand Up @@ -166,6 +172,8 @@ impl<Tab> Tree<Tab> {
Self {
nodes: vec![root],
focused_node: None,
collapsed: false,
collapsed_leaf_count: 0,
}
}

Expand Down Expand Up @@ -520,6 +528,7 @@ impl<Tab> Tree<Tab> {
self[index[1]] = new;

self.focused_node = Some(index[1]);
self.node_update_collapsed(index[1]);

index
}
Expand Down Expand Up @@ -744,6 +753,8 @@ impl<Tab> Tree<Tab> {
let Tree {
focused_node,
nodes,
collapsed,
collapsed_leaf_count,
} = self;
let mut emptied_nodes = HashSet::default();
let nodes = nodes
Expand All @@ -760,6 +771,8 @@ impl<Tab> Tree<Tab> {
let mut new_tree = Tree {
nodes,
focused_node: *focused_node,
collapsed: *collapsed,
collapsed_leaf_count: *collapsed_leaf_count,
};
new_tree.balance(emptied_nodes);
new_tree
Expand Down Expand Up @@ -799,6 +812,26 @@ impl<Tab> Tree<Tab> {
self.balance(emptied_nodes);
}

/// Sets the collapsing state of the [`Tree`].
pub(crate) fn set_collapsed(&mut self, collapsed: bool) {
self.collapsed = collapsed;
}

/// Returns whether the [`Tree`] is collapsed.
pub(crate) fn is_collapsed(&self) -> bool {
self.collapsed
}

/// Sets the number of collapsed layers of leaf subnodes in the [`Tree`].
pub(crate) fn set_collapsed_leaf_count(&mut self, collapsed_leaf_count: i32) {
self.collapsed_leaf_count = collapsed_leaf_count;
}

/// Returns the number of collapsed layers of leaf subnodes in the [`Tree`].
pub(crate) fn collapsed_leaf_count(&self) -> i32 {
self.collapsed_leaf_count
}

fn balance(&mut self, emptied_nodes: HashSet<NodeIndex>) {
let mut emptied_parents = HashSet::default();
for parent_index in emptied_nodes.into_iter().filter_map(|ni| ni.parent()) {
Expand All @@ -817,6 +850,59 @@ impl<Tab> Tree<Tab> {
self.balance(emptied_parents);
}
}

/// Updates the collapsed state of the node and its parents.
pub(crate) fn node_update_collapsed(&mut self, node_index: NodeIndex) {
let collapsed = self[node_index].is_collapsed();
if !collapsed {
// Recursively notify parent nodes that the leaf has expanded
let mut parent_index_option = node_index.parent();
while let Some(parent_index) = parent_index_option {
parent_index_option = parent_index.parent();

// Update collapsed leaf count and collapse status
let left_count = self[parent_index.left()].collapsed_leaf_count();
let right_count = self[parent_index.right()].collapsed_leaf_count();
self[parent_index].set_collapsed(false);

if self[parent_index].is_horizontal() {
self[parent_index].set_collapsed_leaf_count(max(left_count, right_count));
} else {
self[parent_index].set_collapsed_leaf_count(left_count + right_count);
}
}
self.set_collapsed(false);
let root_index = NodeIndex::root();
self.set_collapsed_leaf_count(self[root_index].collapsed_leaf_count());
} else {
// Recursively notify parent nodes that the leaf has collapsed
let mut parent_index_option = node_index.parent();
while let Some(parent_index) = parent_index_option {
parent_index_option = parent_index.parent();

// Update collapsed leaf count and collapse status
let left_count = self[parent_index.left()].collapsed_leaf_count();
let right_count = self[parent_index.right()].collapsed_leaf_count();

if self[parent_index].is_horizontal() {
self[parent_index].set_collapsed_leaf_count(max(left_count, right_count));
} else {
self[parent_index].set_collapsed_leaf_count(left_count + right_count);
}

if self[parent_index.left()].is_collapsed()
&& self[parent_index.right()].is_collapsed()
{
self[parent_index].set_collapsed(true);
}
}
if self.root_node().is_some_and(|root| root.is_collapsed()) {
self.set_collapsed(true);
let root_index = NodeIndex::root();
self.set_collapsed_leaf_count(self[root_index].collapsed_leaf_count());
}
}
}
}

impl<Tab> Tree<Tab>
Expand Down
Loading

0 comments on commit cb5f470

Please sign in to comment.