diff --git a/CHANGELOG.md b/CHANGELOG.md index d6aedb5..c53eebe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,9 +14,11 @@ - `Tree::tabs`: an iterator over the tabs in a tree. ([#53](https://github.com/Adanos020/egui_dock/pull/53)) - `Style` now includes an option to show the hoverd tab's name. ([#56](https://github.com/Adanos020/egui_dock/pull/56)) - `Style` now includes an option to change default inner_margin. ([#67](https://github.com/Adanos020/egui_dock/pull/67)) +- The split separator now highlights on hover ([#68](https://github.com/Adanos020/egui_dock/pull/68)) ### Breaking changes - Renamed `TabViewer::inner_margin` to `TabViewer::inner_margin_override`. ([#67](https://github.com/Adanos020/egui_dock/pull/67)) +- `Style::with_separator_color` has been split into `separator_color_idle`, `separator_color_hovered`, `separator_color_dragged` ([#68](https://github.com/Adanos020/egui_dock/pull/68)) ### Deprecated (will be deleted in the next release) - `dynamic_tab::TabContent` diff --git a/examples/hello.rs b/examples/hello.rs index 615f157..279d4ae 100644 --- a/examples/hello.rs +++ b/examples/hello.rs @@ -113,8 +113,14 @@ impl MyContext { ui.separator(); - ui.label("Color"); - color_picker_color32(ui, &mut style.separator_color, Alpha::OnlyBlend); + ui.label("Idle color"); + color_picker_color32(ui, &mut style.separator_color_idle, Alpha::OnlyBlend); + + ui.label("Hovered color"); + color_picker_color32(ui, &mut style.separator_color_hovered, Alpha::OnlyBlend); + + ui.label("Dragged color"); + color_picker_color32(ui, &mut style.separator_color_dragged, Alpha::OnlyBlend); }); ui.collapsing("Tabs", |ui| { diff --git a/src/lib.rs b/src/lib.rs index ef38412..13f34ff 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -59,8 +59,10 @@ //! # }); //! ``` -use egui::style::Margin; -use egui::*; +use egui::{ + pos2, style::Margin, vec2, Context, CursorIcon, Frame, Id, LayerId, Order, Pos2, Rect, + Rounding, ScrollArea, Sense, Stroke, Ui, WidgetText, +}; #[allow(deprecated)] pub use crate::{ @@ -69,7 +71,8 @@ pub use crate::{ tree::{Node, NodeIndex, Split, TabIndex, Tree}, }; pub use egui; -use utils::*; + +use utils::expand_to_pixel; mod dynamic_tab; mod popup; @@ -257,7 +260,7 @@ impl<'tree, Tab> DockArea<'tree, Tab> { ui.painter().rect( rect, margin.top, - style.separator_color, + style.separator_color_idle, Stroke::new(margin.top, style.border_color), ); } @@ -289,14 +292,21 @@ impl<'tree, Tab> DockArea<'tree, Tab> { { let rect = expand_to_pixel(*rect, pixels_per_point); - let (left, separator, right) = if is_horizontal { + let (response, left, separator, right) = if is_horizontal { style.hsplit(ui, fraction, rect) } else { style.vsplit(ui, fraction, rect) }; - ui.painter() - .rect_filled(separator, Rounding::none(), style.separator_color); + let color = if response.dragged() { + style.separator_color_dragged + } else if response.hovered() { + style.separator_color_hovered + } else { + style.separator_color_idle + }; + + ui.painter().rect_filled(separator, Rounding::none(), color); self.tree[node_index.left()].set_rect(left); self.tree[node_index.right()].set_rect(right); diff --git a/src/style.rs b/src/style.rs index 6c67af6..d8a7de1 100644 --- a/src/style.rs +++ b/src/style.rs @@ -22,7 +22,9 @@ pub struct Style { pub separator_width: f32, pub separator_extra: f32, - pub separator_color: Color32, + pub separator_color_idle: Color32, + pub separator_color_hovered: Color32, + pub separator_color_dragged: Color32, pub tab_bar_background_color: Color32, @@ -65,7 +67,9 @@ impl Default for Style { selection_color: Color32::from_rgb(0, 191, 255).linear_multiply(0.5), separator_width: 1.0, separator_extra: 175.0, - separator_color: Color32::BLACK, + separator_color_idle: Color32::BLACK, + separator_color_hovered: Color32::GRAY, + separator_color_dragged: Color32::WHITE, tab_bar_background_color: Color32::WHITE, @@ -101,18 +105,22 @@ impl Style { /// Derives relevant fields from `egui::Style` and sets the remaining fields to their default values. /// /// Fields overwritten by [`egui::Style`] are: - /// - `selection_color` - /// - `tab_bar_background_color` - /// - `tab_outline_color` - /// - `tab_background_color` - /// - `separator_color` - /// - `border_color` - /// - `close_tab_background_color` - /// - `close_tab_color` - /// - `close_tab_active_color` - /// - `add_tab_background_color` - /// - `add_tab_color` - /// - `add_tab_active_color` + /// - [`Self::selection_color`] + /// - [`Self::tab_bar_background_color`] + /// - [`Self::tab_outline_color`] + /// - [`Self::tab_background_color`] + /// - [`Self::tab_text_color_unfocused`] + /// - [`Self::tab_text_color_focused`] + /// - [`Self::separator_color_idle`] + /// - [`Self::separator_color_hovered`] + /// - [`Self::separator_color_dragged`] + /// - [`Self::border_color`] + /// - [`Self::close_tab_background_color`] + /// - [`Self::close_tab_color`] + /// - [`Self::close_tab_active_color`] + /// - [`Self::add_tab_background_color`] + /// - [`Self::add_tab_color`] + /// - [`Self::add_tab_active_color`] pub fn from_egui(style: &egui::Style) -> Self { Self { selection_color: style.visuals.selection.bg_fill.linear_multiply(0.5), @@ -124,7 +132,10 @@ impl Style { tab_text_color_unfocused: style.visuals.text_color(), tab_text_color_focused: style.visuals.strong_text_color(), - separator_color: style.visuals.widgets.active.bg_fill, + separator_color_idle: style.visuals.widgets.noninteractive.bg_stroke.color, + separator_color_hovered: style.visuals.widgets.hovered.bg_stroke.color, + separator_color_dragged: style.visuals.widgets.active.bg_stroke.color, + border_color: style.visuals.widgets.active.bg_fill, close_tab_background_color: style.visuals.widgets.active.bg_fill, @@ -138,7 +149,12 @@ impl Style { } } - pub(crate) fn hsplit(&self, ui: &mut Ui, fraction: &mut f32, rect: Rect) -> (Rect, Rect, Rect) { + pub(crate) fn hsplit( + &self, + ui: &mut Ui, + fraction: &mut f32, + rect: Rect, + ) -> (Response, Rect, Rect, Rect) { let pixels_per_point = ui.ctx().pixels_per_point(); let mut separator = rect; @@ -173,13 +189,19 @@ impl Style { ); ( + response, rect.intersect(Rect::everything_right_of(separator.max.x)), separator, rect.intersect(Rect::everything_left_of(separator.min.x)), ) } - pub(crate) fn vsplit(&self, ui: &mut Ui, fraction: &mut f32, rect: Rect) -> (Rect, Rect, Rect) { + pub(crate) fn vsplit( + &self, + ui: &mut Ui, + fraction: &mut f32, + rect: Rect, + ) -> (Response, Rect, Rect, Rect) { let pixels_per_point = ui.ctx().pixels_per_point(); let mut separator = rect; @@ -214,6 +236,7 @@ impl Style { ); ( + response, rect.intersect(Rect::everything_above(separator.min.y)), separator, rect.intersect(Rect::everything_below(separator.max.y)), @@ -451,10 +474,24 @@ impl StyleBuilder { self } - /// Sets `separator_color`for the rectangle separator. By `Default` it's [`Color32::BLACK`]. + /// Sets the idle color for the rectangle separator. By `Default` it's [`Color32::BLACK`]. #[inline(always)] - pub fn with_separator_color(mut self, separator_color: Color32) -> Self { - self.style.separator_color = separator_color; + pub fn with_separator_color_idle(mut self, separator_color_idle: Color32) -> Self { + self.style.separator_color_idle = separator_color_idle; + self + } + + /// Sets the hovered color for the rectangle separator. By `Default` it's [`Color32::GRAY`]. + #[inline(always)] + pub fn with_separator_color_hovered(mut self, separator_color_hovered: Color32) -> Self { + self.style.separator_color_hovered = separator_color_hovered; + self + } + + /// Sets the dragged color for the rectangle separator. By `Default` it's [`Color32::WHITE`]. + #[inline(always)] + pub fn with_separator_color_dragged(mut self, separator_color_dragged: Color32) -> Self { + self.style.separator_color_dragged = separator_color_dragged; self } diff --git a/src/tree.rs b/src/tree.rs index 2259848..29ab67b 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -1,4 +1,4 @@ -use egui::*; +use egui::Rect; /// Identifies a tab within a [`Node`]. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)] diff --git a/src/utils.rs b/src/utils.rs index 18f6920..25d6440 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,14 +1,14 @@ -use egui::*; +use egui::{Pos2, Rect}; #[inline(always)] -pub fn expand_to_pixel(mut rect: Rect, ppi: f32) -> egui::Rect { +pub fn expand_to_pixel(mut rect: Rect, ppi: f32) -> Rect { rect.min = map_to_pixel_pos(rect.min, ppi, f32::floor); rect.max = map_to_pixel_pos(rect.max, ppi, f32::ceil); rect } #[inline(always)] -pub fn map_to_pixel_pos(mut pos: Pos2, ppi: f32, map: fn(f32) -> f32) -> egui::Pos2 { +pub fn map_to_pixel_pos(mut pos: Pos2, ppi: f32, map: fn(f32) -> f32) -> Pos2 { pos.x = map_to_pixel(pos.x, ppi, map); pos.y = map_to_pixel(pos.y, ppi, map); pos