Repository: godotengine/godot
File: editor/inspector/editor_inspector.cpp (C++)

Code before:
		const EditorInspector *inspector = get_parent_inspector();
		if (inspector) {
			const String custom_description = inspector->get_custom_property_description(p_text);
			if (!custom_description.is_empty()) {
				if (!prologue.is_empty()) {
					prologue += '\n';
				}
				prologue += custom_description;
			}
		}
	}

	if (!symbol.is_empty() || !prologue.is_empty()) {
		return EditorHelpBitTooltip::show_tooltip(const_cast<EditorProperty *>(this), symbol, prologue);
	}

	return nullptr;
}

void EditorProperty::menu_option(int p_option) {
	switch (p_option) {
		case MENU_COPY_VALUE: {
			InspectorDock::get_inspector_singleton()->set_property_clipboard(object->get(property));
		} break;
		case MENU_PASTE_VALUE: {
			const Dictionary clipboard = InspectorDock::get_inspector_singleton()->get_property_clipboard();
			if (clipboard.has("@pastebin_category_name") || clipboard.has("@pastebin_section_name")) {
				break;
			}
			emit_changed(property, clipboard);
		} break;
		case MENU_COPY_PROPERTY_PATH: {
			DisplayServer::get_singleton()->clipboard_set(property_path);
		} break;
		case MENU_OVERRIDE_FOR_PROJECT: {
			emit_signal(SNAME("property_overridden"));
		} break;
		case MENU_FAVORITE_PROPERTY: {
			emit_signal(SNAME("property_favorited"), property, !favorited);
			queue_redraw();
		} break;
		case MENU_PIN_VALUE: {
			emit_signal(SNAME("property_pinned"), property, !pinned);
			queue_redraw();
		} break;
		case MENU_DELETE: {
			accept_event();
			emit_signal(SNAME("property_deleted"), property);
		} break;
		case MENU_REVERT_VALUE: {
			accept_event();

Review comment (suggestion):
Properties are copied as their actual value, not a Dictionary. You need to first check type of property clipboard.

Code after:
	object = p_object;
	property = p_property;

	_update_flags();
}

static bool _is_value_potential_override(Node *p_node, const String &p_property) {
	// Consider a value is potentially overriding another if either of the following is true:
	// a) The node is foreign (inheriting or an instance), so the original value may come from another scene.
	// b) The node belongs to the scene, but the original value comes from somewhere but the builtin class (i.e., a script).
	Node *edited_scene = EditorNode::get_singleton()->get_edited_scene();
	Vector<SceneState::PackState> states_stack = PropertyUtils::get_node_states_stack(p_node, edited_scene);
	if (states_stack.size()) {
		return true;
	} else {
		bool is_valid_default = false;
		bool is_class_default = false;
		PropertyUtils::get_property_default_value(p_node, p_property, &is_valid_default, &states_stack, false, nullptr, &is_class_default);
		return !is_class_default;
	}
}

void EditorProperty::_update_flags() {
	can_pin = false;
	pin_hidden = true;

	if (read_only) {
		return;
	}

	if (Node *node = Object::cast_to<Node>(object)) {
		// Avoid errors down the road by ignoring nodes which are not part of a scene
		if (!node->get_owner()) {
			bool is_scene_root = false;
			for (int i = 0; i < EditorNode::get_editor_data().get_edited_scene_count(); ++i) {
				if (EditorNode::get_editor_data().get_edited_scene_root(i) == node) {
					is_scene_root = true;
					break;
				}
			}
			if (!is_scene_root) {
				return;
			}
		}
		if (!_is_value_potential_override(node, property)) {
			return;
		}
		pin_hidden = false;
		{
			HashSet<StringName> storable_properties;
			node->get_storable_properties(storable_properties);