Disable editing properties in foreign resources

from imported scenes or objects returning
true from a function named '_is_read_only' and
disable resaving imported resources.
This commit is contained in:
SaracenOne 2022-04-29 07:06:48 +01:00
parent 34aa6b06a7
commit dd814a0dca
15 changed files with 220 additions and 99 deletions

View file

@ -62,9 +62,9 @@
</signal>
<signal name="resource_selected">
<param index="0" name="resource" type="Resource" />
<param index="1" name="edit" type="bool" />
<param index="1" name="inspect" type="bool" />
<description>
Emitted when the resource value was set and user clicked to edit it. When [param edit] is [code]true[/code], the signal was caused by the context menu "Edit" option.
Emitted when the resource value was set and user clicked to edit it. When [param inspect] is [code]true[/code], the signal was caused by the context menu "Edit" or "Inspect" option.
</description>
</signal>
</signals>

View file

@ -60,7 +60,7 @@ public:
return true;
}
bool _read_only() {
bool _is_read_only() {
return animation_read_only;
}
@ -70,7 +70,7 @@ public:
ClassDB::bind_method(D_METHOD("_hide_script_from_inspector"), &AnimationTrackKeyEdit::_hide_script_from_inspector);
ClassDB::bind_method(D_METHOD("get_root_path"), &AnimationTrackKeyEdit::get_root_path);
ClassDB::bind_method(D_METHOD("_dont_undo_redo"), &AnimationTrackKeyEdit::_dont_undo_redo);
ClassDB::bind_method(D_METHOD("_read_only"), &AnimationTrackKeyEdit::_read_only);
ClassDB::bind_method(D_METHOD("_is_read_only"), &AnimationTrackKeyEdit::_is_read_only);
}
void _fix_node_path(Variant &value) {
@ -727,7 +727,7 @@ public:
return true;
}
bool _read_only() {
bool _is_read_only() {
return animation_read_only;
}
@ -737,7 +737,7 @@ public:
ClassDB::bind_method(D_METHOD("_hide_script_from_inspector"), &AnimationMultiTrackKeyEdit::_hide_script_from_inspector);
ClassDB::bind_method(D_METHOD("get_root_path"), &AnimationMultiTrackKeyEdit::get_root_path);
ClassDB::bind_method(D_METHOD("_dont_undo_redo"), &AnimationMultiTrackKeyEdit::_dont_undo_redo);
ClassDB::bind_method(D_METHOD("_read_only"), &AnimationMultiTrackKeyEdit::_read_only);
ClassDB::bind_method(D_METHOD("_is_read_only"), &AnimationMultiTrackKeyEdit::_is_read_only);
}
void _fix_node_path(Variant &value, NodePath &base) {

View file

@ -85,6 +85,7 @@ void EditorDebuggerRemoteObject::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_variant"), &EditorDebuggerRemoteObject::get_variant);
ClassDB::bind_method(D_METHOD("clear"), &EditorDebuggerRemoteObject::clear);
ClassDB::bind_method(D_METHOD("get_remote_object_id"), &EditorDebuggerRemoteObject::get_remote_object_id);
ClassDB::bind_method(D_METHOD("_is_read_only"), &EditorDebuggerRemoteObject::_is_read_only);
ADD_SIGNAL(MethodInfo("value_edited", PropertyInfo(Variant::INT, "object_id"), PropertyInfo(Variant::STRING, "property"), PropertyInfo("value")));
}

View file

@ -50,6 +50,7 @@ public:
HashMap<StringName, Variant> prop_values;
ObjectID get_remote_object_id() { return remote_object_id; };
bool _is_read_only() { return true; };
String get_title();
Variant get_variant(const StringName &p_name);

View file

