mirror of
https://github.com/Relintai/pandemonium_engine.git
synced 2025-01-03 17:39:36 +01:00
Backported PROPERTY_USAGE_ARRAY from Godot 4. Reused one of the old deprecated property usage flags for it.
Original commit:
Implement properties arrays in the Inspector.
- groud
4bd7700e89
This commit is contained in:
parent
bd53556507
commit
2b57397fa7
@ -643,8 +643,7 @@ void register_global_constants() {
|
|||||||
BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_INTERNATIONALIZED);
|
BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_INTERNATIONALIZED);
|
||||||
BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_GROUP);
|
BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_GROUP);
|
||||||
BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_CATEGORY);
|
BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_CATEGORY);
|
||||||
//deprecated, replaced by ClassDB function to check default value
|
BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_ARRAY);
|
||||||
//BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_STORE_IF_NONZERO);
|
|
||||||
//BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_STORE_IF_NONONE);
|
//BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_STORE_IF_NONONE);
|
||||||
BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_NO_INSTANCE_STATE);
|
BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_NO_INSTANCE_STATE);
|
||||||
BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_RESTART_IF_CHANGED);
|
BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_RESTART_IF_CHANGED);
|
||||||
|
@ -890,6 +890,18 @@ void ClassDB::add_property_group(StringName p_class, const String &p_name, const
|
|||||||
type->property_list.push_back(PropertyInfo(Variant::NIL, p_name, PROPERTY_HINT_NONE, p_prefix, PROPERTY_USAGE_GROUP));
|
type->property_list.push_back(PropertyInfo(Variant::NIL, p_name, PROPERTY_HINT_NONE, p_prefix, PROPERTY_USAGE_GROUP));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClassDB::add_property_array_count(const StringName &p_class, const String &p_label, const StringName &p_count_property, const StringName &p_count_setter, const StringName &p_count_getter, const String &p_array_element_prefix, uint32_t p_count_usage) {
|
||||||
|
add_property(p_class, PropertyInfo(Variant::INT, p_count_property, PROPERTY_HINT_NONE, "", p_count_usage | PROPERTY_USAGE_ARRAY, vformat("%s,%s", p_label, p_array_element_prefix)), p_count_setter, p_count_getter);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClassDB::add_property_array(const StringName &p_class, const StringName &p_path, const String &p_array_element_prefix) {
|
||||||
|
OBJTYPE_WLOCK;
|
||||||
|
ClassInfo *type = classes.getptr(p_class);
|
||||||
|
ERR_FAIL_COND(!type);
|
||||||
|
|
||||||
|
type->property_list.push_back(PropertyInfo(Variant::NIL, p_path, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ARRAY, p_array_element_prefix));
|
||||||
|
}
|
||||||
|
|
||||||
void ClassDB::add_property(StringName p_class, const PropertyInfo &p_pinfo, const StringName &p_setter, const StringName &p_getter, int p_index) {
|
void ClassDB::add_property(StringName p_class, const PropertyInfo &p_pinfo, const StringName &p_setter, const StringName &p_getter, int p_index) {
|
||||||
lock.read_lock();
|
lock.read_lock();
|
||||||
ClassInfo *type = classes.getptr(p_class);
|
ClassInfo *type = classes.getptr(p_class);
|
||||||
|
@ -334,6 +334,10 @@ public:
|
|||||||
static void get_signal_list(StringName p_class, List<MethodInfo> *p_signals, bool p_no_inheritance = false);
|
static void get_signal_list(StringName p_class, List<MethodInfo> *p_signals, bool p_no_inheritance = false);
|
||||||
|
|
||||||
static void add_property_group(StringName p_class, const String &p_name, const String &p_prefix = "");
|
static void add_property_group(StringName p_class, const String &p_name, const String &p_prefix = "");
|
||||||
|
|
||||||
|
static void add_property_array_count(const StringName &p_class, const String &p_label, const StringName &p_count_property, const StringName &p_count_setter, const StringName &p_count_getter, const String &p_array_element_prefix, uint32_t p_count_usage = PROPERTY_USAGE_EDITOR);
|
||||||
|
static void add_property_array(const StringName &p_class, const StringName &p_path, const String &p_array_element_prefix);
|
||||||
|
|
||||||
static void add_property(StringName p_class, const PropertyInfo &p_pinfo, const StringName &p_setter, const StringName &p_getter, int p_index = -1);
|
static void add_property(StringName p_class, const PropertyInfo &p_pinfo, const StringName &p_setter, const StringName &p_getter, int p_index = -1);
|
||||||
static void set_property_default_value(StringName p_class, const StringName &p_name, const Variant &p_default);
|
static void set_property_default_value(StringName p_class, const StringName &p_name, const Variant &p_default);
|
||||||
static void get_property_list(StringName p_class, List<PropertyInfo> *p_list, bool p_no_inheritance = false, const Object *p_validator = nullptr);
|
static void get_property_list(StringName p_class, List<PropertyInfo> *p_list, bool p_no_inheritance = false, const Object *p_validator = nullptr);
|
||||||
|
@ -114,9 +114,7 @@ enum PropertyUsageFlags {
|
|||||||
PROPERTY_USAGE_INTERNATIONALIZED = 1 << 6, //hint for internationalized strings
|
PROPERTY_USAGE_INTERNATIONALIZED = 1 << 6, //hint for internationalized strings
|
||||||
PROPERTY_USAGE_GROUP = 1 << 7, //used for grouping props in the editor
|
PROPERTY_USAGE_GROUP = 1 << 7, //used for grouping props in the editor
|
||||||
PROPERTY_USAGE_CATEGORY = 1 << 8,
|
PROPERTY_USAGE_CATEGORY = 1 << 8,
|
||||||
// FIXME: Drop in 4.0, possibly reorder other flags?
|
PROPERTY_USAGE_ARRAY = 1 << 9, // Used in the inspector to group properties as elements of an array.
|
||||||
// Those below are deprecated thanks to ClassDB's now class value cache
|
|
||||||
//PROPERTY_USAGE_STORE_IF_NONZERO = 1 << 9, //only store if nonzero //512
|
|
||||||
//PROPERTY_USAGE_STORE_IF_NONONE = 1 << 10, //only store if false //1024
|
//PROPERTY_USAGE_STORE_IF_NONONE = 1 << 10, //only store if false //1024
|
||||||
PROPERTY_USAGE_NO_INSTANCE_STATE = 1 << 11,
|
PROPERTY_USAGE_NO_INSTANCE_STATE = 1 << 11,
|
||||||
PROPERTY_USAGE_RESTART_IF_CHANGED = 1 << 12,
|
PROPERTY_USAGE_RESTART_IF_CHANGED = 1 << 12,
|
||||||
@ -145,6 +143,10 @@ enum PropertyUsageFlags {
|
|||||||
#define ADD_PROPERTY_DEFAULT(m_property, m_default) ClassDB::set_property_default_value(get_class_static(), m_property, m_default)
|
#define ADD_PROPERTY_DEFAULT(m_property, m_default) ClassDB::set_property_default_value(get_class_static(), m_property, m_default)
|
||||||
#define ADD_GROUP(m_name, m_prefix) ClassDB::add_property_group(get_class_static(), m_name, m_prefix)
|
#define ADD_GROUP(m_name, m_prefix) ClassDB::add_property_group(get_class_static(), m_name, m_prefix)
|
||||||
|
|
||||||
|
#define ADD_ARRAY_COUNT(m_label, m_count_property, m_count_property_setter, m_count_property_getter, m_prefix) ClassDB::add_property_array_count(get_class_static(), m_label, m_count_property, _scs_create(m_count_property_setter), _scs_create(m_count_property_getter), m_prefix)
|
||||||
|
#define ADD_ARRAY_COUNT_WITH_USAGE_FLAGS(m_label, m_count_property, m_count_property_setter, m_count_property_getter, m_prefix, m_property_usage_flags) ClassDB::add_property_array_count(get_class_static(), m_label, m_count_property, _scs_create(m_count_property_setter), _scs_create(m_count_property_getter), m_prefix, m_property_usage_flags)
|
||||||
|
#define ADD_ARRAY(m_array_path, m_prefix) ClassDB::add_property_array(get_class_static(), m_array_path, m_prefix)
|
||||||
|
|
||||||
struct PropertyInfo {
|
struct PropertyInfo {
|
||||||
Variant::Type type;
|
Variant::Type type;
|
||||||
String name;
|
String name;
|
||||||
|
@ -333,7 +333,8 @@ void DocData::generate(bool p_basic_types) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (E->get().usage & PROPERTY_USAGE_GROUP || E->get().usage & PROPERTY_USAGE_CATEGORY || E->get().usage & PROPERTY_USAGE_INTERNAL) {
|
if (E->get().usage & PROPERTY_USAGE_GROUP || E->get().usage & PROPERTY_USAGE_CATEGORY ||
|
||||||
|
E->get().usage & PROPERTY_USAGE_INTERNAL || (E->get().type == Variant::NIL && E->get().usage & PROPERTY_USAGE_ARRAY)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -445,6 +445,22 @@ UndoRedo &EditorData::get_undo_redo() {
|
|||||||
return undo_redo;
|
return undo_redo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EditorData::add_move_array_element_function(const StringName &p_class, const Ref<FuncRef> &p_funcref) {
|
||||||
|
move_element_functions.insert(p_class, p_funcref);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorData::remove_move_array_element_function(const StringName &p_class) {
|
||||||
|
move_element_functions.erase(p_class);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<FuncRef> EditorData::get_move_array_element_function(const StringName &p_class) const {
|
||||||
|
if (move_element_functions.has(p_class)) {
|
||||||
|
return move_element_functions[p_class];
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ref<FuncRef>();
|
||||||
|
}
|
||||||
|
|
||||||
void EditorData::remove_editor_plugin(EditorPlugin *p_plugin) {
|
void EditorData::remove_editor_plugin(EditorPlugin *p_plugin) {
|
||||||
p_plugin->undo_redo = nullptr;
|
p_plugin->undo_redo = nullptr;
|
||||||
editor_plugins.erase(p_plugin);
|
editor_plugins.erase(p_plugin);
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
#include "core/containers/rb_map.h"
|
#include "core/containers/rb_map.h"
|
||||||
#include "core/containers/rb_set.h"
|
#include "core/containers/rb_set.h"
|
||||||
#include "core/containers/vector.h"
|
#include "core/containers/vector.h"
|
||||||
|
#include "core/object/func_ref.h"
|
||||||
#include "core/object/object_id.h"
|
#include "core/object/object_id.h"
|
||||||
#include "core/object/reference.h"
|
#include "core/object/reference.h"
|
||||||
#include "core/object/script_language.h"
|
#include "core/object/script_language.h"
|
||||||
@ -161,6 +162,8 @@ private:
|
|||||||
List<PropertyData> clipboard;
|
List<PropertyData> clipboard;
|
||||||
UndoRedo undo_redo;
|
UndoRedo undo_redo;
|
||||||
|
|
||||||
|
RBMap<StringName, Ref<FuncRef>> move_element_functions;
|
||||||
|
|
||||||
Vector<EditedScene> edited_scene;
|
Vector<EditedScene> edited_scene;
|
||||||
int current_edited_scene;
|
int current_edited_scene;
|
||||||
|
|
||||||
@ -191,6 +194,11 @@ public:
|
|||||||
int get_editor_plugin_count() const;
|
int get_editor_plugin_count() const;
|
||||||
EditorPlugin *get_editor_plugin(int p_idx);
|
EditorPlugin *get_editor_plugin(int p_idx);
|
||||||
|
|
||||||
|
// Function should have this signature: void (Object* undo_redo, Object *modified_object, String array_prefix, int element_index, int new_position)
|
||||||
|
void add_move_array_element_function(const StringName &p_class, const Ref<FuncRef> &p_funcref);
|
||||||
|
void remove_move_array_element_function(const StringName &p_class);
|
||||||
|
Ref<FuncRef> get_move_array_element_function(const StringName &p_class) const;
|
||||||
|
|
||||||
UndoRedo &get_undo_redo();
|
UndoRedo &get_undo_redo();
|
||||||
|
|
||||||
void save_editor_global_states();
|
void save_editor_global_states();
|
||||||
|
@ -55,15 +55,21 @@
|
|||||||
#include "editor_settings.h"
|
#include "editor_settings.h"
|
||||||
#include "multi_node_edit.h"
|
#include "multi_node_edit.h"
|
||||||
#include "scene/gui/box_container.h"
|
#include "scene/gui/box_container.h"
|
||||||
|
#include "scene/gui/button.h"
|
||||||
|
#include "scene/gui/dialogs.h"
|
||||||
#include "scene/gui/label.h"
|
#include "scene/gui/label.h"
|
||||||
#include "scene/gui/line_edit.h"
|
#include "scene/gui/line_edit.h"
|
||||||
|
#include "scene/gui/margin_container.h"
|
||||||
|
#include "scene/gui/panel_container.h"
|
||||||
#include "scene/gui/popup_menu.h"
|
#include "scene/gui/popup_menu.h"
|
||||||
#include "scene/gui/rich_text_label.h"
|
#include "scene/gui/rich_text_label.h"
|
||||||
#include "scene/gui/scroll_bar.h"
|
#include "scene/gui/scroll_bar.h"
|
||||||
|
#include "scene/gui/texture_rect.h"
|
||||||
#include "scene/main/canvas_item.h"
|
#include "scene/main/canvas_item.h"
|
||||||
#include "scene/main/node.h"
|
#include "scene/main/node.h"
|
||||||
#include "scene/main/property_utils.h"
|
#include "scene/main/property_utils.h"
|
||||||
#include "scene/main/scene_tree.h"
|
#include "scene/main/scene_tree.h"
|
||||||
|
#include "scene/main/viewport.h"
|
||||||
#include "scene/resources/font/font.h"
|
#include "scene/resources/font/font.h"
|
||||||
#include "scene/resources/packed_scene.h"
|
#include "scene/resources/packed_scene.h"
|
||||||
#include "scene/resources/style_box.h"
|
#include "scene/resources/style_box.h"
|
||||||
@ -1028,6 +1034,7 @@ EditorInspectorCategory::EditorInspectorCategory() {
|
|||||||
void EditorInspectorSection::_test_unfold() {
|
void EditorInspectorSection::_test_unfold() {
|
||||||
if (!vbox_added) {
|
if (!vbox_added) {
|
||||||
add_child(vbox);
|
add_child(vbox);
|
||||||
|
move_child(vbox, 0);
|
||||||
vbox_added = true;
|
vbox_added = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1059,6 +1066,9 @@ int EditorInspectorSection::_get_header_height() {
|
|||||||
|
|
||||||
void EditorInspectorSection::_notification(int p_what) {
|
void EditorInspectorSection::_notification(int p_what) {
|
||||||
switch (p_what) {
|
switch (p_what) {
|
||||||
|
case NOTIFICATION_THEME_CHANGED: {
|
||||||
|
minimum_size_changed();
|
||||||
|
} break;
|
||||||
case NOTIFICATION_SORT_CHILDREN: {
|
case NOTIFICATION_SORT_CHILDREN: {
|
||||||
Size2 size = get_size();
|
Size2 size = get_size();
|
||||||
Point2 offset;
|
Point2 offset;
|
||||||
@ -1149,6 +1159,7 @@ void EditorInspectorSection::setup(const String &p_section, const String &p_labe
|
|||||||
|
|
||||||
if (!foldable && !vbox_added) {
|
if (!foldable && !vbox_added) {
|
||||||
add_child(vbox);
|
add_child(vbox);
|
||||||
|
move_child(vbox, 0);
|
||||||
vbox_added = true;
|
vbox_added = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1209,7 +1220,7 @@ void EditorInspectorSection::fold() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!vbox_added) {
|
if (!vbox_added) {
|
||||||
return; //kinda pointless
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
object->editor_set_section_unfold(section, false);
|
object->editor_set_section_unfold(section, false);
|
||||||
@ -1241,6 +1252,748 @@ EditorInspectorSection::~EditorInspectorSection() {
|
|||||||
////////////////////////////////////////////////
|
////////////////////////////////////////////////
|
||||||
////////////////////////////////////////////////
|
////////////////////////////////////////////////
|
||||||
|
|
||||||
|
int EditorInspectorArray::_get_array_count() {
|
||||||
|
if (mode == MODE_USE_MOVE_ARRAY_ELEMENT_FUNCTION) {
|
||||||
|
List<PropertyInfo> object_property_list;
|
||||||
|
object->get_property_list(&object_property_list);
|
||||||
|
return _extract_properties_as_array(object_property_list).size();
|
||||||
|
} else if (mode == MODE_USE_COUNT_PROPERTY) {
|
||||||
|
bool valid;
|
||||||
|
int count = object->get(count_property, &valid);
|
||||||
|
ERR_FAIL_COND_V_MSG(!valid, 0, vformat("%s is not a valid property to be used as array count.", count_property));
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorInspectorArray::_add_button_pressed() {
|
||||||
|
_move_element(-1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorInspectorArray::_first_page_button_pressed() {
|
||||||
|
emit_signal("page_change_request", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorInspectorArray::_prev_page_button_pressed() {
|
||||||
|
emit_signal("page_change_request", MAX(0, page - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorInspectorArray::_page_line_edit_text_submitted(String p_text) {
|
||||||
|
if (p_text.is_valid_integer()) {
|
||||||
|
int new_page = p_text.to_int() - 1;
|
||||||
|
new_page = MIN(MAX(0, new_page), max_page);
|
||||||
|
page_line_edit->set_text(Variant(new_page));
|
||||||
|
emit_signal("page_change_request", new_page);
|
||||||
|
} else {
|
||||||
|
page_line_edit->set_text(Variant(page));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorInspectorArray::_next_page_button_pressed() {
|
||||||
|
emit_signal("page_change_request", MIN(max_page, page + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorInspectorArray::_last_page_button_pressed() {
|
||||||
|
emit_signal("page_change_request", max_page);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorInspectorArray::_rmb_popup_id_pressed(int p_id) {
|
||||||
|
switch (p_id) {
|
||||||
|
case OPTION_MOVE_UP:
|
||||||
|
if (popup_array_index_pressed > 0) {
|
||||||
|
_move_element(popup_array_index_pressed, popup_array_index_pressed - 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OPTION_MOVE_DOWN:
|
||||||
|
if (popup_array_index_pressed < count - 1) {
|
||||||
|
_move_element(popup_array_index_pressed, popup_array_index_pressed + 2);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OPTION_NEW_BEFORE:
|
||||||
|
_move_element(-1, popup_array_index_pressed);
|
||||||
|
break;
|
||||||
|
case OPTION_NEW_AFTER:
|
||||||
|
_move_element(-1, popup_array_index_pressed + 1);
|
||||||
|
break;
|
||||||
|
case OPTION_REMOVE:
|
||||||
|
_move_element(popup_array_index_pressed, -1);
|
||||||
|
break;
|
||||||
|
case OPTION_CLEAR_ARRAY:
|
||||||
|
_clear_array();
|
||||||
|
break;
|
||||||
|
case OPTION_RESIZE_ARRAY:
|
||||||
|
new_size = count;
|
||||||
|
new_size_line_edit->set_text(Variant(new_size));
|
||||||
|
resize_dialog->get_ok()->set_disabled(true);
|
||||||
|
resize_dialog->popup_centered();
|
||||||
|
new_size_line_edit->grab_focus();
|
||||||
|
new_size_line_edit->select_all();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorInspectorArray::_control_dropping_draw() {
|
||||||
|
int drop_position = _drop_position();
|
||||||
|
|
||||||
|
if (dropping && drop_position >= 0) {
|
||||||
|
Vector2 from;
|
||||||
|
Vector2 to;
|
||||||
|
if (drop_position < elements_vbox->get_child_count()) {
|
||||||
|
Transform2D xform = Object::cast_to<Control>(elements_vbox->get_child(drop_position))->get_transform();
|
||||||
|
from = xform.xform(Vector2());
|
||||||
|
to = xform.xform(Vector2(elements_vbox->get_size().x, 0));
|
||||||
|
} else {
|
||||||
|
Control *child = Object::cast_to<Control>(elements_vbox->get_child(drop_position - 1));
|
||||||
|
Transform2D xform = child->get_transform();
|
||||||
|
from = xform.xform(Vector2(0, child->get_size().y));
|
||||||
|
to = xform.xform(Vector2(elements_vbox->get_size().x, child->get_size().y));
|
||||||
|
}
|
||||||
|
Color color = get_theme_color("accent_color", "Editor");
|
||||||
|
control_dropping->draw_line(from, to, color, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorInspectorArray::_vbox_visibility_changed() {
|
||||||
|
control_dropping->set_visible(vbox->is_visible_in_tree());
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorInspectorArray::_panel_draw(int p_index) {
|
||||||
|
ERR_FAIL_INDEX(p_index, (int)array_elements.size());
|
||||||
|
|
||||||
|
Ref<StyleBox> style = get_theme_stylebox("Focus", "EditorStyles");
|
||||||
|
if (!style.is_valid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (array_elements[p_index].panel->has_focus()) {
|
||||||
|
array_elements[p_index].panel->draw_style_box(style, Rect2(Vector2(), array_elements[p_index].panel->get_size()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorInspectorArray::_panel_gui_input(Ref<InputEvent> p_event, int p_index) {
|
||||||
|
ERR_FAIL_INDEX(p_index, (int)array_elements.size());
|
||||||
|
|
||||||
|
Ref<InputEventKey> key_ref = p_event;
|
||||||
|
if (key_ref.is_valid()) {
|
||||||
|
const InputEventKey &key = **key_ref;
|
||||||
|
|
||||||
|
if (array_elements[p_index].panel->has_focus() && key.is_pressed() && key.get_scancode() == KEY_DELETE) {
|
||||||
|
_move_element(begin_array_index + p_index, -1);
|
||||||
|
array_elements[p_index].panel->accept_event();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<InputEventMouseButton> mb = p_event;
|
||||||
|
if (mb.is_valid()) {
|
||||||
|
if (mb->get_button_index() == BUTTON_RIGHT) {
|
||||||
|
popup_array_index_pressed = begin_array_index + p_index;
|
||||||
|
rmb_popup->set_item_disabled(OPTION_MOVE_UP, popup_array_index_pressed == 0);
|
||||||
|
rmb_popup->set_item_disabled(OPTION_MOVE_DOWN, popup_array_index_pressed == count - 1);
|
||||||
|
rmb_popup->set_position(mb->get_global_position());
|
||||||
|
rmb_popup->set_size(Vector2());
|
||||||
|
rmb_popup->popup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorInspectorArray::_move_element(int p_element_index, int p_to_pos) {
|
||||||
|
String action_name;
|
||||||
|
if (p_element_index < 0) {
|
||||||
|
action_name = vformat("Add element to property array with prefix %s.", array_element_prefix);
|
||||||
|
} else if (p_to_pos < 0) {
|
||||||
|
action_name = vformat("Remove element %d from property array with prefix %s.", p_element_index, array_element_prefix);
|
||||||
|
} else {
|
||||||
|
action_name = vformat("Move element %d to position %d in property array with prefix %s.", p_element_index, p_to_pos, array_element_prefix);
|
||||||
|
}
|
||||||
|
undo_redo->create_action(action_name);
|
||||||
|
if (mode == MODE_USE_MOVE_ARRAY_ELEMENT_FUNCTION) {
|
||||||
|
// Call the function.
|
||||||
|
Ref<FuncRef> move_function = EditorNode::get_singleton()->get_editor_data().get_move_array_element_function(object->get_class_name());
|
||||||
|
|
||||||
|
if (move_function.is_valid()) {
|
||||||
|
Variant args[] = { (Object *)undo_redo, object, array_element_prefix, p_element_index, p_to_pos };
|
||||||
|
const Variant *args_p[] = { &args[0], &args[1], &args[2], &args[3], &args[4] };
|
||||||
|
Variant::CallError call_error;
|
||||||
|
move_function->call_func(args_p, 5, call_error);
|
||||||
|
} else {
|
||||||
|
WARN_PRINT(vformat("Could not find a function to move arrays elements for class %s. Register a move element function using EditorData::add_move_array_element_function", object->get_class_name()));
|
||||||
|
}
|
||||||
|
} else if (mode == MODE_USE_COUNT_PROPERTY) {
|
||||||
|
ERR_FAIL_COND(p_to_pos < -1 || p_to_pos > count);
|
||||||
|
List<PropertyInfo> object_property_list;
|
||||||
|
object->get_property_list(&object_property_list);
|
||||||
|
|
||||||
|
Array properties_as_array = _extract_properties_as_array(object_property_list);
|
||||||
|
properties_as_array.resize(count);
|
||||||
|
|
||||||
|
// For undoing things
|
||||||
|
undo_redo->add_undo_property(object, count_property, properties_as_array.size());
|
||||||
|
for (int i = 0; i < (int)properties_as_array.size(); i++) {
|
||||||
|
Dictionary d = Dictionary(properties_as_array[i]);
|
||||||
|
Array keys = d.keys();
|
||||||
|
for (int j = 0; j < keys.size(); j++) {
|
||||||
|
String key = keys[j];
|
||||||
|
undo_redo->add_undo_property(object, vformat(key, i), d[key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p_element_index < 0) {
|
||||||
|
// Add an element.
|
||||||
|
properties_as_array.insert(p_to_pos < 0 ? properties_as_array.size() : p_to_pos, Dictionary());
|
||||||
|
} else if (p_to_pos < 0) {
|
||||||
|
// Delete the element.
|
||||||
|
properties_as_array.remove(p_element_index);
|
||||||
|
} else {
|
||||||
|
// Move the element.
|
||||||
|
properties_as_array.insert(p_to_pos, properties_as_array[p_element_index].duplicate());
|
||||||
|
properties_as_array.remove(p_to_pos < p_element_index ? p_element_index + 1 : p_element_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change the array size then set the properties.
|
||||||
|
undo_redo->add_do_property(object, count_property, properties_as_array.size());
|
||||||
|
for (int i = 0; i < (int)properties_as_array.size(); i++) {
|
||||||
|
Dictionary d = properties_as_array[i];
|
||||||
|
Array keys = d.keys();
|
||||||
|
for (int j = 0; j < keys.size(); j++) {
|
||||||
|
String key = keys[j];
|
||||||
|
undo_redo->add_do_property(object, vformat(key, i), d[key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
undo_redo->commit_action();
|
||||||
|
|
||||||
|
// Handle page change and update counts.
|
||||||
|
if (p_element_index < 0) {
|
||||||
|
int added_index = p_to_pos < 0 ? count : p_to_pos;
|
||||||
|
emit_signal("page_change_request", added_index / page_lenght);
|
||||||
|
count += 1;
|
||||||
|
} else if (p_to_pos < 0) {
|
||||||
|
count -= 1;
|
||||||
|
if (page == max_page && (MAX(0, count - 1) / page_lenght != max_page)) {
|
||||||
|
emit_signal("page_change_request", max_page - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
begin_array_index = page * page_lenght;
|
||||||
|
end_array_index = MIN(count, (page + 1) * page_lenght);
|
||||||
|
max_page = MAX(0, count - 1) / page_lenght;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorInspectorArray::_clear_array() {
|
||||||
|
undo_redo->create_action(vformat("Clear property array with prefix %s.", array_element_prefix));
|
||||||
|
if (mode == MODE_USE_MOVE_ARRAY_ELEMENT_FUNCTION) {
|
||||||
|
for (int i = count - 1; i >= 0; i--) {
|
||||||
|
// Call the function.
|
||||||
|
Ref<FuncRef> move_function = EditorNode::get_singleton()->get_editor_data().get_move_array_element_function(object->get_class_name());
|
||||||
|
if (move_function.is_valid()) {
|
||||||
|
Variant args[] = { (Object *)undo_redo, object, array_element_prefix, i, -1 };
|
||||||
|
const Variant *args_p[] = { &args[0], &args[1], &args[2], &args[3], &args[4] };
|
||||||
|
Variant::CallError call_error;
|
||||||
|
move_function->call_func(args_p, 5, call_error);
|
||||||
|
} else {
|
||||||
|
WARN_PRINT(vformat("Could not find a function to move arrays elements for class %s. Register a move element function using EditorData::add_move_array_element_function", object->get_class_name()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (mode == MODE_USE_COUNT_PROPERTY) {
|
||||||
|
List<PropertyInfo> object_property_list;
|
||||||
|
object->get_property_list(&object_property_list);
|
||||||
|
|
||||||
|
Array properties_as_array = _extract_properties_as_array(object_property_list);
|
||||||
|
properties_as_array.resize(count);
|
||||||
|
|
||||||
|
// For undoing things
|
||||||
|
undo_redo->add_undo_property(object, count_property, count);
|
||||||
|
for (int i = 0; i < (int)properties_as_array.size(); i++) {
|
||||||
|
Dictionary d = Dictionary(properties_as_array[i]);
|
||||||
|
Array keys = d.keys();
|
||||||
|
for (int j = 0; j < keys.size(); j++) {
|
||||||
|
String key = keys[j];
|
||||||
|
undo_redo->add_undo_property(object, vformat(key, i), d[key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change the array size then set the properties.
|
||||||
|
undo_redo->add_do_property(object, count_property, 0);
|
||||||
|
}
|
||||||
|
undo_redo->commit_action();
|
||||||
|
|
||||||
|
// Handle page change and update counts.
|
||||||
|
emit_signal("page_change_request", 0);
|
||||||
|
count = 0;
|
||||||
|
begin_array_index = 0;
|
||||||
|
end_array_index = 0;
|
||||||
|
max_page = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorInspectorArray::_resize_array(int p_size) {
|
||||||
|
ERR_FAIL_COND(p_size < 0);
|
||||||
|
if (p_size == count) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
undo_redo->create_action(vformat("Resize property array with prefix %s.", array_element_prefix));
|
||||||
|
if (p_size > count) {
|
||||||
|
if (mode == MODE_USE_MOVE_ARRAY_ELEMENT_FUNCTION) {
|
||||||
|
for (int i = count; i < p_size; i++) {
|
||||||
|
// Call the function.
|
||||||
|
Ref<FuncRef> move_function = EditorNode::get_singleton()->get_editor_data().get_move_array_element_function(object->get_class_name());
|
||||||
|
if (move_function.is_valid()) {
|
||||||
|
Variant args[] = { (Object *)undo_redo, object, array_element_prefix, -1, -1 };
|
||||||
|
const Variant *args_p[] = { &args[0], &args[1], &args[2], &args[3], &args[4] };
|
||||||
|
Variant::CallError call_error;
|
||||||
|
move_function->call_func(args_p, 5, call_error);
|
||||||
|
} else {
|
||||||
|
WARN_PRINT(vformat("Could not find a function to move arrays elements for class %s. Register a move element function using EditorData::add_move_array_element_function", object->get_class_name()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (mode == MODE_USE_COUNT_PROPERTY) {
|
||||||
|
undo_redo->add_undo_property(object, count_property, count);
|
||||||
|
undo_redo->add_do_property(object, count_property, p_size);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (mode == MODE_USE_MOVE_ARRAY_ELEMENT_FUNCTION) {
|
||||||
|
for (int i = count - 1; i > p_size - 1; i--) {
|
||||||
|
// Call the function.
|
||||||
|
Ref<FuncRef> move_function = EditorNode::get_singleton()->get_editor_data().get_move_array_element_function(object->get_class_name());
|
||||||
|
if (move_function.is_valid()) {
|
||||||
|
Variant args[] = { (Object *)undo_redo, object, array_element_prefix, i, -1 };
|
||||||
|
const Variant *args_p[] = { &args[0], &args[1], &args[2], &args[3], &args[4] };
|
||||||
|
Variant::CallError call_error;
|
||||||
|
move_function->call_func(args_p, 5, call_error);
|
||||||
|
} else {
|
||||||
|
WARN_PRINT(vformat("Could not find a function to move arrays elements for class %s. Register a move element function using EditorData::add_move_array_element_function", object->get_class_name()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (mode == MODE_USE_COUNT_PROPERTY) {
|
||||||
|
List<PropertyInfo> object_property_list;
|
||||||
|
object->get_property_list(&object_property_list);
|
||||||
|
|
||||||
|
Array properties_as_array = _extract_properties_as_array(object_property_list);
|
||||||
|
properties_as_array.resize(count);
|
||||||
|
|
||||||
|
// For undoing things
|
||||||
|
undo_redo->add_undo_property(object, count_property, count);
|
||||||
|
for (int i = count - 1; i > p_size - 1; i--) {
|
||||||
|
Dictionary d = Dictionary(properties_as_array[i]);
|
||||||
|
Array keys = d.keys();
|
||||||
|
for (int j = 0; j < keys.size(); j++) {
|
||||||
|
String key = keys[j];
|
||||||
|
undo_redo->add_undo_property(object, vformat(key, i), d[key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change the array size then set the properties.
|
||||||
|
undo_redo->add_do_property(object, count_property, p_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
undo_redo->commit_action();
|
||||||
|
|
||||||
|
// Handle page change and update counts.
|
||||||
|
emit_signal("page_change_request", 0);
|
||||||
|
/*
|
||||||
|
count = 0;
|
||||||
|
begin_array_index = 0;
|
||||||
|
end_array_index = 0;
|
||||||
|
max_page = 0;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
Array EditorInspectorArray::_extract_properties_as_array(const List<PropertyInfo> &p_list) {
|
||||||
|
Array output;
|
||||||
|
|
||||||
|
for (const List<PropertyInfo>::Element *E = p_list.front(); E; E = E->next()) {
|
||||||
|
const PropertyInfo &pi = E->get();
|
||||||
|
|
||||||
|
if (pi.name.begins_with(array_element_prefix)) {
|
||||||
|
String str = pi.name.trim_prefix(array_element_prefix);
|
||||||
|
|
||||||
|
int to_char_index = 0;
|
||||||
|
while (to_char_index < str.length()) {
|
||||||
|
if (str[to_char_index] < '0' || str[to_char_index] > '9') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
to_char_index++;
|
||||||
|
}
|
||||||
|
if (to_char_index > 0) {
|
||||||
|
int array_index = str.left(to_char_index).to_int();
|
||||||
|
Error error = OK;
|
||||||
|
if (array_index >= output.size()) {
|
||||||
|
error = output.resize(array_index + 1);
|
||||||
|
}
|
||||||
|
if (error == OK) {
|
||||||
|
String format_string = String(array_element_prefix) + "%d" + str.substr(to_char_index);
|
||||||
|
Dictionary dict = output[array_index];
|
||||||
|
dict[format_string] = object->get(pi.name);
|
||||||
|
output[array_index] = dict;
|
||||||
|
} else {
|
||||||
|
WARN_PRINT(vformat("Array element %s has an index too high. Array allocaiton failed.", pi.name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
int EditorInspectorArray::_drop_position() const {
|
||||||
|
for (int i = 0; i < (int)array_elements.size(); i++) {
|
||||||
|
const ArrayElement &ae = array_elements[i];
|
||||||
|
|
||||||
|
Size2 size = ae.panel->get_size();
|
||||||
|
Vector2 mp = ae.panel->get_local_mouse_position();
|
||||||
|
|
||||||
|
if (Rect2(Vector2(), size).has_point(mp)) {
|
||||||
|
if (mp.y < size.y / 2) {
|
||||||
|
return i;
|
||||||
|
} else {
|
||||||
|
return i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorInspectorArray::_new_size_line_edit_text_changed(String p_text) {
|
||||||
|
bool valid = false;
|
||||||
|
|
||||||
|
if (p_text.is_valid_integer()) {
|
||||||
|
int val = p_text.to_int();
|
||||||
|
if (val > 0 && val != count) {
|
||||||
|
valid = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resize_dialog->get_ok()->set_disabled(!valid);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorInspectorArray::_new_size_line_edit_text_submitted(String p_text) {
|
||||||
|
bool valid = false;
|
||||||
|
|
||||||
|
if (p_text.is_valid_integer()) {
|
||||||
|
int val = p_text.to_int();
|
||||||
|
if (val > 0 && val != count) {
|
||||||
|
new_size = val;
|
||||||
|
valid = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valid) {
|
||||||
|
resize_dialog->hide();
|
||||||
|
_resize_array(new_size);
|
||||||
|
} else {
|
||||||
|
new_size_line_edit->set_text(Variant(new_size));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorInspectorArray::_resize_dialog_confirmed() {
|
||||||
|
_new_size_line_edit_text_submitted(new_size_line_edit->get_text());
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorInspectorArray::_setup() {
|
||||||
|
// Setup counts.
|
||||||
|
count = _get_array_count();
|
||||||
|
begin_array_index = page * page_lenght;
|
||||||
|
end_array_index = MIN(count, (page + 1) * page_lenght);
|
||||||
|
max_page = MAX(0, count - 1) / page_lenght;
|
||||||
|
array_elements.resize(MAX(0, end_array_index - begin_array_index));
|
||||||
|
if (page < 0 || page > max_page) {
|
||||||
|
WARN_PRINT(vformat("Invalid page number %d", page));
|
||||||
|
page = CLAMP(page, 0, max_page);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < (int)array_elements.size(); i++) {
|
||||||
|
ArrayElement &ae = array_elements[i];
|
||||||
|
|
||||||
|
// Panel and its hbox.
|
||||||
|
ae.panel = memnew(PanelContainer);
|
||||||
|
ae.panel->set_focus_mode(FOCUS_ALL);
|
||||||
|
ae.panel->set_mouse_filter(MOUSE_FILTER_PASS);
|
||||||
|
ae.panel->set_drag_forwarding(this);
|
||||||
|
ae.panel->set_meta("index", begin_array_index + i);
|
||||||
|
ae.panel->set_tooltip(vformat(TTR("Element %d: %s%d*"), i, array_element_prefix, i));
|
||||||
|
ae.panel->connect("focus_entered", ae.panel, "update");
|
||||||
|
ae.panel->connect("focus_exited", ae.panel, "update");
|
||||||
|
ae.panel->connect("draw", this, "_panel_draw", varray(i));
|
||||||
|
ae.panel->connect("gui_input", this, "_panel_gui_input", varray(i));
|
||||||
|
ae.panel->add_theme_style_override("panel", i % 2 ? odd_style : even_style);
|
||||||
|
elements_vbox->add_child(ae.panel);
|
||||||
|
|
||||||
|
ae.margin = memnew(MarginContainer);
|
||||||
|
ae.margin->set_mouse_filter(MOUSE_FILTER_PASS);
|
||||||
|
if (is_inside_tree()) {
|
||||||
|
Size2 min_size = get_theme_stylebox("Focus", "EditorStyles")->get_minimum_size();
|
||||||
|
ae.margin->add_theme_constant_override("margin_left", min_size.x / 2);
|
||||||
|
ae.margin->add_theme_constant_override("margin_top", min_size.y / 2);
|
||||||
|
ae.margin->add_theme_constant_override("margin_right", min_size.x / 2);
|
||||||
|
ae.margin->add_theme_constant_override("margin_bottom", min_size.y / 2);
|
||||||
|
}
|
||||||
|
ae.panel->add_child(ae.margin);
|
||||||
|
|
||||||
|
ae.hbox = memnew(HBoxContainer);
|
||||||
|
ae.hbox->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||||
|
ae.hbox->set_v_size_flags(SIZE_EXPAND_FILL);
|
||||||
|
ae.margin->add_child(ae.hbox);
|
||||||
|
|
||||||
|
// Move button.
|
||||||
|
ae.move_texture_rect = memnew(TextureRect);
|
||||||
|
ae.move_texture_rect->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED);
|
||||||
|
if (is_inside_tree()) {
|
||||||
|
ae.move_texture_rect->set_texture(get_theme_icon("TripleBar", "EditorIcons"));
|
||||||
|
}
|
||||||
|
ae.hbox->add_child(ae.move_texture_rect);
|
||||||
|
|
||||||
|
// Right vbox.
|
||||||
|
ae.vbox = memnew(VBoxContainer);
|
||||||
|
ae.vbox->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||||
|
ae.vbox->set_v_size_flags(SIZE_EXPAND_FILL);
|
||||||
|
ae.hbox->add_child(ae.vbox);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hide/show the add button.
|
||||||
|
add_button->set_visible(page == max_page);
|
||||||
|
|
||||||
|
if (max_page == 0) {
|
||||||
|
hbox_pagination->hide();
|
||||||
|
} else {
|
||||||
|
// Update buttons.
|
||||||
|
first_page_button->set_disabled(page == 0);
|
||||||
|
prev_page_button->set_disabled(page == 0);
|
||||||
|
next_page_button->set_disabled(page == max_page);
|
||||||
|
last_page_button->set_disabled(page == max_page);
|
||||||
|
|
||||||
|
// Update page number and page count.
|
||||||
|
page_line_edit->set_text(vformat("%d", page + 1));
|
||||||
|
page_count_label->set_text(vformat("/ %d", max_page + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Variant EditorInspectorArray::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
|
||||||
|
int index = p_from->get_meta("index");
|
||||||
|
Dictionary dict;
|
||||||
|
dict["type"] = "property_array_element";
|
||||||
|
dict["property_array_prefix"] = array_element_prefix;
|
||||||
|
dict["index"] = index;
|
||||||
|
|
||||||
|
return dict;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorInspectorArray::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
|
||||||
|
Dictionary dict = p_data;
|
||||||
|
|
||||||
|
int to_drop = dict["index"];
|
||||||
|
int drop_position = _drop_position();
|
||||||
|
if (drop_position < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_move_element(to_drop, begin_array_index + drop_position);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EditorInspectorArray::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
|
||||||
|
// First, update drawing.
|
||||||
|
control_dropping->update();
|
||||||
|
|
||||||
|
if (p_data.get_type() != Variant::DICTIONARY) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Dictionary dict = p_data;
|
||||||
|
int drop_position = _drop_position();
|
||||||
|
if (!dict.has("type") || dict["type"] != "property_array_element" || String(dict["property_array_prefix"]) != array_element_prefix || drop_position < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check in dropping at the given index does indeed move the item.
|
||||||
|
int moved_array_index = (int)dict["index"];
|
||||||
|
int drop_array_index = begin_array_index + drop_position;
|
||||||
|
|
||||||
|
return drop_array_index != moved_array_index && drop_array_index - 1 != moved_array_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorInspectorArray::_notification(int p_what) {
|
||||||
|
switch (p_what) {
|
||||||
|
case NOTIFICATION_ENTER_TREE:
|
||||||
|
case NOTIFICATION_THEME_CHANGED: {
|
||||||
|
Color color = get_theme_color("dark_color_1", "Editor");
|
||||||
|
odd_style->set_bg_color(color.lightened(0.15));
|
||||||
|
even_style->set_bg_color(color.darkened(0.15));
|
||||||
|
|
||||||
|
for (int i = 0; i < (int)array_elements.size(); i++) {
|
||||||
|
ArrayElement &ae = array_elements[i];
|
||||||
|
ae.move_texture_rect->set_texture(get_theme_icon("TripleBar", "EditorIcons"));
|
||||||
|
|
||||||
|
Size2 min_size = get_theme_stylebox("Focus", "EditorStyles")->get_minimum_size();
|
||||||
|
ae.margin->add_theme_constant_override("margin_left", min_size.x / 2);
|
||||||
|
ae.margin->add_theme_constant_override("margin_top", min_size.y / 2);
|
||||||
|
ae.margin->add_theme_constant_override("margin_right", min_size.x / 2);
|
||||||
|
ae.margin->add_theme_constant_override("margin_bottom", min_size.y / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
add_button->set_icon(get_theme_icon("Add", "EditorIcons"));
|
||||||
|
first_page_button->set_icon(get_theme_icon("PageFirst", "EditorIcons"));
|
||||||
|
prev_page_button->set_icon(get_theme_icon("PagePrevious", "EditorIcons"));
|
||||||
|
next_page_button->set_icon(get_theme_icon("PageNext", "EditorIcons"));
|
||||||
|
last_page_button->set_icon(get_theme_icon("PageLast", "EditorIcons"));
|
||||||
|
minimum_size_changed();
|
||||||
|
} break;
|
||||||
|
case NOTIFICATION_DRAG_BEGIN: {
|
||||||
|
Dictionary dict = get_viewport()->gui_get_drag_data();
|
||||||
|
if (dict.has("type") && dict["type"] == "property_array_element" && String(dict["property_array_prefix"]) == array_element_prefix) {
|
||||||
|
dropping = true;
|
||||||
|
control_dropping->update();
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case NOTIFICATION_DRAG_END: {
|
||||||
|
if (dropping) {
|
||||||
|
dropping = false;
|
||||||
|
control_dropping->update();
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorInspectorArray::_bind_methods() {
|
||||||
|
ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &EditorInspectorArray::get_drag_data_fw);
|
||||||
|
ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &EditorInspectorArray::can_drop_data_fw);
|
||||||
|
ClassDB::bind_method(D_METHOD("_drop_data_fw"), &EditorInspectorArray::drop_data_fw);
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("_panel_draw"), &EditorInspectorArray::_panel_draw);
|
||||||
|
ClassDB::bind_method(D_METHOD("_rmb_popup_id_pressed"), &EditorInspectorArray::_rmb_popup_id_pressed);
|
||||||
|
ClassDB::bind_method(D_METHOD("_add_button_pressed"), &EditorInspectorArray::_add_button_pressed);
|
||||||
|
ClassDB::bind_method(D_METHOD("_first_page_button_pressed"), &EditorInspectorArray::_first_page_button_pressed);
|
||||||
|
ClassDB::bind_method(D_METHOD("_prev_page_button_pressed"), &EditorInspectorArray::_prev_page_button_pressed);
|
||||||
|
ClassDB::bind_method(D_METHOD("_page_line_edit_text_submitted"), &EditorInspectorArray::_page_line_edit_text_submitted);
|
||||||
|
ClassDB::bind_method(D_METHOD("_next_page_button_pressed"), &EditorInspectorArray::_next_page_button_pressed);
|
||||||
|
ClassDB::bind_method(D_METHOD("_last_page_button_pressed"), &EditorInspectorArray::_last_page_button_pressed);
|
||||||
|
ClassDB::bind_method(D_METHOD("_control_dropping_draw"), &EditorInspectorArray::_control_dropping_draw);
|
||||||
|
ClassDB::bind_method(D_METHOD("_resize_dialog_confirmed"), &EditorInspectorArray::_resize_dialog_confirmed);
|
||||||
|
ClassDB::bind_method(D_METHOD("_new_size_line_edit_text_changed"), &EditorInspectorArray::_new_size_line_edit_text_changed);
|
||||||
|
ClassDB::bind_method(D_METHOD("_new_size_line_edit_text_submitted"), &EditorInspectorArray::_new_size_line_edit_text_submitted);
|
||||||
|
ClassDB::bind_method(D_METHOD("_vbox_visibility_changed"), &EditorInspectorArray::_vbox_visibility_changed);
|
||||||
|
|
||||||
|
ADD_SIGNAL(MethodInfo("page_change_request"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorInspectorArray::set_undo_redo(UndoRedo *p_undo_redo) {
|
||||||
|
undo_redo = p_undo_redo;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorInspectorArray::setup_with_move_element_function(Object *p_object, String p_label, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable) {
|
||||||
|
count_property = "";
|
||||||
|
mode = MODE_USE_MOVE_ARRAY_ELEMENT_FUNCTION;
|
||||||
|
array_element_prefix = p_array_element_prefix;
|
||||||
|
page = p_page;
|
||||||
|
|
||||||
|
EditorInspectorSection::setup(String(p_array_element_prefix) + "_array", p_label, p_object, p_bg_color, p_foldable);
|
||||||
|
|
||||||
|
_setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorInspectorArray::setup_with_count_property(Object *p_object, String p_label, const StringName &p_count_property, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable) {
|
||||||
|
count_property = p_count_property;
|
||||||
|
mode = MODE_USE_COUNT_PROPERTY;
|
||||||
|
array_element_prefix = p_array_element_prefix;
|
||||||
|
page = p_page;
|
||||||
|
|
||||||
|
EditorInspectorSection::setup(String(count_property) + "_array", p_label, p_object, p_bg_color, p_foldable);
|
||||||
|
|
||||||
|
_setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
VBoxContainer *EditorInspectorArray::get_vbox(int p_index) {
|
||||||
|
if (p_index >= begin_array_index && p_index < end_array_index) {
|
||||||
|
return array_elements[p_index - begin_array_index].vbox;
|
||||||
|
} else if (p_index < 0) {
|
||||||
|
return vbox;
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorInspectorArray::EditorInspectorArray() {
|
||||||
|
set_mouse_filter(Control::MOUSE_FILTER_STOP);
|
||||||
|
|
||||||
|
odd_style.instance();
|
||||||
|
even_style.instance();
|
||||||
|
|
||||||
|
rmb_popup = memnew(PopupMenu);
|
||||||
|
rmb_popup->add_item(TTR("Move Up"), OPTION_MOVE_UP);
|
||||||
|
rmb_popup->add_item(TTR("Move Down"), OPTION_MOVE_DOWN);
|
||||||
|
rmb_popup->add_separator();
|
||||||
|
rmb_popup->add_item(TTR("Insert New Before"), OPTION_NEW_BEFORE);
|
||||||
|
rmb_popup->add_item(TTR("Insert New After"), OPTION_NEW_AFTER);
|
||||||
|
rmb_popup->add_separator();
|
||||||
|
rmb_popup->add_item(TTR("Remove"), OPTION_REMOVE);
|
||||||
|
rmb_popup->add_separator();
|
||||||
|
rmb_popup->add_item(TTR("Clear Array"), OPTION_CLEAR_ARRAY);
|
||||||
|
rmb_popup->add_item(TTR("Resize Array..."), OPTION_RESIZE_ARRAY);
|
||||||
|
rmb_popup->connect("id_pressed", this, "_rmb_popup_id_pressed");
|
||||||
|
add_child(rmb_popup);
|
||||||
|
|
||||||
|
elements_vbox = memnew(VBoxContainer);
|
||||||
|
elements_vbox->add_theme_constant_override("separation", 0);
|
||||||
|
vbox->add_child(elements_vbox);
|
||||||
|
|
||||||
|
add_button = memnew(Button);
|
||||||
|
add_button->set_text(TTR("Add Element"));
|
||||||
|
add_button->set_text_align(Button::ALIGN_CENTER);
|
||||||
|
add_button->connect("pressed", this, "_add_button_pressed");
|
||||||
|
vbox->add_child(add_button);
|
||||||
|
|
||||||
|
hbox_pagination = memnew(HBoxContainer);
|
||||||
|
hbox_pagination->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||||
|
hbox_pagination->set_alignment(HBoxContainer::ALIGN_CENTER);
|
||||||
|
vbox->add_child(hbox_pagination);
|
||||||
|
|
||||||
|
first_page_button = memnew(Button);
|
||||||
|
first_page_button->set_flat(true);
|
||||||
|
first_page_button->connect("pressed", this, "_first_page_button_pressed");
|
||||||
|
hbox_pagination->add_child(first_page_button);
|
||||||
|
|
||||||
|
prev_page_button = memnew(Button);
|
||||||
|
prev_page_button->set_flat(true);
|
||||||
|
prev_page_button->connect("pressed", this, "_prev_page_button_pressed");
|
||||||
|
hbox_pagination->add_child(prev_page_button);
|
||||||
|
|
||||||
|
page_line_edit = memnew(LineEdit);
|
||||||
|
page_line_edit->connect("text_submitted", this, "_page_line_edit_text_submitted");
|
||||||
|
page_line_edit->add_theme_constant_override("minimum_character_width", 2);
|
||||||
|
hbox_pagination->add_child(page_line_edit);
|
||||||
|
|
||||||
|
page_count_label = memnew(Label);
|
||||||
|
hbox_pagination->add_child(page_count_label);
|
||||||
|
next_page_button = memnew(Button);
|
||||||
|
next_page_button->set_flat(true);
|
||||||
|
next_page_button->connect("pressed", this, "_next_page_button_pressed");
|
||||||
|
hbox_pagination->add_child(next_page_button);
|
||||||
|
|
||||||
|
last_page_button = memnew(Button);
|
||||||
|
last_page_button->set_flat(true);
|
||||||
|
last_page_button->connect("pressed", this, "_last_page_button_pressed");
|
||||||
|
hbox_pagination->add_child(last_page_button);
|
||||||
|
|
||||||
|
control_dropping = memnew(Control);
|
||||||
|
control_dropping->connect("draw", this, "_control_dropping_draw");
|
||||||
|
control_dropping->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
|
||||||
|
add_child(control_dropping);
|
||||||
|
|
||||||
|
resize_dialog = memnew(AcceptDialog);
|
||||||
|
resize_dialog->set_title(TTRC("Resize Array"));
|
||||||
|
resize_dialog->add_cancel();
|
||||||
|
resize_dialog->connect("confirmed", this, "_resize_dialog_confirmed");
|
||||||
|
add_child(resize_dialog);
|
||||||
|
|
||||||
|
VBoxContainer *resize_dialog_vbox = memnew(VBoxContainer);
|
||||||
|
resize_dialog->add_child(resize_dialog_vbox);
|
||||||
|
|
||||||
|
new_size_line_edit = memnew(LineEdit);
|
||||||
|
new_size_line_edit->connect("text_changed", this, "_new_size_line_edit_text_changed");
|
||||||
|
new_size_line_edit->connect("text_submitted", this, "_new_size_line_edit_text_submitted");
|
||||||
|
resize_dialog_vbox->add_margin_child(TTRC("New Size:"), new_size_line_edit);
|
||||||
|
|
||||||
|
vbox->connect("visibility_changed", this, "_vbox_visibility_changed");
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////
|
||||||
|
////////////////////////////////////////////////
|
||||||
|
|
||||||
Ref<EditorInspectorPlugin> EditorInspector::inspector_plugins[MAX_PLUGINS];
|
Ref<EditorInspectorPlugin> EditorInspector::inspector_plugins[MAX_PLUGINS];
|
||||||
int EditorInspector::inspector_plugin_count = 0;
|
int EditorInspector::inspector_plugin_count = 0;
|
||||||
|
|
||||||
|
@ -61,6 +61,12 @@ class LineEdit;
|
|||||||
class Node;
|
class Node;
|
||||||
class PopupMenu;
|
class PopupMenu;
|
||||||
class VBoxContainer;
|
class VBoxContainer;
|
||||||
|
class Button;
|
||||||
|
class AcceptDialog;
|
||||||
|
class MarginContainer;
|
||||||
|
class HBoxContainer;
|
||||||
|
class PanelContainer;
|
||||||
|
class TextureRect;
|
||||||
|
|
||||||
class EditorPropertyRevert {
|
class EditorPropertyRevert {
|
||||||
public:
|
public:
|
||||||
@ -254,9 +260,8 @@ class EditorInspectorSection : public Container {
|
|||||||
|
|
||||||
String label;
|
String label;
|
||||||
String section;
|
String section;
|
||||||
Object *object;
|
|
||||||
VBoxContainer *vbox;
|
bool vbox_added; // Optimization
|
||||||
bool vbox_added; //optimization
|
|
||||||
Color bg_color;
|
Color bg_color;
|
||||||
bool foldable;
|
bool foldable;
|
||||||
|
|
||||||
@ -265,6 +270,9 @@ class EditorInspectorSection : public Container {
|
|||||||
Ref<Texture> _get_arrow();
|
Ref<Texture> _get_arrow();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
Object *object;
|
||||||
|
VBoxContainer *vbox;
|
||||||
|
|
||||||
void _notification(int p_what);
|
void _notification(int p_what);
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
void _gui_input(const Ref<InputEvent> &p_event);
|
void _gui_input(const Ref<InputEvent> &p_event);
|
||||||
@ -281,6 +289,121 @@ public:
|
|||||||
~EditorInspectorSection();
|
~EditorInspectorSection();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class EditorInspectorArray : public EditorInspectorSection {
|
||||||
|
GDCLASS(EditorInspectorArray, EditorInspectorSection);
|
||||||
|
|
||||||
|
UndoRedo *undo_redo;
|
||||||
|
|
||||||
|
enum Mode {
|
||||||
|
MODE_NONE,
|
||||||
|
MODE_USE_COUNT_PROPERTY,
|
||||||
|
MODE_USE_MOVE_ARRAY_ELEMENT_FUNCTION,
|
||||||
|
} mode;
|
||||||
|
|
||||||
|
StringName count_property;
|
||||||
|
StringName array_element_prefix;
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
VBoxContainer *elements_vbox;
|
||||||
|
|
||||||
|
Control *control_dropping;
|
||||||
|
bool dropping = false;
|
||||||
|
|
||||||
|
Button *add_button;
|
||||||
|
|
||||||
|
AcceptDialog *resize_dialog;
|
||||||
|
int new_size = 0;
|
||||||
|
LineEdit *new_size_line_edit;
|
||||||
|
|
||||||
|
// Pagination
|
||||||
|
int page_lenght = 5;
|
||||||
|
int page = 0;
|
||||||
|
int max_page = 0;
|
||||||
|
int begin_array_index = 0;
|
||||||
|
int end_array_index = 0;
|
||||||
|
HBoxContainer *hbox_pagination;
|
||||||
|
Button *first_page_button;
|
||||||
|
Button *prev_page_button;
|
||||||
|
LineEdit *page_line_edit;
|
||||||
|
Label *page_count_label;
|
||||||
|
Button *next_page_button;
|
||||||
|
Button *last_page_button;
|
||||||
|
|
||||||
|
enum MenuOptions {
|
||||||
|
OPTION_MOVE_UP = 0,
|
||||||
|
OPTION_MOVE_DOWN,
|
||||||
|
OPTION_NEW_BEFORE,
|
||||||
|
OPTION_NEW_AFTER,
|
||||||
|
OPTION_REMOVE,
|
||||||
|
OPTION_CLEAR_ARRAY,
|
||||||
|
OPTION_RESIZE_ARRAY,
|
||||||
|
};
|
||||||
|
|
||||||
|
int popup_array_index_pressed = -1;
|
||||||
|
PopupMenu *rmb_popup;
|
||||||
|
|
||||||
|
struct ArrayElement {
|
||||||
|
PanelContainer *panel;
|
||||||
|
MarginContainer *margin;
|
||||||
|
HBoxContainer *hbox;
|
||||||
|
TextureRect *move_texture_rect;
|
||||||
|
VBoxContainer *vbox;
|
||||||
|
};
|
||||||
|
|
||||||
|
LocalVector<ArrayElement> array_elements;
|
||||||
|
|
||||||
|
Ref<StyleBoxFlat> odd_style;
|
||||||
|
Ref<StyleBoxFlat> even_style;
|
||||||
|
|
||||||
|
int _get_array_count();
|
||||||
|
void _add_button_pressed();
|
||||||
|
|
||||||
|
void _first_page_button_pressed();
|
||||||
|
void _prev_page_button_pressed();
|
||||||
|
void _page_line_edit_text_submitted(String p_text);
|
||||||
|
void _next_page_button_pressed();
|
||||||
|
void _last_page_button_pressed();
|
||||||
|
|
||||||
|
void _rmb_popup_id_pressed(int p_id);
|
||||||
|
|
||||||
|
void _control_dropping_draw();
|
||||||
|
|
||||||
|
void _vbox_visibility_changed();
|
||||||
|
|
||||||
|
void _panel_draw(int p_index);
|
||||||
|
void _panel_gui_input(Ref<InputEvent> p_event, int p_index);
|
||||||
|
void _move_element(int p_element_index, int p_to_pos);
|
||||||
|
void _clear_array();
|
||||||
|
void _resize_array(int p_size);
|
||||||
|
Array _extract_properties_as_array(const List<PropertyInfo> &p_list);
|
||||||
|
int _drop_position() const;
|
||||||
|
|
||||||
|
void _new_size_line_edit_text_changed(String p_text);
|
||||||
|
void _new_size_line_edit_text_submitted(String p_text);
|
||||||
|
void _resize_dialog_confirmed();
|
||||||
|
|
||||||
|
void _update_elements_visibility();
|
||||||
|
void _setup();
|
||||||
|
|
||||||
|
Variant get_drag_data_fw(const Point2 &p_point, Control *p_from);
|
||||||
|
void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
|
||||||
|
bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void _notification(int p_what);
|
||||||
|
static void _bind_methods();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void set_undo_redo(UndoRedo *p_undo_redo);
|
||||||
|
|
||||||
|
void setup_with_move_element_function(Object *p_object, String p_label, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable);
|
||||||
|
void setup_with_count_property(Object *p_object, String p_label, const StringName &p_count_property, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable);
|
||||||
|
VBoxContainer *get_vbox(int p_index);
|
||||||
|
|
||||||
|
EditorInspectorArray();
|
||||||
|
};
|
||||||
|
|
||||||
class EditorInspector : public ScrollContainer {
|
class EditorInspector : public ScrollContainer {
|
||||||
GDCLASS(EditorInspector, ScrollContainer);
|
GDCLASS(EditorInspector, ScrollContainer);
|
||||||
|
|
||||||
|
1
editor/icons/icon_page_first.svg
Normal file
1
editor/icons/icon_page_first.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg height="12" width="12" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg"><path d="M6 3 3 6l3 3m3-6v6" stroke-linecap="round" stroke-linejoin="round" fill="none" stroke="#e0e0e0" stroke-width="2"/></svg>
|
After Width: | Height: | Size: 213 B |
1
editor/icons/icon_page_last.svg
Normal file
1
editor/icons/icon_page_last.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg height="12" width="12" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg"><path d="m6 9 3-3-3-3M3 9V3" stroke-linecap="round" stroke-linejoin="round" fill="none" stroke="#e0e0e0" stroke-width="2"/></svg>
|
After Width: | Height: | Size: 213 B |
1
editor/icons/icon_page_next.svg
Normal file
1
editor/icons/icon_page_next.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg height="12" width="12" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg"><path d="m4.5 9 3-3-3-3" fill="none" stroke="#e0e0e0" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/></svg>
|
After Width: | Height: | Size: 209 B |
1
editor/icons/icon_page_previous.svg
Normal file
1
editor/icons/icon_page_previous.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg height="12" width="12" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg"><path d="m7.5 3-3 3 3 3" fill="none" stroke="#e0e0e0" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/></svg>
|
After Width: | Height: | Size: 209 B |
Loading…
Reference in New Issue
Block a user