Quellcode durchsuchen

Merge pull request #63429 from RandomShaper/indicate_overridden

Rémi Verschelde vor 3 Jahren
Ursprung
Commit
6c5330154e

+ 7 - 0
doc/classes/EditorProperty.xml

@@ -101,6 +101,13 @@
 				Used by sub-inspectors. Emit it if what was selected was an Object ID.
 			</description>
 		</signal>
+		<signal name="property_can_revert_changed">
+			<argument index="0" name="property" type="StringName" />
+			<argument index="1" name="can_revert" type="bool" />
+			<description>
+				Emitted when the revertability (i.e., whether it has a non-default value and thus is displayed with a revert icon) of a property has changed.
+			</description>
+		</signal>
 		<signal name="property_changed">
 			<argument index="0" name="property" type="StringName" />
 			<argument index="1" name="value" type="Variant" />

+ 141 - 24
editor/editor_inspector.cpp

@@ -471,6 +471,9 @@ void EditorProperty::update_revert_and_pin_status() {
 	bool new_can_revert = EditorPropertyRevert::can_property_revert(object, property, &current) && !is_read_only();
 
 	if (new_can_revert != can_revert || new_pinned != pinned) {
+		if (new_can_revert != can_revert) {
+			emit_signal(SNAME("property_can_revert_changed"), property, new_can_revert);
+		}
 		can_revert = new_can_revert;
 		pinned = new_pinned;
 		update();
@@ -784,6 +787,9 @@ void EditorProperty::expand_all_folding() {
 void EditorProperty::collapse_all_folding() {
 }
 
+void EditorProperty::expand_revertable() {
+}
+
 void EditorProperty::set_selectable(bool p_selectable) {
 	selectable = p_selectable;
 }
@@ -966,6 +972,7 @@ void EditorProperty::_bind_methods() {
 	ADD_SIGNAL(MethodInfo("property_keyed_with_value", PropertyInfo(Variant::STRING_NAME, "property"), PropertyInfo(Variant::NIL, "value", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT)));
 	ADD_SIGNAL(MethodInfo("property_checked", PropertyInfo(Variant::STRING_NAME, "property"), PropertyInfo(Variant::BOOL, "checked")));
 	ADD_SIGNAL(MethodInfo("property_pinned", PropertyInfo(Variant::STRING_NAME, "property"), PropertyInfo(Variant::BOOL, "pinned")));
+	ADD_SIGNAL(MethodInfo("property_can_revert_changed", PropertyInfo(Variant::STRING_NAME, "property"), PropertyInfo(Variant::BOOL, "can_revert")));
 	ADD_SIGNAL(MethodInfo("resource_selected", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource")));
 	ADD_SIGNAL(MethodInfo("object_id_selected", PropertyInfo(Variant::STRING_NAME, "property"), PropertyInfo(Variant::INT, "id")));
 	ADD_SIGNAL(MethodInfo("selected", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "focusable_idx")));
@@ -1225,12 +1232,15 @@ void EditorInspectorSection::_notification(int p_what) {
 			// Get the section header font.
 			Ref<Font> font = get_theme_font(SNAME("bold"), SNAME("EditorFonts"));
 			int font_size = get_theme_font_size(SNAME("bold_size"), SNAME("EditorFonts"));
+			Color font_color = get_theme_color(SNAME("font_color"), SNAME("Editor"));
 
 			// Get the right direction arrow texture, if the section is foldable.
 			Ref<Texture2D> arrow;
+			bool folded = foldable;
 			if (foldable) {
 				if (object->editor_is_section_unfolded(section)) {
 					arrow = get_theme_icon(SNAME("arrow"), SNAME("Tree"));
+					folded = false;
 				} else {
 					if (is_layout_rtl()) {
 						arrow = get_theme_icon(SNAME("arrow_collapsed_mirrored"), SNAME("Tree"));
@@ -1274,28 +1284,71 @@ void EditorInspectorSection::_notification(int p_what) {
 			}
 			draw_rect(header_rect, c);
 
-			// Draw header title and folding arrow.
-			const int arrow_margin = 2;
-			const int arrow_width = arrow.is_valid() ? arrow->get_width() : 0;
-			Color color = get_theme_color(SNAME("font_color"));
-			float text_width = get_size().width - Math::round(arrow_width + arrow_margin * EDSCALE) - section_indent;
-			Point2 text_offset = Point2(0, font->get_ascent(font_size) + (header_height - font->get_height(font_size)) / 2);
-			HorizontalAlignment text_align = HORIZONTAL_ALIGNMENT_LEFT;
-			if (rtl) {
-				text_align = HORIZONTAL_ALIGNMENT_RIGHT;
-			} else {
-				text_offset.x = section_indent + Math::round(arrow_width + arrow_margin * EDSCALE);
-			}
-			draw_string(font, text_offset.floor(), label, text_align, text_width, font_size, color);
+			// Draw header title, folding arrow and coutn of revertable properties.
+			{
+				int separation = Math::round(2 * EDSCALE);
 
-			if (arrow.is_valid()) {
-				Point2 arrow_position = Point2(0, (header_height - arrow->get_height()) / 2);
+				int margin_start = section_indent + separation;
+				int margin_end = separation;
+
+				// - Arrow.
+				if (arrow.is_valid()) {
+					Point2 arrow_position;
+					if (rtl) {
+						arrow_position.x = get_size().width - (margin_start + arrow->get_width());
+					} else {
+						arrow_position.x = margin_start;
+					}
+					arrow_position.y = (header_height - arrow->get_height()) / 2;
+					draw_texture(arrow, arrow_position);
+					margin_start += arrow->get_width();
+				}
+
+				int available = get_size().width - (margin_start + margin_end);
+
+				// - Count of revertable properties.
+				String num_revertable_str;
+				int num_revertable_width = 0;
+				if (folded && revertable_properties.size()) {
+					int label_width = font->get_string_size(label, HORIZONTAL_ALIGNMENT_LEFT, available, font_size, TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_CONSTRAIN_ELLIPSIS).x;
+
+					Ref<Font> light_font = get_theme_font(SNAME("main"), SNAME("EditorFonts"));
+					int light_font_size = get_theme_font_size(SNAME("main_size"), SNAME("EditorFonts"));
+					Color light_font_color = get_theme_color(SNAME("disabled_font_color"), SNAME("Editor"));
+
+					// Can we fit the long version of the revertable count text?
+					if (revertable_properties.size() == 1) {
+						num_revertable_str = "(1 change)";
+					} else {
+						num_revertable_str = vformat("(%d changes)", revertable_properties.size());
+					}
+					num_revertable_width = light_font->get_string_size(num_revertable_str, HORIZONTAL_ALIGNMENT_LEFT, -1.0f, light_font_size, TextServer::JUSTIFICATION_NONE).x;
+					if (label_width + separation + num_revertable_width > available) {
+						// We'll have to use the short version.
+						num_revertable_str = vformat("(%d)", revertable_properties.size());
+						num_revertable_width = light_font->get_string_size(num_revertable_str, HORIZONTAL_ALIGNMENT_LEFT, -1.0f, light_font_size, TextServer::JUSTIFICATION_NONE).x;
+					}
+
+					Point2 text_offset = Point2(
+							margin_end,
+							light_font->get_ascent(light_font_size) + (header_height - light_font->get_height(light_font_size)) / 2);
+					if (!rtl) {
+						text_offset.x = get_size().width - (text_offset.x + num_revertable_width);
+					}
+					draw_string(light_font, text_offset, num_revertable_str, HORIZONTAL_ALIGNMENT_LEFT, -1.0f, light_font_size, light_font_color, TextServer::JUSTIFICATION_NONE);
+					margin_end += num_revertable_width + separation;
+					available -= num_revertable_width + separation;
+				}
+
+				// - Label.
+				Point2 text_offset = Point2(
+						margin_start,
+						font->get_ascent(font_size) + (header_height - font->get_height(font_size)) / 2);
 				if (rtl) {
-					arrow_position.x = get_size().width - section_indent - arrow->get_width() - Math::round(arrow_margin * EDSCALE);
-				} else {
-					arrow_position.x = section_indent + Math::round(arrow_margin * EDSCALE);
+					text_offset.x = margin_end;
 				}
-				draw_texture(arrow, arrow_position.floor());
+				HorizontalAlignment text_align = rtl ? HORIZONTAL_ALIGNMENT_RIGHT : HORIZONTAL_ALIGNMENT_LEFT;
+				draw_string(font, text_offset, label, text_align, available, font_size, font_color, TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_CONSTRAIN_ELLIPSIS);
 			}
 
 			// Draw dropping highlight.
@@ -1471,6 +1524,22 @@ void EditorInspectorSection::fold() {
 	update();
 }
 
+bool EditorInspectorSection::has_revertable_properties() const {
+	return !revertable_properties.is_empty();
+}
+
+void EditorInspectorSection::property_can_revert_changed(const String &p_path, bool p_can_revert) {
+	bool had_revertable_properties = has_revertable_properties();
+	if (p_can_revert) {
+		revertable_properties.insert(p_path);
+	} else {
+		revertable_properties.erase(p_path);
+	}
+	if (has_revertable_properties() != had_revertable_properties) {
+		update();
+	}
+}
+
 void EditorInspectorSection::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("setup", "section", "label", "object", "bg_color", "foldable"), &EditorInspectorSection::setup);
 	ClassDB::bind_method(D_METHOD("get_vbox"), &EditorInspectorSection::get_vbox);
@@ -2330,7 +2399,7 @@ String EditorInspector::get_selected_path() const {
 	return property_selected;
 }
 
-void EditorInspector::_parse_added_editors(VBoxContainer *current_vbox, Ref<EditorInspectorPlugin> ped) {
+void EditorInspector::_parse_added_editors(VBoxContainer *current_vbox, EditorInspectorSection *p_section, Ref<EditorInspectorPlugin> ped) {
 	for (const EditorInspectorPlugin::AddedEditor &F : ped->added_editors) {
 		EditorProperty *ep = Object::cast_to<EditorProperty>(F.property_editor);
 		current_vbox->add_child(F.property_editor);
@@ -2370,6 +2439,10 @@ void EditorInspector::_parse_added_editors(VBoxContainer *current_vbox, Ref<Edit
 				}
 			}
 
+			if (p_section) {
+				ep->connect("property_can_revert_changed", callable_mp(p_section, &EditorInspectorSection::property_can_revert_changed));
+			}
+
 			ep->set_read_only(read_only);
 			ep->update_property();
 			ep->_update_pin_flags();
@@ -2476,7 +2549,7 @@ void EditorInspector::update_tree() {
 	// Get the lists of editors to add the beginning.
 	for (Ref<EditorInspectorPlugin> &ped : valid_plugins) {
 		ped->parse_begin(object);
-		_parse_added_editors(main_vbox, ped);
+		_parse_added_editors(main_vbox, nullptr, ped);
 	}
 
 	StringName type_name;
@@ -2601,7 +2674,7 @@ void EditorInspector::update_tree() {
 			// Add editors at the start of a category.
 			for (Ref<EditorInspectorPlugin> &ped : valid_plugins) {
 				ped->parse_category(object, p.name);
-				_parse_added_editors(main_vbox, ped);
+				_parse_added_editors(main_vbox, nullptr, ped);
 			}
 
 			continue;
@@ -2793,7 +2866,7 @@ void EditorInspector::update_tree() {
 				// Add editors at the start of a group.
 				for (Ref<EditorInspectorPlugin> &ped : valid_plugins) {
 					ped->parse_group(object, path);
-					_parse_added_editors(section->get_vbox(), ped);
+					_parse_added_editors(section->get_vbox(), section, ped);
 				}
 
 				vbox_per_path[root_vbox][acc_path] = section->get_vbox();
@@ -2975,6 +3048,12 @@ void EditorInspector::update_tree() {
 						editor_property_map[prop].push_back(ep);
 					}
 				}
+
+				EditorInspectorSection *section = Object::cast_to<EditorInspectorSection>(current_vbox->get_parent());
+				if (section) {
+					ep->connect("property_can_revert_changed", callable_mp(section, &EditorInspectorSection::property_can_revert_changed));
+				}
+
 				ep->set_draw_warning(draw_warning);
 				ep->set_use_folding(use_folding);
 				ep->set_checkable(checkable);
@@ -3027,7 +3106,7 @@ void EditorInspector::update_tree() {
 	// Get the lists of to add at the end.
 	for (Ref<EditorInspectorPlugin> &ped : valid_plugins) {
 		ped->parse_end(object);
-		_parse_added_editors(main_vbox, ped);
+		_parse_added_editors(main_vbox, nullptr, ped);
 	}
 }
 
@@ -3180,6 +3259,44 @@ void EditorInspector::expand_all_folding() {
 	}
 }
 
+void EditorInspector::expand_revertable() {
+	HashSet<EditorInspectorSection *> sections_to_unfold[2];
+	for (EditorInspectorSection *E : sections) {
+		if (E->has_revertable_properties()) {
+			sections_to_unfold[0].insert(E);
+		}
+	}
+
+	// Climb up the hierachy doing double buffering with the sets.
+	int a = 0;
+	int b = 1;
+	while (sections_to_unfold[a].size()) {
+		for (EditorInspectorSection *E : sections_to_unfold[a]) {
+			E->unfold();
+
+			Node *n = E->get_parent();
+			while (n) {
+				if (Object::cast_to<EditorInspector>(n)) {
+					break;
+				}
+				if (Object::cast_to<EditorInspectorSection>(n) && !sections_to_unfold[a].has((EditorInspectorSection *)n)) {
+					sections_to_unfold[b].insert((EditorInspectorSection *)n);
+				}
+				n = n->get_parent();
+			}
+		}
+
+		sections_to_unfold[a].clear();
+		SWAP(a, b);
+	}
+
+	for (const KeyValue<StringName, List<EditorProperty *>> &F : editor_property_map) {
+		for (EditorProperty *E : F.value) {
+			E->expand_revertable();
+		}
+	}
+}
+
 void EditorInspector::set_scroll_offset(int p_offset) {
 	set_v_scroll(p_offset);
 }

+ 8 - 1
editor/editor_inspector.h

@@ -184,6 +184,7 @@ public:
 
 	virtual void expand_all_folding();
 	virtual void collapse_all_folding();
+	virtual void expand_revertable();
 
 	virtual Variant get_drag_data(const Point2 &p_point) override;
 	virtual void update_cache();
@@ -281,6 +282,8 @@ class EditorInspectorSection : public Container {
 	Timer *dropping_unfold_timer = nullptr;
 	bool dropping = false;
 
+	HashSet<StringName> revertable_properties;
+
 	void _test_unfold();
 
 protected:
@@ -299,6 +302,9 @@ public:
 	void unfold();
 	void fold();
 
+	bool has_revertable_properties() const;
+	void property_can_revert_changed(const String &p_path, bool p_can_revert);
+
 	EditorInspectorSection();
 	~EditorInspectorSection();
 };
@@ -517,7 +523,7 @@ class EditorInspector : public ScrollContainer {
 	void _edit_request_change(Object *p_object, const String &p_prop);
 
 	void _filter_changed(const String &p_text);
-	void _parse_added_editors(VBoxContainer *current_vbox, Ref<EditorInspectorPlugin> ped);
+	void _parse_added_editors(VBoxContainer *current_vbox, EditorInspectorSection *p_section, Ref<EditorInspectorPlugin> ped);
 
 	void _vscroll_changed(double);
 
@@ -579,6 +585,7 @@ public:
 
 	void collapse_all_folding();
 	void expand_all_folding();
+	void expand_revertable();
 
 	void set_scroll_offset(int p_offset);
 	int get_scroll_offset() const;

+ 6 - 0
editor/editor_properties.cpp

@@ -3918,6 +3918,12 @@ void EditorPropertyResource::expand_all_folding() {
 	}
 }
 
+void EditorPropertyResource::expand_revertable() {
+	if (sub_inspector) {
+		sub_inspector->expand_revertable();
+	}
+}
+
 void EditorPropertyResource::set_use_sub_inspector(bool p_enable) {
 	use_sub_inspector = p_enable;
 }

+ 1 - 0
editor/editor_properties.h

@@ -856,6 +856,7 @@ public:
 
 	void collapse_all_folding() override;
 	void expand_all_folding() override;
+	void expand_revertable() override;
 
 	void set_use_sub_inspector(bool p_enable);
 

+ 9 - 0
editor/inspector_dock.cpp

@@ -65,6 +65,9 @@ void InspectorDock::_menu_option_confirm(int p_option, bool p_confirmed) {
 		case COLLAPSE_ALL: {
 			_menu_collapseall();
 		} break;
+		case EXPAND_REVERTABLE: {
+			_menu_expand_revertable();
+		} break;
 
 		case RESOURCE_SAVE: {
 			_save_resource(false);
@@ -401,6 +404,10 @@ void InspectorDock::_menu_expandall() {
 	inspector->expand_all_folding();
 }
 
+void InspectorDock::_menu_expand_revertable() {
+	inspector->expand_revertable();
+}
+
 void InspectorDock::_warning_pressed() {
 	warning_dialog->popup_centered();
 }
@@ -519,6 +526,8 @@ void InspectorDock::update(Object *p_object) {
 	p->clear();
 	p->add_icon_shortcut(get_theme_icon(SNAME("GuiTreeArrowDown"), SNAME("EditorIcons")), ED_SHORTCUT("property_editor/expand_all", TTR("Expand All")), EXPAND_ALL);
 	p->add_icon_shortcut(get_theme_icon(SNAME("GuiTreeArrowRight"), SNAME("EditorIcons")), ED_SHORTCUT("property_editor/collapse_all", TTR("Collapse All")), COLLAPSE_ALL);
+	// Calling it 'revertable' internally, because that's what the implementation is based on, but labeling it as 'non-default' because that's more user friendly, even if not 100% accurate.
+	p->add_shortcut(ED_SHORTCUT("property_editor/expand_revertable", TTR("Expand Non-Default")), EXPAND_REVERTABLE);
 
 	p->add_separator(TTR("Property Name Style"));
 	p->add_radio_check_item(TTR("Raw"), PROPERTY_NAME_STYLE_RAW);

+ 2 - 0
editor/inspector_dock.h

@@ -61,6 +61,7 @@ class InspectorDock : public VBoxContainer {
 
 		COLLAPSE_ALL,
 		EXPAND_ALL,
+		EXPAND_REVERTABLE,
 
 		// Matches `EditorPropertyNameProcessor::Style`.
 		PROPERTY_NAME_STYLE_RAW,
@@ -124,6 +125,7 @@ class InspectorDock : public VBoxContainer {
 	void _edit_back();
 	void _menu_collapseall();
 	void _menu_expandall();
+	void _menu_expand_revertable();
 	void _select_history(int p_idx);
 	void _prepare_history();