Skip to content

Commit

Permalink
Added #[derive(Serialize, Deserialize)] to the Style structs under th…
Browse files Browse the repository at this point in the history
…e serde feature (#227)

* Fix docking on empty main surface. (#222)

* Fix docking on empty main surface.

* Update changelog and bump patch number.

* Bugfixes (#225)

* Fix visual bug happening while a tab is being dragged.

* Fix crash on retaining tabs.

* Fix `filter_map_tabs` leaving leaf nodes empty.

* Update changelog

* Revert simple.rs

* Bump patch version number.

* added the derives

---------

Co-authored-by: Adam Gąsior <adanos020@gmail.com>
  • Loading branch information
Quinntyx and Adanos020 authored Feb 28, 2024
1 parent 2fce1be commit ea50ca1
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 13 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# egui_dock changelog

## 0.11.2 - 2024-02-16

### Fixed
From [#225](https://github.com/Adanos020/egui_dock/pull/225):
- Tabs now always appear at the pointer position while being dragged.
- Retaining tabs no longer breaks the binary tree leading to a panic.
- Filtering tabs no longer leaves some leaves empty and now correctly rearranges the tree.

## 0.11.1 - 2024-02-09

### Fixed
- Bug where tabs couldn't be re-docked onto the main surface if it's empty ([#222](https://github.com/Adanos020/egui_dock/pull/222))

## 0.11.0 - 2024-02-06

### Added
Expand Down
46 changes: 37 additions & 9 deletions src/dock_state/tree/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub use node_index::NodeIndex;
pub use tab_index::TabIndex;
pub use tab_iter::TabIter;

use egui::ahash::HashSet;
use egui::Rect;
use std::{
fmt,
Expand Down Expand Up @@ -744,20 +745,24 @@ impl<Tab> Tree<Tab> {
focused_node,
nodes,
} = self;
let mut emptied_nodes = HashSet::default();
let nodes = nodes
.iter()
.filter_map(|node| {
.enumerate()
.map(|(index, node)| {
let node = node.filter_map_tabs(function.clone());
match node {
Node::Leaf { ref tabs, .. } => (!tabs.is_empty()).then_some(node),
_ => Some(node),
if node.is_empty() {
emptied_nodes.insert(NodeIndex(index));
}
node
})
.collect();
Tree {
let mut new_tree = Tree {
nodes,
focused_node: *focused_node,
}
};
new_tree.balance(emptied_nodes);
new_tree
}

/// Returns a new [`Tree`] while mapping the tab type.
Expand All @@ -784,10 +789,33 @@ impl<Tab> Tree<Tab> {
where
F: Clone + FnMut(&mut Tab) -> bool,
{
self.nodes.retain_mut(|node| {
let mut emptied_nodes = HashSet::default();
for (index, node) in self.nodes.iter_mut().enumerate() {
node.retain_tabs(predicate.clone());
!node.is_empty()
});
if node.is_empty() {
emptied_nodes.insert(NodeIndex(index));
}
}
self.balance(emptied_nodes);
}

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()) {
if self[parent_index.left()].is_empty() && self[parent_index.right()].is_empty() {
self[parent_index] = Node::Empty;
emptied_parents.insert(parent_index);
} else if self[parent_index.left()].is_empty() {
self.nodes.swap(parent_index.0, parent_index.right().0);
self[parent_index.right()] = Node::Empty;
} else if self[parent_index.right()].is_empty() {
self.nodes.swap(parent_index.0, parent_index.left().0);
self[parent_index.left()] = Node::Empty;
}
}
if !emptied_parents.is_empty() {
self.balance(emptied_parents);
}
}
}

Expand Down
11 changes: 11 additions & 0 deletions src/style.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ pub enum TabAddAlign {
/// #
/// ```
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[allow(missing_docs)]
pub struct Style {
/// Sets padding to indent from the edges of the window. By `Default` it's `None`.
Expand All @@ -63,6 +64,7 @@ pub struct Style {

/// Specifies the look and feel of buttons.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct ButtonsStyle {
/// Color of the close tab button.
pub close_tab_color: Color32,
Expand Down Expand Up @@ -91,6 +93,7 @@ pub struct ButtonsStyle {

/// Specifies the look and feel of node separators.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct SeparatorStyle {
/// Width of the rectangle separator between nodes. By `Default` it's `1.0`.
pub width: f32,
Expand All @@ -115,6 +118,7 @@ pub struct SeparatorStyle {

/// Specifies the look and feel of tab bars.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct TabBarStyle {
/// Background color of tab bar. By `Default` it's [`Color32::WHITE`].
pub bg_fill: Color32,
Expand All @@ -138,6 +142,7 @@ pub struct TabBarStyle {

/// Specifies the look and feel of an individual tab.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct TabStyle {
/// Style of the tab when it is active.
pub active: TabInteractionStyle,
Expand Down Expand Up @@ -177,6 +182,7 @@ pub struct TabStyle {

/// Specifies the look and feel of individual tabs while they are being interacted with.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct TabInteractionStyle {
/// Color of the outline around tabs. By `Default` it's [`Color32::BLACK`].
pub outline_color: Color32,
Expand All @@ -193,6 +199,7 @@ pub struct TabInteractionStyle {

/// Specifies the look and feel of the tab body.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct TabBodyStyle {
/// Inner margin of tab body. By `Default` it's `Margin::same(4.0)`.
pub inner_margin: Margin,
Expand All @@ -209,6 +216,7 @@ pub struct TabBodyStyle {

/// Specifies the look and feel of the tab drop overlay.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct OverlayStyle {
/// Sets selection color for the placing area of the tab where this tab targeted on it.
/// By `Default` it's `(0, 191, 255)` (light blue) with `0.5` capacity.
Expand Down Expand Up @@ -246,6 +254,7 @@ pub struct OverlayStyle {

/// Specifies the feel of the tab drop overlay, i.e anything non visual about the overlay.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct OverlayFeel {
/// range is `0.0..=1.0`.
pub window_drop_coverage: f32,
Expand All @@ -265,6 +274,7 @@ pub struct OverlayFeel {

/// Specifies the type of overlay used.
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub enum OverlayType {
/// Shows highlighted areas predicting where a dropped tab would land were it to be dropped this frame.
///
Expand All @@ -279,6 +289,7 @@ pub enum OverlayType {

/// Highlighting on the currently hovered leaf.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct LeafHighlighting {
/// Fill color.
pub color: Color32,
Expand Down
6 changes: 3 additions & 3 deletions src/widgets/dock_area/show/leaf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ impl<'tree, Tab> DockArea<'tree, Tab> {
.with((tab_index, "tab"));
let tab_index = TabIndex(tab_index);
let is_being_dragged = tabs_ui.memory(|mem| mem.is_being_dragged(id))
&& tabs_ui.input(|i| i.pointer.primary_down() || i.pointer.primary_released())
&& tabs_ui.input(|i| i.pointer.is_decidedly_dragging())
&& self.draggable_tabs;

if is_being_dragged {
Expand Down Expand Up @@ -255,8 +255,7 @@ impl<'tree, Tab> DockArea<'tree, Tab> {
.response;
let title_id = response.id;

let sense = Sense::click_and_drag();
let response = tabs_ui.interact(response.rect, id, sense);
let response = tabs_ui.interact(response.rect, id, Sense::click_and_drag());

if let Some(pointer_pos) = tabs_ui.ctx().pointer_interact_pos() {
let start = *state.drag_start.get_or_insert(pointer_pos);
Expand Down Expand Up @@ -369,6 +368,7 @@ impl<'tree, Tab> DockArea<'tree, Tab> {
// the underlying tab
if state.drag_start.is_some() && response.rect.contains(pos) {
self.tab_hover_rect = Some((response.rect, tab_index));
state.drag_start = None;
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/widgets/dock_area/show/main_surface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ impl<'tree, Tab> DockArea<'tree, Tab> {
if self.dock_state.main_surface().is_empty() {
let rect = ui.available_rect_before_wrap();
let response = ui.allocate_rect(rect, Sense::hover());
if response.hovered() {
if response.contains_pointer() {
self.hover_data = Some(HoverData {
rect,
dst: TreeComponent::Surface(surf_index),
Expand Down

0 comments on commit ea50ca1

Please sign in to comment.