Browse Source

Merge pull request #51722 from TokageItLab/implement-set-read-only-in-extended-class

Apply `set_read_only()` to child classes of `EditorProperty` elements
Gilles Roudière 4 years ago
parent
commit
c6f6c05a52

+ 1 - 0
core/object/object.h

@@ -132,6 +132,7 @@ enum PropertyUsageFlags {
 	PROPERTY_USAGE_DEFERRED_SET_RESOURCE = 1 << 26, // when loading, the resource for this property can be set at the end of loading
 	PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT = 1 << 27, // For Object properties, instantiate them when creating in editor.
 	PROPERTY_USAGE_EDITOR_BASIC_SETTING = 1 << 28, //for project or editor settings, show when basic settings are selected
+	PROPERTY_USAGE_READ_ONLY = 1 << 29,
 
 	PROPERTY_USAGE_DEFAULT = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_NETWORK,
 	PROPERTY_USAGE_DEFAULT_INTL = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_NETWORK | PROPERTY_USAGE_INTERNATIONALIZED,

+ 10 - 5
editor/editor_inspector.cpp

@@ -246,9 +246,9 @@ void EditorProperty::_notification(int p_what) {
 
 		Color color;
 		if (draw_red) {
-			color = get_theme_color(SNAME("error_color"));
+			color = get_theme_color(is_read_only() ? SNAME("readonly_error_color") : SNAME("error_color"));
 		} else {
-			color = get_theme_color(SNAME("property_color"));
+			color = get_theme_color(is_read_only() ? SNAME("readonly_color") : SNAME("property_color"));
 		}
 		if (label.find(".") != -1) {
 			color.a = 0.5; //this should be un-hacked honestly, as it's used for editor overrides
@@ -283,7 +283,7 @@ void EditorProperty::_notification(int p_what) {
 			check_rect = Rect2();
 		}
 
-		if (can_revert) {
+		if (can_revert && !is_read_only()) {
 			Ref<Texture2D> reload_icon = get_theme_icon(SNAME("ReloadSmall"), SNAME("EditorIcons"));
 			text_limit -= reload_icon->get_width() + get_theme_constant(SNAME("hseparator"), SNAME("Tree")) * 2;
 			revert_rect = Rect2(text_limit + get_theme_constant(SNAME("hseparator"), SNAME("Tree")), (size.height - reload_icon->get_height()) / 2, reload_icon->get_width(), reload_icon->get_height());
@@ -384,8 +384,12 @@ void EditorProperty::update_property() {
 	GDVIRTUAL_CALL(_update_property);
 }
 
+void EditorProperty::_set_read_only(bool p_read_only) {
+}
+
 void EditorProperty::set_read_only(bool p_read_only) {
 	read_only = p_read_only;
+	_set_read_only(p_read_only);
 }
 
 bool EditorProperty::is_read_only() const {
@@ -1910,6 +1914,8 @@ void EditorInspector::update_tree() {
 			checked = p.usage & PROPERTY_USAGE_CHECKED;
 		}
 
+		bool property_read_only = (p.usage & PROPERTY_USAGE_READ_ONLY) || read_only;
+
 		if (p.usage & PROPERTY_USAGE_RESTART_IF_CHANGED) {
 			restart_request_props.insert(p.name);
 		}
@@ -2008,8 +2014,7 @@ void EditorInspector::update_tree() {
 					ep->set_checkable(checkable);
 					ep->set_checked(checked);
 					ep->set_keying(keying);
-
-					ep->set_read_only(read_only);
+					ep->set_read_only(property_read_only);
 					ep->set_deletable(deletable_properties);
 				}
 

+ 1 - 0
editor/editor_inspector.h

@@ -115,6 +115,7 @@ private:
 protected:
 	void _notification(int p_what);
 	static void _bind_methods();
+	virtual void _set_read_only(bool p_read_only);
 
 	virtual void gui_input(const Ref<InputEvent> &p_event) override;
 	virtual void unhandled_key_input(const Ref<InputEvent> &p_event) override;

+ 164 - 5
editor/editor_properties.cpp

@@ -51,6 +51,10 @@ EditorPropertyNil::EditorPropertyNil() {
 
 ///////////////////// TEXT /////////////////////////
 
+void EditorPropertyText::_set_read_only(bool p_read_only) {
+	text->set_editable(!p_read_only);
+};
+
 void EditorPropertyText::_text_submitted(const String &p_string) {
 	if (updating) {
 		return;
@@ -108,6 +112,11 @@ EditorPropertyText::EditorPropertyText() {
 
 ///////////////////// MULTILINE TEXT /////////////////////////
 
+void EditorPropertyMultilineText::_set_read_only(bool p_read_only) {
+	text->set_editable(!p_read_only);
+	open_big_text->set_disabled(p_read_only);
+};
+
 void EditorPropertyMultilineText::_big_text_changed() {
 	text->set_text(big_text->get_text());
 	emit_changed(get_edited_property(), big_text->get_text(), "", true);
@@ -180,6 +189,11 @@ EditorPropertyMultilineText::EditorPropertyMultilineText() {
 
 ///////////////////// TEXT ENUM /////////////////////////
 
+void EditorPropertyTextEnum::_set_read_only(bool p_read_only) {
+	option_button->set_disabled(p_read_only);
+	edit_button->set_disabled(p_read_only);
+};
+
 void EditorPropertyTextEnum::_emit_changed_value(String p_string) {
 	if (string_name) {
 		emit_changed(get_edited_property(), StringName(p_string));
@@ -328,6 +342,11 @@ EditorPropertyTextEnum::EditorPropertyTextEnum() {
 
 ///////////////////// PATH /////////////////////////
 
+void EditorPropertyPath::_set_read_only(bool p_read_only) {
+	path->set_editable(!p_read_only);
+	path_edit->set_disabled(p_read_only);
+};
+
 void EditorPropertyPath::_path_selected(const String &p_path) {
 	emit_changed(get_edited_property(), p_path);
 	update_property();
@@ -420,6 +439,10 @@ EditorPropertyPath::EditorPropertyPath() {
 
 ///////////////////// CLASS NAME /////////////////////////
 
+void EditorPropertyClassName::_set_read_only(bool p_read_only) {
+	property->set_disabled(p_read_only);
+};
+
 void EditorPropertyClassName::setup(const String &p_base_type, const String &p_selected_type) {
 	base_type = p_base_type;
 	dialog->set_base_type(base_type);
@@ -461,6 +484,10 @@ EditorPropertyClassName::EditorPropertyClassName() {
 
 ///////////////////// MEMBER /////////////////////////
 
+void EditorPropertyMember::_set_read_only(bool p_read_only) {
+	property->set_disabled(p_read_only);
+};
+
 void EditorPropertyMember::_property_selected(const String &p_selected) {
 	emit_changed(get_edited_property(), p_selected);
 	update_property();
@@ -557,6 +584,11 @@ EditorPropertyMember::EditorPropertyMember() {
 }
 
 ///////////////////// CHECK /////////////////////////
+
+void EditorPropertyCheck::_set_read_only(bool p_read_only) {
+	checkbox->set_disabled(p_read_only);
+};
+
 void EditorPropertyCheck::_checkbox_pressed() {
 	emit_changed(get_edited_property(), checkbox->is_pressed());
 }
@@ -580,6 +612,10 @@ EditorPropertyCheck::EditorPropertyCheck() {
 
 ///////////////////// ENUM /////////////////////////
 
+void EditorPropertyEnum::_set_read_only(bool p_read_only) {
+	options->set_disabled(p_read_only);
+};
+
 void EditorPropertyEnum::_option_selected(int p_which) {
 	int64_t val = options->get_item_metadata(p_which);
 	emit_changed(get_edited_property(), val);
@@ -628,6 +664,12 @@ EditorPropertyEnum::EditorPropertyEnum() {
 
 ///////////////////// FLAGS /////////////////////////
 
+void EditorPropertyFlags::_set_read_only(bool p_read_only) {
+	for (CheckBox *check : flags) {
+		check->set_disabled(p_read_only);
+	}
+};
+
 void EditorPropertyFlags::_flag_toggled() {
 	uint32_t value = 0;
 	for (int i = 0; i < flags.size(); i++) {
@@ -698,6 +740,7 @@ private:
 	bool expanded = false;
 	int expansion_rows = 0;
 	int hovered_index = -1;
+	bool read_only = false;
 
 	Size2 get_grid_size() const {
 		Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Label"));
@@ -712,6 +755,10 @@ public:
 	Vector<String> names;
 	Vector<String> tooltips;
 
+	void set_read_only(bool p_read_only) {
+		read_only = p_read_only;
+	}
+
 	virtual Size2 get_minimum_size() const override {
 		Size2 min_size = get_grid_size();
 
@@ -736,6 +783,9 @@ public:
 	}
 
 	void gui_input(const Ref<InputEvent> &p_ev) override {
+		if (read_only) {
+			return;
+		}
 		const Ref<InputEventMouseMotion> mm = p_ev;
 		if (mm.is_valid()) {
 			bool expand_was_hovered = expand_hovered;
@@ -799,12 +849,12 @@ public:
 				const int bsize = (grid_size.height * 80 / 100) / 2;
 				const int h = bsize * 2 + 1;
 
-				Color color = get_theme_color(SNAME("highlight_color"), SNAME("Editor"));
+				Color color = get_theme_color(read_only ? SNAME("disabled_highlight_color") : SNAME("highlight_color"), SNAME("Editor"));
 
-				Color text_color = get_theme_color(SNAME("font_color"), SNAME("Editor"));
+				Color text_color = get_theme_color(read_only ? SNAME("disabled_font_color") : SNAME("font_color"), SNAME("Editor"));
 				text_color.a *= 0.5;
 
-				Color text_color_on = get_theme_color(SNAME("font_hover_color"), SNAME("Editor"));
+				Color text_color_on = get_theme_color(read_only ? SNAME("disabled_font_color") : SNAME("font_hover_color"), SNAME("Editor"));
 				text_color_on.a *= 0.7;
 
 				const int vofs = (grid_size.height - h) / 2;
@@ -935,6 +985,11 @@ public:
 	}
 };
 
+void EditorPropertyLayers::_set_read_only(bool p_read_only) {
+	button->set_disabled(p_read_only);
+	grid->set_read_only(p_read_only);
+};
+
 void EditorPropertyLayers::_grid_changed(uint32_t p_grid) {
 	emit_changed(get_edited_property(), p_grid);
 }
@@ -1071,6 +1126,10 @@ EditorPropertyLayers::EditorPropertyLayers() {
 
 ///////////////////// INT /////////////////////////
 
+void EditorPropertyInteger::_set_read_only(bool p_read_only) {
+	spin->set_read_only(p_read_only);
+};
+
 void EditorPropertyInteger::_value_changed(int64_t val) {
 	if (setting) {
 		return;
@@ -1113,6 +1172,10 @@ EditorPropertyInteger::EditorPropertyInteger() {
 
 ///////////////////// OBJECT ID /////////////////////////
 
+void EditorPropertyObjectID::_set_read_only(bool p_read_only) {
+	edit->set_disabled(p_read_only);
+};
+
 void EditorPropertyObjectID::_edit_pressed() {
 	emit_signal(SNAME("object_id_selected"), get_edited_property(), get_edited_object()->get(get_edited_property()));
 }
@@ -1151,6 +1214,10 @@ EditorPropertyObjectID::EditorPropertyObjectID() {
 
 ///////////////////// FLOAT /////////////////////////
 
+void EditorPropertyFloat::_set_read_only(bool p_read_only) {
+	spin->set_read_only(p_read_only);
+};
+
 void EditorPropertyFloat::_value_changed(double val) {
 	if (setting) {
 		return;
@@ -1197,7 +1264,14 @@ EditorPropertyFloat::EditorPropertyFloat() {
 
 ///////////////////// EASING /////////////////////////
 
+void EditorPropertyEasing::_set_read_only(bool p_read_only) {
+	spin->set_read_only(p_read_only);
+};
+
 void EditorPropertyEasing::_drag_easing(const Ref<InputEvent> &p_ev) {
+	if (is_read_only()) {
+		return;
+	}
 	const Ref<InputEventMouseButton> mb = p_ev;
 	if (mb.is_valid()) {
 		if (mb->is_double_click() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
@@ -1271,12 +1345,12 @@ void EditorPropertyEasing::_draw_easing() {
 
 	const Ref<Font> f = get_theme_font(SNAME("font"), SNAME("Label"));
 	int font_size = get_theme_font_size(SNAME("font_size"), SNAME("Label"));
-	const Color font_color = get_theme_color(SNAME("font_color"), SNAME("Label"));
+	const Color font_color = get_theme_color(is_read_only() ? SNAME("font_uneditable_color") : SNAME("font_color"), SNAME("LineEdit"));
 	Color line_color;
 	if (dragging) {
 		line_color = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
 	} else {
-		line_color = get_theme_color(SNAME("font_color"), SNAME("Label")) * Color(1, 1, 1, 0.9);
+		line_color = get_theme_color(is_read_only() ? SNAME("font_uneditable_color") : SNAME("font_color"), SNAME("LineEdit")) * Color(1, 1, 1, 0.9);
 	}
 
 	Vector<Point2> points;
@@ -1409,6 +1483,12 @@ EditorPropertyEasing::EditorPropertyEasing() {
 
 ///////////////////// VECTOR2 /////////////////////////
 
+void EditorPropertyVector2::_set_read_only(bool p_read_only) {
+	for (int i = 0; i < 2; i++) {
+		spin[i]->set_read_only(p_read_only);
+	}
+};
+
 void EditorPropertyVector2::_value_changed(double val, const String &p_name) {
 	if (setting) {
 		return;
@@ -1492,6 +1572,12 @@ EditorPropertyVector2::EditorPropertyVector2(bool p_force_wide) {
 
 ///////////////////// RECT2 /////////////////////////
 
+void EditorPropertyRect2::_set_read_only(bool p_read_only) {
+	for (int i = 0; i < 4; i++) {
+		spin[i]->set_read_only(p_read_only);
+	}
+};
+
 void EditorPropertyRect2::_value_changed(double val, const String &p_name) {
 	if (setting) {
 		return;
@@ -1589,6 +1675,12 @@ EditorPropertyRect2::EditorPropertyRect2(bool p_force_wide) {
 
 ///////////////////// VECTOR3 /////////////////////////
 
+void EditorPropertyVector3::_set_read_only(bool p_read_only) {
+	for (int i = 0; i < 3; i++) {
+		spin[i]->set_read_only(p_read_only);
+	}
+};
+
 void EditorPropertyVector3::_value_changed(double val, const String &p_name) {
 	if (setting) {
 		return;
@@ -1701,6 +1793,12 @@ EditorPropertyVector3::EditorPropertyVector3(bool p_force_wide) {
 
 ///////////////////// VECTOR2i /////////////////////////
 
+void EditorPropertyVector2i::_set_read_only(bool p_read_only) {
+	for (int i = 0; i < 2; i++) {
+		spin[i]->set_read_only(p_read_only);
+	}
+};
+
 void EditorPropertyVector2i::_value_changed(double val, const String &p_name) {
 	if (setting) {
 		return;
@@ -1784,6 +1882,12 @@ EditorPropertyVector2i::EditorPropertyVector2i(bool p_force_wide) {
 
 ///////////////////// RECT2i /////////////////////////
 
+void EditorPropertyRect2i::_set_read_only(bool p_read_only) {
+	for (int i = 0; i < 4; i++) {
+		spin[i]->set_read_only(p_read_only);
+	}
+};
+
 void EditorPropertyRect2i::_value_changed(double val, const String &p_name) {
 	if (setting) {
 		return;
@@ -1881,6 +1985,12 @@ EditorPropertyRect2i::EditorPropertyRect2i(bool p_force_wide) {
 
 ///////////////////// VECTOR3i /////////////////////////
 
+void EditorPropertyVector3i::_set_read_only(bool p_read_only) {
+	for (int i = 0; i < 3; i++) {
+		spin[i]->set_read_only(p_read_only);
+	}
+};
+
 void EditorPropertyVector3i::_value_changed(double val, const String &p_name) {
 	if (setting) {
 		return;
@@ -1965,6 +2075,12 @@ EditorPropertyVector3i::EditorPropertyVector3i(bool p_force_wide) {
 
 ///////////////////// PLANE /////////////////////////
 
+void EditorPropertyPlane::_set_read_only(bool p_read_only) {
+	for (int i = 0; i < 4; i++) {
+		spin[i]->set_read_only(p_read_only);
+	}
+};
+
 void EditorPropertyPlane::_value_changed(double val, const String &p_name) {
 	if (setting) {
 		return;
@@ -2052,6 +2168,12 @@ EditorPropertyPlane::EditorPropertyPlane(bool p_force_wide) {
 
 ///////////////////// QUATERNION /////////////////////////
 
+void EditorPropertyQuaternion::_set_read_only(bool p_read_only) {
+	for (int i = 0; i < 4; i++) {
+		spin[i]->set_read_only(p_read_only);
+	}
+};
+
 void EditorPropertyQuaternion::_value_changed(double val, const String &p_name) {
 	if (setting) {
 		return;
@@ -2136,6 +2258,12 @@ EditorPropertyQuaternion::EditorPropertyQuaternion() {
 
 ///////////////////// AABB /////////////////////////
 
+void EditorPropertyAABB::_set_read_only(bool p_read_only) {
+	for (int i = 0; i < 6; i++) {
+		spin[i]->set_read_only(p_read_only);
+	}
+};
+
 void EditorPropertyAABB::_value_changed(double val, const String &p_name) {
 	if (setting) {
 		return;
@@ -2213,6 +2341,12 @@ EditorPropertyAABB::EditorPropertyAABB() {
 
 ///////////////////// TRANSFORM2D /////////////////////////
 
+void EditorPropertyTransform2D::_set_read_only(bool p_read_only) {
+	for (int i = 0; i < 6; i++) {
+		spin[i]->set_read_only(p_read_only);
+	}
+};
+
 void EditorPropertyTransform2D::_value_changed(double val, const String &p_name) {
 	if (setting) {
 		return;
@@ -2289,6 +2423,12 @@ EditorPropertyTransform2D::EditorPropertyTransform2D() {
 
 ///////////////////// BASIS /////////////////////////
 
+void EditorPropertyBasis::_set_read_only(bool p_read_only) {
+	for (int i = 0; i < 9; i++) {
+		spin[i]->set_read_only(p_read_only);
+	}
+};
+
 void EditorPropertyBasis::_value_changed(double val, const String &p_name) {
 	if (setting) {
 		return;
@@ -2371,6 +2511,12 @@ EditorPropertyBasis::EditorPropertyBasis() {
 
 ///////////////////// TRANSFORM /////////////////////////
 
+void EditorPropertyTransform3D::_set_read_only(bool p_read_only) {
+	for (int i = 0; i < 12; i++) {
+		spin[i]->set_read_only(p_read_only);
+	}
+};
+
 void EditorPropertyTransform3D::_value_changed(double val, const String &p_name) {
 	if (setting) {
 		return;
@@ -2461,6 +2607,10 @@ EditorPropertyTransform3D::EditorPropertyTransform3D() {
 
 ////////////// COLOR PICKER //////////////////////
 
+void EditorPropertyColor::_set_read_only(bool p_read_only) {
+	picker->set_disabled(p_read_only);
+};
+
 void EditorPropertyColor::_color_changed(const Color &p_color) {
 	// Cancel the color change if the current color is identical to the new one.
 	if (get_edited_object()->get(get_edited_property()) == p_color) {
@@ -2533,6 +2683,11 @@ EditorPropertyColor::EditorPropertyColor() {
 
 ////////////// NODE PATH //////////////////////
 
+void EditorPropertyNodePath::_set_read_only(bool p_read_only) {
+	assign->set_disabled(p_read_only);
+	clear->set_disabled(p_read_only);
+};
+
 void EditorPropertyNodePath::_node_selected(const NodePath &p_path) {
 	NodePath path = p_path;
 	Node *base_node = nullptr;
@@ -2678,6 +2833,10 @@ EditorPropertyRID::EditorPropertyRID() {
 
 ////////////// RESOURCE //////////////////////
 
+void EditorPropertyResource::_set_read_only(bool p_read_only) {
+	resource_picker->set_editable(!p_read_only);
+};
+
 void EditorPropertyResource::_resource_selected(const RES &p_resource) {
 	if (use_sub_inspector) {
 		bool unfold = !get_edited_object()->editor_is_section_unfolded(get_edited_property());

+ 29 - 1
editor/editor_properties.h

@@ -59,6 +59,7 @@ class EditorPropertyText : public EditorProperty {
 	void _text_submitted(const String &p_string);
 
 protected:
+	virtual void _set_read_only(bool p_read_only) override;
 	static void _bind_methods();
 
 public:
@@ -81,6 +82,7 @@ class EditorPropertyMultilineText : public EditorProperty {
 	void _open_big_text();
 
 protected:
+	virtual void _set_read_only(bool p_read_only) override;
 	void _notification(int p_what);
 	static void _bind_methods();
 
@@ -115,6 +117,7 @@ class EditorPropertyTextEnum : public EditorProperty {
 	void _custom_value_cancelled();
 
 protected:
+	virtual void _set_read_only(bool p_read_only) override;
 	static void _bind_methods();
 	void _notification(int p_what);
 
@@ -139,6 +142,7 @@ class EditorPropertyPath : public EditorProperty {
 	void _path_focus_exited();
 
 protected:
+	virtual void _set_read_only(bool p_read_only) override;
 	static void _bind_methods();
 	void _notification(int p_what);
 
@@ -161,6 +165,7 @@ private:
 	void _dialog_created();
 
 protected:
+	virtual void _set_read_only(bool p_read_only) override;
 	static void _bind_methods();
 
 public:
@@ -182,7 +187,6 @@ public:
 		MEMBER_PROPERTY_OF_BASE_TYPE, ///< a property of a base type
 		MEMBER_PROPERTY_OF_INSTANCE, ///< a property of an instance
 		MEMBER_PROPERTY_OF_SCRIPT, ///< a property of a script & base
-
 	};
 
 private:
@@ -195,6 +199,7 @@ private:
 	void _property_select();
 
 protected:
+	virtual void _set_read_only(bool p_read_only) override;
 	static void _bind_methods();
 
 public:
@@ -210,6 +215,7 @@ class EditorPropertyCheck : public EditorProperty {
 	void _checkbox_pressed();
 
 protected:
+	virtual void _set_read_only(bool p_read_only) override;
 	static void _bind_methods();
 
 public:
@@ -224,6 +230,7 @@ class EditorPropertyEnum : public EditorProperty {
 	void _option_selected(int p_which);
 
 protected:
+	virtual void _set_read_only(bool p_read_only) override;
 	static void _bind_methods();
 
 public:
@@ -242,6 +249,7 @@ class EditorPropertyFlags : public EditorProperty {
 	void _flag_toggled();
 
 protected:
+	virtual void _set_read_only(bool p_read_only) override;
 	static void _bind_methods();
 
 public:
@@ -276,6 +284,7 @@ private:
 	void _menu_pressed(int p_menu);
 
 protected:
+	virtual void _set_read_only(bool p_read_only) override;
 	static void _bind_methods();
 
 public:
@@ -291,6 +300,7 @@ class EditorPropertyInteger : public EditorProperty {
 	void _value_changed(int64_t p_val);
 
 protected:
+	virtual void _set_read_only(bool p_read_only) override;
 	static void _bind_methods();
 
 public:
@@ -306,6 +316,7 @@ class EditorPropertyObjectID : public EditorProperty {
 	void _edit_pressed();
 
 protected:
+	virtual void _set_read_only(bool p_read_only) override;
 	static void _bind_methods();
 
 public:
@@ -322,6 +333,7 @@ class EditorPropertyFloat : public EditorProperty {
 	void _value_changed(double p_val);
 
 protected:
+	virtual void _set_read_only(bool p_read_only) override;
 	static void _bind_methods();
 
 public:
@@ -363,6 +375,7 @@ class EditorPropertyEasing : public EditorProperty {
 	void _notification(int p_what);
 
 protected:
+	virtual void _set_read_only(bool p_read_only) override;
 	static void _bind_methods();
 
 public:
@@ -378,6 +391,7 @@ class EditorPropertyVector2 : public EditorProperty {
 	void _value_changed(double p_val, const String &p_name);
 
 protected:
+	virtual void _set_read_only(bool p_read_only) override;
 	void _notification(int p_what);
 	static void _bind_methods();
 
@@ -394,6 +408,7 @@ class EditorPropertyRect2 : public EditorProperty {
 	void _value_changed(double p_val, const String &p_name);
 
 protected:
+	virtual void _set_read_only(bool p_read_only) override;
 	void _notification(int p_what);
 	static void _bind_methods();
 
@@ -411,6 +426,7 @@ class EditorPropertyVector3 : public EditorProperty {
 	void _value_changed(double p_val, const String &p_name);
 
 protected:
+	virtual void _set_read_only(bool p_read_only) override;
 	void _notification(int p_what);
 	static void _bind_methods();
 
@@ -429,6 +445,7 @@ class EditorPropertyVector2i : public EditorProperty {
 	void _value_changed(double p_val, const String &p_name);
 
 protected:
+	virtual void _set_read_only(bool p_read_only) override;
 	void _notification(int p_what);
 	static void _bind_methods();
 
@@ -445,6 +462,7 @@ class EditorPropertyRect2i : public EditorProperty {
 	void _value_changed(double p_val, const String &p_name);
 
 protected:
+	virtual void _set_read_only(bool p_read_only) override;
 	void _notification(int p_what);
 	static void _bind_methods();
 
@@ -461,6 +479,7 @@ class EditorPropertyVector3i : public EditorProperty {
 	void _value_changed(double p_val, const String &p_name);
 
 protected:
+	virtual void _set_read_only(bool p_read_only) override;
 	void _notification(int p_what);
 	static void _bind_methods();
 
@@ -477,6 +496,7 @@ class EditorPropertyPlane : public EditorProperty {
 	void _value_changed(double p_val, const String &p_name);
 
 protected:
+	virtual void _set_read_only(bool p_read_only) override;
 	void _notification(int p_what);
 	static void _bind_methods();
 
@@ -493,6 +513,7 @@ class EditorPropertyQuaternion : public EditorProperty {
 	void _value_changed(double p_val, const String &p_name);
 
 protected:
+	virtual void _set_read_only(bool p_read_only) override;
 	void _notification(int p_what);
 	static void _bind_methods();
 
@@ -509,6 +530,7 @@ class EditorPropertyAABB : public EditorProperty {
 	void _value_changed(double p_val, const String &p_name);
 
 protected:
+	virtual void _set_read_only(bool p_read_only) override;
 	void _notification(int p_what);
 	static void _bind_methods();
 
@@ -525,6 +547,7 @@ class EditorPropertyTransform2D : public EditorProperty {
 	void _value_changed(double p_val, const String &p_name);
 
 protected:
+	virtual void _set_read_only(bool p_read_only) override;
 	void _notification(int p_what);
 	static void _bind_methods();
 
@@ -541,6 +564,7 @@ class EditorPropertyBasis : public EditorProperty {
 	void _value_changed(double p_val, const String &p_name);
 
 protected:
+	virtual void _set_read_only(bool p_read_only) override;
 	void _notification(int p_what);
 	static void _bind_methods();
 
@@ -557,6 +581,7 @@ class EditorPropertyTransform3D : public EditorProperty {
 	void _value_changed(double p_val, const String &p_name);
 
 protected:
+	virtual void _set_read_only(bool p_read_only) override;
 	void _notification(int p_what);
 	static void _bind_methods();
 
@@ -578,6 +603,7 @@ class EditorPropertyColor : public EditorProperty {
 	Color last_color;
 
 protected:
+	virtual void _set_read_only(bool p_read_only) override;
 	static void _bind_methods();
 
 public:
@@ -600,6 +626,7 @@ class EditorPropertyNodePath : public EditorProperty {
 	void _node_clear();
 
 protected:
+	virtual void _set_read_only(bool p_read_only) override;
 	static void _bind_methods();
 	void _notification(int p_what);
 
@@ -644,6 +671,7 @@ class EditorPropertyResource : public EditorProperty {
 	void _update_property_bg();
 
 protected:
+	virtual void _set_read_only(bool p_read_only) override;
 	static void _bind_methods();
 	void _notification(int p_what);
 

+ 4 - 4
editor/editor_spin_slider.cpp

@@ -221,7 +221,7 @@ void EditorSpinSlider::_draw_spin_slider() {
 	bool rtl = is_layout_rtl();
 	Vector2 size = get_size();
 
-	Ref<StyleBox> sb = get_theme_stylebox(SNAME("normal"), SNAME("LineEdit"));
+	Ref<StyleBox> sb = get_theme_stylebox(is_read_only() ? SNAME("read_only") : SNAME("normal"), SNAME("LineEdit"));
 	if (!flat) {
 		draw_style_box(sb, Rect2(Vector2(), size));
 	}
@@ -233,7 +233,7 @@ void EditorSpinSlider::_draw_spin_slider() {
 	int label_width = font->get_string_size(label, font_size).width;
 	int number_width = size.width - sb->get_minimum_size().width - label_width - sep;
 
-	Ref<Texture2D> updown = get_theme_icon(SNAME("updown"), SNAME("SpinBox"));
+	Ref<Texture2D> updown = get_theme_icon(is_read_only() ? SNAME("updown_disabled") : SNAME("updown"), SNAME("SpinBox"));
 
 	if (get_step() == 1) {
 		number_width -= updown->get_width();
@@ -243,7 +243,7 @@ void EditorSpinSlider::_draw_spin_slider() {
 
 	int vofs = (size.height - font->get_height(font_size)) / 2 + font->get_ascent(font_size);
 
-	Color fc = get_theme_color(SNAME("font_color"), SNAME("LineEdit"));
+	Color fc = get_theme_color(is_read_only() ? SNAME("font_uneditable_color") : SNAME("font_color"), SNAME("LineEdit"));
 	Color lc;
 	if (use_custom_label_color) {
 		lc = custom_label_color;
@@ -299,7 +299,7 @@ void EditorSpinSlider::_draw_spin_slider() {
 	TS->free(num_rid);
 
 	if (get_step() == 1) {
-		Ref<Texture2D> updown2 = get_theme_icon(SNAME("updown"), SNAME("SpinBox"));
+		Ref<Texture2D> updown2 = get_theme_icon(is_read_only() ? SNAME("updown_disabled") : SNAME("updown"), SNAME("SpinBox"));
 		int updown_vofs = (size.height - updown2->get_height()) / 2;
 		if (rtl) {
 			updown_offset = sb->get_margin(SIDE_LEFT);

+ 18 - 1
editor/editor_themes.cpp

@@ -395,12 +395,14 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
 
 	const Color separator_color = Color(mono_color.r, mono_color.g, mono_color.b, 0.1);
 	const Color highlight_color = Color(accent_color.r, accent_color.g, accent_color.b, 0.275);
+	const Color disabled_highlight_color = highlight_color.lerp(dark_theme ? Color(0, 0, 0) : Color(1, 1, 1), 0.5);
 
 	float prev_icon_saturation = theme->has_color("icon_saturation", "Editor") ? theme->get_color("icon_saturation", "Editor").r : 1.0;
 
 	theme->set_color("icon_saturation", "Editor", Color(icon_saturation, icon_saturation, icon_saturation)); //can't save single float in theme, so using color
 	theme->set_color("accent_color", "Editor", accent_color);
 	theme->set_color("highlight_color", "Editor", highlight_color);
+	theme->set_color("disabled_highlight_color", "Editor", disabled_highlight_color);
 	theme->set_color("base_color", "Editor", base_color);
 	theme->set_color("dark_color_1", "Editor", dark_color_1);
 	theme->set_color("dark_color_2", "Editor", dark_color_2);
@@ -424,6 +426,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
 	Color warning_color = Color(1, 0.87, 0.4);
 	Color error_color = Color(1, 0.47, 0.42);
 	Color property_color = font_color.lerp(Color(0.5, 0.5, 0.5), 0.5);
+	Color readonly_color = property_color.lerp(dark_theme ? Color(0, 0, 0) : Color(1, 1, 1), 0.5);
+	Color readonly_error_color = error_color.lerp(dark_theme ? Color(0, 0, 0) : Color(1, 1, 1), 0.5);
 
 	if (!dark_theme) {
 		// Darken some colors to be readable on a light background
@@ -436,6 +440,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
 	theme->set_color("warning_color", "Editor", warning_color);
 	theme->set_color("error_color", "Editor", error_color);
 	theme->set_color("property_color", "Editor", property_color);
+	theme->set_color("readonly_color", "Editor", readonly_color);
+	theme->set_color("readonly_error_color", "EditorProperty", readonly_error_color);
 
 	if (!dark_theme) {
 		theme->set_color("vulkan_color", "Editor", Color::hex(0xad1128ff));
@@ -696,6 +702,10 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
 	theme->set_icon("unchecked", "CheckBox", theme->get_icon("GuiUnchecked", "EditorIcons"));
 	theme->set_icon("radio_checked", "CheckBox", theme->get_icon("GuiRadioChecked", "EditorIcons"));
 	theme->set_icon("radio_unchecked", "CheckBox", theme->get_icon("GuiRadioUnchecked", "EditorIcons"));
+	theme->set_icon("checked_disabled", "CheckBox", theme->get_icon("GuiCheckedDisabled", "EditorIcons"));
+	theme->set_icon("unchecked_disabled", "CheckBox", theme->get_icon("GuiUncheckedDisabled", "EditorIcons"));
+	theme->set_icon("radio_checked_disabled", "CheckBox", theme->get_icon("GuiRadioCheckedDisabled", "EditorIcons"));
+	theme->set_icon("radio_unchecked_disabled", "CheckBox", theme->get_icon("GuiRadioUncheckedDisabled", "EditorIcons"));
 
 	theme->set_color("font_color", "CheckBox", font_color);
 	theme->set_color("font_hover_color", "CheckBox", font_hover_color);
@@ -742,6 +752,10 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
 	theme->set_icon("unchecked", "PopupMenu", theme->get_icon("GuiUnchecked", "EditorIcons"));
 	theme->set_icon("radio_checked", "PopupMenu", theme->get_icon("GuiRadioChecked", "EditorIcons"));
 	theme->set_icon("radio_unchecked", "PopupMenu", theme->get_icon("GuiRadioUnchecked", "EditorIcons"));
+	theme->set_icon("checked_disabled", "PopupMenu", theme->get_icon("GuiCheckedDisabled", "EditorIcons"));
+	theme->set_icon("unchecked_disabled", "PopupMenu", theme->get_icon("GuiUncheckedDisabled", "EditorIcons"));
+	theme->set_icon("radio_checked_disabled", "PopupMenu", theme->get_icon("GuiRadioCheckedDisabled", "EditorIcons"));
+	theme->set_icon("radio_unchecked_disabled", "PopupMenu", theme->get_icon("GuiRadioUncheckedDisabled", "EditorIcons"));
 	theme->set_icon("submenu", "PopupMenu", theme->get_icon("ArrowRight", "EditorIcons"));
 	theme->set_icon("submenu_mirrored", "PopupMenu", theme->get_icon("ArrowLeft", "EditorIcons"));
 	theme->set_icon("visibility_hidden", "PopupMenu", theme->get_icon("GuiVisibilityHidden", "EditorIcons"));
@@ -803,6 +817,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
 	theme->set_constant("vseparation", "EditorProperty", (extra_spacing + default_margin_size) * EDSCALE);
 	theme->set_color("error_color", "EditorProperty", error_color);
 	theme->set_color("property_color", "EditorProperty", property_color);
+	theme->set_color("readonly_color", "EditorProperty", readonly_color);
+	theme->set_color("readonly_error_color", "EditorProperty", readonly_error_color);
 
 	Color inspector_section_color = font_color.lerp(Color(0.5, 0.5, 0.5), 0.35);
 	theme->set_color("font_color", "EditorInspectorSection", inspector_section_color);
@@ -1052,7 +1068,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
 	theme->set_icon("tab", "TextEdit", theme->get_icon("GuiTab", "EditorIcons"));
 	theme->set_icon("space", "TextEdit", theme->get_icon("GuiSpace", "EditorIcons"));
 	theme->set_color("font_color", "TextEdit", font_color);
-	theme->set_color("font_readonly_color", "LineEdit", font_readonly_color);
+	theme->set_color("font_readonly_color", "TextEdit", font_readonly_color);
 	theme->set_color("caret_color", "TextEdit", font_color);
 	theme->set_color("selection_color", "TextEdit", selection_color);
 	theme->set_constant("line_spacing", "TextEdit", 4 * EDSCALE);
@@ -1216,6 +1232,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
 
 	// SpinBox
 	theme->set_icon("updown", "SpinBox", theme->get_icon("GuiSpinboxUpdown", "EditorIcons"));
+	theme->set_icon("updown_disabled", "SpinBox", theme->get_icon("GuiSpinboxUpdownDisabled", "EditorIcons"));
 
 	// ProgressBar
 	theme->set_stylebox("bg", "ProgressBar", make_stylebox(theme->get_icon("GuiProgressBar", "EditorIcons"), 4, 4, 4, 4, 0, 0, 0, 0));

+ 1 - 0
editor/icons/GuiCheckedDisabled.svg

@@ -0,0 +1 @@
+<svg enable-background="new 0 0 16 16" height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3.333 1c-1.289 0-2.333 1.045-2.333 2.333v9.333c0 1.289 1.044 2.334 2.333 2.334h9.333c1.289 0 2.334-1.045 2.334-2.334v-9.333c0-1.289-1.045-2.333-2.334-2.333z" fill="#808080"/><path d="m11.501 3.734-5.612 5.612-1.704-1.681-1.5 1.5 3.204 3.181 7.111-7.113z" fill="#b3b3b3"/></svg>

+ 1 - 0
editor/icons/GuiRadioCheckedDisabled.svg

@@ -0,0 +1 @@
+<svg enable-background="new 0 0 16 16" height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m15 8c0 3.866-3.134 7-7 7s-7-3.134-7-7 3.134-7 7-7 7 3.134 7 7" fill="#808080"/><path d="m12 8c0 2.209-1.791 4-4 4s-4-1.791-4-4 1.791-4 4-4 4 1.791 4 4" fill="#b3b3b3"/></svg>

+ 1 - 0
editor/icons/GuiRadioUncheckedDisabled.svg

@@ -0,0 +1 @@
+<svg enable-background="new 0 0 16 16" height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m15 8c0 3.866-3.134 7-7 7s-7-3.134-7-7 3.134-7 7-7 7 3.134 7 7" fill="#808080" fill-opacity=".1882"/></svg>

+ 1 - 0
editor/icons/GuiSpinboxUpdownDisabled.svg

@@ -0,0 +1 @@
+<svg enable-background="new 0 0 16 16" height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7.984 1.002c-.259.004-.507.108-.691.291l-4 4c-.398.383-.41 1.016-.027 1.414s1.016.41 1.414.027l.027-.027 3.293-3.293 3.293 3.293c.383.398 1.016.41 1.414.027s.41-1.016.027-1.414c-.01-.009-.018-.018-.027-.027l-4-4c-.191-.19-.452-.296-.723-.291zm4.006 7.984c-.264.006-.514.117-.697.307l-3.293 3.293-3.293-3.293c-.188-.193-.447-.303-.717-.303-.552 0-1 .448-1 1 0 .271.109.529.303.717l4 4c.391.391 1.023.391 1.414 0l4-4c.398-.383.41-1.016.027-1.414-.193-.202-.463-.313-.744-.307z" fill="#b3b3b3" fill-opacity=".7843"/></svg>

+ 1 - 0
editor/icons/GuiUncheckedDisabled.svg

@@ -0,0 +1 @@
+<svg enable-background="new 0 0 16 16" height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3.333 1c-1.289 0-2.333 1.045-2.333 2.333v9.333c0 1.289 1.044 2.334 2.333 2.334h9.333c1.289 0 2.334-1.045 2.334-2.334v-9.333c0-1.289-1.045-2.333-2.334-2.333z" fill="#808080" fill-opacity=".1882"/></svg>

+ 16 - 2
scene/gui/check_box.cpp

@@ -34,11 +34,13 @@
 
 Size2 CheckBox::get_icon_size() const {
 	Ref<Texture2D> checked = Control::get_theme_icon(SNAME("checked"));
-	Ref<Texture2D> checked_disabled = Control::get_theme_icon(SNAME("checked_disabled"));
 	Ref<Texture2D> unchecked = Control::get_theme_icon(SNAME("unchecked"));
-	Ref<Texture2D> unchecked_disabled = Control::get_theme_icon(SNAME("unchecked_disabled"));
 	Ref<Texture2D> radio_checked = Control::get_theme_icon(SNAME("radio_checked"));
 	Ref<Texture2D> radio_unchecked = Control::get_theme_icon(SNAME("radio_unchecked"));
+	Ref<Texture2D> checked_disabled = Control::get_theme_icon(SNAME("checked_disabled"));
+	Ref<Texture2D> unchecked_disabled = Control::get_theme_icon(SNAME("unchecked_disabled"));
+	Ref<Texture2D> radio_checked_disabled = Control::get_theme_icon(SNAME("radio_checked_disabled"));
+	Ref<Texture2D> radio_unchecked_disabled = Control::get_theme_icon(SNAME("radio_unchecked_disabled"));
 
 	Size2 tex_size = Size2(0, 0);
 	if (!checked.is_null()) {
@@ -53,6 +55,18 @@ Size2 CheckBox::get_icon_size() const {
 	if (!radio_unchecked.is_null()) {
 		tex_size = Size2(MAX(tex_size.width, radio_unchecked->get_width()), MAX(tex_size.height, radio_unchecked->get_height()));
 	}
+	if (!checked_disabled.is_null()) {
+		tex_size = Size2(MAX(tex_size.width, checked_disabled->get_width()), MAX(tex_size.height, checked_disabled->get_height()));
+	}
+	if (!unchecked_disabled.is_null()) {
+		tex_size = Size2(MAX(tex_size.width, unchecked_disabled->get_width()), MAX(tex_size.height, unchecked_disabled->get_height()));
+	}
+	if (!radio_checked_disabled.is_null()) {
+		tex_size = Size2(MAX(tex_size.width, radio_checked_disabled->get_width()), MAX(tex_size.height, radio_checked_disabled->get_height()));
+	}
+	if (!radio_unchecked_disabled.is_null()) {
+		tex_size = Size2(MAX(tex_size.width, radio_unchecked_disabled->get_width()), MAX(tex_size.height, radio_unchecked_disabled->get_height()));
+	}
 	return tex_size;
 }
 

+ 1 - 1
scene/gui/line_edit.cpp

@@ -674,7 +674,7 @@ void LineEdit::_notification(int p_what) {
 			int y_ofs = style->get_offset().y + (y_area - text_height) / 2;
 
 			Color selection_color = get_theme_color(SNAME("selection_color"));
-			Color font_color = is_editable() ? get_theme_color(SNAME("font_color")) : get_theme_color(SNAME("font_uneditable_color"));
+			Color font_color = get_theme_color(is_editable() ? SNAME("font_color") : SNAME("font_uneditable_color"));
 			Color font_selected_color = get_theme_color(SNAME("font_selected_color"));
 			Color caret_color = get_theme_color(SNAME("caret_color"));