Implement ActionBanner class for actionable editor alerts
This commit is contained in:
parent
4942173e5b
commit
24678e4332
|
@ -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);
|
||||||
|
}
|
|
@ -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
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
#include "limbo_ai_editor_plugin.h"
|
#include "limbo_ai_editor_plugin.h"
|
||||||
|
|
||||||
|
#include "action_banner.h"
|
||||||
#include "modules/limboai/bt/behavior_tree.h"
|
#include "modules/limboai/bt/behavior_tree.h"
|
||||||
#include "modules/limboai/bt/tasks/bt_action.h"
|
#include "modules/limboai/bt/tasks/bt_action.h"
|
||||||
#include "modules/limboai/bt/tasks/bt_comment.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 = dir->make_dir_recursive(task_dir);
|
||||||
ERR_FAIL_COND_MSG(err != OK, "LimboAIEditor: Failed to create directory: " + task_dir);
|
ERR_FAIL_COND_MSG(err != OK, "LimboAIEditor: Failed to create directory: " + task_dir);
|
||||||
|
|
||||||
_update_warnings();
|
|
||||||
EditorFileSystem::get_singleton()->scan_changes();
|
EditorFileSystem::get_singleton()->scan_changes();
|
||||||
|
_update_banners();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LimboAIEditor::_edit_project_settings() {
|
void LimboAIEditor::_edit_project_settings() {
|
||||||
ProjectSettingsEditor::get_singleton()->set_general_page("limbo_ai/behavior_tree");
|
ProjectSettingsEditor::get_singleton()->set_general_page("limbo_ai/behavior_tree");
|
||||||
ProjectSettingsEditor::get_singleton()->popup_project_settings();
|
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<InputEvent> &p_event) {
|
void LimboAIEditor::shortcut_input(const Ref<InputEvent> &p_event) {
|
||||||
|
@ -1393,8 +1395,21 @@ void LimboAIEditor::_update_misc_menu() {
|
||||||
MISC_CREATE_SCRIPT_TEMPLATE);
|
MISC_CREATE_SCRIPT_TEMPLATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LimboAIEditor::_update_warnings() {
|
void LimboAIEditor::_update_banners() {
|
||||||
task_dir_warning->set_visible(!DirAccess::exists(GLOBAL_GET("limbo_ai/behavior_tree/user_task_dir_1")));
|
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) {
|
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")));
|
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_favorite_tasks();
|
||||||
_update_header();
|
_update_header();
|
||||||
}
|
}
|
||||||
|
@ -1476,13 +1489,13 @@ LimboAIEditor::LimboAIEditor() {
|
||||||
load_dialog->hide();
|
load_dialog->hide();
|
||||||
add_child(load_dialog);
|
add_child(load_dialog);
|
||||||
|
|
||||||
VBoxContainer *vb = memnew(VBoxContainer);
|
vbox = memnew(VBoxContainer);
|
||||||
vb->set_anchor(SIDE_RIGHT, ANCHOR_END);
|
vbox->set_anchor(SIDE_RIGHT, ANCHOR_END);
|
||||||
vb->set_anchor(SIDE_BOTTOM, ANCHOR_END);
|
vbox->set_anchor(SIDE_BOTTOM, ANCHOR_END);
|
||||||
add_child(vb);
|
add_child(vbox);
|
||||||
|
|
||||||
HBoxContainer *toolbar = memnew(HBoxContainer);
|
HBoxContainer *toolbar = memnew(HBoxContainer);
|
||||||
vb->add_child(toolbar);
|
vbox->add_child(toolbar);
|
||||||
|
|
||||||
Array favorite_tasks_default;
|
Array favorite_tasks_default;
|
||||||
favorite_tasks_default.append("BTSelector");
|
favorite_tasks_default.append("BTSelector");
|
||||||
|
@ -1567,13 +1580,13 @@ LimboAIEditor::LimboAIEditor() {
|
||||||
header->set_text_alignment(HORIZONTAL_ALIGNMENT_LEFT);
|
header->set_text_alignment(HORIZONTAL_ALIGNMENT_LEFT);
|
||||||
header->add_theme_constant_override("hseparation", 8);
|
header->add_theme_constant_override("hseparation", 8);
|
||||||
header->connect("pressed", callable_mp(this, &LimboAIEditor::_on_header_pressed));
|
header->connect("pressed", callable_mp(this, &LimboAIEditor::_on_header_pressed));
|
||||||
vb->add_child(header);
|
vbox->add_child(header);
|
||||||
|
|
||||||
hsc = memnew(HSplitContainer);
|
hsc = memnew(HSplitContainer);
|
||||||
hsc->set_h_size_flags(SIZE_EXPAND_FILL);
|
hsc->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||||
hsc->set_v_size_flags(SIZE_EXPAND_FILL);
|
hsc->set_v_size_flags(SIZE_EXPAND_FILL);
|
||||||
hsc->set_focus_mode(FOCUS_NONE);
|
hsc->set_focus_mode(FOCUS_NONE);
|
||||||
vb->add_child(hsc);
|
vbox->add_child(hsc);
|
||||||
|
|
||||||
task_tree = memnew(TaskTree);
|
task_tree = memnew(TaskTree);
|
||||||
task_tree->set_v_size_flags(SIZE_EXPAND_FILL);
|
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_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("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::_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);
|
hsc->add_child(task_tree);
|
||||||
|
|
||||||
usage_hint = memnew(Panel);
|
usage_hint = memnew(Panel);
|
||||||
|
@ -1607,50 +1620,8 @@ LimboAIEditor::LimboAIEditor() {
|
||||||
task_panel->hide();
|
task_panel->hide();
|
||||||
hsc->add_child(task_panel);
|
hsc->add_child(task_panel);
|
||||||
|
|
||||||
task_dir_warning = memnew(MarginContainer);
|
banners = memnew(VBoxContainer);
|
||||||
{
|
vbox->add_child(banners);
|
||||||
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);
|
|
||||||
|
|
||||||
menu = memnew(PopupMenu);
|
menu = memnew(PopupMenu);
|
||||||
add_child(menu);
|
add_child(menu);
|
||||||
|
|
|
@ -167,9 +167,11 @@ private:
|
||||||
int idx_history;
|
int idx_history;
|
||||||
HashSet<Ref<BehaviorTree>> dirty;
|
HashSet<Ref<BehaviorTree>> dirty;
|
||||||
|
|
||||||
|
VBoxContainer *vbox;
|
||||||
Button *header;
|
Button *header;
|
||||||
HSplitContainer *hsc;
|
HSplitContainer *hsc;
|
||||||
TaskTree *task_tree;
|
TaskTree *task_tree;
|
||||||
|
VBoxContainer *banners;
|
||||||
Panel *usage_hint;
|
Panel *usage_hint;
|
||||||
PopupMenu *menu;
|
PopupMenu *menu;
|
||||||
FileDialog *save_dialog;
|
FileDialog *save_dialog;
|
||||||
|
@ -178,8 +180,6 @@ private:
|
||||||
Button *history_forward;
|
Button *history_forward;
|
||||||
TaskPanel *task_panel;
|
TaskPanel *task_panel;
|
||||||
HBoxContainer *fav_tasks_hbox;
|
HBoxContainer *fav_tasks_hbox;
|
||||||
MarginContainer *task_dir_warning;
|
|
||||||
TextureRect *warning_icon;
|
|
||||||
|
|
||||||
Button *comment_btn;
|
Button *comment_btn;
|
||||||
Button *new_btn;
|
Button *new_btn;
|
||||||
|
@ -203,7 +203,7 @@ private:
|
||||||
void _update_history_buttons();
|
void _update_history_buttons();
|
||||||
void _update_favorite_tasks();
|
void _update_favorite_tasks();
|
||||||
void _update_misc_menu();
|
void _update_misc_menu();
|
||||||
void _update_warnings();
|
void _update_banners();
|
||||||
void _new_bt();
|
void _new_bt();
|
||||||
void _save_bt(String p_path);
|
void _save_bt(String p_path);
|
||||||
void _load_bt(String p_path);
|
void _load_bt(String p_path);
|
||||||
|
|
Loading…
Reference in New Issue