Handle theme change in the LimboAI editor

Also fixes warning: "Attempting to access theme items too early".
This commit is contained in:
Serhii Snitsaruk 2023-08-16 11:19:51 +02:00
parent 13f5eb1f71
commit 8d89f80d6b
2 changed files with 103 additions and 56 deletions

View File

@ -73,7 +73,7 @@
#include "scene/gui/tree.h"
#include "servers/display_server.h"
////////////////////////////// TaskTree //////////////////////////////////////
//**** TaskTree
TreeItem *TaskTree::_create_tree(const Ref<BTTask> &p_task, TreeItem *p_parent, int p_idx) {
ERR_FAIL_COND_V(p_task.is_null(), nullptr);
@ -130,6 +130,10 @@ void TaskTree::_update_tree() {
}
tree->clear();
if (bt.is_null()) {
return;
}
if (bt->get_root_task().is_valid()) {
_create_tree(bt->get_root_task(), nullptr);
}
@ -280,6 +284,14 @@ void TaskTree::_drop_data_fw(const Point2 &p_point, const Variant &p_data) {
}
}
void TaskTree::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED: {
_update_tree();
} break;
}
}
void TaskTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("load_bt", "p_behavior_tree"), &TaskTree::load_bt);
ClassDB::bind_method(D_METHOD("get_bt"), &TaskTree::get_bt);
@ -327,9 +339,9 @@ TaskTree::~TaskTree() {
}
}
////////////////////////////// TaskTree //////////////////////////////////////
//**** TaskTree ^
////////////////////////////// TaskSection ////////////////////////////////////
//**** TaskSection
void TaskSection::_on_task_button_pressed(const StringName &p_task) {
emit_signal(SNAME("task_button_pressed"), p_task);
@ -374,6 +386,13 @@ bool TaskSection::is_collapsed() const {
return !tasks_container->is_visible();
}
void TaskSection::_notification(int p_what) {
if (p_what == NOTIFICATION_THEME_CHANGED) {
section_header->set_icon(is_collapsed() ? get_theme_icon(SNAME("GuiTreeArrowRight"), SNAME("EditorIcons")) : get_theme_icon(SNAME("GuiTreeArrowDown"), SNAME("EditorIcons")));
section_header->add_theme_font_override(SNAME("font"), get_theme_font(SNAME("bold"), SNAME("EditorFonts")));
}
}
void TaskSection::_bind_methods() {
ADD_SIGNAL(MethodInfo("task_button_pressed"));
}
@ -382,9 +401,7 @@ TaskSection::TaskSection(String p_category_name) {
section_header = memnew(Button);
add_child(section_header);
section_header->set_text(p_category_name);
section_header->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("GuiTreeArrowDown"), SNAME("EditorIcons")));
section_header->set_focus_mode(FOCUS_NONE);
section_header->add_theme_font_override(SNAME("font"), get_theme_font(SNAME("bold"), SNAME("EditorFonts")));
section_header->connect("pressed", callable_mp(this, &TaskSection::_on_header_pressed));
tasks_container = memnew(HFlowContainer);
@ -394,9 +411,9 @@ TaskSection::TaskSection(String p_category_name) {
TaskSection::~TaskSection() {
}
////////////////////////////// TaskSection ////////////////////////////////////
//**** TaskSection ^
////////////////////////////// TaskPanel /////////////////////////////////////
//**** TaskPanel
void TaskPanel::_on_task_button_pressed(const StringName &p_task) {
emit_signal(SNAME("task_selected"), p_task);
@ -560,22 +577,29 @@ void TaskPanel::_populate_scripted_tasks_from_dir(String p_path, List<String> *p
}
void TaskPanel::_notification(int p_what) {
if (p_what == NOTIFICATION_EXIT_TREE) {
if (sections->get_child_count() == 0) {
return;
}
Array collapsed_sections;
for (int i = 0; i < sections->get_child_count(); i++) {
TaskSection *sec = Object::cast_to<TaskSection>(sections->get_child(i));
if (sec->is_collapsed()) {
collapsed_sections.push_back(sec->get_category_name());
switch (p_what) {
case NOTIFICATION_EXIT_TREE: {
if (sections->get_child_count() == 0) {
return;
}
}
ConfigFile conf;
String conf_path = EditorPaths::get_singleton()->get_project_settings_dir().path_join("limbo_ai.cfg");
conf.load(conf_path);
conf.set_value("bt_editor", "collapsed_sections", collapsed_sections);
conf.save(conf_path);
Array collapsed_sections;
for (int i = 0; i < sections->get_child_count(); i++) {
TaskSection *sec = Object::cast_to<TaskSection>(sections->get_child(i));
if (sec->is_collapsed()) {
collapsed_sections.push_back(sec->get_category_name());
}
}
ConfigFile conf;
String conf_path = EditorPaths::get_singleton()->get_project_settings_dir().path_join("limbo_ai.cfg");
conf.load(conf_path);
conf.set_value("bt_editor", "collapsed_sections", collapsed_sections);
conf.save(conf_path);
} break;
case NOTIFICATION_THEME_CHANGED: {
if (is_visible_in_tree()) {
refresh();
}
} break;
}
}
@ -590,28 +614,28 @@ TaskPanel::TaskPanel() {
add_child(vb);
filter_edit = memnew(LineEdit);
vb->add_child(filter_edit);
filter_edit->set_clear_button_enabled(true);
filter_edit->set_placeholder(TTR("Filter tasks"));
filter_edit->connect("text_changed", callable_mp(this, &TaskPanel::_on_filter_text_changed));
vb->add_child(filter_edit);
ScrollContainer *sc = memnew(ScrollContainer);
vb->add_child(sc);
sc->set_h_size_flags(SIZE_EXPAND_FILL);
sc->set_v_size_flags(SIZE_EXPAND_FILL);
vb->add_child(sc);
sections = memnew(VBoxContainer);
sc->add_child(sections);
sections->set_h_size_flags(SIZE_EXPAND_FILL);
sections->set_v_size_flags(SIZE_EXPAND_FILL);
sc->add_child(sections);
}
TaskPanel::~TaskPanel() {
}
////////////////////////////// TaskPanel /////////////////////////////////////
//**** TaskPanel ^
//////////////////////////// LimboAIEditor ///////////////////////////////////
//**** LimboAIEditor
void LimboAIEditor::_add_task(const Ref<BTTask> &p_task) {
ERR_FAIL_COND(p_task.is_null());
@ -654,6 +678,12 @@ void LimboAIEditor::_remove_task(const Ref<BTTask> &p_task) {
}
void LimboAIEditor::_update_header() const {
if (task_tree->get_bt().is_null()) {
header->set_text("");
header->set_icon(nullptr);
return;
}
String text = task_tree->get_bt()->get_path();
if (text.is_empty()) {
text = TTR("New Behavior Tree");
@ -1059,6 +1089,19 @@ void LimboAIEditor::_notification(int p_what) {
conf.set_value("bt_editor", "bteditor_hsplit", hsc->get_split_offset());
conf.save(conf_path);
} break;
case NOTIFICATION_THEME_CHANGED: {
selector_btn->set_icon(EditorNode::get_singleton()->get_class_icon("BTSelector"));
sequence_btn->set_icon(EditorNode::get_singleton()->get_class_icon("BTSequence"));
parallel_btn->set_icon(EditorNode::get_singleton()->get_class_icon("BTParallel"));
new_btn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("New"), SNAME("EditorIcons")));
load_btn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Load"), SNAME("EditorIcons")));
save_btn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Save"), SNAME("EditorIcons")));
new_script_btn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("ScriptCreate"), SNAME("EditorIcons")));
history_back->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Back"), SNAME("EditorIcons")));
history_forward->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Forward"), SNAME("EditorIcons")));
_update_header();
}
}
}
@ -1078,20 +1121,20 @@ LimboAIEditor::LimboAIEditor() {
idx_history = 0;
save_dialog = memnew(FileDialog);
add_child(save_dialog);
save_dialog->set_file_mode(FileDialog::FILE_MODE_SAVE_FILE);
save_dialog->set_title("Save Behavior Tree");
save_dialog->add_filter("*.tres");
save_dialog->connect("file_selected", callable_mp(this, &LimboAIEditor::_save_bt));
save_dialog->hide();
add_child(save_dialog);
load_dialog = memnew(FileDialog);
add_child(load_dialog);
load_dialog->set_file_mode(FileDialog::FILE_MODE_OPEN_FILE);
load_dialog->set_title("Load Behavior Tree");
load_dialog->add_filter("*.tres");
load_dialog->connect("file_selected", callable_mp(this, &LimboAIEditor::_load_bt));
load_dialog->hide();
add_child(load_dialog);
VBoxContainer *vb = memnew(VBoxContainer);
vb->set_anchor(SIDE_RIGHT, ANCHOR_END);
@ -1101,28 +1144,25 @@ LimboAIEditor::LimboAIEditor() {
HBoxContainer *panel = memnew(HBoxContainer);
vb->add_child(panel);
Button *selector_btn = memnew(Button);
selector_btn = memnew(Button);
selector_btn->set_text(TTR("Selector"));
selector_btn->set_tooltip_text(TTR("Add Selector task."));
selector_btn->set_icon(EditorNode::get_singleton()->get_class_icon("BTSelector"));
selector_btn->set_flat(true);
selector_btn->set_focus_mode(Control::FOCUS_NONE);
selector_btn->connect("pressed", callable_mp(this, &LimboAIEditor::_add_task_with_prototype).bind(Ref<BTTask>(memnew(BTSelector))));
panel->add_child(selector_btn);
Button *sequence_btn = memnew(Button);
sequence_btn = memnew(Button);
sequence_btn->set_text(TTR("Sequence"));
sequence_btn->set_tooltip_text(TTR("Add Sequence task."));
sequence_btn->set_icon(EditorNode::get_singleton()->get_class_icon("BTSequence"));
sequence_btn->set_flat(true);
sequence_btn->set_focus_mode(Control::FOCUS_NONE);
sequence_btn->connect("pressed", callable_mp(this, &LimboAIEditor::_add_task_with_prototype).bind(Ref<BTTask>(memnew(BTSequence))));
panel->add_child(sequence_btn);
Button *parallel_btn = memnew(Button);
parallel_btn = memnew(Button);
parallel_btn->set_text(TTR("Parallel"));
parallel_btn->set_tooltip_text(TTR("Add Parallel task."));
parallel_btn->set_icon(EditorNode::get_singleton()->get_class_icon("BTParallel"));
parallel_btn->set_flat(true);
parallel_btn->set_focus_mode(Control::FOCUS_NONE);
parallel_btn->connect("pressed", callable_mp(this, &LimboAIEditor::_add_task_with_prototype).bind(Ref<BTTask>(memnew(BTParallel))));
@ -1130,74 +1170,67 @@ LimboAIEditor::LimboAIEditor() {
panel->add_child(memnew(VSeparator));
Button *new_btn = memnew(Button);
panel->add_child(new_btn);
new_btn = memnew(Button);
new_btn->set_text(TTR("New"));
new_btn->set_tooltip_text(TTR("Create new behavior tree."));
new_btn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("New"), SNAME("EditorIcons")));
new_btn->set_flat(true);
new_btn->set_focus_mode(Control::FOCUS_NONE);
new_btn->connect("pressed", callable_mp(this, &LimboAIEditor::_new_bt));
panel->add_child(new_btn);
Button *load_btn = memnew(Button);
panel->add_child(load_btn);
load_btn = memnew(Button);
load_btn->set_text(TTR("Load"));
load_btn->set_tooltip_text(TTR("Load behavior tree."));
load_btn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Load"), SNAME("EditorIcons")));
load_btn->set_flat(true);
load_btn->set_focus_mode(Control::FOCUS_NONE);
load_btn->connect("pressed", callable_mp(load_dialog, &FileDialog::popup_file_dialog));
panel->add_child(load_btn);
Button *save_btn = memnew(Button);
panel->add_child(save_btn);
save_btn = memnew(Button);
save_btn->set_text(TTR("Save"));
save_btn->set_tooltip_text(TTR("Save current behavior tree."));
save_btn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Save"), SNAME("EditorIcons")));
save_btn->set_flat(true);
save_btn->set_focus_mode(Control::FOCUS_NONE);
save_btn->connect("pressed", callable_mp(this, &LimboAIEditor::_on_save_pressed));
panel->add_child(save_btn);
panel->add_child(memnew(VSeparator));
Button *new_script_btn = memnew(Button);
panel->add_child(new_script_btn);
new_script_btn = memnew(Button);
new_script_btn->set_text(TTR("New Task"));
new_script_btn->set_tooltip_text(TTR("Create new task script and edit it."));
new_script_btn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("ScriptCreate"), SNAME("EditorIcons")));
new_script_btn->set_flat(true);
new_script_btn->set_focus_mode(Control::FOCUS_NONE);
panel->add_child(new_script_btn);
HBoxContainer *nav = memnew(HBoxContainer);
panel->add_child(nav);
nav->set_h_size_flags(SIZE_EXPAND | SIZE_SHRINK_END);
panel->add_child(nav);
history_back = memnew(Button);
history_back->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Back"), SNAME("EditorIcons")));
history_back->set_flat(true);
history_back->set_focus_mode(FOCUS_NONE);
history_back->connect("pressed", callable_mp(this, &LimboAIEditor::_on_history_back));
nav->add_child(history_back);
history_forward = memnew(Button);
history_forward->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Forward"), SNAME("EditorIcons")));
history_forward->set_flat(true);
history_forward->set_focus_mode(FOCUS_NONE);
history_forward->connect("pressed", callable_mp(this, &LimboAIEditor::_on_history_forward));
nav->add_child(history_forward);
header = memnew(Button);
vb->add_child(header);
header->set_text_alignment(HORIZONTAL_ALIGNMENT_LEFT);
header->add_theme_constant_override("hseparation", 8);
header->connect("pressed", callable_mp(this, &LimboAIEditor::_on_header_pressed));
vb->add_child(header);
hsc = memnew(HSplitContainer);
vb->add_child(hsc);
hsc->set_h_size_flags(SIZE_EXPAND_FILL);
hsc->set_v_size_flags(SIZE_EXPAND_FILL);
vb->add_child(hsc);
task_tree = memnew(TaskTree);
hsc->add_child(task_tree);
task_tree->set_v_size_flags(SIZE_EXPAND_FILL);
task_tree->set_h_size_flags(SIZE_EXPAND_FILL);
task_tree->connect("rmb_pressed", callable_mp(this, &LimboAIEditor::_on_tree_rmb));
@ -1206,11 +1239,13 @@ LimboAIEditor::LimboAIEditor() {
task_tree->connect("task_dragged", callable_mp(this, &LimboAIEditor::_on_task_dragged));
task_tree->connect("task_double_clicked", callable_mp(this, &LimboAIEditor::_on_tree_task_double_clicked));
task_tree->hide();
hsc->add_child(task_tree);
usage_hint = memnew(Panel);
usage_hint->set_v_size_flags(SIZE_EXPAND_FILL);
usage_hint->set_h_size_flags(SIZE_EXPAND_FILL);
hsc->add_child(usage_hint);
Label *usage_label = memnew(Label);
usage_label->set_anchor(SIDE_RIGHT, 1);
usage_label->set_anchor(SIDE_BOTTOM, 1);
@ -1220,10 +1255,10 @@ LimboAIEditor::LimboAIEditor() {
usage_hint->add_child(usage_label);
task_panel = memnew(TaskPanel());
hsc->add_child(task_panel);
hsc->set_split_offset(-300);
task_panel->connect("task_selected", callable_mp(this, &LimboAIEditor::_on_panel_task_selected));
task_panel->hide();
hsc->add_child(task_panel);
menu = memnew(PopupMenu);
add_child(menu);
@ -1284,9 +1319,9 @@ LimboAIEditor::LimboAIEditor() {
LimboAIEditor::~LimboAIEditor() {
}
//////////////////////////// LimboAIEditor ///////////////////////////////////
//**** LimboAIEditor ^
///////////////////////// LimboAIEditorPlugin ////////////////////////////////
//**** LimboAIEditorPlugin
const Ref<Texture2D> LimboAIEditorPlugin::get_icon() const {
return EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("LimboAIEditor"), SNAME("EditorIcons"));

View File

@ -58,6 +58,8 @@ private:
protected:
static void _bind_methods();
void _notification(int p_what);
public:
void load_bt(const Ref<BehaviorTree> &p_behavior_tree);
void unload();
@ -86,6 +88,8 @@ private:
protected:
static void _bind_methods();
void _notification(int p_what);
public:
void set_filter(String p_filter);
void add_task_button(String p_name, const Ref<Texture> &icon, Variant p_meta);
@ -151,6 +155,14 @@ private:
Button *history_forward;
TaskPanel *task_panel;
Button *selector_btn;
Button *sequence_btn;
Button *parallel_btn;
Button *new_btn;
Button *load_btn;
Button *save_btn;
Button *new_script_btn;
ConfirmationDialog *rename_dialog;
LineEdit *rename_edit;