tirbofish/dropbear · diff
feature: docks implemented as a trait instead of hardcoded, potential plugin possibility
Signature present but could not be verified.
Unverified
@@ -55,6 +55,7 @@ rfd.workspace = true semver.workspace = true serde.workspace = true bitflags.workspace = true +downcast-rs.workspace = true [target.'cfg(unix)'.dependencies] daemonize = "0.5.0" @@ -1,5 +1,4 @@ use dropbear_engine::asset::ASSET_REGISTRY; -use dropbear_engine::entity::MeshRenderer; use dropbear_engine::model::Model; use dropbear_engine::texture::Texture; use dropbear_engine::{graphics::NO_TEXTURE, utils::ResourceReference}; @@ -13,8 +12,8 @@ use std::{cmp::Ordering, fs, hash::DefaultHasher, io, path::Path}; use crate::editor::{ AssetDivision, AssetNodeInfo, AssetNodeKind, ComponentNodeSelection, DraggedAsset, - EditorTabViewer, FsEntry, ResourceDivision, SceneDivision, ScriptDivision, Signal, - StaticallyKept, TABS_GLOBAL, + EditorTabDock, EditorTabDockDescriptor, EditorTabViewer, FsEntry, ResourceDivision, + SceneDivision, ScriptDivision, Signal, StaticallyKept, TABS_GLOBAL, }; use eucalyptus_core::component::DRAGGED_ASSET_ID; @@ -882,10 +881,10 @@ impl<'a> EditorTabViewer<'a> { ) } - fn with_icon_kind<'ui>( - builder: NodeBuilder<'ui, u64>, + fn with_icon_kind( + builder: NodeBuilder<u64>, kind: AssetNodeKind, - ) -> NodeBuilder<'ui, u64> { + ) -> NodeBuilder<u64> { builder.icon(move |ui| { egui_extras::install_image_loaders(ui.ctx()); Self::draw_asset_icon(ui, kind) @@ -1241,7 +1240,7 @@ impl<'a> EditorTabViewer<'a> { .get_texture_handle_by_reference(&reference) .is_some() { - info!("Texture already loaded: {}", label); + eucalyptus_core::info!("Texture already loaded: {}", label); return; } @@ -1252,7 +1251,7 @@ impl<'a> EditorTabViewer<'a> { let texture = match Texture::from_file(graphics.clone(), &path, Some(&label)).await { Ok(v) => v, Err(e) => { - warn!("Unable to load texture {}: {}", reference, e); + eucalyptus_core::warn!("Unable to load texture {}: {}", reference, e); return Err(e); } }; @@ -1299,13 +1298,14 @@ impl<'a> EditorTabViewer<'a> { .first() .and_then(|node_id| cfg.component_selection(*node_id)) }); - + if let Some(selection) = selection { self.inspect_component_selection(cfg, selection); if let Some(target_entity) = Self::entity_from_node_id(drag.target) { - log::info!( - "Component id #{} ready to drop onto entity {:?}", - selection.component_type_id, + let v = if crate::features::is_enabled(crate::features::ShowComponentTypeIDInEditor) { format!(" id #{}", selection.component_type_id) } else { "".to_string() }; + eucalyptus_core::info!( + "Component{} ready to drop onto entity {:?}", + v, target_entity ); } @@ -1366,3 +1366,17 @@ impl<'a> EditorTabViewer<'a> { } } } + +pub struct AssetViewerDock; + +impl EditorTabDock for AssetViewerDock { + fn desc() -> EditorTabDockDescriptor { + EditorTabDockDescriptor { + title: "Asset Viewer".to_string(), + } + } + + fn display(viewer: &mut EditorTabViewer<'_>, ui: &mut egui::Ui) { + viewer.show_asset_viewer(ui); + } +} @@ -3,7 +3,7 @@ use std::path::PathBuf; use egui::{Margin, RichText}; use crate::editor::{ - EditorTabViewer, + EditorTabDock, EditorTabDockDescriptor, EditorTabViewer, console_error::{ConsoleItem, ErrorLevel}, }; @@ -142,3 +142,17 @@ impl<'a> EditorTabViewer<'a> { }); } } + +pub struct BuildConsoleDock; + +impl EditorTabDock for BuildConsoleDock { + fn desc() -> EditorTabDockDescriptor { + EditorTabDockDescriptor { + title: "Build Output".to_string(), + } + } + + fn display(viewer: &mut EditorTabViewer<'_>, ui: &mut egui::Ui) { + viewer.build_console(ui); + } +} @@ -1,7 +1,7 @@ use super::*; use crate::editor::ViewportMode; -use std::{collections::HashMap, hash::Hash, path::PathBuf, sync::LazyLock}; - +use std::hash::Hasher; +use std::{any::TypeId, collections::HashMap, hash::Hash, path::PathBuf, sync::LazyLock}; use crate::editor::console::EucalyptusConsole; use crate::plugin::PluginRegistry; use dropbear_engine::entity::{EntityTransform, Transform}; @@ -28,13 +28,14 @@ pub struct EditorTabViewer<'a> { pub active_camera: &'a mut Arc<Mutex<Option<Entity>>>, pub plugin_registry: &'a mut PluginRegistry, pub component_registry: &'a ComponentRegistry, + pub tab_registry: &'a EditorTabRegistry, pub build_logs: &'a mut Vec<String>, pub eucalyptus_console: &'a mut EucalyptusConsole, - - // "wah wah its unsafe, its using raw pointers" shut the fuck up if it breaks i will know - pub editor: *mut Editor, + pub current_scene_name: &'a mut Option<String>, } +pub type EditorTabId = u64; + #[derive(Clone, Debug)] pub struct DraggedAsset { pub name: String, @@ -89,7 +90,7 @@ pub static TABS_GLOBAL: LazyLock<Mutex<StaticallyKept>> = pub struct StaticallyKept { show_context_menu: bool, context_menu_pos: egui::Pos2, - context_menu_tab: Option<EditorTab>, + context_menu_tab: Option<EditorTabId>, pub(crate) is_focused: bool, pub(crate) old_pos: Transform, @@ -144,25 +145,105 @@ impl StaticallyKept { } } +pub struct EditorTabRegistry { + pub title_to_id: HashMap<String, EditorTabId>, + pub descriptors: HashMap<EditorTabId, EditorTabDockDescriptor>, + pub displayers: HashMap<EditorTabId, EditorTabDisplayer>, +} + +pub type EditorTabDisplayer = Box< + dyn for<'a> Fn(&mut EditorTabViewer<'a>, &mut egui::Ui) + Send + Sync + 'static, +>; + +impl EditorTabRegistry { + pub fn new() -> Self { + Self { + title_to_id: HashMap::new(), + descriptors: HashMap::new(), + displayers: HashMap::new(), + } + } + + pub fn register<D>(&mut self) + where + D: EditorTabDock + Send + Sync + 'static, + { + let desc = D::desc(); + let id = Self::id_for_type::<D>(); + + self.title_to_id.insert(desc.title.to_string(), id); + self.descriptors.insert(id, desc); + self.displayers + .insert(id, Box::new(|viewer, ui| D::display(viewer, ui))); + } + + pub fn get_descriptor_by_title(&self, title: &str) -> Option<&EditorTabDockDescriptor> { + self.title_to_id + .get(title) + .and_then(|tab_id| self.descriptors.get(tab_id)) + } + + pub fn id_for_title(&self, title: &str) -> Option<EditorTabId> { + self.title_to_id.get(title).copied() + } + + pub fn display_by_id( + &self, + tab_id: EditorTabId, + viewer: &mut EditorTabViewer<'_>, + ui: &mut egui::Ui, + ) -> bool { + let Some(displayer) = self.displayers.get(&tab_id) else { + return false; + }; + displayer(viewer, ui); + true + } + + fn id_for_type<T: 'static>() -> EditorTabId { + Self::numeric_id(TypeId::of::<T>()) + } + + fn numeric_id(type_id: TypeId) -> EditorTabId { + let mut hasher = std::collections::hash_map::DefaultHasher::new(); + type_id.hash(&mut hasher); + Self::normalize_id(hasher.finish()) + } + + fn normalize_id(id: u64) -> u64 { + if id == 0 { + 1 + } else { + id + } + } +} + +impl Default for EditorTabRegistry { + fn default() -> Self { + Self::new() + } +} + + +pub struct EditorTabDockDescriptor { + pub title: String, +} + +pub trait EditorTabDock { + fn desc() -> EditorTabDockDescriptor; + fn display(viewer: &mut EditorTabViewer<'_>, ui: &mut egui::Ui); +} + impl<'a> TabViewer for EditorTabViewer<'a> { - type Tab = EditorTab; + type Tab = EditorTabId; fn title(&mut self, tab: &mut Self::Tab) -> egui::WidgetText { - match tab { - EditorTab::Viewport => "Viewport".into(), - EditorTab::ModelEntityList => "Model/Entity List".into(), - EditorTab::AssetViewer => "Asset Viewer".into(), - EditorTab::ResourceInspector => "Resource Inspector".into(), - EditorTab::Plugin(dock_index) => { - if let Some((_, plugin)) = self.plugin_registry.plugins.get_index_mut(*dock_index) { - plugin.display_name().into() - } else { - "Unknown Plugin Name".into() - } - } - EditorTab::ErrorConsole => "Build Output".into(), - EditorTab::Console => "Console".into(), - } + self.tab_registry + .descriptors + .get(tab) + .map(|desc| desc.title.clone().into()) + .unwrap_or_else(|| "Unknown Tab".into()) } fn ui(&mut self, ui: &mut egui::Ui, tab: &mut Self::Tab) { @@ -178,113 +259,102 @@ impl<'a> TabViewer for EditorTabViewer<'a> { } }); - match tab { - EditorTab::Viewport => { - self.viewport_tab(ui); - } - EditorTab::ModelEntityList => { - self.entity_list(ui); - } - EditorTab::AssetViewer => { - self.show_asset_viewer(ui); - } - EditorTab::ResourceInspector => { - self.resource_inspector(ui); + if !self.tab_registry.display_by_id(*tab, self, ui) { + ui.label("Unknown dock"); + } + } +} + +impl<'a> EditorTabViewer<'a> { + pub(crate) fn console_tab(&mut self, ui: &mut egui::Ui) { + ui.separator(); + + ui.horizontal(|ui| { + if ui.button("Clear").clicked() { + self.eucalyptus_console.history.clear(); } - EditorTab::Plugin(dock_info) => { - if self.editor.is_null() { - panic!("Editor pointer is null, unexpected behaviour"); + + ui.separator(); + + ui.checkbox(&mut self.eucalyptus_console.show_info, "Info"); + ui.checkbox(&mut self.eucalyptus_console.show_warning, "Warning"); + ui.checkbox(&mut self.eucalyptus_console.show_error, "Error"); + ui.checkbox(&mut self.eucalyptus_console.show_debug, "Debug"); + ui.checkbox(&mut self.eucalyptus_console.show_trace, "Trace"); + + ui.separator(); + + ui.checkbox(&mut self.eucalyptus_console.auto_scroll, "Auto-scroll"); + + ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| { + ui.label(format!("Logs: {}", self.eucalyptus_console.history.len())); + }); + }); + + ui.separator(); + + let _ = self.eucalyptus_console.take(); + + let scroll = egui::ScrollArea::vertical() + .auto_shrink([false, false]) + .stick_to_bottom(self.eucalyptus_console.auto_scroll); + + scroll.show(ui, |ui| { + for log in &self.eucalyptus_console.history { + let is_error = log.contains("[ERROR]") || log.contains("[FATAL]"); + let is_warn = log.contains("[WARN]"); + let is_debug = log.contains("[DEBUG]"); + let is_trace = log.contains("[TRACE]"); + let is_info = !is_error && !is_warn && !is_debug && !is_trace; + + if is_error && !self.eucalyptus_console.show_error { + continue; } - let editor = unsafe { &mut *self.editor }; - if let Some((_, plugin)) = self.plugin_registry.plugins.get_index_mut(*dock_info) { - plugin.ui(ui, editor); - } else { - ui.colored_label( - egui::Color32::RED, - format!("Plugin at index '{}' not found", *dock_info), - ); + if is_warn && !self.eucalyptus_console.show_warning { + continue; } + if is_debug && !self.eucalyptus_console.show_debug { + continue; + } + if is_trace && !self.eucalyptus_console.show_trace { + continue; + } + if is_info && !self.eucalyptus_console.show_info { + continue; + } + + let color = if is_error { + egui::Color32::from_rgb(255, 100, 100) + } else if is_warn { + egui::Color32::from_rgb(255, 200, 50) + } else if is_debug { + egui::Color32::from_rgb(100, 200, 255) + } else if is_trace { + egui::Color32::from_rgb(150, 150, 150) + } else { + egui::Color32::LIGHT_GRAY + }; + + ui.add(egui::Label::new( + egui::RichText::new(log).color(color).monospace(), + )); } - EditorTab::ErrorConsole => { - self.build_console(ui); - } - EditorTab::Console => { - ui.separator(); - - ui.horizontal(|ui| { - if ui.button("Clear").clicked() { - self.eucalyptus_console.history.clear(); - } - - ui.separator(); - - ui.checkbox(&mut self.eucalyptus_console.show_info, "Info"); - ui.checkbox(&mut self.eucalyptus_console.show_warning, "Warning"); - ui.checkbox(&mut self.eucalyptus_console.show_error, "Error"); - ui.checkbox(&mut self.eucalyptus_console.show_debug, "Debug"); - ui.checkbox(&mut self.eucalyptus_console.show_trace, "Trace"); - - ui.separator(); - - ui.checkbox(&mut self.eucalyptus_console.auto_scroll, "Auto-scroll"); - - ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| { - ui.label(format!("Logs: {}", self.eucalyptus_console.history.len())); - }); - }); - - ui.separator(); - - let _ = self.eucalyptus_console.take(); - - let scroll = egui::ScrollArea::vertical() - .auto_shrink([false, false]) - .stick_to_bottom(self.eucalyptus_console.auto_scroll); - - scroll.show(ui, |ui| { - for log in &self.eucalyptus_console.history { - let is_error = log.contains("[ERROR]") || log.contains("[FATAL]"); - let is_warn = log.contains("[WARN]"); - let is_debug = log.contains("[DEBUG]"); - let is_trace = log.contains("[TRACE]"); - let is_info = !is_error && !is_warn && !is_debug && !is_trace; - - if is_error && !self.eucalyptus_console.show_error { - continue; - } - if is_warn && !self.eucalyptus_console.show_warning { - continue; - } - if is_debug && !self.eucalyptus_console.show_debug { - continue; - } - if is_trace && !self.eucalyptus_console.show_trace { - continue; - } - if is_info && !self.eucalyptus_console.show_info { - continue; - } - - let color = if is_error { - egui::Color32::from_rgb(255, 100, 100) - } else if is_warn { - egui::Color32::from_rgb(255, 200, 50) - } else if is_debug { - egui::Color32::from_rgb(100, 200, 255) - } else if is_trace { - egui::Color32::from_rgb(150, 150, 150) - } else { - egui::Color32::LIGHT_GRAY - }; - - ui.add(egui::Label::new( - egui::RichText::new(log).color(color).monospace(), - )); - } - }); - } + }); + } +} + +pub struct ConsoleDock; + +impl EditorTabDock for ConsoleDock { + fn desc() -> EditorTabDockDescriptor { + EditorTabDockDescriptor { + title: "Console".to_string(), } } + + fn display(viewer: &mut EditorTabViewer<'_>, ui: &mut egui::Ui) { + viewer.console_tab(ui); + } } #[derive(Clone)] @@ -7,7 +7,7 @@ use eucalyptus_core::{ }; use hecs::{Entity, World}; -use crate::editor::{Editor, EditorTabViewer, Signal, StaticallyKept, TABS_GLOBAL}; +use crate::editor::{Editor, EditorTabDock, EditorTabDockDescriptor, EditorTabViewer, Signal, StaticallyKept, TABS_GLOBAL}; impl<'a> EditorTabViewer<'a> { pub(crate) fn entity_list(&mut self, ui: &mut egui::Ui) { @@ -204,3 +204,17 @@ impl<'a> EditorTabViewer<'a> { } } } + +pub struct EntityListDock; + +impl EditorTabDock for EntityListDock { + fn desc() -> EditorTabDockDescriptor { + EditorTabDockDescriptor { + title: "Model/Entity List".to_string(), + } + } + + fn display(viewer: &mut EditorTabViewer<'_>, ui: &mut egui::Ui) { + viewer.entity_list(ui); + } +} @@ -76,7 +76,10 @@ impl Keyboard for Editor { KeyCode::Delete => { if !is_playing { if let Some((_, tab)) = self.dock_state.find_active_focused() - && matches!(tab, EditorTab::ModelEntityList) + && self + .tab_registry + .id_for_title("Model/Entity List") + .map_or(false, |id| *tab == id) { if self.selected_entity.is_some() { self.signal = Signal::Delete; @@ -161,7 +164,10 @@ impl Keyboard for Editor { KeyCode::KeyC => { if ctrl_pressed && !is_playing { if let Some((_, tab)) = self.dock_state.find_active_focused() - && matches!(tab, EditorTab::ModelEntityList) + && self + .tab_registry + .id_for_title("Model/Entity List") + .map_or(false, |id| *tab == id) { if let Some(entity) = &self.selected_entity { let Ok(label) = self.world.get::<&Label>(*entity) else { @@ -52,7 +52,7 @@ use eucalyptus_core::{ input::InputState, scripting::BuildStatus, states, - states::{EditorTab, PROJECT, SCENES, WorldLoadingStatus}, + states::{PROJECT, SCENES, WorldLoadingStatus}, success, utils::ViewportMode, warn, @@ -75,7 +75,7 @@ pub struct Editor { pub scene_command: SceneCommand, pub world: Box<World>, pub physics_state: PhysicsState, - pub dock_state: DockState<EditorTab>, + pub dock_state: DockState<EditorTabId>, pub texture_id: Option<egui::TextureId>, pub size: Extent3d, pub instance_buffer_cache: HashMap<u64, ResizableBuffer<InstanceRaw>>, @@ -120,6 +120,7 @@ pub struct Editor { pub gizmo_mode: EnumSet<GizmoMode>, pub gizmo_orientation: GizmoOrientation, pub console: EucalyptusConsole, + pub tab_registry: EditorTabRegistry, // might as well save some memory if its not required... // #[allow(unused)] // unused to allow for JVM to startup @@ -155,7 +156,7 @@ pub struct Editor { // plugins pub plugin_registry: PluginRegistry, - pub dock_state_shared: Option<Arc<Mutex<DockState<EditorTab>>>>, + pub dock_state_shared: Option<Arc<Mutex<DockState<EditorTabId>>>>, // scene creation open_new_scene_window: bool, @@ -180,15 +181,30 @@ pub struct Editor { impl Editor { pub fn new() -> anyhow::Result<Self> { - let tabs = vec![EditorTab::Viewport]; + let mut tab_registry = EditorTabRegistry::new(); + crate::register_docks(&mut tab_registry); + + let viewport_tab = tab_registry + .id_for_title("Viewport") + .expect("Viewport tab must be registered"); + let entity_list_tab = tab_registry + .id_for_title("Model/Entity List") + .expect("Entity list tab must be registered"); + let resource_tab = tab_registry + .id_for_title("Resource Inspector") + .expect("Resource inspector tab must be registered"); + let asset_tab = tab_registry + .id_for_title("Asset Viewer") + .expect("Asset viewer tab must be registered"); + + let tabs = vec![viewport_tab]; let mut dock_state = DockState::new(tabs); let surface = dock_state.main_surface_mut(); let [_old, right] = - surface.split_right(NodeIndex::root(), 0.25, vec![EditorTab::ModelEntityList]); - let [_old, _] = - surface.split_left(NodeIndex::root(), 0.20, vec![EditorTab::ResourceInspector]); - let [_old, _] = surface.split_below(right, 0.5, vec![EditorTab::AssetViewer]); + surface.split_right(NodeIndex::root(), 0.25, vec![entity_list_tab]); + let [_old, _] = surface.split_left(NodeIndex::root(), 0.20, vec![resource_tab]); + let [_old, _] = surface.split_below(right, 0.5, vec![asset_tab]); eucalyptus_core::utils::start_deadlock_detector(); @@ -244,6 +260,7 @@ impl Editor { gizmo_mode: EnumSet::empty(), gizmo_orientation: GizmoOrientation::Global, console: EucalyptusConsole::new(None), + tab_registry, input_state: Box::new(InputState::new()), light_cube_pipeline: None, active_camera: Arc::new(Mutex::new(None)), @@ -555,7 +572,7 @@ impl Editor { world_sender: Option<oneshot::Sender<hecs::World>>, active_camera: Arc<Mutex<Option<hecs::Entity>>>, project_path: Arc<Mutex<Option<PathBuf>>>, - dock_state: Arc<Mutex<DockState<EditorTab>>>, + dock_state: Arc<Mutex<DockState<EditorTabId>>>, component_registry: Arc<ComponentRegistry>, ) -> anyhow::Result<()> { { @@ -1057,39 +1074,9 @@ impl Editor { }); ui.menu_button("Window", |ui_window| { - if ui_window.button("Open Asset Viewer").clicked() { - self.dock_state.push_to_focused_leaf(EditorTab::AssetViewer); - } - if ui_window.button("Open Resource Inspector").clicked() { - self.dock_state - .push_to_focused_leaf(EditorTab::ResourceInspector); - } - if ui_window.button("Open Entity List").clicked() { - self.dock_state - .push_to_focused_leaf(EditorTab::ModelEntityList); - } - if ui_window.button("Open Viewport").clicked() { - self.dock_state.push_to_focused_leaf(EditorTab::Viewport); - } - if ui_window.button("Open Error Console").clicked() { - self.dock_state - .push_to_focused_leaf(EditorTab::ErrorConsole); - } - if ui_window.button("Open Debug Console").clicked() { - self.dock_state.push_to_focused_leaf(EditorTab::Console); - } - if self.plugin_registry.plugins.len() == 0 { - ui_window.label( - egui::RichText::new("No plugins") - .color(ui_window.visuals().weak_text_color()), - ); - } - for (i, (_, plugin)) in self.plugin_registry.plugins.iter().enumerate() { - if ui_window - .button(format!("Open {}", plugin.display_name())) - .clicked() - { - self.dock_state.push_to_focused_leaf(EditorTab::Plugin(i)); + for (k, v) in self.tab_registry.descriptors.iter() { + if ui_window.button(v.title.as_str()).clicked() { + self.dock_state.push_to_focused_leaf(*k); } } }); @@ -1239,8 +1226,6 @@ impl Editor { }); }); - let editor_ptr = self as *mut Editor; - let Some(view) = self.texture_id else { egui::CentralPanel::default().show(ctx, |ui| { ui.centered_and_justified(|ui| { @@ -1270,10 +1255,11 @@ impl Editor { gizmo_orientation: &mut self.gizmo_orientation, editor_mode: &mut self.editor_state, plugin_registry: &mut self.plugin_registry, - editor: editor_ptr, build_logs: &mut self.build_logs, component_registry: &self.component_registry, + tab_registry: &self.tab_registry, eucalyptus_console: &mut self.console, + current_scene_name: &mut self.current_scene_name, }, ); }); @@ -1,5 +1,5 @@ use hecs::Entity; -use crate::editor::{EditorTabViewer, TABS_GLOBAL}; +use crate::editor::{EditorTabDock, EditorTabDockDescriptor, EditorTabViewer, TABS_GLOBAL}; use dropbear_engine::camera::Camera; use eucalyptus_core::camera::{CameraComponent, CameraType}; @@ -84,3 +84,17 @@ impl<'a> EditorTabViewer<'a> { } } } + +pub struct ResourceInspectorDock; + +impl EditorTabDock for ResourceInspectorDock { + fn desc() -> EditorTabDockDescriptor { + EditorTabDockDescriptor { + title: "Resource Inspector".to_string(), + } + } + + fn display(viewer: &mut EditorTabViewer<'_>, ui: &mut egui::Ui) { + viewer.resource_inspector(ui); + } +} @@ -217,7 +217,8 @@ impl Scene for Editor { } if let Some((_, tab)) = self.dock_state.find_active_focused() { - self.is_viewport_focused = matches!(tab, EditorTab::Viewport); + let viewport_tab = self.tab_registry.id_for_title("Viewport"); + self.is_viewport_focused = viewport_tab.map_or(false, |id| *tab == id); } else { self.is_viewport_focused = false; } @@ -8,8 +8,7 @@ impl<'a> EditorTabViewer<'a> { pub fn scene_settings(&mut self, _cfg: &mut StaticallyKept, ui: &mut egui::Ui) { ui.label("Scene Settings"); - let editor = unsafe { &mut *self.editor }; - let current_scene_name = editor.current_scene_name.clone(); + let current_scene_name = self.current_scene_name.clone(); if let Some(scene_name) = current_scene_name { let mut scenes = SCENES.write(); @@ -7,7 +7,7 @@ use egui::{CentralPanel, Id, Slider, SliderClamping}; use egui_dock::DockState; use egui_ltreeview::{Action, NodeBuilder}; use eucalyptus_core::input::InputState; -use eucalyptus_core::states::EditorTab; +use crate::editor::EditorTabId; use eucalyptus_core::utils::option::HistoricalOption; use eucalyptus_core::{APP_INFO, warn}; use gilrs::{Button, GamepadId}; @@ -30,7 +30,7 @@ pub static EDITOR_SETTINGS: Lazy<RwLock<EditorSettings>> = pub struct EditorSettings { /// The layout of the dock. #[serde(default)] - pub dock_layout: Option<DockState<EditorTab>>, + pub dock_layout: Option<DockState<EditorTabId>>, #[serde(default)] pub target_fps: HistoricalOption<u32>, @@ -1,4 +1,4 @@ -use crate::editor::{EditorTabViewer, Signal, TABS_GLOBAL, UndoableAction}; +use crate::editor::{EditorTabDock, EditorTabDockDescriptor, EditorTabViewer, Signal, TABS_GLOBAL, UndoableAction}; use dropbear_engine::camera::Camera; use dropbear_engine::entity::{EntityTransform, Transform}; use dropbear_engine::lighting::Light; @@ -262,3 +262,17 @@ impl<'a> EditorTabViewer<'a> { } } } + +pub struct ViewportDock; + +impl EditorTabDock for ViewportDock { + fn desc() -> EditorTabDockDescriptor { + EditorTabDockDescriptor { + title: "Viewport".to_string(), + } + } + + fn display(viewer: &mut EditorTabViewer<'_>, ui: &mut egui::Ui) { + viewer.viewport_tab(ui); + } +} @@ -12,8 +12,23 @@ pub mod stats; pub mod utils; pub use redback_runtime as runtime; +use crate::editor::{ + EditorTabRegistry, asset_viewer::AssetViewerDock, build_console::BuildConsoleDock, + dock::ConsoleDock, entity_list::EntityListDock, resource::ResourceInspectorDock, + viewport::ViewportDock, +}; + dropbear_engine::features! { pub mod features { const ShowComponentTypeIDInEditor = 0b00000001 } } + +pub fn register_docks(registry: &mut EditorTabRegistry) { + registry.register::<ViewportDock>(); + registry.register::<EntityListDock>(); + registry.register::<AssetViewerDock>(); + registry.register::<ResourceInspectorDock>(); + registry.register::<BuildConsoleDock>(); + registry.register::<ConsoleDock>(); +} @@ -6,6 +6,7 @@ use clap::{Arg, Command}; use dropbear_engine::DropbearWindowBuilder; use dropbear_engine::future::FutureQueue; use dropbear_engine::texture::DropbearEngineLogo; +use eucalyptus_core::APP_INFO; use eucalyptus_core::config::ProjectConfig; use eucalyptus_core::scripting::jni::{RUNTIME_MODE, RuntimeMode}; use eucalyptus_core::scripting::{AWAIT_JDB, JVM_ARGS}; @@ -205,7 +206,13 @@ async fn main() -> anyhow::Result<()> { dropbear_engine::feature_list::enable(dropbear_engine::feature_list::EnablePuffinTracer) } - EditorSettings::read()?; + if let Err(e) = EditorSettings::read() { + panic!( + "Unable to launch eucalyptus-editor: {} + \nTry deleting your editor.eucc file located at {:?}", + e, app_dirs2::app_root(app_dirs2::AppDataType::UserData, &APP_INFO)? + ); + } match matches.subcommand() { Some(("build", sub_matches)) => { @@ -1,4 +1,4 @@ -use crate::editor::Editor; +use crate::editor::EditorTabViewer; use app_dirs2::AppDataType; use egui::Ui; use eucalyptus_core::APP_INFO; @@ -14,7 +14,7 @@ use std::time::Instant; pub trait EditorPlugin: Send + Sync { fn id(&self) -> &str; fn display_name(&self) -> &str; - fn ui(&mut self, ui: &mut Ui, editor: &mut Editor); + fn ui(&mut self, ui: &mut Ui, viewer: &mut EditorTabViewer<'_>); fn tab_title(&self) -> &str; }