diff --git a/editor/action_banner.cpp b/editor/action_banner.cpp new file mode 100644 index 0000000..312139b --- /dev/null +++ b/editor/action_banner.cpp @@ -0,0 +1,79 @@ +/** + * action_banner.cpp + * ============================================================================= + * Copyright 2021-2023 Serhii Snitsaruk + * + * Use of this source code is governed by an MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT. + * ============================================================================= + */ + +#include "action_banner.h" + +#include "scene/gui/button.h" + +void ActionBanner::set_text(const String &p_text) { + message->set_text(p_text); +} + +String ActionBanner::get_text() const { + return message->get_text(); +} + +void ActionBanner::close() { + queue_free(); +} + +void ActionBanner::add_action(const String &p_name, const Callable &p_action, bool p_auto_close) { + Button *action_btn = memnew(Button); + action_btn->set_text(p_name); + action_btn->connect(SNAME("pressed"), callable_mp(this, &ActionBanner::_execute_action).bind(p_action, p_auto_close)); + hbox->add_child(action_btn); +} + +void ActionBanner::_execute_action(const Callable &p_action, bool p_auto_close) { + Callable::CallError ce; + Variant ret; + p_action.callp(nullptr, 0, ret, ce); + + if (p_auto_close) { + queue_free(); + } +} + +void ActionBanner::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_THEME_CHANGED: { + icon->set_texture(get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons"))); + } break; + } +} + +void ActionBanner::_bind_methods() { +} + +ActionBanner::ActionBanner() { + add_theme_constant_override("margin_bottom", 4); + add_theme_constant_override("margin_top", 4); + add_theme_constant_override("margin_left", 10); + add_theme_constant_override("margin_right", 10); + + hbox = memnew(HBoxContainer); + hbox->add_theme_constant_override("hseparation", 8); + add_child(hbox); + + icon = memnew(TextureRect); + icon->set_expand_mode(TextureRect::ExpandMode::EXPAND_KEEP_SIZE); + icon->set_stretch_mode(TextureRect::StretchMode::STRETCH_KEEP_CENTERED); + hbox->add_child(icon); + + message = memnew(Label); + message->set_text(vformat(TTR("User task folder doesn't exist"))); + message->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER); + hbox->add_child(message); + + Control *spacer = memnew(Control); + spacer->set_custom_minimum_size(Size2(0, 16)); + hbox->add_child(spacer); +} diff --git a/editor/action_banner.h b/editor/action_banner.h new file mode 100644 index 0000000..a4a7ad0 --- /dev/null +++ b/editor/action_banner.h @@ -0,0 +1,48 @@ +/** + * action_banner.h + * ============================================================================= + * Copyright 2021-2023 Serhii Snitsaruk + * + * Use of this source code is governed by an MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT. + * ============================================================================= + */ +/* action_banner.h */ + +#ifndef ACTION_BANNER_H +#define ACTION_BANNER_H + +#include "scene/gui/margin_container.h" + +#include "scene/gui/box_container.h" +#include "scene/gui/label.h" +#include "scene/gui/texture_rect.h" + +class ActionBanner : public MarginContainer { + GDCLASS(ActionBanner, MarginContainer); + +private: + TextureRect *icon; + Label *message; + HBoxContainer *hbox; + + void _execute_action(const Callable &p_action, bool p_auto_close); + +protected: + static void _bind_methods(); + + void _notification(int p_what); + +public: + void set_text(const String &p_text); + String get_text() const; + + void add_action(const String &p_name, const Callable &p_action, bool p_auto_close = false); + + void close(); + + ActionBanner(); +}; + +#endif // ACTION_BANNER \ No newline at end of file diff --git a/editor/limbo_ai_editor_plugin.cpp b/editor/limbo_ai_editor_plugin.cpp index c32a806..3a27193 100644 --- a/editor/limbo_ai_editor_plugin.cpp +++ b/editor/limbo_ai_editor_plugin.cpp @@ -13,6 +13,7 @@ #include "limbo_ai_editor_plugin.h" +#include "action_banner.h" #include "modules/limboai/bt/behavior_tree.h" #include "modules/limboai/bt/tasks/bt_action.h" #include "modules/limboai/bt/tasks/bt_comment.h" @@ -911,13 +912,14 @@ void LimboAIEditor::_create_user_task_dir() { err = dir->make_dir_recursive(task_dir); ERR_FAIL_COND_MSG(err != OK, "LimboAIEditor: Failed to create directory: " + task_dir); - _update_warnings(); EditorFileSystem::get_singleton()->scan_changes(); + _update_banners(); } void LimboAIEditor::_edit_project_settings() { ProjectSettingsEditor::get_singleton()->set_general_page("limbo_ai/behavior_tree"); ProjectSettingsEditor::get_singleton()->popup_project_settings(); + ProjectSettingsEditor::get_singleton()->connect(SNAME("visibility_changed"), callable_mp(this, &LimboAIEditor::_update_banners), CONNECT_ONE_SHOT); } void LimboAIEditor::shortcut_input(const Ref &p_event) { @@ -1393,8 +1395,21 @@ void LimboAIEditor::_update_misc_menu() { MISC_CREATE_SCRIPT_TEMPLATE); } -void LimboAIEditor::_update_warnings() { - task_dir_warning->set_visible(!DirAccess::exists(GLOBAL_GET("limbo_ai/behavior_tree/user_task_dir_1"))); +void LimboAIEditor::_update_banners() { + for (int i = 0; i < banners->get_child_count(); i++) { + banners->get_child(i)->queue_free(); + } + + for (String dir_setting : { "limbo_ai/behavior_tree/user_task_dir_1", "limbo_ai/behavior_tree/user_task_dir_2", "limbo_ai/behavior_tree/user_task_dir_3" }) { + String task_dir = GLOBAL_GET(dir_setting); + if (!task_dir.is_empty() && !DirAccess::exists(task_dir)) { + ActionBanner *banner = memnew(ActionBanner); + banner->set_text(vformat(TTR("Task folder not found: %s"), task_dir)); + banner->add_action(TTR("Create"), callable_mp(this, &LimboAIEditor::_create_user_task_dir), true); + banner->add_action(TTR("Edit Path..."), callable_mp(this, &LimboAIEditor::_edit_project_settings)); + banners->call_deferred(SNAME("add_child"), banner); + } + } } void LimboAIEditor::_notification(int p_what) { @@ -1423,8 +1438,6 @@ void LimboAIEditor::_notification(int p_what) { misc_btn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Tools"), SNAME("EditorIcons"))); - warning_icon->set_texture(get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons"))); - _update_favorite_tasks(); _update_header(); } @@ -1476,13 +1489,13 @@ LimboAIEditor::LimboAIEditor() { load_dialog->hide(); add_child(load_dialog); - VBoxContainer *vb = memnew(VBoxContainer); - vb->set_anchor(SIDE_RIGHT, ANCHOR_END); - vb->set_anchor(SIDE_BOTTOM, ANCHOR_END); - add_child(vb); + vbox = memnew(VBoxContainer); + vbox->set_anchor(SIDE_RIGHT, ANCHOR_END); + vbox->set_anchor(SIDE_BOTTOM, ANCHOR_END); + add_child(vbox); HBoxContainer *toolbar = memnew(HBoxContainer); - vb->add_child(toolbar); + vbox->add_child(toolbar); Array favorite_tasks_default; favorite_tasks_default.append("BTSelector"); @@ -1567,13 +1580,13 @@ LimboAIEditor::LimboAIEditor() { 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); + vbox->add_child(header); hsc = memnew(HSplitContainer); hsc->set_h_size_flags(SIZE_EXPAND_FILL); hsc->set_v_size_flags(SIZE_EXPAND_FILL); hsc->set_focus_mode(FOCUS_NONE); - vb->add_child(hsc); + vbox->add_child(hsc); task_tree = memnew(TaskTree); task_tree->set_v_size_flags(SIZE_EXPAND_FILL); @@ -1584,7 +1597,7 @@ 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->connect("visibility_changed", callable_mp(this, &LimboAIEditor::_on_visibility_changed)); - task_tree->connect("visibility_changed", callable_mp(this, &LimboAIEditor::_update_warnings)); + task_tree->connect("visibility_changed", callable_mp(this, &LimboAIEditor::_update_banners)); hsc->add_child(task_tree); usage_hint = memnew(Panel); @@ -1607,50 +1620,8 @@ LimboAIEditor::LimboAIEditor() { task_panel->hide(); hsc->add_child(task_panel); - task_dir_warning = memnew(MarginContainer); - { - task_dir_warning->add_theme_constant_override("margin_bottom", 4); - task_dir_warning->add_theme_constant_override("margin_top", 4); - task_dir_warning->add_theme_constant_override("margin_left", 4); - task_dir_warning->add_theme_constant_override("margin_right", 4); - - HBoxContainer *hb = memnew(HBoxContainer); - hb->add_theme_constant_override("hseparation", 8); - task_dir_warning->add_child(hb); - - warning_icon = memnew(TextureRect); - warning_icon->set_expand_mode(TextureRect::ExpandMode::EXPAND_KEEP_SIZE); - warning_icon->set_stretch_mode(TextureRect::StretchMode::STRETCH_KEEP_CENTERED); - hb->add_child(warning_icon); - - Label *warning_label = memnew(Label); - warning_label->set_text(vformat(TTR("User task folder doesn't exist"))); - warning_label->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER); - hb->add_child(warning_label); - - Control *spacer = memnew(Control); - spacer->set_custom_minimum_size(Size2(0, 16)); - hb->add_child(spacer); - - Button *create_action = memnew(Button); - create_action->set_text(TTR("Create")); - create_action->connect("pressed", callable_mp(this, &LimboAIEditor::_create_user_task_dir)); - hb->add_child(create_action); - - Button *edit_action = memnew(Button); - edit_action->set_text(TTR("Edit Path...")); - edit_action->connect("pressed", callable_mp(this, &LimboAIEditor::_edit_project_settings)); - hb->add_child(edit_action); - - Button *refresh_action = memnew(Button); - refresh_action->set_text(TTR("Refresh")); - refresh_action->connect("pressed", callable_mp(task_panel, &TaskPanel::refresh)); - refresh_action->connect("pressed", callable_mp(this, &LimboAIEditor::_update_warnings)); - hb->add_child(refresh_action); - - task_dir_warning->hide(); - } - vb->add_child(task_dir_warning); + banners = memnew(VBoxContainer); + vbox->add_child(banners); menu = memnew(PopupMenu); add_child(menu); diff --git a/editor/limbo_ai_editor_plugin.h b/editor/limbo_ai_editor_plugin.h index e5cfbb5..f59f418 100644 --- a/editor/limbo_ai_editor_plugin.h +++ b/editor/limbo_ai_editor_plugin.h @@ -167,9 +167,11 @@ private: int idx_history; HashSet> dirty; + VBoxContainer *vbox; Button *header; HSplitContainer *hsc; TaskTree *task_tree; + VBoxContainer *banners; Panel *usage_hint; PopupMenu *menu; FileDialog *save_dialog; @@ -178,8 +180,6 @@ private: Button *history_forward; TaskPanel *task_panel; HBoxContainer *fav_tasks_hbox; - MarginContainer *task_dir_warning; - TextureRect *warning_icon; Button *comment_btn; Button *new_btn; @@ -203,7 +203,7 @@ private: void _update_history_buttons(); void _update_favorite_tasks(); void _update_misc_menu(); - void _update_warnings(); + void _update_banners(); void _new_bt(); void _save_bt(String p_path); void _load_bt(String p_path);