From 6f8f95b5de68e4661926d5303e3a8f1930c1c950 Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Mon, 27 May 2024 13:48:08 +0200 Subject: [PATCH] Editor: Replace BT resource button with tabs --- editor/limbo_ai_editor_plugin.cpp | 87 +++++++++++++++++++++++++++++-- editor/limbo_ai_editor_plugin.h | 10 ++++ 2 files changed, 93 insertions(+), 4 deletions(-) diff --git a/editor/limbo_ai_editor_plugin.cpp b/editor/limbo_ai_editor_plugin.cpp index 09c91a0..a16b92b 100644 --- a/editor/limbo_ai_editor_plugin.cpp +++ b/editor/limbo_ai_editor_plugin.cpp @@ -208,6 +208,7 @@ void LimboAIEditor::_save_bt(String p_path) { #endif RESOURCE_SAVE(task_tree->get_bt(), p_path, ResourceSaver::FLAG_CHANGE_PATH); _update_header(); + _update_tabs(); _mark_as_dirty(false); } @@ -218,14 +219,19 @@ void LimboAIEditor::_load_bt(String p_path) { if (bt->get_blackboard_plan().is_null()) { bt->set_blackboard_plan(memnew(BlackboardPlan)); } - if (history.find(bt) != -1) { - history.erase(bt); - history.push_back(bt); - } + // if (history.find(bt) != -1) { + // history.erase(bt); + // history.push_back(bt); + // } EDIT_RESOURCE(bt); } +void LimboAIEditor::_disable_editing() { + task_tree->unload(); + task_palette->hide(); +} + void LimboAIEditor::edit_bt(Ref p_behavior_tree, bool p_force_refresh) { ERR_FAIL_COND_MSG(p_behavior_tree.is_null(), "p_behavior_tree is null"); @@ -263,6 +269,7 @@ void LimboAIEditor::edit_bt(Ref p_behavior_tree, bool p_force_refr _update_history_buttons(); _update_header(); + _update_tabs(); } Ref LimboAIEditor::get_edited_blackboard_plan() { @@ -937,6 +944,57 @@ void LimboAIEditor::_replace_task(const Ref &p_task, const Ref & } } +void LimboAIEditor::_tab_clicked(int p_tab) { + if (updating_tabs) { + return; + } + ERR_FAIL_INDEX(p_tab, history.size()); + EDIT_RESOURCE(history[p_tab]); +} + +void LimboAIEditor::_tab_closed(int p_tab) { + history.remove_at(p_tab); + idx_history = MIN(idx_history, history.size() - 1); + if (idx_history < 0) { + _disable_editing(); + } else { + EDIT_RESOURCE(history[idx_history]); + } + _update_history_buttons(); + _update_tabs(); +} + +void LimboAIEditor::_update_tabs() { + updating_tabs = true; + tab_bar->clear_tabs(); + for (int i = 0; i < history.size(); i++) { + String tab_name; + if (history[i]->get_path().is_empty()) { + tab_name = "[new]"; + } else { + tab_name = history[i]->get_path().get_file().get_basename(); + } + tab_bar->add_tab(tab_name, LimboUtility::get_singleton()->get_task_icon("BehaviorTree")); + } + if (idx_history >= 0) { + tab_bar->set_current_tab(idx_history); + } + updating_tabs = false; +} + +void LimboAIEditor::_move_active_tab(int p_to_index) { + ERR_FAIL_INDEX(p_to_index, history.size()); + if (idx_history == p_to_index) { + return; + } + Ref bt = history[idx_history]; + history.remove_at(idx_history); + history.insert(p_to_index, bt); + idx_history = p_to_index; + _update_history_buttons(); + _update_tabs(); +} + void LimboAIEditor::_reload_modified() { for (const String &res_path : disk_changed_files) { Ref res = RESOURCE_LOAD(res_path, "BehaviorTree"); @@ -1161,6 +1219,9 @@ void LimboAIEditor::_notification(int p_what) { disk_changed->connect("custom_action", callable_mp(this, &LimboAIEditor::_resave_modified)); rename_dialog->connect("confirmed", callable_mp(this, &LimboAIEditor::_rename_task_confirmed)); new_script_btn->connect(LW_NAME(pressed), callable_mp(SCRIPT_EDITOR(), &ScriptEditor::open_script_create_dialog).bind("BTAction", String(GLOBAL_GET("limbo_ai/behavior_tree/user_task_dir_1")).path_join("new_task"))); + tab_bar->connect("tab_clicked", callable_mp(this, &LimboAIEditor::_tab_clicked)); + tab_bar->connect("active_tab_rearranged", callable_mp(this, &LimboAIEditor::_move_active_tab)); + tab_bar->connect("tab_close_pressed", callable_mp(this, &LimboAIEditor::_tab_closed)); EDITOR_FILE_SYSTEM()->connect("resources_reload", callable_mp(this, &LimboAIEditor::_on_resources_reload)); @@ -1171,6 +1232,8 @@ void LimboAIEditor::_notification(int p_what) { case NOTIFICATION_THEME_CHANGED: { _do_update_theme_item_cache(); + tab_bar_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("tabbar_background"), SNAME("TabContainer"))); + BUTTON_SET_ICON(new_btn, get_theme_icon(LW_NAME(New), LW_NAME(EditorIcons))); BUTTON_SET_ICON(load_btn, get_theme_icon(LW_NAME(Load), LW_NAME(EditorIcons))); BUTTON_SET_ICON(save_btn, get_theme_icon(LW_NAME(Save), LW_NAME(EditorIcons))); @@ -1315,10 +1378,26 @@ LimboAIEditor::LimboAIEditor() { history_forward->set_focus_mode(FOCUS_NONE); nav->add_child(history_forward); + tab_bar_panel = memnew(PanelContainer); + vbox->add_child(tab_bar_panel); + tab_bar_container = memnew(HBoxContainer); + tab_bar_panel->add_child(tab_bar_container); + + tab_bar = memnew(TabBar); + tab_bar->set_select_with_rmb(true); + tab_bar->set_drag_to_rearrange_enabled(true); + tab_bar->set_max_tab_width(int(EDITOR_GET("interface/scene_tabs/maximum_width")) * EDSCALE); + tab_bar->set_auto_translate(false); + tab_bar->set_tab_close_display_policy(TabBar::CLOSE_BUTTON_SHOW_ACTIVE_ONLY); + tab_bar->set_h_size_flags(Control::SIZE_EXPAND_FILL); + tab_bar->set_focus_mode(FocusMode::FOCUS_NONE); + tab_bar_container->add_child(tab_bar); + header = memnew(Button); header->set_text_alignment(HORIZONTAL_ALIGNMENT_LEFT); header->add_theme_constant_override("hseparation", 8); vbox->add_child(header); + header->hide(); hsc = memnew(HSplitContainer); hsc->set_h_size_flags(SIZE_EXPAND_FILL); diff --git a/editor/limbo_ai_editor_plugin.h b/editor/limbo_ai_editor_plugin.h index 6ee0725..8254ec4 100644 --- a/editor/limbo_ai_editor_plugin.h +++ b/editor/limbo_ai_editor_plugin.h @@ -121,10 +121,14 @@ private: EditorPlugin *plugin; Vector> history; int idx_history; + bool updating_tabs = false; HashSet> dirty; Ref clipboard_task; VBoxContainer *vbox; + PanelContainer *tab_bar_panel; + HBoxContainer *tab_bar_container; + TabBar *tab_bar; Button *header; HSplitContainer *hsc; TaskTree *task_tree; @@ -176,12 +180,18 @@ private: void _new_bt(); void _save_bt(String p_path); void _load_bt(String p_path); + void _disable_editing(); void _mark_as_dirty(bool p_dirty); void _create_user_task_dir(); void _remove_task_from_favorite(const String &p_task); void _extract_subtree(const String &p_path); void _replace_task(const Ref &p_task, const Ref &p_by_task); + void _tab_clicked(int p_tab); + void _tab_closed(int p_tab); + void _update_tabs(); + void _move_active_tab(int p_to_index); + void _reload_modified(); void _resave_modified(String _str = ""); void _popup_file_dialog(FileDialog *p_dialog) { p_dialog->popup_centered_clamped(Size2i(700, 500), 0.8f); }