2024-01-28 16:49:38 +00:00
|
|
|
/**
|
|
|
|
* editor_property_variable_name.cpp
|
|
|
|
* =============================================================================
|
|
|
|
* Copyright 2021-2024 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.
|
|
|
|
* =============================================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef TOOLS_ENABLED
|
|
|
|
|
|
|
|
#include "editor_property_variable_name.h"
|
|
|
|
|
|
|
|
#include "../blackboard/bb_param/bb_param.h"
|
|
|
|
#include "../bt/tasks/bt_task.h"
|
|
|
|
#include "../util/limbo_compat.h"
|
|
|
|
#include "../util/limbo_string_names.h"
|
|
|
|
#include "../util/limbo_utility.h"
|
|
|
|
#include "blackboard_plan_editor.h"
|
|
|
|
|
|
|
|
#ifdef LIMBOAI_MODULE
|
|
|
|
#include "scene/gui/box_container.h"
|
|
|
|
#include "scene/gui/button.h"
|
|
|
|
#include "scene/gui/line_edit.h"
|
|
|
|
#include "scene/gui/popup_menu.h"
|
|
|
|
#endif // LIMBOAI_MODULE
|
|
|
|
|
|
|
|
#ifdef LIMBOAI_GDEXTENSION
|
|
|
|
#include <godot_cpp/classes/h_box_container.hpp>
|
|
|
|
#endif // LIMBOAI_GDEXTENSION
|
|
|
|
|
2024-05-17 19:48:34 +00:00
|
|
|
int EditorPropertyVariableName::last_caret_column = 0;
|
|
|
|
|
2024-01-28 16:49:38 +00:00
|
|
|
//***** EditorPropertyVariableName
|
|
|
|
|
|
|
|
void EditorPropertyVariableName::_show_variables_popup() {
|
2024-11-03 03:53:56 +00:00
|
|
|
ERR_FAIL_COND(plan.is_null());
|
2024-01-28 16:49:38 +00:00
|
|
|
|
|
|
|
variables_popup->clear();
|
|
|
|
variables_popup->reset_size();
|
2024-05-31 09:57:27 +00:00
|
|
|
TypedArray<StringName> var_names = plan->list_vars();
|
|
|
|
for (int i = 0; i < var_names.size(); i++) {
|
|
|
|
variables_popup->add_item(var_names[i], i);
|
2024-01-28 16:49:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Transform2D xform = name_edit->get_screen_transform();
|
|
|
|
Rect2 rect(xform.get_origin(), xform.get_scale() * name_edit->get_size());
|
|
|
|
rect.position.y += rect.size.height;
|
|
|
|
rect.size.height = 0;
|
|
|
|
variables_popup->set_size(rect.size);
|
|
|
|
variables_popup->set_position(rect.position);
|
|
|
|
|
|
|
|
variables_popup->popup(rect);
|
|
|
|
}
|
|
|
|
|
2024-05-17 19:48:34 +00:00
|
|
|
void EditorPropertyVariableName::_name_changed(const String &p_new_name) {
|
|
|
|
if (updating) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
emit_changed(get_edited_property(), p_new_name);
|
|
|
|
last_caret_column = name_edit->get_caret_column();
|
2024-01-28 16:49:38 +00:00
|
|
|
_update_status();
|
|
|
|
}
|
|
|
|
|
2024-05-15 10:50:33 +00:00
|
|
|
void EditorPropertyVariableName::_name_submitted() {
|
2024-05-17 19:48:34 +00:00
|
|
|
_name_changed(name_edit->get_text());
|
2024-05-15 10:50:33 +00:00
|
|
|
if (name_edit->has_focus()) {
|
|
|
|
name_edit->release_focus();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-28 16:49:38 +00:00
|
|
|
void EditorPropertyVariableName::_variable_selected(int p_id) {
|
2024-01-28 18:24:59 +00:00
|
|
|
String var_name = plan->get_var_by_index(p_id).first;
|
|
|
|
name_edit->set_text(var_name);
|
2024-05-15 10:50:33 +00:00
|
|
|
_name_submitted();
|
2024-01-28 16:49:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EditorPropertyVariableName::_update_status() {
|
2024-01-29 09:16:24 +00:00
|
|
|
status_btn->set_visible(plan.is_valid());
|
|
|
|
drop_btn->set_visible(plan.is_valid());
|
2024-01-28 18:24:59 +00:00
|
|
|
if (plan.is_null()) {
|
|
|
|
return;
|
|
|
|
}
|
2024-05-14 11:29:04 +00:00
|
|
|
String var_name = name_edit->get_text();
|
|
|
|
if (var_name.is_empty() && allow_empty) {
|
2024-11-03 00:55:48 +00:00
|
|
|
status_btn->set_button_icon(theme_cache.var_empty_icon);
|
2024-05-14 11:29:04 +00:00
|
|
|
status_btn->set_tooltip_text(TTR("Variable name not specified.\nClick to open the blackboard plan."));
|
|
|
|
} else if (plan->has_var(var_name)) {
|
2024-05-14 20:55:25 +00:00
|
|
|
if (expected_type == Variant::NIL || plan->get_var(var_name).get_type() == expected_type) {
|
2024-11-03 00:55:48 +00:00
|
|
|
status_btn->set_button_icon(theme_cache.var_exists_icon);
|
2024-05-14 11:29:04 +00:00
|
|
|
status_btn->set_tooltip_text(TTR("This variable is present in the blackboard plan.\nClick to open the blackboard plan."));
|
|
|
|
} else {
|
2024-11-03 00:55:48 +00:00
|
|
|
status_btn->set_button_icon(theme_cache.var_error_icon);
|
2024-05-14 11:29:04 +00:00
|
|
|
status_btn->set_tooltip_text(TTR(vformat(
|
2024-05-18 11:37:24 +00:00
|
|
|
"The %s variable in the blackboard plan should be of type %s.\nClick to open the blackboard plan.",
|
2024-05-14 11:29:04 +00:00
|
|
|
LimboUtility::get_singleton()->decorate_var(var_name),
|
2024-05-14 20:55:25 +00:00
|
|
|
Variant::get_type_name(expected_type))));
|
2024-05-14 11:29:04 +00:00
|
|
|
}
|
2024-01-28 20:58:18 +00:00
|
|
|
} else if (name_edit->get_text().begins_with("_")) {
|
2024-11-03 00:55:48 +00:00
|
|
|
status_btn->set_button_icon(theme_cache.var_private_icon);
|
2024-01-29 09:26:13 +00:00
|
|
|
status_btn->set_tooltip_text(TTR("This variable is private and is not included in the blackboard plan.\nClick to open the blackboard plan."));
|
2024-01-28 16:49:38 +00:00
|
|
|
} else {
|
2024-11-03 00:55:48 +00:00
|
|
|
status_btn->set_button_icon(theme_cache.var_not_found_icon);
|
2024-01-29 09:26:13 +00:00
|
|
|
status_btn->set_tooltip_text(TTR("No matching variable found in the blackboard plan!\nClick to open the blackboard plan."));
|
2024-01-28 16:49:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditorPropertyVariableName::_status_pressed() {
|
2024-11-03 03:53:56 +00:00
|
|
|
ERR_FAIL_COND(plan.is_null());
|
2024-01-28 20:03:22 +00:00
|
|
|
if (!plan->has_var(name_edit->get_text())) {
|
2024-05-15 18:43:24 +00:00
|
|
|
BlackboardPlanEditor::get_singleton()->set_defaults(name_edit->get_text(),
|
2024-05-17 09:08:58 +00:00
|
|
|
expected_type == Variant::NIL ? Variant::FLOAT : expected_type,
|
|
|
|
default_hint, default_hint_string, default_value);
|
2024-01-28 20:03:22 +00:00
|
|
|
}
|
2024-01-28 16:49:38 +00:00
|
|
|
BlackboardPlanEditor::get_singleton()->edit_plan(plan);
|
|
|
|
BlackboardPlanEditor::get_singleton()->popup_centered();
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditorPropertyVariableName::_status_mouse_entered() {
|
2024-11-03 03:53:56 +00:00
|
|
|
ERR_FAIL_COND(plan.is_null());
|
2024-01-28 16:49:38 +00:00
|
|
|
if (!plan->has_var(name_edit->get_text())) {
|
2024-11-03 00:55:48 +00:00
|
|
|
status_btn->set_button_icon(theme_cache.var_add_icon);
|
2024-01-28 16:49:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditorPropertyVariableName::_status_mouse_exited() {
|
2024-11-03 03:53:56 +00:00
|
|
|
ERR_FAIL_COND(plan.is_null());
|
2024-01-28 16:49:38 +00:00
|
|
|
_update_status();
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef LIMBOAI_MODULE
|
|
|
|
void EditorPropertyVariableName::update_property() {
|
|
|
|
#elif LIMBOAI_GDEXTENSION
|
|
|
|
void EditorPropertyVariableName::_update_property() {
|
|
|
|
#endif // LIMBOAI_GDEXTENSION
|
|
|
|
String s = get_edited_object()->get(get_edited_property());
|
2024-05-17 19:48:34 +00:00
|
|
|
updating = true;
|
2024-01-28 16:49:38 +00:00
|
|
|
if (name_edit->get_text() != s) {
|
|
|
|
int caret = name_edit->get_caret_column();
|
2024-05-17 19:48:34 +00:00
|
|
|
if (caret == 0) {
|
|
|
|
caret = last_caret_column;
|
|
|
|
}
|
2024-01-28 16:49:38 +00:00
|
|
|
name_edit->set_text(s);
|
|
|
|
name_edit->set_caret_column(caret);
|
|
|
|
}
|
|
|
|
name_edit->set_editable(!is_read_only());
|
|
|
|
_update_status();
|
2024-05-17 19:48:34 +00:00
|
|
|
updating = false;
|
2024-01-28 16:49:38 +00:00
|
|
|
}
|
|
|
|
|
2024-05-15 18:43:24 +00:00
|
|
|
void EditorPropertyVariableName::setup(const Ref<BlackboardPlan> &p_plan, bool p_allow_empty, Variant::Type p_type, PropertyHint p_hint, String p_hint_string, Variant p_default_value) {
|
2024-01-28 16:49:38 +00:00
|
|
|
plan = p_plan;
|
2024-05-14 11:29:04 +00:00
|
|
|
allow_empty = p_allow_empty;
|
2024-05-14 20:55:25 +00:00
|
|
|
expected_type = p_type;
|
2024-05-15 18:43:24 +00:00
|
|
|
default_hint = p_hint;
|
|
|
|
default_hint_string = p_hint_string;
|
|
|
|
default_value = p_default_value;
|
2024-01-28 18:24:59 +00:00
|
|
|
_update_status();
|
2024-01-28 16:49:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void EditorPropertyVariableName::_notification(int p_what) {
|
|
|
|
switch (p_what) {
|
|
|
|
case NOTIFICATION_READY: {
|
2024-05-17 19:48:34 +00:00
|
|
|
name_edit->connect(LW_NAME(text_changed), callable_mp(this, &EditorPropertyVariableName::_name_changed));
|
2024-05-15 10:50:33 +00:00
|
|
|
name_edit->connect(LW_NAME(text_submitted), callable_mp(this, &EditorPropertyVariableName::_name_submitted).unbind(1));
|
|
|
|
name_edit->connect(LW_NAME(focus_exited), callable_mp(this, &EditorPropertyVariableName::_name_submitted));
|
2024-01-28 16:49:38 +00:00
|
|
|
variables_popup->connect(LW_NAME(id_pressed), callable_mp(this, &EditorPropertyVariableName::_variable_selected));
|
|
|
|
drop_btn->connect(LW_NAME(pressed), callable_mp(this, &EditorPropertyVariableName::_show_variables_popup));
|
|
|
|
status_btn->connect(LW_NAME(pressed), callable_mp(this, &EditorPropertyVariableName::_status_pressed));
|
|
|
|
status_btn->connect(LW_NAME(mouse_entered), callable_mp(this, &EditorPropertyVariableName::_status_mouse_entered));
|
|
|
|
status_btn->connect(LW_NAME(mouse_exited), callable_mp(this, &EditorPropertyVariableName::_status_mouse_exited));
|
|
|
|
} break;
|
|
|
|
case NOTIFICATION_ENTER_TREE: {
|
|
|
|
BlackboardPlanEditor::get_singleton()->connect(LW_NAME(visibility_changed), callable_mp(this, &EditorPropertyVariableName::_update_status));
|
|
|
|
} break;
|
|
|
|
case NOTIFICATION_EXIT_TREE: {
|
|
|
|
if (BlackboardPlanEditor::get_singleton()) {
|
|
|
|
BlackboardPlanEditor::get_singleton()->disconnect(LW_NAME(visibility_changed), callable_mp(this, &EditorPropertyVariableName::_update_status));
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
case NOTIFICATION_THEME_CHANGED: {
|
2024-11-03 00:55:48 +00:00
|
|
|
drop_btn->set_button_icon(get_theme_icon(LW_NAME(GuiOptionArrow), LW_NAME(EditorIcons)));
|
2024-01-28 16:49:38 +00:00
|
|
|
theme_cache.var_add_icon = LimboUtility::get_singleton()->get_task_icon(LW_NAME(LimboVarAdd));
|
|
|
|
theme_cache.var_exists_icon = LimboUtility::get_singleton()->get_task_icon(LW_NAME(LimboVarExists));
|
|
|
|
theme_cache.var_not_found_icon = LimboUtility::get_singleton()->get_task_icon(LW_NAME(LimboVarNotFound));
|
2024-01-28 20:58:18 +00:00
|
|
|
theme_cache.var_private_icon = LimboUtility::get_singleton()->get_task_icon(LW_NAME(LimboVarPrivate));
|
2024-05-14 11:29:04 +00:00
|
|
|
theme_cache.var_empty_icon = LimboUtility::get_singleton()->get_task_icon(LW_NAME(LimboVarEmpty));
|
|
|
|
theme_cache.var_error_icon = LimboUtility::get_singleton()->get_task_icon(LW_NAME(LimboVarError));
|
2024-01-28 16:49:38 +00:00
|
|
|
} break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
EditorPropertyVariableName::EditorPropertyVariableName() {
|
|
|
|
HBoxContainer *hbox = memnew(HBoxContainer);
|
|
|
|
add_child(hbox);
|
|
|
|
hbox->add_theme_constant_override(LW_NAME(separation), 0);
|
|
|
|
|
|
|
|
name_edit = memnew(LineEdit);
|
|
|
|
hbox->add_child(name_edit);
|
|
|
|
add_focusable(name_edit);
|
|
|
|
name_edit->set_h_size_flags(SIZE_EXPAND_FILL);
|
|
|
|
name_edit->set_placeholder(TTR("Variable name"));
|
|
|
|
|
|
|
|
drop_btn = memnew(Button);
|
|
|
|
hbox->add_child(drop_btn);
|
|
|
|
drop_btn->set_flat(true);
|
|
|
|
drop_btn->set_focus_mode(FOCUS_NONE);
|
|
|
|
|
|
|
|
status_btn = memnew(Button);
|
|
|
|
hbox->add_child(status_btn);
|
|
|
|
status_btn->set_flat(true);
|
|
|
|
status_btn->set_focus_mode(FOCUS_NONE);
|
|
|
|
|
|
|
|
variables_popup = memnew(PopupMenu);
|
|
|
|
add_child(variables_popup);
|
|
|
|
}
|
|
|
|
|
|
|
|
//***** EditorInspectorPluginVariableName
|
|
|
|
|
|
|
|
#ifdef LIMBOAI_MODULE
|
|
|
|
bool EditorInspectorPluginVariableName::can_handle(Object *p_object) {
|
|
|
|
#elif LIMBOAI_GDEXTENSION
|
|
|
|
bool EditorInspectorPluginVariableName::_can_handle(Object *p_object) const {
|
|
|
|
#endif
|
|
|
|
Ref<BTTask> task = Object::cast_to<BTTask>(p_object);
|
|
|
|
if (task.is_valid()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
Ref<BBParam> param = Object::cast_to<BBParam>(p_object);
|
|
|
|
if (param.is_valid()) {
|
|
|
|
return true;
|
|
|
|
}
|
2024-05-14 11:29:04 +00:00
|
|
|
Ref<BlackboardPlan> plan = Object::cast_to<BlackboardPlan>(p_object);
|
|
|
|
if (plan.is_valid()) {
|
|
|
|
return true;
|
|
|
|
}
|
2024-01-28 16:49:38 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef LIMBOAI_MODULE
|
|
|
|
bool EditorInspectorPluginVariableName::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const BitField<PropertyUsageFlags> p_usage, const bool p_wide) {
|
|
|
|
#elif LIMBOAI_GDEXTENSION
|
|
|
|
bool EditorInspectorPluginVariableName::_parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const BitField<PropertyUsageFlags> p_usage, const bool p_wide) {
|
|
|
|
#endif
|
2024-11-15 17:00:55 +00:00
|
|
|
if (p_usage & PROPERTY_USAGE_READ_ONLY) {
|
|
|
|
// Don't handle read-only properties using this plugin.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-05-14 11:29:04 +00:00
|
|
|
bool is_mapping = p_path.begins_with("mapping/");
|
|
|
|
if (!(p_type == Variant::Type::STRING_NAME || p_type == Variant::Type::STRING) || !(is_mapping || p_path.ends_with("_var") || p_path.ends_with("variable"))) {
|
2024-01-28 16:49:38 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-05-14 11:29:04 +00:00
|
|
|
Ref<BlackboardPlan> plan;
|
2024-05-14 20:55:25 +00:00
|
|
|
Variant::Type expected_type = Variant::NIL;
|
2024-05-15 18:43:24 +00:00
|
|
|
PropertyHint default_hint = PROPERTY_HINT_NONE;
|
|
|
|
String default_hint_string;
|
|
|
|
Variant default_value;
|
2024-05-14 11:29:04 +00:00
|
|
|
if (is_mapping) {
|
|
|
|
plan.reference_ptr(Object::cast_to<BlackboardPlan>(p_object));
|
2024-11-03 03:53:56 +00:00
|
|
|
ERR_FAIL_COND_V(plan.is_null(), false);
|
2024-05-14 11:29:04 +00:00
|
|
|
String var_name = p_path.trim_prefix("mapping/");
|
|
|
|
if (plan->has_var(var_name)) {
|
|
|
|
BBVariable variable = plan->get_var(var_name);
|
2024-05-14 20:55:25 +00:00
|
|
|
expected_type = variable.get_type();
|
2024-05-15 18:43:24 +00:00
|
|
|
default_hint = variable.get_hint();
|
|
|
|
default_hint_string = variable.get_hint_string();
|
|
|
|
default_value = variable.get_value();
|
2024-05-14 11:29:04 +00:00
|
|
|
}
|
2024-05-15 09:38:53 +00:00
|
|
|
if (plan->get_parent_scope_plan_provider().is_valid()) {
|
|
|
|
Ref<BlackboardPlan> parent_plan = plan->get_parent_scope_plan_provider().call();
|
|
|
|
if (parent_plan.is_valid()) {
|
|
|
|
plan = parent_plan;
|
|
|
|
}
|
|
|
|
}
|
2024-11-03 03:53:56 +00:00
|
|
|
ERR_FAIL_COND_V(plan.is_null(), false);
|
2024-05-14 11:29:04 +00:00
|
|
|
} else {
|
2024-05-15 18:43:24 +00:00
|
|
|
plan = editor_plan_provider.call();
|
2024-05-14 11:29:04 +00:00
|
|
|
}
|
|
|
|
|
2024-01-28 16:49:38 +00:00
|
|
|
EditorPropertyVariableName *ed = memnew(EditorPropertyVariableName);
|
2024-05-15 18:43:24 +00:00
|
|
|
ed->setup(plan, is_mapping, expected_type, default_hint, default_hint_string, default_value);
|
2024-05-14 20:55:25 +00:00
|
|
|
add_property_editor(p_path, ed, expected_type);
|
2024-01-28 16:49:38 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // TOOLS_ENABLED
|