Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multi-viewport support #203

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ include = ["src/**/*.rs", "Cargo.toml", "LICENSE"]

[features]
default = []
viewports = []

# Enable serialization of `Tree`.
serde = ["dep:serde", "egui/serde"]
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
[![github](https://img.shields.io/badge/github-Adanos020/egui_dock-8da0cb?logo=github)](https://github.com/Adanos020/egui_dock)
[![Crates.io](https://img.shields.io/crates/v/egui_dock)](https://crates.io/crates/egui_dock)
[![docs.rs](https://img.shields.io/docsrs/egui_dock)](https://docs.rs/egui_dock/)
[![egui_version](https://img.shields.io/badge/egui-0.25-blue)](https://github.com/emilk/egui)
[![egui_version](https://img.shields.io/badge/egui-0.24-blue)](https://github.com/emilk/egui)

Originally created by [@lain-dono](https://github.com/lain-dono), this library provides a docking system for `egui`.

Expand Down Expand Up @@ -33,7 +33,7 @@ Add `egui` and `egui_dock` to your project's dependencies.
```toml
[dependencies]
egui = "0.25"
egui_dock = "0.10"
egui_dock = "0.11"
```

Then proceed by setting up `egui`, following its [quick start guide](https://github.com/emilk/egui#quick-start).
Expand Down
35 changes: 29 additions & 6 deletions src/dock_state/window_state.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
use egui::{Id, Pos2, Rect, Vec2};

#[cfg(feature = "viewports")]
use egui::ViewportBuilder;

#[cfg(not(feature = "viewports"))]
use egui::Window;

/// The state of a [`Surface::Window`](crate::Surface::Window).
///
/// Doubles as a handle for the surface, allowing the user to set its size and position.
Expand Down Expand Up @@ -77,13 +83,30 @@ impl WindowState {
self.next_size.take()
}

//the 'static in this case means that the `open` field is always `None`
pub(crate) fn create_window(&mut self, id: Id, bounds: Rect) -> (egui::Window<'static>, bool) {
#[cfg(feature = "viewports")]
pub(crate) fn create_window(&mut self, id: Id, bounds: Rect) -> (ViewportBuilder, bool) {
let new = self.new;
let mut viewport_builder = ViewportBuilder::default()
.with_decorations(false)
.with_resizable(true)
.with_drag_and_drop(true);

if let Some(position) = self.next_position() {
viewport_builder = viewport_builder.with_position(position);
}
if let Some(size) = self.next_size() {
viewport_builder = viewport_builder.with_inner_size(size);
}

self.new = false;
(viewport_builder, new)
}

// The 'static in this case means that the `open` field is always `None`
#[cfg(not(feature = "viewports"))]
pub(crate) fn create_window(&mut self, id: Id, bounds: Rect) -> (Window<'static>, bool) {
let new = self.new;
let mut window_constructor = egui::Window::new("")
.id(id)
.constrain_to(bounds)
.title_bar(false);
let mut window_constructor = Window::new("").id(id).constrain_to(bounds).title_bar(false);

if let Some(position) = self.next_position() {
window_constructor = window_constructor.current_pos(position);
Expand Down
125 changes: 81 additions & 44 deletions src/widgets/dock_area/show/window_surface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ use egui::{
TextStyle, Ui, Vec2, Widget,
};

#[cfg(feature = "viewports")]
use egui::{CentralPanel, ViewportId};

use crate::{
dock_area::{state::State, tab_removal::TabRemoval},
utils::fade_visuals,
DockArea, Node, Style, SurfaceIndex, TabViewer,
dock_area::state::State, utils::fade_visuals, DockArea, Node, Style, SurfaceIndex, TabViewer,
};

impl<'tree, Tab> DockArea<'tree, Tab> {
Expand Down Expand Up @@ -72,51 +73,87 @@ impl<'tree, Tab> DockArea<'tree, Tab> {
frame.shadow.color = frame.shadow.color.linear_multiply(fade_factor);
}

window
.frame(frame)
.min_width(min_window_width(&title, ui.spacing().indent))
.show(ui.ctx(), |ui| {
//fade inner ui (if necessary)
if fade_factor != 1.0 {
fade_visuals(ui.visuals_mut(), fade_factor);
// Finds out if theres a reason for the close button to be disabled
// by iterating over the tree and finding if theres any non-closable nodes.
let disabled = !self.dock_state[surf_index]
.iter_mut()
.filter_map(|node| {
if let Node::Leaf { tabs, .. } = node {
Some(
tabs.iter_mut()
.map(|tab| tab_viewer.closeable(tab))
.all(identity),
)
} else {
None
}
})
.all(identity);

let collapser_id = id.with("collapser");
let collapser_state = new.then_some(true);
let ch_res = self.show_window_body(
ui,
surf_index,
tab_viewer,
state,
fade_style,
collapser_state,
collapser_id,
title,
);
if self.show_window_close_buttons {
// Finds out if theres a reason for the close button to be disabled
// by iterating over the tree and finding if theres any non-closable nodes.
let disabled = !self.dock_state[surf_index]
.iter_mut()
.filter_map(|node| {
if let Node::Leaf { tabs, .. } = node {
Some(
tabs.iter_mut()
.map(|tab| tab_viewer.closeable(tab))
.all(identity),
)
} else {
None
}
})
.all(identity);
#[cfg(feature = "viewports")]
{
let window = window
.with_close_button(self.show_window_close_buttons && disabled)
.with_title(title.text());
ui.ctx().show_viewport_immediate(
ViewportId::from_hash_of(id),
window,
|ctx, viewport_class| {
CentralPanel::default().show(ctx, |ui| {
if fade_factor != 1.0 {
fade_visuals(ui.visuals_mut(), fade_factor);
}

self.show_close_button(ui, &mut open, ch_res, disabled);
}
});
let collapser_id = id.with("collapser");
let collapser_state = new.then_some(true);
let ch_res = self.show_window_body(
ui,
surf_index,
tab_viewer,
state,
fade_style,
collapser_state,
collapser_id,
title,
);
if self.show_window_close_buttons {
self.show_close_button(ui, &mut open, ch_res, disabled);
}
});
},
)
}
#[cfg(not(feature = "viewports"))]
{
window
.frame(frame)
.min_width(min_window_width(&title, ui.spacing().indent))
.show(ui.ctx(), |ui| {
//fade inner ui (if neccesary)
if fade_factor != 1.0 {
fade_visuals(ui.visuals_mut(), fade_factor);
}

if !open {
self.to_remove.push(TabRemoval::Window(surf_index));
let collapser_id = id.with("collapser");
let collapser_state = new.then_some(true);
let ch_res = self.show_window_body(
ui,
surf_index,
tab_viewer,
state,
fade_style,
collapser_state,
collapser_id,
title,
);
if self.show_window_close_buttons {
self.show_close_button(ui, &mut open, ch_res, disabled);
}
});

if !open {
self.to_remove.push(TabRemoval::Window(surf_index));
}
}
}

Expand Down
Loading