Skip to content

Commit f3396e4

Browse files
committed
Updates to TabViewer::{is_closable,on_close}.
1 parent be9bedf commit f3396e4

File tree

4 files changed

+87
-59
lines changed

4 files changed

+87
-59
lines changed

examples/hello.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use egui::{
99
WidgetText,
1010
};
1111

12+
use egui_dock::tab_viewer::OnCloseResponse;
1213
use egui_dock::{
1314
AllowedSplits, DockArea, DockState, NodeIndex, OverlayType, Style, SurfaceIndex,
1415
TabInteractionStyle, TabViewer,
@@ -119,13 +120,13 @@ impl TabViewer for MyContext {
119120
}
120121
}
121122

122-
fn closeable(&mut self, tab: &mut Self::Tab) -> bool {
123+
fn is_closeable(&self, tab: &mut Self::Tab) -> bool {
123124
["Inspector", "Style Editor"].contains(&tab.as_str())
124125
}
125126

126-
fn on_close(&mut self, tab: &mut Self::Tab) -> bool {
127+
fn on_close(&mut self, tab: &mut Self::Tab) -> OnCloseResponse {
127128
self.open_tabs.remove(tab);
128-
true
129+
OnCloseResponse::Close
129130
}
130131
}
131132

examples/simple.rs

+6
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
use eframe::{egui, NativeOptions};
44

5+
use egui_dock::tab_viewer::OnCloseResponse;
56
use egui_dock::{DockArea, DockState, NodeIndex, Style};
67

78
fn main() -> eframe::Result<()> {
@@ -25,6 +26,11 @@ impl egui_dock::TabViewer for TabViewer {
2526
fn ui(&mut self, ui: &mut egui::Ui, tab: &mut Self::Tab) {
2627
ui.label(format!("Content of {tab}"));
2728
}
29+
30+
fn on_close(&mut self, _tab: &mut Self::Tab) -> OnCloseResponse {
31+
println!("Closed tab: {_tab}");
32+
OnCloseResponse::Focus
33+
}
2834
}
2935

3036
struct MyApp {

src/widgets/dock_area/show/leaf.rs

+45-40
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use crate::{
1616
};
1717

1818
use crate::popup::popup_under_widget;
19+
use crate::tab_viewer::OnCloseResponse;
1920

2021
impl<Tab> DockArea<'_, Tab> {
2122
pub(super) fn show_leaf(
@@ -205,7 +206,7 @@ impl<Tab> DockArea<'_, Tab> {
205206
let disabled = if let Node::Leaf { tabs, .. } =
206207
&mut self.dock_state[surface_index][node_index]
207208
{
208-
!tabs.iter_mut().all(|tab| tab_viewer.closeable(tab))
209+
!tabs.iter_mut().all(|tab| tab_viewer.is_closeable(tab))
209210
} else {
210211
unreachable!()
211212
};
@@ -214,7 +215,7 @@ impl<Tab> DockArea<'_, Tab> {
214215
let close_window_disabled = disabled
215216
|| !self.dock_state[surface_index].iter_mut().all(|node| {
216217
if let Node::Leaf { tabs, .. } = node {
217-
tabs.iter_mut().all(|tab| tab_viewer.closeable(tab))
218+
tabs.iter_mut().all(|tab| tab_viewer.is_closeable(tab))
218219
} else {
219220
true
220221
}
@@ -307,7 +308,7 @@ impl<Tab> DockArea<'_, Tab> {
307308
*active == tab_index || is_being_dragged,
308309
tab_viewer.title(&mut tabs[tab_index.0]),
309310
tab_style.unwrap_or(style.tab.clone()),
310-
tab_viewer.closeable(&mut tabs[tab_index.0]),
311+
tab_viewer.is_closeable(&mut tabs[tab_index.0]),
311312
)
312313
};
313314

@@ -392,14 +393,14 @@ impl<Tab> DockArea<'_, Tab> {
392393
let close_button =
393394
Button::new(&self.dock_state.translations.tab_context_menu.close_button);
394395

395-
let Node::Leaf { tabs, active, .. } =
396-
&mut self.dock_state[surface_index][node_index]
397-
else {
398-
unreachable!()
399-
};
400-
let tab = &mut tabs[tab_index.0];
401-
402396
response.context_menu(|ui| {
397+
let Node::Leaf { tabs, .. } =
398+
&mut self.dock_state[surface_index][node_index]
399+
else {
400+
unreachable!()
401+
};
402+
let tab = &mut tabs[tab_index.0];
403+
403404
tab_viewer.context_menu(ui, tab, surface_index, node_index);
404405
if (surface_index.is_main() || !is_lonely_tab)
405406
&& tab_viewer.allowed_in_windows(tab)
@@ -409,33 +410,14 @@ impl<Tab> DockArea<'_, Tab> {
409410
ui.close_menu();
410411
}
411412
if show_close_button && ui.add(close_button).clicked() {
412-
if tab_viewer.on_close(tab) {
413-
self.to_remove
414-
.push((surface_index, node_index, tab_index).into());
415-
} else {
416-
*active = tab_index;
417-
self.new_focused = Some((surface_index, node_index));
418-
}
413+
self.close_tab(tab_viewer, surface_index, node_index, tab_index);
419414
ui.close_menu();
420415
}
421416
});
422417
}
423418

424419
if close_clicked {
425-
let Node::Leaf { tabs, active, .. } =
426-
&mut self.dock_state[surface_index][node_index]
427-
else {
428-
unreachable!()
429-
};
430-
let tab = &mut tabs[tab_index.0];
431-
432-
if tab_viewer.on_close(tab) {
433-
self.to_remove
434-
.push((surface_index, node_index, tab_index).into());
435-
} else {
436-
*active = tab_index;
437-
self.new_focused = Some((surface_index, node_index));
438-
}
420+
self.close_tab(tab_viewer, surface_index, node_index, tab_index);
439421
}
440422

441423
if let Some(pos) = state.last_hover_pos {
@@ -477,17 +459,40 @@ impl<Tab> DockArea<'_, Tab> {
477459
self.new_focused = Some((surface_index, node_index));
478460
}
479461

480-
if self.show_close_buttons && tab_viewer.closeable(tab) && response.middle_clicked() {
481-
if tab_viewer.on_close(tab) {
482-
self.to_remove
483-
.push((surface_index, node_index, tab_index).into());
484-
} else {
485-
*active = tab_index;
486-
self.new_focused = Some((surface_index, node_index));
487-
}
462+
tab_viewer.on_tab_button(tab, &response);
463+
464+
if self.show_close_buttons && tab_viewer.is_closeable(tab) && response.middle_clicked()
465+
{
466+
self.close_tab(tab_viewer, surface_index, node_index, tab_index);
488467
}
468+
}
469+
}
489470

490-
tab_viewer.on_tab_button(tab, &response);
471+
fn close_tab(
472+
&mut self,
473+
tab_viewer: &mut impl TabViewer<Tab = Tab>,
474+
surface_index: SurfaceIndex,
475+
node_index: NodeIndex,
476+
tab_index: TabIndex,
477+
) {
478+
let Node::Leaf { tabs, active, .. } = &mut self.dock_state[surface_index][node_index]
479+
else {
480+
unreachable!()
481+
};
482+
let tab = &mut tabs[tab_index.0];
483+
484+
match tab_viewer.on_close(tab) {
485+
OnCloseResponse::Close => {
486+
self.to_remove
487+
.push((surface_index, node_index, tab_index).into());
488+
}
489+
OnCloseResponse::Focus => {
490+
*active = tab_index;
491+
self.new_focused = Some((surface_index, node_index));
492+
}
493+
OnCloseResponse::Ignore => {
494+
// no-op
495+
}
491496
}
492497
}
493498

src/widgets/tab_viewer.rs

+32-16
Original file line numberDiff line numberDiff line change
@@ -35,21 +35,35 @@ pub trait TabViewer {
3535
/// Called after each tab button is shown, so you can add a tooltip, check for clicks, etc.
3636
fn on_tab_button(&mut self, _tab: &mut Self::Tab, _response: &egui::Response) {}
3737

38+
/// This is called when the `_tab` gets closed by the user.
39+
///
40+
/// Returns an `OnCloseResponse` which determines what happens to the tab after this function gets called.
41+
fn on_close(&mut self, _tab: &mut Self::Tab) -> OnCloseResponse {
42+
OnCloseResponse::Close
43+
}
44+
45+
/// Returns `true` if the user of your app should be able to close a given `_tab`.
46+
///
47+
/// By default, `true` is always returned.
48+
fn is_closeable(&self, _tab: &mut Self::Tab) -> bool {
49+
true
50+
}
51+
3852
/// Returns `true` if the user of your app should be able to close a given `_tab`.
3953
///
40-
/// By default `true` is always returned.
54+
/// By default, `true` is always returned.
55+
#[deprecated = "Use the `TabViewer::is_closeable` function instead."]
4156
fn closeable(&mut self, _tab: &mut Self::Tab) -> bool {
4257
true
4358
}
4459

45-
/// This is called when the `_tab` gets closed by the user.
60+
/// This is called every frame after [`ui`](Self::ui) is called, if the `_tab` is active.
4661
///
47-
/// Returns `true` if the tab should close immediately, otherwise `false`.
62+
/// Returns `true` if the tab should be forced to close, `false` otherwise.
4863
///
49-
/// **Note**: if `false` is returned, [`ui`](Self::ui) will still be called once more if this
50-
/// tab is active.
51-
fn on_close(&mut self, _tab: &mut Self::Tab) -> bool {
52-
true
64+
/// In the event this function returns true the tab will be removed without calling `on_close`.
65+
fn force_close(&mut self, _tab: &mut Self::Tab) -> bool {
66+
false
5367
}
5468

5569
/// This is called when the add button is pressed.
@@ -64,15 +78,6 @@ pub trait TabViewer {
6478
/// [`DockArea::show_add_popup`](crate::DockArea::show_add_popup) are set to `true`.
6579
fn add_popup(&mut self, _ui: &mut Ui, _surface: SurfaceIndex, _node: NodeIndex) {}
6680

67-
/// This is called every frame after [`ui`](Self::ui) is called, if the `_tab` is active.
68-
///
69-
/// Returns `true` if the tab should be forced to close, `false` otherwise.
70-
///
71-
/// In the event this function returns true the tab will be removed without calling `on_close`.
72-
fn force_close(&mut self, _tab: &mut Self::Tab) -> bool {
73-
false
74-
}
75-
7681
/// Sets custom style for given tab.
7782
fn tab_style_override(&self, _tab: &Self::Tab, _global_style: &TabStyle) -> Option<TabStyle> {
7883
None
@@ -98,3 +103,14 @@ pub trait TabViewer {
98103
[true, true]
99104
}
100105
}
106+
107+
/// Determines what happens to a tab when a user attempts to close it.
108+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
109+
pub enum OnCloseResponse {
110+
/// Closes the tab.
111+
Close,
112+
/// Focuses on the tab.
113+
Focus,
114+
/// Ignores the close request.
115+
Ignore,
116+
}

0 commit comments

Comments
 (0)