@ -2628,15 +2628,28 @@ void EditorInspector::update_tree() {
valid_plugins.push_back(inspector_plugins[i]);
}
// Decide if properties should be drawn with the warning color (yellow).
// Decide if properties should be drawn with the warning color (yellow),
// or if the whole object should be considered read-only.
bool draw_warning = false;
bool all_read_only = false;
if (is_inside_tree()) {
if (object->has_method("_is_read_only")) {
all_read_only = object->call("_is_read_only");
}
Node *nod = Object::cast_to<Node>(object);
Node *es = EditorNode::get_singleton()->get_edited_scene();
if (nod && es != nod && nod->get_owner() != es) {
// Draw in warning color edited nodes that are not in the currently edited scene,
// as changes may be lost in the future.
draw_warning = true;
} else {
if (!all_read_only) {
Resource *res = Object::cast_to<Resource>(object);
if (res) {
all_read_only = EditorNode::get_singleton()->is_resource_read_only(res);
}
}
}
}
@ -3179,7 +3192,6 @@ void EditorInspector::update_tree() {
ep->property_usage = p.usage;
//and set label?
}
if (!editors[i].label.is_empty()) {
ep->set_label(editors[i].label);
} else {
@ -3206,7 +3218,7 @@ void EditorInspector::update_tree() {
ep->set_checkable(checkable);
ep->set_checked(checked);
ep->set_keying(keying);
ep->set_read_only(property_read_only);
ep->set_read_only(property_read_only || all_read_only);
ep->set_deletable(deletable_properties || p.name.begins_with("metadata/"));
}
@ -3253,6 +3265,9 @@ void EditorInspector::update_tree() {
add_md->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
add_md->connect(SNAME("pressed"), callable_mp(this, &EditorInspector::_show_add_meta_dialog));
main_vbox->add_child(add_md);
if (all_read_only) {
add_md->set_disabled(true);
}
}
// Get the lists of to add at the end.

View file

@ -1250,7 +1250,9 @@ void EditorNode::save_resource_in_path(const Ref<Resource> &p_resource, const St
}
void EditorNode::save_resource(const Ref<Resource> &p_resource) {
if (p_resource->get_path().is_resource_file()) {
// If the resource has been imported, ask the user to use a different path in order to save it.
String path = p_resource->get_path();
if (path.is_resource_file() && !FileAccess::exists(path + ".import")) {
save_resource_in_path(p_resource, p_resource->get_path());
} else {
save_resource_as(p_resource);
@ -1260,11 +1262,18 @@ void EditorNode::save_resource(const Ref<Resource> &p_resource) {
void EditorNode::save_resource_as(const Ref<Resource> &p_resource, const String &p_at_path) {
{
String path = p_resource->get_path();
int srpos = path.find("::");
if (srpos != -1) {
String base = path.substr(0, srpos);
if (!get_edited_scene() || get_edited_scene()->get_scene_file_path() != base) {
show_warning(TTR("This resource can't be saved because it does not belong to the edited scene. Make it unique first."));
if (!path.is_resource_file()) {
int srpos = path.find("::");
if (srpos != -1) {
String base = path.substr(0, srpos);
if (!get_edited_scene() || get_edited_scene()->get_scene_file_path() != base) {
show_warning(TTR("This resource can't be saved because it does not belong to the edited scene. Make it unique first."));
return;
}
}
} else {
if (FileAccess::exists(path + ".import")) {
show_warning(TTR("This resource can't be saved because it was imported from another file. Make it unique first."));
return;
}
}
@ -2223,7 +2232,14 @@ void EditorNode::_edit_current(bool p_skip_foreign) {
bool stay_in_script_editor_on_node_selected = bool(EDITOR_GET("text_editor/behavior/navigation/stay_in_script_editor_on_node_selected"));
bool skip_main_plugin = false;
String editable_warning; // None by default.
String editable_info; // None by default.
bool info_is_warning = false;
if (current_obj->has_method("_is_read_only")) {
if (current_obj->call("_is_read_only")) {
editable_info = TTR("This object is marked as read-only, so it's not editable.");
}
}
if (is_resource) {
Resource *current_res = Object::cast_to<Resource>(current_obj);
@ -2237,16 +2253,25 @@ void EditorNode::_edit_current(bool p_skip_foreign) {
int subr_idx = current_res->get_path().find("::");
if (subr_idx != -1) {
String base_path = current_res->get_path().substr(0, subr_idx);
if (FileAccess::exists(base_path + ".import")) {
editable_warning = TTR("This resource belongs to a scene that was imported, so it's not editable.\nPlease read the documentation relevant to importing scenes to better understand this workflow.");
if (!base_path.is_resource_file()) {
if (FileAccess::exists(base_path + ".import")) {
if (get_edited_scene() && get_edited_scene()->get_scene_file_path() == base_path) {
info_is_warning = true;
}
editable_info = TTR("This resource belongs to a scene that was imported, so it's not editable.\nPlease read the documentation relevant to importing scenes to better understand this workflow.");
} else {
if ((!get_edited_scene() || get_edited_scene()->get_scene_file_path() != base_path) && ResourceLoader::get_resource_type(base_path) == "PackedScene") {
editable_info = TTR("This resource belongs to a scene that was instantiated or inherited.\nChanges to it must be made inside the original scene.");
}
}
} else {
if ((!get_edited_scene() || get_edited_scene()->get_scene_file_path() != base_path) && ResourceLoader::get_resource_type(base_path) == "PackedScene") {
editable_warning = TTR("This resource belongs to a scene that was instantiated or inherited.\nChanges to it won't be kept when saving the current scene.");
if (FileAccess::exists(base_path + ".import")) {
editable_info = TTR("This resource belongs to a scene that was imported, so it's not editable.\nPlease read the documentation relevant to importing scenes to better understand this workflow.");
}
}
} else if (current_res->get_path().is_resource_file()) {
if (FileAccess::exists(current_res->get_path() + ".import")) {
editable_warning = TTR("This resource was imported, so it's not editable. Change its settings in the import panel and then re-import.");
editable_info = TTR("This resource was imported, so it's not editable. Change its settings in the import panel and then re-import.");
}
}
} else if (is_node) {
@ -2270,7 +2295,8 @@ void EditorNode::_edit_current(bool p_skip_foreign) {
if (get_edited_scene() && !get_edited_scene()->get_scene_file_path().is_empty()) {
String source_scene = get_edited_scene()->get_scene_file_path();
if (FileAccess::exists(source_scene + ".import")) {
editable_warning = TTR("This scene was imported, so changes to it won't be kept.\nInstancing it or inheriting will allow making changes to it.\nPlease read the documentation relevant to importing scenes to better understand this workflow.");
editable_info = TTR("This scene was imported, so changes to it won't be kept.\nInstancing it or inheriting will allow making changes to it.\nPlease read the documentation relevant to importing scenes to better understand this workflow.");
info_is_warning = true;
}
}
@ -2278,7 +2304,7 @@ void EditorNode::_edit_current(bool p_skip_foreign) {
Node *selected_node = nullptr;
if (current_obj->is_class("EditorDebuggerRemoteObject")) {
editable_warning = TTR("This is a remote object, so changes to it won't be kept.\nPlease read the documentation relevant to debugging to better understand this workflow.");
editable_info = TTR("This is a remote object, so it's not editable.\nPlease read the documentation relevant to debugging to better understand this workflow.");
disable_folding = true;
} else if (current_obj->is_class("MultiNodeEdit")) {
Node *scene = get_edited_scene();
@ -2313,7 +2339,10 @@ void EditorNode::_edit_current(bool p_skip_foreign) {
InspectorDock::get_inspector_singleton()->update_tree();
}
InspectorDock::get_singleton()->set_warning(editable_warning);
InspectorDock::get_singleton()->set_info(
info_is_warning ? TTR("Changes may be lost!") : TTR("This object is read-only."),
editable_info,
info_is_warning);
if (InspectorDock::get_inspector_singleton()->is_using_folding() == disable_folding) {
InspectorDock::get_inspector_singleton()->set_use_folding(!disable_folding);
@ -3828,6 +3857,37 @@ void EditorNode::edit_foreign_resource(Ref<Resource> p_resource) {
InspectorDock::get_singleton()->call_deferred("edit_resource", p_resource);
}
bool EditorNode::is_resource_read_only(Ref<Resource> p_resource) {
ERR_FAIL_COND_V(p_resource.is_null(), false);
String path = p_resource->get_path();
if (!path.is_resource_file()) {
// If the resource name contains '::', that means it is a subresource embedded in another resource.
int srpos = path.find("::");
if (srpos != -1) {
String base = path.substr(0, srpos);
// If the base resource is a packed scene, we treat it as read-only if it is not the currently edited scene.
if (ResourceLoader::get_resource_type(base) == "PackedScene") {
if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) {
return true;
}
} else {
// If a corresponding .import file exists for the base file, we assume it to be imported and should therefore treated as read-only.
if (FileAccess::exists(base + ".import")) {
return true;
}
}
}
} else {
// The resource is not a subresource, but if it has an .import file, it's imported so treat it as read only.
if (FileAccess::exists(path + ".import")) {
return true;
}
}
return false;
}
void EditorNode::request_instance_scene(const String &p_path) {
SceneTreeDock::get_singleton()->instantiate(p_path);
}
@ -5837,6 +5897,7 @@ void EditorNode::_bind_methods() {
ClassDB::bind_method("set_edited_scene", &EditorNode::set_edited_scene);
ClassDB::bind_method("open_request", &EditorNode::open_request);
ClassDB::bind_method("edit_foreign_resource", &EditorNode::edit_foreign_resource);
ClassDB::bind_method("is_resource_read_only", &EditorNode::is_resource_read_only);
ClassDB::bind_method("_close_messages", &EditorNode::_close_messages);
ClassDB::bind_method("_show_messages", &EditorNode::_show_messages);

View file

@ -776,6 +776,8 @@ public:
void open_request(const String &p_path);
void edit_foreign_resource(Ref<Resource> p_resource);
bool is_resource_read_only(Ref<Resource> p_resource);
bool is_changing_scene() const;
Control *get_main_control();

View file

@ -3653,20 +3653,24 @@ void EditorPropertyResource::_set_read_only(bool p_read_only) {
resource_picker->set_editable(!p_read_only);
};
void EditorPropertyResource::_resource_selected(const Ref<Resource> &p_resource, bool p_edit) {
void EditorPropertyResource::_resource_selected(const Ref<Resource> &p_resource, bool p_inspect) {
if (p_resource->is_built_in() && !p_resource->get_path().is_empty()) {
String parent = p_resource->get_path().get_slice("::", 0);
List<String> extensions;
ResourceLoader::get_recognized_extensions_for_type("PackedScene", &extensions);
if (extensions.find(parent.get_extension()) && (!EditorNode::get_singleton()->get_edited_scene() || EditorNode::get_singleton()->get_edited_scene()->get_scene_file_path() != parent)) {
// If the resource belongs to another scene, edit it in that scene instead.
EditorNode::get_singleton()->call_deferred("edit_foreign_resource", p_resource);
return;
if (p_inspect) {
if (extensions.find(parent.get_extension()) && (!EditorNode::get_singleton()->get_edited_scene() || EditorNode::get_singleton()->get_edited_scene()->get_scene_file_path() != parent)) {
// If the resource belongs to another (non-imported) scene, edit it in that scene instead.
if (!FileAccess::exists(parent + ".import")) {
EditorNode::get_singleton()->call_deferred("edit_foreign_resource", p_resource);
return;
}
}
}
}
if (!p_edit && use_sub_inspector) {
if (!p_inspect && use_sub_inspector) {
bool unfold = !get_edited_object()->editor_is_section_unfolded(get_edited_property());
get_edited_object()->editor_set_section_unfold(get_edited_property(), unfold);
update_property();

View file

@ -835,7 +835,7 @@ class EditorPropertyResource : public EditorProperty {
bool updating_theme = false;
bool opened_editor = false;
void _resource_selected(const Ref<Resource> &p_resource, bool p_edit);
void _resource_selected(const Ref<Resource> &p_resource, bool p_inspect);
void _resource_changed(const Ref<Resource> &p_resource);
void _viewport_selected(const NodePath &p_path);

View file

@ -81,6 +81,8 @@ void EditorResourcePicker::_update_resource() {
} else if (edited_resource.is_valid()) {
assign_button->set_tooltip(resource_path + TTR("Type:") + " " + edited_resource->get_class());
}
assign_button->set_disabled(!editable && !edited_resource.is_valid());
}
void EditorResourcePicker::_update_resource_preview(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, ObjectID p_obj) {
@ -171,35 +173,50 @@ void EditorResourcePicker::_update_menu_items() {
edit_menu->clear();
// Add options for creating specific subtypes of the base resource type.
set_create_options(edit_menu);
if (is_editable()) {
set_create_options(edit_menu);
// Add an option to load a resource from a file using the QuickOpen dialog.
edit_menu->add_icon_item(get_theme_icon(SNAME("Load"), SNAME("EditorIcons")), TTR("Quick Load"), OBJ_MENU_QUICKLOAD);
// Add an option to load a resource from a file using the QuickOpen dialog.
edit_menu->add_icon_item(get_theme_icon(SNAME("Load"), SNAME("EditorIcons")), TTR("Quick Load"), OBJ_MENU_QUICKLOAD);
// Add an option to load a resource from a file using the regular file dialog.
edit_menu->add_icon_item(get_theme_icon(SNAME("Load"), SNAME("EditorIcons")), TTR("Load"), OBJ_MENU_LOAD);
// Add an option to load a resource from a file using the regular file dialog.
edit_menu->add_icon_item(get_theme_icon(SNAME("Load"), SNAME("EditorIcons")), TTR("Load"), OBJ_MENU_LOAD);
}
// Add options for changing existing value of the resource.
if (edited_resource.is_valid()) {
edit_menu->add_icon_item(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")), TTR("Edit"), OBJ_MENU_EDIT);
edit_menu->add_icon_item(get_theme_icon(SNAME("Clear"), SNAME("EditorIcons")), TTR("Clear"), OBJ_MENU_CLEAR);
edit_menu->add_icon_item(get_theme_icon(SNAME("Duplicate"), SNAME("EditorIcons")), TTR("Make Unique"), OBJ_MENU_MAKE_UNIQUE);
// Determine if the edited resource is part of another scene (foreign) which was imported
bool is_edited_resource_foreign_import = EditorNode::get_singleton()->is_resource_read_only(edited_resource);
// Check whether the resource has subresources.
List<PropertyInfo> property_list;
edited_resource->get_property_list(&property_list);
bool has_subresources = false;
for (PropertyInfo &p : property_list) {
if ((p.type == Variant::OBJECT) && (p.hint == PROPERTY_HINT_RESOURCE_TYPE) && (p.name != "script")) {
has_subresources = true;
break;
// If the resource is determined to be foreign and imported, change the menu entry's description to 'inspect' rather than 'edit'
// since will only be able to view its properties in read-only mode.
if (is_edited_resource_foreign_import) {
// The 'Search' icon is a magnifying glass, which seems appropriate, but maybe a bespoke icon is preferred here.
edit_menu->add_icon_item(get_theme_icon(SNAME("Search"), SNAME("EditorIcons")), TTR("Inspect"), OBJ_MENU_INSPECT);
} else {
edit_menu->add_icon_item(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")), TTR("Edit"), OBJ_MENU_INSPECT);
}
if (is_editable()) {
edit_menu->add_icon_item(get_theme_icon(SNAME("Clear"), SNAME("EditorIcons")), TTR("Clear"), OBJ_MENU_CLEAR);
edit_menu->add_icon_item(get_theme_icon(SNAME("Duplicate"), SNAME("EditorIcons")), TTR("Make Unique"), OBJ_MENU_MAKE_UNIQUE);
// Check whether the resource has subresources.
List<PropertyInfo> property_list;
edited_resource->get_property_list(&property_list);
bool has_subresources = false;
for (PropertyInfo &p : property_list) {
if ((p.type == Variant::OBJECT) && (p.hint == PROPERTY_HINT_RESOURCE_TYPE) && (p.name != "script")) {
has_subresources = true;
break;
}
}
if (has_subresources) {
edit_menu->add_icon_item(get_theme_icon(SNAME("Duplicate"), SNAME("EditorIcons")), TTR("Make Unique (Recursive)"), OBJ_MENU_MAKE_UNIQUE_RECURSIVE);
}
}
if (has_subresources) {
edit_menu->add_icon_item(get_theme_icon(SNAME("Duplicate"), SNAME("EditorIcons")), TTR("Make Unique (Recursive)"), OBJ_MENU_MAKE_UNIQUE_RECURSIVE);
}
edit_menu->add_icon_item(get_theme_icon(SNAME("Save"), SNAME("EditorIcons")), TTR("Save"), OBJ_MENU_SAVE);
edit_menu->add_icon_item(get_theme_icon(SNAME("Save"), SNAME("EditorIcons")), TTR("Save"), OBJ_MENU_SAVE);
}
if (edited_resource->get_path().is_resource_file()) {
edit_menu->add_separator();
@ -210,14 +227,16 @@ void EditorResourcePicker::_update_menu_items() {
// Add options to copy/paste resource.
Ref<Resource> cb = EditorSettings::get_singleton()->get_resource_clipboard();
bool paste_valid = false;
if (cb.is_valid()) {
if (base_type.is_empty()) {
paste_valid = true;
} else {
for (int i = 0; i < base_type.get_slice_count(","); i++) {
if (ClassDB::is_parent_class(cb->get_class(), base_type.get_slice(",", i))) {
paste_valid = true;
break;
if (is_editable()) {
if (cb.is_valid()) {
if (base_type.is_empty()) {
paste_valid = true;
} else {
for (int i = 0; i < base_type.get_slice_count(","); i++) {
if (ClassDB::is_parent_class(cb->get_class(), base_type.get_slice(",", i))) {
paste_valid = true;
break;
}
}
}
}
@ -236,7 +255,7 @@ void EditorResourcePicker::_update_menu_items() {
}
// Add options to convert existing resource to another type of resource.
if (edited_resource.is_valid()) {
if (is_editable() && edited_resource.is_valid()) {
Vector<Ref<EditorResourceConversionPlugin>> conversions = EditorNode::get_singleton()->find_resource_conversion_plugin(edited_resource);
if (conversions.size()) {
edit_menu->add_separator();
@ -295,7 +314,7 @@ void EditorResourcePicker::_edit_menu_cbk(int p_which) {
quick_open->set_title(TTR("Resource"));
} break;
case OBJ_MENU_EDIT: {
case OBJ_MENU_INSPECT: {
if (edited_resource.is_valid()) {
emit_signal(SNAME("resource_selected"), edited_resource, true);
}
@ -491,20 +510,21 @@ void EditorResourcePicker::_button_draw() {
}
void EditorResourcePicker::_button_input(const Ref<InputEvent> &p_event) {
if (!editable) {
return;
}
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
if (mb->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) {
_update_menu_items();
// Only attempt to update and show the menu if we have
// a valid resource or the Picker is editable, as
// there will otherwise be nothing to display.
if (edited_resource.is_valid() || is_editable()) {
_update_menu_items();
Vector2 pos = get_screen_position() + mb->get_position();
edit_menu->reset_size();
edit_menu->set_position(pos);
edit_menu->popup();
Vector2 pos = get_screen_position() + mb->get_position();
edit_menu->reset_size();
edit_menu->set_position(pos);
edit_menu->popup();
}
}
}
}
@ -734,7 +754,7 @@ void EditorResourcePicker::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editable"), "set_editable", "is_editable");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "toggle_mode"), "set_toggle_mode", "is_toggle_mode");
ADD_SIGNAL(MethodInfo("resource_selected", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"), PropertyInfo(Variant::BOOL, "edit")));
ADD_SIGNAL(MethodInfo("resource_selected", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"), PropertyInfo(Variant::BOOL, "inspect")));
ADD_SIGNAL(MethodInfo("resource_changed", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource")));
}
@ -866,7 +886,7 @@ void EditorResourcePicker::set_toggle_pressed(bool p_pressed) {
void EditorResourcePicker::set_editable(bool p_editable) {
editable = p_editable;
assign_button->set_disabled(!editable);
assign_button->set_disabled(!editable && !edited_resource.is_valid());
edit_button->set_visible(editable);
}

View file

@ -63,7 +63,7 @@ class EditorResourcePicker : public HBoxContainer {
enum MenuOption {
OBJ_MENU_LOAD,
OBJ_MENU_QUICKLOAD,
OBJ_MENU_EDIT,
OBJ_MENU_INSPECT,
OBJ_MENU_CLEAR,
OBJ_MENU_MAKE_UNIQUE,
OBJ_MENU_MAKE_UNIQUE_RECURSIVE,

View file

@ -518,8 +518,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_warning_color = error_color.lerp(dark_theme ? Color(0, 0, 0) : Color(1, 1, 1), 0.5);
Color readonly_color = property_color.lerp(dark_theme ? Color(0, 0, 0) : Color(1, 1, 1), 0.25);
Color readonly_warning_color = error_color.lerp(dark_theme ? Color(0, 0, 0) : Color(1, 1, 1), 0.25);
if (!dark_theme) {
// Darken some colors to be readable on a light background

View file

@ -0,0 +1 @@
<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a7 7 0 0 0 -7 7 7 7 0 0 0 7 7 7 7 0 0 0 7-7 7 7 0 0 0 -7-7zm-1 3h2v2h-2zm0 3h2v5h-2z" fill="#fff"/></svg>

After

Width:  |  Height:  |  Size: 202 B

View file

@ -247,7 +247,7 @@ void InspectorDock::_resource_file_selected(String p_file) {
}
if (res.is_null()) {
warning_dialog->set_text(TTR("Failed to load resource."));
info_dialog->set_text(TTR("Failed to load resource."));
return;
};
@ -409,8 +409,8 @@ void InspectorDock::_menu_expand_revertable() {
inspector->expand_revertable();
}
void InspectorDock::_warning_pressed() {
warning_dialog->popup_centered();
void InspectorDock::_info_pressed() {
info_dialog->popup_centered();
}
Container *InspectorDock::get_addon_area() {
@ -446,8 +446,13 @@ void InspectorDock::_notification(int p_what) {
history_menu->set_icon(get_theme_icon(SNAME("History"), SNAME("EditorIcons")));
object_menu->set_icon(get_theme_icon(SNAME("Tools"), SNAME("EditorIcons")));
search->set_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
warning->set_icon(get_theme_icon(SNAME("NodeWarning"), SNAME("EditorIcons")));
warning->add_theme_color_override("font_color", get_theme_color(SNAME("warning_color"), SNAME("Editor")));
if (info_is_warning) {
info->set_icon(get_theme_icon(SNAME("NodeWarning"), SNAME("EditorIcons")));
info->add_theme_color_override("font_color", get_theme_color(SNAME("warning_color"), SNAME("Editor")));
} else {
info->set_icon(get_theme_icon(SNAME("NodeInfo"), SNAME("EditorIcons")));
info->add_theme_color_override("font_color", get_theme_color(SNAME("font_color"), SNAME("Editor")));
}
} break;
}
}
@ -476,11 +481,22 @@ void InspectorDock::open_resource(const String &p_type) {
_load_resource(p_type);
}
void InspectorDock::set_warning(const String &p_message) {
warning->hide();
if (!p_message.is_empty()) {
warning->show();
warning_dialog->set_text(p_message);
void InspectorDock::set_info(const String &p_button_text, const String &p_message, bool p_is_warning) {
info->hide();
info_is_warning = p_is_warning;
if (info_is_warning) {
info->set_icon(get_theme_icon(SNAME("NodeWarning"), SNAME("EditorIcons")));
info->add_theme_color_override("font_color", get_theme_color(SNAME("warning_color"), SNAME("Editor")));
} else {
info->set_icon(get_theme_icon(SNAME("NodeInfo"), SNAME("EditorIcons")));
info->add_theme_color_override("font_color", get_theme_color(SNAME("font_color"), SNAME("Editor")));
}
if (!p_button_text.is_empty() && !p_message.is_empty()) {
info->show();
info->set_text(p_button_text);
info_dialog->set_text(p_message);
}
}
@ -515,7 +531,7 @@ void InspectorDock::update(Object *p_object) {
resource_extra_popup->set_item_disabled(resource_extra_popup->get_item_index(RESOURCE_MAKE_BUILT_IN), !is_resource || is_text_file);
if (!is_object || is_text_file) {
warning->hide();
info->hide();
editor_path->clear_path();
return;
}
@ -707,12 +723,11 @@ InspectorDock::InspectorDock(EditorData &p_editor_data) {
object_menu->get_popup()->connect("about_to_popup", callable_mp(this, &InspectorDock::_prepare_menu));
object_menu->get_popup()->connect("id_pressed", callable_mp(this, &InspectorDock::_menu_option));
warning = memnew(Button);
add_child(warning);
warning->set_text(TTR("Changes may be lost!"));
warning->set_clip_text(true);
warning->hide();
warning->connect("pressed", callable_mp(this, &InspectorDock::_warning_pressed));
info = memnew(Button);
add_child(info);
info->set_clip_text(true);
info->hide();
info->connect("pressed", callable_mp(this, &InspectorDock::_info_pressed));
unique_resources_confirmation = memnew(ConfirmationDialog);
add_child(unique_resources_confirmation);
@ -737,8 +752,8 @@ InspectorDock::InspectorDock(EditorData &p_editor_data) {
unique_resources_confirmation->connect("confirmed", callable_mp(this, &InspectorDock::_menu_confirm_current));
warning_dialog = memnew(AcceptDialog);
EditorNode::get_singleton()->get_gui_base()->add_child(warning_dialog);
info_dialog = memnew(AcceptDialog);
EditorNode::get_singleton()->get_gui_base()->add_child(info_dialog);
load_resource_dialog = memnew(EditorFileDialog);
add_child(load_resource_dialog);

View file

@ -93,8 +93,9 @@ class InspectorDock : public VBoxContainer {
MenuButton *object_menu = nullptr;
EditorPath *editor_path = nullptr;
Button *warning = nullptr;
AcceptDialog *warning_dialog = nullptr;
bool info_is_warning = false; // Display in yellow and use warning icon if true.
Button *info = nullptr;
AcceptDialog *info_dialog = nullptr;
int current_option = -1;
ConfirmationDialog *unique_resources_confirmation = nullptr;
@ -118,7 +119,7 @@ class InspectorDock : public VBoxContainer {
void _paste_resource();
void _prepare_resource_extra_popup();
void _warning_pressed();
void _info_pressed();
void _resource_created();
void _resource_selected(const Ref<Resource> &p_res, const String &p_property);
void _edit_forward();
@ -145,7 +146,7 @@ public:
void edit_resource(const Ref<Resource> &p_resource);
void open_resource(const String &p_type);
void clear();
void set_warning(const String &p_message);
void set_info(const String &p_button_text, const String &p_message, bool p_is_warning);
void update(Object *p_object);
Container *get_addon_area();
EditorInspector *get_inspector() { return inspector; }