Explorar o código

Fix update property for dictionnaries so that it updates only what is necessary

ajreckof hai 1 ano
pai
achega
0331ecb527
Modificáronse 2 ficheiros con 187 adicións e 366 borrados
  1. 146 364
      editor/editor_properties_array_dict.cpp
  2. 41 2
      editor/editor_properties_array_dict.h

+ 146 - 364
editor/editor_properties_array_dict.cpp

@@ -111,6 +111,7 @@ bool EditorPropertyDictionaryObject::_set(const StringName &p_name, const Varian
 	}
 
 	if (name.begins_with("indices")) {
+		dict = dict.duplicate();
 		int index = name.get_slicec('/', 1).to_int();
 		Variant key = dict.get_key_at_index(index);
 		dict[key] = p_value;
@@ -171,6 +172,31 @@ Variant EditorPropertyDictionaryObject::get_new_item_value() {
 	return new_item_value;
 }
 
+String EditorPropertyDictionaryObject::get_property_name_for_index(int p_index) {
+	switch (p_index) {
+		case NEW_KEY_INDEX:
+			return "new_item_key";
+		case NEW_VALUE_INDEX:
+			return "new_item_value";
+		default:
+			return "indices/" + itos(p_index);
+	}
+}
+
+String EditorPropertyDictionaryObject::get_label_for_index(int p_index) {
+	switch (p_index) {
+		case NEW_KEY_INDEX:
+			return TTR("New Key:");
+			break;
+		case NEW_VALUE_INDEX:
+			return TTR("New Value:");
+			break;
+		default:
+			return dict.get_key_at_index(p_index).get_construct_string();
+			break;
+	}
+}
+
 EditorPropertyDictionaryObject::EditorPropertyDictionaryObject() {
 }
 
@@ -230,15 +256,14 @@ void EditorPropertyArray::_change_type_menu(int p_index) {
 	Variant array = object->get_array().duplicate();
 	array.set(slots[changing_type_index].index, value);
 
-	emit_changed(get_edited_property(), array, "", true);
-	update_property();
+	emit_changed(get_edited_property(), array);
 }
 
 void EditorPropertyArray::_object_id_selected(const StringName &p_property, ObjectID p_id) {
 	emit_signal(SNAME("object_id_selected"), p_property, p_id);
 }
 
-void EditorPropertyArray::create_new_property_slot() {
+void EditorPropertyArray::_create_new_property_slot() {
 	int idx = slots.size();
 	HBoxContainer *hbox = memnew(HBoxContainer);
 
@@ -365,7 +390,7 @@ void EditorPropertyArray::update_property() {
 			vbox->add_child(paginator);
 
 			for (int i = 0; i < page_length; i++) {
-				create_new_property_slot();
+				_create_new_property_slot();
 			}
 		}
 
@@ -434,8 +459,7 @@ void EditorPropertyArray::_remove_pressed(int p_slot_index) {
 	Variant array = object->get_array().duplicate();
 	array.call("remove_at", slots[p_slot_index].index);
 
-	emit_changed(get_edited_property(), array, "", false);
-	update_property();
+	emit_changed(get_edited_property(), array);
 }
 
 void EditorPropertyArray::_button_draw() {
@@ -514,8 +538,7 @@ void EditorPropertyArray::drop_data_fw(const Point2 &p_point, const Variant &p_d
 			}
 		}
 
-		emit_changed(get_edited_property(), array, "", false);
-		update_property();
+		emit_changed(get_edited_property(), array);
 	}
 }
 
@@ -607,8 +630,7 @@ void EditorPropertyArray::_length_changed(double p_page) {
 	Variant array = object->get_array().duplicate();
 	array.call("resize", int(p_page));
 
-	emit_changed(get_edited_property(), array, "", false);
-	update_property();
+	emit_changed(get_edited_property(), array);
 }
 
 void EditorPropertyArray::_add_element() {
@@ -700,8 +722,7 @@ void EditorPropertyArray::_reorder_button_up() {
 		array.call("remove_at", reorder_slot.index);
 		array.call("insert", reorder_to_index, value_to_move);
 
-		reorder_slot.index = reorder_slot.index % page_length + page_index * page_length;
-		emit_changed(get_edited_property(), array, "", false);
+		emit_changed(get_edited_property(), array);
 	}
 
 	Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
@@ -748,31 +769,19 @@ void EditorPropertyDictionary::_property_changed(const String &p_property, Varia
 		p_value = Variant(); // `EditorResourcePicker` resets to `Ref<Resource>()`. See GH-82716.
 	}
 
-	if (p_property == "new_item_key") {
-		object->set_new_item_key(p_value);
-	} else if (p_property == "new_item_value") {
-		object->set_new_item_value(p_value);
-	} else if (p_property.begins_with("indices")) {
-		int index = p_property.get_slice("/", 1).to_int();
-
-		Dictionary dict = object->get_dict().duplicate();
-		Variant key = dict.get_key_at_index(index);
-		dict[key] = p_value;
-
-		object->set_dict(dict);
-		emit_changed(get_edited_property(), dict, "", true);
-	}
+	object->set(p_property, p_value);
+	emit_changed(get_edited_property(), object->get_dict(), p_name, p_changing);
 }
 
-void EditorPropertyDictionary::_change_type(Object *p_button, int p_index) {
+void EditorPropertyDictionary::_change_type(Object *p_button, int p_slot_index) {
 	Button *button = Object::cast_to<Button>(p_button);
-
+	int index = slots[p_slot_index].index;
 	Rect2 rect = button->get_screen_rect();
-	change_type->set_item_disabled(change_type->get_item_index(Variant::VARIANT_MAX), p_index < 0);
+	change_type->set_item_disabled(change_type->get_item_index(Variant::VARIANT_MAX), index < 0);
 	change_type->reset_size();
 	change_type->set_position(rect.get_end() - Vector2(change_type->get_contents_minimum_size().x, 0));
 	change_type->popup();
-	changing_type_index = p_index;
+	changing_type_index = index;
 }
 
 void EditorPropertyDictionary::_add_key_value() {
@@ -796,36 +805,59 @@ void EditorPropertyDictionary::_add_key_value() {
 	VariantInternal::initialize(&new_value, type);
 	object->set_new_item_value(new_value);
 
-	emit_changed(get_edited_property(), dict, "", false);
-	update_property();
+	emit_changed(get_edited_property(), dict);
 }
 
-void EditorPropertyDictionary::_change_type_menu(int p_index) {
-	if (changing_type_index < 0) {
-		Variant value;
-		VariantInternal::initialize(&value, Variant::Type(p_index));
-		if (changing_type_index == -1) {
-			object->set_new_item_key(value);
-		} else {
-			object->set_new_item_value(value);
-		}
-		update_property();
-		return;
-	}
+void EditorPropertyDictionary::_create_new_property_slot(int p_idx) {
+	HBoxContainer *hbox = memnew(HBoxContainer);
+	EditorProperty *prop = memnew(EditorPropertyNil);
+	hbox->add_child(prop);
 
-	Dictionary dict = object->get_dict().duplicate();
-	if (p_index < Variant::VARIANT_MAX) {
-		Variant value;
-		VariantInternal::initialize(&value, Variant::Type(p_index));
-		Variant key = dict.get_key_at_index(changing_type_index);
-		dict[key] = value;
+	Button *edit_btn = memnew(Button);
+	edit_btn->set_icon(get_editor_theme_icon(SNAME("Edit")));
+	edit_btn->set_disabled(is_read_only());
+	edit_btn->connect("pressed", callable_mp(this, &EditorPropertyDictionary::_change_type).bind(edit_btn, slots.size()));
+	hbox->add_child(edit_btn);
+	if (add_panel) {
+		add_panel->get_child(0)->add_child(hbox);
 	} else {
-		Variant key = dict.get_key_at_index(changing_type_index);
-		dict.erase(key);
+		property_vbox->add_child(hbox);
 	}
+	Slot slot;
+	slot.prop = prop;
+	slot.object = object;
+	slot.container = hbox;
+	int index = p_idx + (p_idx >= 0 ? page_index * page_length : 0);
+	slot.set_index(index);
+	slots.push_back(slot);
+}
 
-	emit_changed(get_edited_property(), dict, "", false);
-	update_property();
+void EditorPropertyDictionary::_change_type_menu(int p_index) {
+	Variant value;
+	switch (changing_type_index) {
+		case EditorPropertyDictionaryObject::NEW_KEY_INDEX:
+		case EditorPropertyDictionaryObject::NEW_VALUE_INDEX:
+			VariantInternal::initialize(&value, Variant::Type(p_index));
+			if (changing_type_index == EditorPropertyDictionaryObject::NEW_KEY_INDEX) {
+				object->set_new_item_key(value);
+			} else {
+				object->set_new_item_value(value);
+			}
+			update_property();
+			break;
+
+		default:
+			Dictionary dict = object->get_dict().duplicate();
+			Variant key = dict.get_key_at_index(changing_type_index);
+			if (p_index < Variant::VARIANT_MAX) {
+				VariantInternal::initialize(&value, Variant::Type(p_index));
+				dict[key] = value;
+			} else {
+				dict.erase(key);
+			}
+
+			emit_changed(get_edited_property(), dict);
+	}
 }
 
 void EditorPropertyDictionary::setup(PropertyHint p_hint) {
@@ -877,331 +909,72 @@ void EditorPropertyDictionary::update_property() {
 			paginator = memnew(EditorPaginator);
 			paginator->connect("page_changed", callable_mp(this, &EditorPropertyDictionary::_page_changed));
 			vbox->add_child(paginator);
-		} else {
-			// Queue children for deletion, deleting immediately might cause errors.
-			for (int i = property_vbox->get_child_count() - 1; i >= 0; i--) {
-				property_vbox->get_child(i)->queue_free();
+
+			for (int i = 0; i < page_length; i++) {
+				_create_new_property_slot(slots.size());
 			}
+
+			add_panel = memnew(PanelContainer);
+			property_vbox->add_child(add_panel);
+			add_panel->add_theme_style_override(SNAME("panel"), get_theme_stylebox(SNAME("DictionaryAddItem"), EditorStringName(EditorStyles)));
+			VBoxContainer *add_vbox = memnew(VBoxContainer);
+			add_panel->add_child(add_vbox);
+
+			_create_new_property_slot(EditorPropertyDictionaryObject::NEW_KEY_INDEX);
+			_create_new_property_slot(EditorPropertyDictionaryObject::NEW_VALUE_INDEX);
+
+			button_add_item = EditorInspector::create_inspector_action_button(TTR("Add Key/Value Pair"));
+			button_add_item->set_icon(get_theme_icon(SNAME("Add"), EditorStringName(EditorIcons)));
+			button_add_item->set_disabled(is_read_only());
+			button_add_item->connect("pressed", callable_mp(this, &EditorPropertyDictionary::_add_key_value));
+			add_vbox->add_child(button_add_item);
 		}
 
 		int size = dict.size();
 
 		int max_page = MAX(0, size - 1) / page_length;
-		page_index = MIN(page_index, max_page);
+		if (page_index > max_page) {
+			_page_changed(max_page);
+		}
 
 		paginator->update(page_index, max_page);
 		paginator->set_visible(max_page > 0);
 
-		int offset = page_index * page_length;
-
-		int amount = MIN(size - offset, page_length);
-		int total_amount = page_index == max_page ? amount + 2 : amount; // For the "Add Key/Value Pair" box on last page.
-
-		VBoxContainer *add_vbox = nullptr;
-		double default_float_step = EDITOR_GET("interface/inspector/default_float_step");
-
-		for (int i = 0; i < total_amount; i++) {
-			String prop_name;
-			Variant key;
-			Variant value;
+		add_panel->set_visible(page_index == max_page);
 
-			if (i < amount) {
-				prop_name = "indices/" + itos(i + offset);
-				key = dict.get_key_at_index(i + offset);
-				value = dict.get_value_at_index(i + offset);
-			} else if (i == amount) {
-				prop_name = "new_item_key";
-				value = object->get_new_item_key();
-			} else if (i == amount + 1) {
-				prop_name = "new_item_value";
-				value = object->get_new_item_value();
+		for (Slot &slot : slots) {
+			bool slot_visible = slot.index < size;
+			slot.container->set_visible(slot_visible);
+			// If not visible no need to update it.
+			if (!slot_visible) {
+				continue;
 			}
+			Variant value = object->get(slot.prop_name);
+			Variant::Type value_type = value.get_type();
 
-			EditorProperty *prop = nullptr;
-
-			switch (value.get_type()) {
-				case Variant::NIL: {
-					prop = memnew(EditorPropertyNil);
-
-				} break;
-
-				// Atomic types.
-				case Variant::BOOL: {
-					prop = memnew(EditorPropertyCheck);
-
-				} break;
-				case Variant::INT: {
-					EditorPropertyInteger *editor = memnew(EditorPropertyInteger);
-					editor->setup(-100000, 100000, 1, false, true, true);
-					prop = editor;
-
-				} break;
-				case Variant::FLOAT: {
-					EditorPropertyFloat *editor = memnew(EditorPropertyFloat);
-					editor->setup(-100000, 100000, default_float_step, true, false, true, true);
-					prop = editor;
-				} break;
-				case Variant::STRING: {
-					if (i != amount && property_hint == PROPERTY_HINT_MULTILINE_TEXT) {
-						// If this is NOT the new key field and there's a multiline hint,
-						// show the field as multiline
-						prop = memnew(EditorPropertyMultilineText);
-					} else {
-						prop = memnew(EditorPropertyText);
-					}
-
-				} break;
-
-				// Math types.
-				case Variant::VECTOR2: {
-					EditorPropertyVector2 *editor = memnew(EditorPropertyVector2);
-					editor->setup(-100000, 100000, default_float_step, true);
-					prop = editor;
-
-				} break;
-				case Variant::VECTOR2I: {
-					EditorPropertyVector2i *editor = memnew(EditorPropertyVector2i);
-					editor->setup(-100000, 100000);
-					prop = editor;
-
-				} break;
-				case Variant::RECT2: {
-					EditorPropertyRect2 *editor = memnew(EditorPropertyRect2);
-					editor->setup(-100000, 100000, default_float_step, true);
-					prop = editor;
-
-				} break;
-				case Variant::RECT2I: {
-					EditorPropertyRect2i *editor = memnew(EditorPropertyRect2i);
-					editor->setup(-100000, 100000);
-					prop = editor;
-
-				} break;
-				case Variant::VECTOR3: {
-					EditorPropertyVector3 *editor = memnew(EditorPropertyVector3);
-					editor->setup(-100000, 100000, default_float_step, true);
-					prop = editor;
-
-				} break;
-				case Variant::VECTOR3I: {
-					EditorPropertyVector3i *editor = memnew(EditorPropertyVector3i);
-					editor->setup(-100000, 100000);
-					prop = editor;
-
-				} break;
-				case Variant::VECTOR4: {
-					EditorPropertyVector4 *editor = memnew(EditorPropertyVector4);
-					editor->setup(-100000, 100000, default_float_step, true);
-					prop = editor;
-
-				} break;
-				case Variant::VECTOR4I: {
-					EditorPropertyVector4i *editor = memnew(EditorPropertyVector4i);
-					editor->setup(-100000, 100000);
-					prop = editor;
-
-				} break;
-				case Variant::TRANSFORM2D: {
-					EditorPropertyTransform2D *editor = memnew(EditorPropertyTransform2D);
-					editor->setup(-100000, 100000, default_float_step, true);
-					prop = editor;
-
-				} break;
-				case Variant::PLANE: {
-					EditorPropertyPlane *editor = memnew(EditorPropertyPlane);
-					editor->setup(-100000, 100000, default_float_step, true);
-					prop = editor;
-
-				} break;
-				case Variant::QUATERNION: {
-					EditorPropertyQuaternion *editor = memnew(EditorPropertyQuaternion);
-					editor->setup(-100000, 100000, default_float_step, true);
-					prop = editor;
-
-				} break;
-				case Variant::AABB: {
-					EditorPropertyAABB *editor = memnew(EditorPropertyAABB);
-					editor->setup(-100000, 100000, default_float_step, true);
-					prop = editor;
-
-				} break;
-				case Variant::BASIS: {
-					EditorPropertyBasis *editor = memnew(EditorPropertyBasis);
-					editor->setup(-100000, 100000, default_float_step, true);
-					prop = editor;
-
-				} break;
-				case Variant::TRANSFORM3D: {
-					EditorPropertyTransform3D *editor = memnew(EditorPropertyTransform3D);
-					editor->setup(-100000, 100000, default_float_step, true);
-					prop = editor;
-
-				} break;
-				case Variant::PROJECTION: {
-					EditorPropertyProjection *editor = memnew(EditorPropertyProjection);
-					editor->setup(-100000, 100000, default_float_step, true);
-					prop = editor;
-
-				} break;
-
-				// Miscellaneous types.
-				case Variant::COLOR: {
-					prop = memnew(EditorPropertyColor);
-
-				} break;
-				case Variant::STRING_NAME: {
-					EditorPropertyText *ept = memnew(EditorPropertyText);
-					ept->set_string_name(true);
-					prop = ept;
-
-				} break;
-				case Variant::NODE_PATH: {
-					prop = memnew(EditorPropertyNodePath);
-
-				} break;
-				case Variant::RID: {
-					prop = memnew(EditorPropertyRID);
-
-				} break;
-				case Variant::SIGNAL: {
-					prop = memnew(EditorPropertySignal);
-
-				} break;
-				case Variant::CALLABLE: {
-					prop = memnew(EditorPropertyCallable);
-
-				} break;
-				case Variant::OBJECT: {
-					if (Object::cast_to<EncodedObjectAsID>(value)) {
-						EditorPropertyObjectID *editor = memnew(EditorPropertyObjectID);
-						editor->setup("Object");
-						prop = editor;
-
-					} else {
-						EditorPropertyResource *editor = memnew(EditorPropertyResource);
-						editor->setup(object.ptr(), prop_name, "Resource");
-						editor->set_use_folding(is_using_folding());
-						prop = editor;
-					}
-
-				} break;
-				case Variant::DICTIONARY: {
-					prop = memnew(EditorPropertyDictionary);
-
-				} break;
-				case Variant::ARRAY: {
-					EditorPropertyArray *editor = memnew(EditorPropertyArray);
-					editor->setup(Variant::ARRAY);
-					prop = editor;
-				} break;
-
-				// Arrays.
-				case Variant::PACKED_BYTE_ARRAY: {
-					EditorPropertyArray *editor = memnew(EditorPropertyArray);
-					editor->setup(Variant::PACKED_BYTE_ARRAY);
-					prop = editor;
-				} break;
-				case Variant::PACKED_INT32_ARRAY: {
-					EditorPropertyArray *editor = memnew(EditorPropertyArray);
-					editor->setup(Variant::PACKED_INT32_ARRAY);
-					prop = editor;
-				} break;
-				case Variant::PACKED_FLOAT32_ARRAY: {
-					EditorPropertyArray *editor = memnew(EditorPropertyArray);
-					editor->setup(Variant::PACKED_FLOAT32_ARRAY);
-					prop = editor;
-				} break;
-				case Variant::PACKED_INT64_ARRAY: {
-					EditorPropertyArray *editor = memnew(EditorPropertyArray);
-					editor->setup(Variant::PACKED_INT64_ARRAY);
-					prop = editor;
-				} break;
-				case Variant::PACKED_FLOAT64_ARRAY: {
-					EditorPropertyArray *editor = memnew(EditorPropertyArray);
-					editor->setup(Variant::PACKED_FLOAT64_ARRAY);
-					prop = editor;
-				} break;
-				case Variant::PACKED_STRING_ARRAY: {
-					EditorPropertyArray *editor = memnew(EditorPropertyArray);
-					editor->setup(Variant::PACKED_STRING_ARRAY);
-					prop = editor;
-				} break;
-				case Variant::PACKED_VECTOR2_ARRAY: {
-					EditorPropertyArray *editor = memnew(EditorPropertyArray);
-					editor->setup(Variant::PACKED_VECTOR2_ARRAY);
-					prop = editor;
-				} break;
-				case Variant::PACKED_VECTOR3_ARRAY: {
-					EditorPropertyArray *editor = memnew(EditorPropertyArray);
-					editor->setup(Variant::PACKED_VECTOR3_ARRAY);
-					prop = editor;
-				} break;
-				case Variant::PACKED_COLOR_ARRAY: {
-					EditorPropertyArray *editor = memnew(EditorPropertyArray);
-					editor->setup(Variant::PACKED_COLOR_ARRAY);
-					prop = editor;
-				} break;
-				default: {
+			// Check if the editor property needs to be updated.
+			bool value_as_id = Object::cast_to<EncodedObjectAsID>(value);
+			if (value_type != slot.type || (value_type == Variant::OBJECT && value_as_id != slot.as_id)) {
+				slot.as_id = value_as_id;
+				slot.type = value_type;
+				EditorProperty *new_prop = nullptr;
+				if (value_type == Variant::OBJECT && value_as_id) {
+					EditorPropertyObjectID *editor = memnew(EditorPropertyObjectID);
+					editor->setup("Object");
+					new_prop = editor;
+				} else {
+					new_prop = EditorInspector::instantiate_property_editor(nullptr, value_type, "", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE);
 				}
+				new_prop->set_selectable(false);
+				new_prop->set_use_folding(is_using_folding());
+				new_prop->connect(SNAME("property_changed"), callable_mp(this, &EditorPropertyDictionary::_property_changed));
+				new_prop->connect(SNAME("object_id_selected"), callable_mp(this, &EditorPropertyDictionary::_object_id_selected));
+				new_prop->set_h_size_flags(SIZE_EXPAND_FILL);
+				new_prop->set_read_only(is_read_only());
+				slot.set_prop(new_prop);
 			}
-
-			ERR_FAIL_NULL(prop);
-
-			prop->set_read_only(is_read_only());
-
-			if (i == amount) {
-				PanelContainer *pc = memnew(PanelContainer);
-				property_vbox->add_child(pc);
-				pc->add_theme_style_override(SNAME("panel"), get_theme_stylebox(SNAME("DictionaryAddItem"), EditorStringName(EditorStyles)));
-
-				add_vbox = memnew(VBoxContainer);
-				pc->add_child(add_vbox);
-			}
-			prop->set_object_and_property(object.ptr(), prop_name);
-			int change_index = 0;
-
-			if (i < amount) {
-				String cs = key.get_construct_string();
-				prop->set_label(key.get_construct_string());
-				prop->set_tooltip_text(cs);
-				change_index = i + offset;
-			} else if (i == amount) {
-				prop->set_label(TTR("New Key:"));
-				change_index = -1;
-			} else if (i == amount + 1) {
-				prop->set_label(TTR("New Value:"));
-				change_index = -2;
-			}
-
-			prop->set_selectable(false);
-			prop->connect("property_changed", callable_mp(this, &EditorPropertyDictionary::_property_changed));
-			prop->connect("object_id_selected", callable_mp(this, &EditorPropertyDictionary::_object_id_selected));
-
-			HBoxContainer *hbox = memnew(HBoxContainer);
-			if (add_vbox) {
-				add_vbox->add_child(hbox);
-			} else {
-				property_vbox->add_child(hbox);
-			}
-			hbox->add_child(prop);
-			prop->set_h_size_flags(SIZE_EXPAND_FILL);
-			Button *edit_btn = memnew(Button);
-			edit_btn->set_icon(get_editor_theme_icon(SNAME("Edit")));
-			edit_btn->set_disabled(is_read_only());
-			hbox->add_child(edit_btn);
-			edit_btn->connect("pressed", callable_mp(this, &EditorPropertyDictionary::_change_type).bind(edit_btn, change_index));
-
-			prop->update_property();
-
-			if (i == amount + 1) {
-				button_add_item = EditorInspector::create_inspector_action_button(TTR("Add Key/Value Pair"));
-				button_add_item->set_icon(get_editor_theme_icon(SNAME("Add")));
-				button_add_item->set_disabled(is_read_only());
-				button_add_item->connect("pressed", callable_mp(this, &EditorPropertyDictionary::_add_key_value));
-				add_vbox->add_child(button_add_item);
-			}
+			slot.prop->update_property();
 		}
-
 		updating = false;
 
 	} else {
@@ -1210,6 +983,8 @@ void EditorPropertyDictionary::update_property() {
 			memdelete(container);
 			button_add_item = nullptr;
 			container = nullptr;
+			add_panel = nullptr;
+			slots.clear();
 		}
 	}
 }
@@ -1254,10 +1029,17 @@ void EditorPropertyDictionary::_edit_pressed() {
 }
 
 void EditorPropertyDictionary::_page_changed(int p_page) {
+	page_index = p_page;
+	int i = p_page * page_length;
+	for (Slot &slot : slots) {
+		if (slot.index > -1) {
+			slot.set_index(i);
+			i++;
+		}
+	}
 	if (updating) {
 		return;
 	}
-	page_index = p_page;
 	update_property();
 }
 

+ 41 - 2
editor/editor_properties_array_dict.h

@@ -66,6 +66,11 @@ protected:
 	bool _get(const StringName &p_name, Variant &r_ret) const;
 
 public:
+	enum {
+		NEW_KEY_INDEX = -2,
+		NEW_VALUE_INDEX,
+	};
+
 	void set_dict(const Dictionary &p_dict);
 	Dictionary get_dict();
 
@@ -75,6 +80,9 @@ public:
 	void set_new_item_value(const Variant &p_new_item);
 	Variant get_new_item_value();
 
+	String get_label_for_index(int p_index);
+	String get_property_name_for_index(int p_index);
+
 	EditorPropertyDictionaryObject();
 };
 
@@ -125,7 +133,7 @@ class EditorPropertyArray : public EditorProperty {
 	void _reorder_button_gui_input(const Ref<InputEvent> &p_event);
 	void _reorder_button_down(int p_index);
 	void _reorder_button_up();
-	void create_new_property_slot();
+	void _create_new_property_slot();
 
 protected:
 	Ref<EditorPropertyArrayObject> object;
@@ -160,6 +168,34 @@ public:
 class EditorPropertyDictionary : public EditorProperty {
 	GDCLASS(EditorPropertyDictionary, EditorProperty);
 
+	struct Slot {
+		Ref<EditorPropertyDictionaryObject> object;
+		HBoxContainer *container = nullptr;
+		int index = -1;
+		Variant::Type type = Variant::VARIANT_MAX;
+		bool as_id = false;
+		EditorProperty *prop = nullptr;
+		String prop_name;
+
+		void set_index(int p_idx) {
+			index = p_idx;
+			prop_name = object->get_property_name_for_index(p_idx);
+			update_prop_or_index();
+		}
+
+		void set_prop(EditorProperty *p_prop) {
+			prop->add_sibling(p_prop);
+			prop->queue_free();
+			prop = p_prop;
+			update_prop_or_index();
+		}
+
+		void update_prop_or_index() {
+			prop->set_object_and_property(object.ptr(), prop_name);
+			prop->set_label(object->get_label_for_index(index));
+		}
+	};
+
 	PopupMenu *change_type = nullptr;
 	bool updating = false;
 
@@ -170,15 +206,18 @@ class EditorPropertyDictionary : public EditorProperty {
 	Button *edit = nullptr;
 	MarginContainer *container = nullptr;
 	VBoxContainer *property_vbox = nullptr;
+	PanelContainer *add_panel = nullptr;
 	EditorSpinSlider *size_sliderv = nullptr;
 	Button *button_add_item = nullptr;
 	EditorPaginator *paginator = nullptr;
 	PropertyHint property_hint;
+	LocalVector<Slot> slots;
+	void _create_new_property_slot(int p_idx);
 
 	void _page_changed(int p_page);
 	void _edit_pressed();
 	void _property_changed(const String &p_property, Variant p_value, const String &p_name = "", bool p_changing = false);
-	void _change_type(Object *p_button, int p_index);
+	void _change_type(Object *p_button, int p_slot_index);
 	void _change_type_menu(int p_index);
 
 	void _add_key_value();