#[cfg(all(not(target_arch = "wasm32"), feature = "desktop"))]
use crate::simple_vnode::VNode;
use std::rc::Rc;
use std::sync::{Arc, Mutex};
#[cfg(all(not(target_arch = "wasm32"), feature = "desktop"))]
pub struct DockingApp {
title: String,
render_fn: Rc<dyn Fn() -> VNode>,
needs_rerender: Arc<Mutex<bool>>,
dock_state: Arc<Mutex<egui_dock::DockState<String>>>,
}
#[cfg(all(not(target_arch = "wasm32"), feature = "desktop"))]
impl DockingApp {
pub fn new<F>(title: String, render_fn: F) -> Self
where
F: Fn() -> VNode + 'static,
{
let mut dock_state = egui_dock::DockState::new(vec!["main".to_string()]);
let main_surface = dock_state.main_surface_mut();
let [_main, _right] = main_surface.split_right(
egui_dock::NodeIndex::root(),
0.8, vec!["properties".to_string()],
);
let [_files, _editor] = main_surface.split_left(
egui_dock::NodeIndex::root(),
0.2, vec!["files".to_string()],
);
let [_, _console] = main_surface.split_below(
egui_dock::NodeIndex::root(),
0.75, vec!["console".to_string()],
);
Self {
title,
render_fn: Rc::new(render_fn),
needs_rerender: Arc::new(Mutex::new(true)),
dock_state: Arc::new(Mutex::new(dock_state)),
}
}
pub fn run(self) {
use crate::desktop_renderer::DesktopRenderer;
println!("🔧 Starting DockingApp (native with egui_dock)");
let needs_rerender = self.needs_rerender.clone();
crate::app_reactive_eframe::set_render_callback(move || {
*needs_rerender.lock().unwrap() = true;
});
let render_fn = self.render_fn.clone();
let needs_rerender = self.needs_rerender.clone();
let dock_state = self.dock_state.clone();
let mut renderer = DesktopRenderer::new();
let native_options = eframe::NativeOptions {
viewport: egui::ViewportBuilder::default()
.with_inner_size([1200.0, 800.0])
.with_title(&self.title),
..Default::default()
};
eframe::run_simple_native(&self.title, native_options, move |ctx, _frame| {
if *needs_rerender.lock().unwrap() {
*needs_rerender.lock().unwrap() = false;
ctx.request_repaint();
}
let vnode = (render_fn)();
let panels = extract_panels_from_vnode(&vnode);
let mut dock_state_guard = dock_state.lock().unwrap();
egui_dock::DockArea::new(&mut *dock_state_guard).show(
ctx,
&mut TabViewer {
panels,
renderer: &mut renderer,
},
);
})
.map_err(|e| format!("eframe error: {}", e))
.unwrap();
}
}
#[cfg(all(not(target_arch = "wasm32"), feature = "desktop"))]
struct TabViewer<'a> {
panels: std::collections::HashMap<String, VNode>,
renderer: &'a mut crate::desktop_renderer::DesktopRenderer,
}
#[cfg(all(not(target_arch = "wasm32"), feature = "desktop"))]
impl egui_dock::TabViewer for TabViewer<'_> {
type Tab = String;
fn title(&mut self, tab: &mut Self::Tab) -> egui::WidgetText {
tab.as_str().into()
}
fn ui(&mut self, ui: &mut egui::Ui, tab: &mut Self::Tab) {
if let Some(vnode) = self.panels.get(tab) {
self.renderer.render_vnode(ui, vnode);
} else {
ui.label(format!("Panel '{}' not found", tab));
}
}
}
#[cfg(all(not(target_arch = "wasm32"), feature = "desktop"))]
fn extract_panels_from_vnode(vnode: &VNode) -> std::collections::HashMap<String, VNode> {
use std::collections::HashMap;
let mut panels = HashMap::new();
panels.insert("files".to_string(), vnode.clone());
panels.insert("main".to_string(), vnode.clone());
panels.insert("properties".to_string(), vnode.clone());
panels.insert("console".to_string(), vnode.clone());
panels
}