1
0
mirror of https://github.com/emilk/egui.git synced 2026-06-27 07:03:14 -04:00
Files
egui/examples/dock/src/main.rs
Emil Ernerfeldt e84eef7815 Code cleanup
2023-05-04 21:59:45 +02:00

287 lines
8.1 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
use eframe::egui;
use egui_extras::dock;
fn main() -> Result<(), eframe::Error> {
env_logger::init(); // Log to stderr (if you run with `RUST_LOG=debug`).
let options = eframe::NativeOptions {
initial_window_size: Some(egui::vec2(800.0, 600.0)),
..Default::default()
};
eframe::run_native(
"Dock",
options,
Box::new(|cc| {
let mut app = MyApp::default();
if let Some(storage) = cc.storage {
if let Some(state) = eframe::get_value(storage, eframe::APP_KEY) {
app = state;
}
}
Box::new(app)
}),
)
}
#[derive(serde::Deserialize, serde::Serialize)]
pub struct View {
nr: usize,
}
impl std::fmt::Debug for View {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("View").field("nr", &self.nr).finish()
}
}
impl View {
pub fn with_nr(nr: usize) -> Self {
Self { nr }
}
pub fn ui(&mut self, ui: &mut egui::Ui) -> dock::UiResponse {
let color = egui::epaint::Hsva::new(0.1 * self.nr as f32, 0.5, 0.5, 1.0);
ui.painter().rect_filled(ui.max_rect(), 0.0, color);
let dragged = ui
.allocate_rect(ui.max_rect(), egui::Sense::drag())
.on_hover_cursor(egui::CursorIcon::Grab)
.dragged();
if dragged {
dock::UiResponse::DragStarted
} else {
dock::UiResponse::None
}
}
}
struct DockBehavior {
simplification_options: dock::SimplificationOptions,
tab_bar_height: f32,
gap_width: f32,
add_child_to: Option<dock::NodeId>,
}
impl Default for DockBehavior {
fn default() -> Self {
Self {
simplification_options: Default::default(),
tab_bar_height: 24.0,
gap_width: 2.0,
add_child_to: None,
}
}
}
impl DockBehavior {
fn ui(&mut self, ui: &mut egui::Ui) {
let Self {
simplification_options,
tab_bar_height,
gap_width,
add_child_to: _,
} = self;
egui::Grid::new("behavior_ui")
.num_columns(2)
.show(ui, |ui| {
ui.label("All leaves must have tabs:");
ui.checkbox(&mut simplification_options.all_leaves_must_have_tabs, "");
ui.end_row();
ui.label("Tab bar height:");
ui.add(
egui::DragValue::new(tab_bar_height)
.clamp_range(0.0..=100.0)
.speed(1.0),
);
ui.end_row();
ui.label("Gap width:");
ui.add(
egui::DragValue::new(gap_width)
.clamp_range(0.0..=20.0)
.speed(1.0),
);
ui.end_row();
});
}
}
impl dock::Behavior<View> for DockBehavior {
fn leaf_ui(
&mut self,
ui: &mut egui::Ui,
_node_id: dock::NodeId,
view: &mut View,
) -> dock::UiResponse {
view.ui(ui)
}
fn tab_title_for_leaf(&mut self, view: &View) -> egui::WidgetText {
format!("View {}", view.nr).into()
}
fn top_bar_rtl_ui(&mut self, ui: &mut egui::Ui, node_id: dock::NodeId) {
if ui.button("").clicked() {
self.add_child_to = Some(node_id);
}
}
// ---
// Settings:
fn tab_bar_height(&self, _style: &egui::Style) -> f32 {
self.tab_bar_height
}
fn gap_width(&self, _style: &egui::Style) -> f32 {
self.gap_width
}
fn simplification_options(&self) -> dock::SimplificationOptions {
self.simplification_options
}
}
#[derive(serde::Deserialize, serde::Serialize)]
struct MyApp {
dock: dock::Dock<View>,
#[serde(skip)]
behavior: DockBehavior,
#[serde(skip)]
last_dock_debug: String,
}
impl Default for MyApp {
fn default() -> Self {
let mut next_view_nr = 0;
let mut gen_view = || {
let view = View::with_nr(next_view_nr);
next_view_nr += 1;
view
};
let mut nodes = dock::Nodes::default();
let mut tabs = vec![];
let tab_node = {
let children = (0..7).map(|_| nodes.insert_leaf(gen_view())).collect();
nodes.insert_tab_node(children)
};
tabs.push(tab_node);
tabs.push({
let children = (0..7).map(|_| nodes.insert_leaf(gen_view())).collect();
nodes.insert_horizontal_node(children)
});
tabs.push({
let children = (0..7).map(|_| nodes.insert_leaf(gen_view())).collect();
nodes.insert_vertical_node(children)
});
tabs.push({
let cells = (0..12).map(|_| nodes.insert_leaf(gen_view())).collect();
nodes.insert_grid_node(cells)
});
tabs.push(nodes.insert_leaf(gen_view()));
let root = nodes.insert_tab_node(tabs);
let dock = dock::Dock::new(root, nodes);
Self {
dock,
behavior: Default::default(),
last_dock_debug: Default::default(),
}
}
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::SidePanel::left("tree").show(ctx, |ui| {
if ui.button("Reset").clicked() {
*self = Default::default();
}
self.behavior.ui(ui);
ui.separator();
tree_ui(ui, &mut self.behavior, &mut self.dock.nodes, self.dock.root);
if let Some(parent) = self.behavior.add_child_to.take() {
let new_child = self.dock.nodes.insert_leaf(View::with_nr(100));
if let Some(dock::Node::Branch(dock::Branch::Tabs(tabs))) =
self.dock.nodes.get_mut(parent)
{
tabs.add_child(new_child);
tabs.set_active(new_child);
}
}
ui.separator();
ui.style_mut().wrap = Some(false);
let dock_debug = format!("{:#?}", self.dock);
ui.monospace(&dock_debug);
if self.last_dock_debug != dock_debug {
self.last_dock_debug = dock_debug;
log::debug!("{}", self.last_dock_debug);
}
});
egui::CentralPanel::default().show(ctx, |ui| {
self.dock.ui(&mut self.behavior, ui);
});
}
fn save(&mut self, storage: &mut dyn eframe::Storage) {
eframe::set_value(storage, eframe::APP_KEY, &self);
}
}
fn tree_ui(
ui: &mut egui::Ui,
behavior: &mut dyn dock::Behavior<View>,
nodes: &mut dock::Nodes<View>,
node_id: dock::NodeId,
) {
// Get the name BEFORE we remove the node below!
let text = format!(
"{} - {node_id:?}",
behavior.tab_title_for_node(nodes, node_id).text()
);
let Some(mut node) = nodes.nodes.remove(&node_id) else {
log::warn!("Missing node {node_id:?}");
return;
};
egui::CollapsingHeader::new(text)
.id_source((node_id, "tree"))
.default_open(true)
.show(ui, |ui| match &mut node {
dock::Node::Leaf(_) => {}
dock::Node::Branch(branch) => {
let mut layout = branch.get_layout();
egui::ComboBox::from_label("Layout")
.selected_text(format!("{:?}", layout))
.show_ui(ui, |ui| {
for typ in dock::Layout::ALL {
ui.selectable_value(&mut layout, typ, format!("{:?}", typ))
.clicked();
}
});
if layout != branch.get_layout() {
branch.set_layout(layout);
}
for &child in branch.children() {
tree_ui(ui, behavior, nodes, child);
}
}
});
nodes.nodes.insert(node_id, node);
}