diff --git a/editor/editor_property_bb_param.cpp b/editor/editor_property_bb_param.cpp index cd36f63..42ca0cf 100644 --- a/editor/editor_property_bb_param.cpp +++ b/editor/editor_property_bb_param.cpp @@ -12,6 +12,7 @@ #include "editor_property_bb_param.h" #include "modules/limboai/blackboard/bb_param/bb_param.h" +#include "modules/limboai/editor/mode_switch_button.h" #include "core/error/error_macros.h" #include "core/object/class_db.h" @@ -204,7 +205,7 @@ void EditorPropertyBBParam::_value_edited(const String &p_property, Variant p_va } void EditorPropertyBBParam::_mode_changed() { - _get_edited_param()->set_value_source(value_mode->is_pressed() ? BBParam::SAVED_VALUE : BBParam::BLACKBOARD_VAR); + _get_edited_param()->set_value_source(mode_button->get_mode() == Mode::SPECIFY_VALUE ? BBParam::SAVED_VALUE : BBParam::BLACKBOARD_VAR); update_property(); } @@ -219,15 +220,13 @@ void EditorPropertyBBParam::update_property() { variable_edit->set_text(param->get_variable()); variable_edit->set_editable(true); variable_edit->show(); - variable_mode->set_pressed_no_signal(true); - value_mode->set_pressed_no_signal(false); + mode_button->set_mode(Mode::BIND_VAR, true); } else { variable_edit->hide(); _create_value_editor(param->get_type()); value_editor->show(); value_editor->set_object_and_property(param.ptr(), SNAME("saved_value")); - value_mode->set_pressed_no_signal(true); - variable_mode->set_pressed_no_signal(false); + mode_button->set_mode(Mode::SPECIFY_VALUE, true); value_editor->update_property(); } } @@ -241,8 +240,13 @@ void EditorPropertyBBParam::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: case NOTIFICATION_THEME_CHANGED: { - value_mode->set_icon(get_editor_theme_icon(SNAME("LimboSpecifyValue"))); - variable_mode->set_icon(get_editor_theme_icon(SNAME("BTSetVar"))); + int id = mode_button->get_mode(); + mode_button->clear(); + mode_button->add_mode(Mode::SPECIFY_VALUE, get_editor_theme_icon(SNAME("LimboSpecifyValue")), TTR("Mode: Specify value.\nClick to switch mode.")); + mode_button->add_mode(Mode::BIND_VAR, get_editor_theme_icon(SNAME("BTSetVar")), TTR("Mode: Bind blackboard variable.\nClick to switch mode.")); + if (id >= 0) { + mode_button->set_mode(id); + } } break; } } @@ -251,28 +255,10 @@ EditorPropertyBBParam::EditorPropertyBBParam() { hbox = memnew(HBoxContainer); add_child(hbox); - HBoxContainer *modes = memnew(HBoxContainer); - hbox->add_child(modes); - modes->add_theme_constant_override("separation", 0); - - Ref modes_group; - modes_group.instantiate(); - - value_mode = memnew(Button); - modes->add_child(value_mode); - value_mode->set_focus_mode(FOCUS_NONE); - value_mode->set_button_group(modes_group); - value_mode->set_toggle_mode(true); - value_mode->set_tooltip_text(TTR("Specify value")); - value_mode->connect(SNAME("pressed"), callable_mp(this, &EditorPropertyBBParam::_mode_changed)); - - variable_mode = memnew(Button); - modes->add_child(variable_mode); - variable_mode->set_focus_mode(FOCUS_NONE); - variable_mode->set_button_group(modes_group); - variable_mode->set_toggle_mode(true); - variable_mode->set_tooltip_text(TTR("Bind to a blackboard variable")); - variable_mode->connect(SNAME("pressed"), callable_mp(this, &EditorPropertyBBParam::_mode_changed)); + mode_button = memnew(ModeSwitchButton); + hbox->add_child(mode_button); + mode_button->set_focus_mode(FOCUS_NONE); + mode_button->connect(SNAME("mode_changed"), callable_mp(this, &EditorPropertyBBParam::_mode_changed)); variable_edit = memnew(LineEdit); hbox->add_child(variable_edit); diff --git a/editor/editor_property_bb_param.h b/editor/editor_property_bb_param.h index 63b1130..85c2e86 100644 --- a/editor/editor_property_bb_param.h +++ b/editor/editor_property_bb_param.h @@ -16,17 +16,23 @@ #include "editor/editor_inspector.h" #include "modules/limboai/blackboard/bb_param/bb_param.h" +#include "modules/limboai/editor/mode_switch_button.h" class EditorPropertyBBParam : public EditorProperty { GDCLASS(EditorPropertyBBParam, EditorProperty); private: + enum Mode { + SPECIFY_VALUE, + BIND_VAR, + }; + StringName param_type; PropertyHint property_hint = PROPERTY_HINT_NONE; + Mode mode = Mode::SPECIFY_VALUE; HBoxContainer *hbox = nullptr; - Button *value_mode = nullptr; - Button *variable_mode = nullptr; + ModeSwitchButton *mode_button = nullptr; EditorProperty *value_editor = nullptr; LineEdit *variable_edit = nullptr; diff --git a/editor/mode_switch_button.cpp b/editor/mode_switch_button.cpp new file mode 100644 index 0000000..e0051c5 --- /dev/null +++ b/editor/mode_switch_button.cpp @@ -0,0 +1,73 @@ +/** + * mode_switch_button.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 "mode_switch_button.h" + +#include "core/error/error_macros.h" +#include "core/object/object.h" +#include "core/variant/variant.h" + +void ModeSwitchButton::add_mode(int p_id, const Ref &p_icon, const String &p_tooltip) { + bool unique_id = true; + for (int i = 0; i < modes.size(); i++) { + if (modes[i].id == p_id) { + unique_id = false; + break; + } + } + ERR_FAIL_COND_MSG(unique_id == false, "ID is already in use by another button state: " + itos(p_id)); + + Mode mode; + mode.id = p_id; + mode.icon = p_icon; + mode.tooltip = p_tooltip; + modes.append(mode); + + if (current_mode_index == -1) { + _set_mode(0); + } +} + +void ModeSwitchButton::set_mode(int p_id, bool p_no_signal) { + ERR_FAIL_COND_MSG(modes.is_empty(), "Cannot set button state with zero states."); + + int idx = -1; + for (int i = 0; i < modes.size(); i++) { + if (modes[i].id == p_id) { + idx = i; + break; + } + } + ERR_FAIL_COND_MSG(idx == -1, "Button state not found with such id: " + itos(p_id)); + + _set_mode(p_id); + if (!p_no_signal) { + emit_signal(SNAME("mode_changed")); + } +} + +void ModeSwitchButton::clear() { + current_mode_index = -1; + modes.clear(); +} + +void ModeSwitchButton::_bind_methods() { + ClassDB::bind_method(D_METHOD("add_mode", "p_id", "p_icon", "p_tooltip"), &ModeSwitchButton::add_mode); + ClassDB::bind_method(D_METHOD("get_mode"), &ModeSwitchButton::get_mode); + ClassDB::bind_method(D_METHOD("set_mode", "p_id"), &ModeSwitchButton::set_mode); + ClassDB::bind_method(D_METHOD("next_mode"), &ModeSwitchButton::next_mode); + + ADD_SIGNAL(MethodInfo("mode_changed")); +} + +ModeSwitchButton::ModeSwitchButton() { + call_deferred(SNAME("connect"), SNAME("pressed"), callable_mp(this, &ModeSwitchButton::next_mode)); +} diff --git a/editor/mode_switch_button.h b/editor/mode_switch_button.h new file mode 100644 index 0000000..e4830b4 --- /dev/null +++ b/editor/mode_switch_button.h @@ -0,0 +1,54 @@ +/** + * mode_switch_button.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. + * ============================================================================= + */ + +#ifndef MODE_SWITCH_BUTTON +#define MODE_SWITCH_BUTTON + +#include "scene/gui/button.h" + +#include "core/typedefs.h" +#include "scene/resources/texture.h" + +class ModeSwitchButton : public Button { + GDCLASS(ModeSwitchButton, Button); + +private: + struct Mode { + int id = 0; + Ref icon = nullptr; + String tooltip = ""; + }; + int current_mode_index = -1; + + Vector modes; + + _FORCE_INLINE_ void _set_mode(int p_id) { + current_mode_index = p_id; + set_icon(modes[current_mode_index].icon); + if (!modes[current_mode_index].tooltip.is_empty()) { + set_tooltip_text(modes[current_mode_index].tooltip); + } + } + +protected: + static void _bind_methods(); + +public: + void add_mode(int p_id, const Ref &p_icon, const String &p_tooltip = ""); + int get_mode() const { return modes.size() > 0 ? modes[current_mode_index].id : -1; } + void set_mode(int p_id, bool p_no_signal = false); + _FORCE_INLINE_ void next_mode() { set_mode((current_mode_index + 1) % modes.size()); }; + void clear(); + + ModeSwitchButton(); +}; + +#endif // MODE_SWITCH_BUTTON