use crate::editor::TOOLLIST;
use crate::prelude::*;
use codegridfx::DebugModule;
#[derive(Clone, Copy, PartialEq)]
pub enum DockManagerState {
Minimized,
Maximized,
Editor,
}
pub struct DockManager {
pub state: DockManagerState,
pub docks: IndexMap<String, Box<dyn Dock>>,
pub editor_canvases: IndexMap<String, usize>,
pub editor_docks: IndexMap<String, Box<dyn Dock>>,
pub dock: String,
pub index: usize,
pub editor_index: Option<usize>,
pub supports_undo: bool,
pub auto_text_play_prev_dock: Option<String>,
pub auto_text_play_active: bool,
}
impl Default for DockManager {
fn default() -> Self {
Self::new()
}
}
impl DockManager {
pub fn new() -> Self {
let mut docks = IndexMap::default();
let dock: Box<dyn Dock> = Box::new(crate::docks::tiles::TilesDock::new());
docks.insert("Tiles".into(), dock);
let dock: Box<dyn Dock> = Box::new(crate::docks::builder::BuilderDock::new());
docks.insert("Builder".into(), dock);
let dock: Box<dyn Dock> = Box::new(crate::docks::palette::PaletteDock::new());
docks.insert("Palette".into(), dock);
let dock: Box<dyn Dock> = Box::new(crate::docks::dungeon::DungeonDock::new());
docks.insert("Dungeon".into(), dock);
let dock: Box<dyn Dock> = Box::new(crate::docks::authoring::AuthoringDock::new());
docks.insert("Authoring".into(), dock);
let dock: Box<dyn Dock> = Box::new(crate::docks::visual_code::VisualCodeDock::new());
docks.insert("Visual Code".into(), dock);
let dock: Box<dyn Dock> = Box::new(crate::docks::code::CodeDock::new());
docks.insert("Code".into(), dock);
let dock: Box<dyn Dock> = Box::new(crate::docks::data::DataDock::new());
docks.insert("Data".into(), dock);
let dock: Box<dyn Dock> = Box::new(crate::docks::log::LogDock::new());
docks.insert("Log".into(), dock);
let dock: Box<dyn Dock> = Box::new(crate::docks::console::ConsoleDock::new());
docks.insert("Console".into(), dock);
let dock: Box<dyn Dock> = Box::new(crate::docks::organic::OrganicDock::new());
docks.insert("Organic".into(), dock);
let dock: Box<dyn Dock> = Box::new(crate::docks::tilemap::TilemapDock::new());
docks.insert("Tilemap".into(), dock);
let dock: Box<dyn Dock> = Box::new(crate::docks::text_play::TextPlayDock::new());
docks.insert("Text Play".into(), dock);
Self {
state: DockManagerState::Minimized,
docks,
editor_canvases: IndexMap::default(),
editor_docks: IndexMap::default(),
dock: "".into(),
index: 0,
editor_index: None,
supports_undo: false,
auto_text_play_prev_dock: None,
auto_text_play_active: false,
}
}
pub fn init(&mut self, ctx: &mut TheContext) -> TheCanvas {
let mut canvas: TheCanvas = TheCanvas::new();
let mut shared_layout = TheSharedHLayout::new(TheId::named("Dock Shared Layout"));
shared_layout.set_shared_ratio(1.0 - 0.27);
shared_layout.set_mode(TheSharedHLayoutMode::Shared);
let mut dock_canvas = TheCanvas::new();
let mut dock_stack = TheStackLayout::new(TheId::named("Dock Stack"));
for dock in &mut self.docks.values_mut() {
let canvas = dock.setup(ctx);
dock_stack.add_canvas(canvas);
}
dock_canvas.set_layout(dock_stack);
shared_layout.add_canvas(dock_canvas);
let mut action_canvas: TheCanvas = TheCanvas::new();
let mut toolbar_canvas = TheCanvas::default();
let traybar_widget = TheTraybar::new(TheId::empty());
toolbar_canvas.set_widget(traybar_widget);
let mut toolbar_hlayout = TheHLayout::new(TheId::empty());
toolbar_hlayout.set_background_color(None);
let mut text = TheText::new(TheId::named("Action Text"));
text.set_text(fl!("dock_auto"));
text.set_text_size(12.0);
let mut action_auto_button = TheCheckButton::new(TheId::named("Action Auto"));
action_auto_button.set_status_text(&fl!("status_dock_action_auto"));
action_auto_button.set_value(TheValue::Bool(false));
let mut action_apply_button = TheTraybarButton::new(TheId::named("Action Apply"));
action_apply_button.set_text(fl!("apply"));
action_apply_button.set_status_text(&fl!("status_dock_action_apply"));
toolbar_hlayout.set_margin(Vec4::new(10, 1, 5, 1));
toolbar_hlayout.set_padding(3);
toolbar_hlayout.add_widget(Box::new(text));
toolbar_hlayout.add_widget(Box::new(action_auto_button));
toolbar_hlayout.add_widget(Box::new(action_apply_button));
toolbar_hlayout.set_reverse_index(Some(1));
toolbar_canvas.set_layout(toolbar_hlayout);
let action_list_layout = TheListLayout::new(TheId::named("Action List"));
action_canvas.set_layout(action_list_layout);
action_canvas.set_top(toolbar_canvas);
shared_layout.add_canvas(action_canvas);
canvas.set_layout(shared_layout);
canvas
}
pub fn set_dock(
&mut self,
dock: String,
ui: &mut TheUI,
ctx: &mut TheContext,
project: &Project,
server_ctx: &mut ServerContext,
) {
if dock != self.dock {
self.minimize(ui, ctx);
if let Some(index) = self.docks.get_index_of(&dock) {
self.index = index;
self.dock = dock;
if let Some(stack) = ui.get_stack_layout("Dock Stack") {
stack.set_index(index);
}
self.editor_index = self.editor_canvases.get(&self.dock).copied();
} else {
eprint!("Dock \"{}\" not found!", self.dock);
return;
}
if let Some(layout) = ui.get_sharedhlayout("Dock Shared Layout") {
if self.docks[self.index].supports_actions() {
layout.set_mode(TheSharedHLayoutMode::Shared);
} else {
layout.set_mode(TheSharedHLayoutMode::Left);
}
}
if let Some(layout) = ui.get_sharedvlayout("Shared VLayout") {
let state = self.docks[self.index].default_state();
if state == DockDefaultState::Minimized {
self.state = DockManagerState::Minimized;
layout.set_mode(TheSharedVLayoutMode::Shared);
} else {
self.state = DockManagerState::Maximized;
layout.set_mode(TheSharedVLayoutMode::Bottom);
}
}
}
self.docks[self.index].activate(ui, ctx, project, server_ctx);
self.set_supports_undo(self.docks[self.index].supports_undo(), ctx);
if self.supports_undo {
self.docks[self.index].set_undo_state_to_ui(ctx);
}
}
pub fn import(
&mut self,
content: String,
ui: &mut TheUI,
ctx: &mut TheContext,
project: &mut Project,
server_ctx: &mut ServerContext,
) {
if let Some((_, dock)) = self.docks.get_index_mut(self.index) {
dock.import(content.clone(), ui, ctx, project, server_ctx);
if let Some(editor_dock) = self.editor_docks.get_mut(&self.dock) {
editor_dock.import(content, ui, ctx, project, server_ctx);
}
}
}
pub fn export(&self) -> Option<String> {
if let Some((_, dock)) = self.docks.get_index(self.index) {
dock.export()
} else {
None
}
}
pub fn handle_event(
&mut self,
event: &TheEvent,
ui: &mut TheUI,
ctx: &mut TheContext,
project: &mut Project,
server_ctx: &mut ServerContext,
) -> bool {
let mut redraw = false;
if let Some((_, dock)) = self.docks.get_index_mut(self.index) {
redraw = dock.handle_event(event, ui, ctx, project, server_ctx);
if let Some(editor_dock) = self.editor_docks.get_mut(&self.dock) {
if editor_dock.handle_event(event, ui, ctx, project, server_ctx) {
redraw = true;
}
}
}
redraw
}
pub fn get_state(&self) -> DockManagerState {
self.state
}
pub fn add_editors_to_stack(&mut self, stack: &mut TheStackLayout, ctx: &mut TheContext) {
let mut tiles_editor: Box<dyn Dock> =
Box::new(crate::docks::tiles_editor::TilesEditorDock::new());
let tiles_editor_canvas = tiles_editor.setup(ctx);
let index = stack.add_canvas(tiles_editor_canvas);
self.editor_canvases.insert("Tiles".to_string(), index);
self.editor_docks.insert("Tiles".to_string(), tiles_editor);
let mut builder_editor: Box<dyn Dock> =
Box::new(crate::docks::builder_editor::BuilderEditorDock::new());
let builder_editor_canvas = builder_editor.setup(ctx);
let index = stack.add_canvas(builder_editor_canvas);
self.editor_canvases.insert("Builder".to_string(), index);
self.editor_docks
.insert("Builder".to_string(), builder_editor);
let mut data_editor: Box<dyn Dock> =
Box::new(crate::docks::data_editor::DataEditorDock::new());
let data_editor_canvas = data_editor.setup(ctx);
let index = stack.add_canvas(data_editor_canvas);
self.editor_canvases.insert("Data".to_string(), index);
self.editor_docks.insert("Data".to_string(), data_editor);
}
pub fn edit_maximize(
&mut self,
ui: &mut TheUI,
ctx: &mut TheContext,
project: &mut Project,
server_ctx: &mut ServerContext,
) {
if self.dock == "Tiles"
&& server_ctx.tile_node_group_id.is_none()
&& let Some(TileSource::TileGroup(group_id)) = server_ctx.curr_tile_source
&& project.is_tile_node_group(&group_id)
{
server_ctx.tile_node_group_id = Some(group_id);
}
let use_editor_canvas = if self.dock == "Data" {
matches!(server_ctx.pc, ProjectContext::CharacterPreviewRigging(_))
} else {
self.editor_index.is_some()
};
if use_editor_canvas {
let Some(editor_index) = self.editor_index else {
return;
};
if let Some(stack) = ui.get_stack_layout("Editor Stack") {
stack.set_index(editor_index);
self.state = DockManagerState::Editor;
let mut supports_undo = None;
if let Some(editor_dock) = self.editor_docks.get_mut(&self.dock) {
editor_dock.activate(ui, ctx, project, server_ctx);
supports_undo = Some(editor_dock.supports_undo());
if let Some(supports_undo) = supports_undo
&& supports_undo
{
editor_dock.set_undo_state_to_ui(ctx);
}
if let Some(tools) = editor_dock.editor_tools() {
TOOLLIST.write().unwrap().set_editor_tools(tools, ui, ctx);
}
}
if let Some(supports_undo) = supports_undo {
self.set_supports_undo(supports_undo, ctx);
}
}
} else if let Some(layout) = ui.get_sharedvlayout("Shared VLayout") {
layout.set_mode(TheSharedVLayoutMode::Bottom);
self.state = DockManagerState::Maximized;
}
}
pub fn minimize(&mut self, ui: &mut TheUI, ctx: &mut TheContext) {
if self.state != DockManagerState::Minimized {
if self.state == DockManagerState::Editor {
if let Some(editor_dock) = self.editor_docks.get_mut(&self.dock) {
editor_dock.minimized(ui, ctx);
}
TOOLLIST.write().unwrap().set_game_tools(ui, ctx);
if let Some(stack) = ui.get_stack_layout("Editor Stack") {
stack.set_index(0);
}
self.state = DockManagerState::Minimized;
} else if let Some(layout) = ui.get_sharedvlayout("Shared VLayout") {
layout.set_mode(TheSharedVLayoutMode::Shared);
self.state = DockManagerState::Minimized;
}
self.set_supports_undo(self.docks[self.index].supports_undo(), ctx);
}
}
pub fn current_dock_supports_undo(&self) -> bool {
self.supports_undo
}
fn set_supports_undo(&mut self, supports_undo: bool, ctx: &mut TheContext) {
if !supports_undo {
ctx.ui.send(TheEvent::Custom(
TheId::named("Set Project Undo State"),
TheValue::Empty,
));
}
self.supports_undo = supports_undo;
}
pub fn undo(
&mut self,
ui: &mut TheUI,
ctx: &mut TheContext,
project: &mut Project,
server_ctx: &mut ServerContext,
) {
if self.state == DockManagerState::Editor {
if let Some(editor_dock) = self.editor_docks.get_mut(&self.dock) {
editor_dock.undo(ui, ctx, project, server_ctx);
}
} else {
self.docks[self.index].undo(ui, ctx, project, server_ctx);
}
}
pub fn redo(
&mut self,
ui: &mut TheUI,
ctx: &mut TheContext,
project: &mut Project,
server_ctx: &mut ServerContext,
) {
if self.state == DockManagerState::Editor {
if let Some(editor_dock) = self.editor_docks.get_mut(&self.dock) {
editor_dock.redo(ui, ctx, project, server_ctx);
}
} else {
self.docks[self.index].redo(ui, ctx, project, server_ctx);
}
}
pub fn current_dock_supports_minimap_animation(&self) -> bool {
match self.state {
DockManagerState::Editor => self
.editor_docks
.get(&self.dock)
.map(|d| d.supports_minimap_animation())
.unwrap_or(false),
_ => self
.docks
.get_index(self.index)
.map(|(_, d)| d.supports_minimap_animation())
.unwrap_or(false),
}
}
pub fn get_active_dock(&self) -> Option<&dyn Dock> {
if self.state == DockManagerState::Editor {
self.editor_docks.get(&self.dock).map(|d| d.as_ref())
} else {
Some(self.docks[self.index].as_ref())
}
}
pub fn has_dock_changes(&self) -> bool {
for dock in self.docks.values() {
if dock.has_changes() {
return true;
}
}
for dock in self.editor_docks.values() {
if dock.has_changes() {
return true;
}
}
false
}
pub fn mark_saved(&mut self) {
for dock in self.docks.values_mut() {
dock.mark_saved();
}
for dock in self.editor_docks.values_mut() {
dock.mark_saved();
}
}
pub fn apply_debug_data(
&mut self,
ui: &mut TheUI,
ctx: &mut TheContext,
project: &Project,
server_ctx: &ServerContext,
debug: &DebugModule,
) {
if self.state == DockManagerState::Editor {
if let Some(editor_dock) = self.editor_docks.get_mut(&self.dock) {
editor_dock.apply_debug_data(ui, ctx, project, server_ctx, debug);
}
} else if let Some((_, dock)) = self.docks.get_index_mut(self.index) {
dock.apply_debug_data(ui, ctx, project, server_ctx, debug);
}
}
pub fn sync_text_play_dock(
&mut self,
_ui: &mut TheUI,
ctx: &mut TheContext,
project: &Project,
server_ctx: &mut ServerContext,
is_running: bool,
) {
let toollist = TOOLLIST.read().unwrap();
let current_tool_name = toollist.game_tools[toollist.curr_game_tool]
.id()
.name
.clone();
let in_game_tool_mode = server_ctx.game_mode || current_tool_name == "Game Tool";
let should_show = is_running
&& server_ctx.text_game_mode
&& !server_ctx.game_mode
&& !toollist.editor_mode
&& current_tool_name != "Game Tool"
&& server_ctx.get_map_context() == MapContext::Region;
drop(toollist);
if should_show {
if !self.auto_text_play_active {
self.auto_text_play_prev_dock = if !self.dock.is_empty() && self.dock != "Text Play"
{
Some(self.dock.clone())
} else {
None
};
self.auto_text_play_active = true;
}
if self.dock != "Text Play" {
self.set_dock("Text Play".into(), _ui, ctx, project, server_ctx);
}
} else if self.auto_text_play_active {
if in_game_tool_mode {
self.auto_text_play_active = false;
self.auto_text_play_prev_dock = None;
return;
}
let restore_dock = self.auto_text_play_prev_dock.take();
self.auto_text_play_active = false;
if self.dock == "Text Play" {
if let Some(dock) = restore_dock {
self.set_dock(dock, _ui, ctx, project, server_ctx);
} else {
self.minimize(_ui, ctx);
}
}
}
}
}