|
@@ -1827,7 +1827,7 @@ void EditorInspectorSection::_notification(int p_what) {
|
|
|
header_offset_x += section_indent;
|
|
|
}
|
|
|
|
|
|
- bool has_children_to_show = vbox->get_child_count(false) != 0;
|
|
|
+ bool can_click_unfold = vbox->get_child_count(false) != 0 && !(checkable && !checked && hide_feature);
|
|
|
|
|
|
// Draw header area.
|
|
|
int header_height = _get_header_height();
|
|
@@ -1835,7 +1835,7 @@ void EditorInspectorSection::_notification(int p_what) {
|
|
|
Color c = bg_color;
|
|
|
c.a *= 0.4;
|
|
|
if (foldable && header_rect.has_point(get_local_mouse_position())) {
|
|
|
- c = c.lightened((has_children_to_show && Input::get_singleton()->is_mouse_button_pressed(MouseButton::LEFT)) ? -0.05 : 0.2);
|
|
|
+ c = c.lightened((can_click_unfold && Input::get_singleton()->is_mouse_button_pressed(MouseButton::LEFT)) ? -0.05 : 0.2);
|
|
|
}
|
|
|
draw_rect(header_rect, c);
|
|
|
|
|
@@ -1857,32 +1857,52 @@ void EditorInspectorSection::_notification(int p_what) {
|
|
|
arrow_position.x = margin_start;
|
|
|
}
|
|
|
arrow_position.y = (header_height - arrow->get_height()) / 2;
|
|
|
- if (has_children_to_show) {
|
|
|
+ if (can_click_unfold) {
|
|
|
draw_texture(arrow, arrow_position);
|
|
|
}
|
|
|
margin_start += arrow->get_width() + separation;
|
|
|
}
|
|
|
|
|
|
+ Ref<Font> font = get_theme_font(SNAME("bold"), EditorStringName(EditorFonts));
|
|
|
+ int font_size = get_theme_font_size(SNAME("bold_size"), EditorStringName(EditorFonts));
|
|
|
+ Color font_color = get_theme_color(SceneStringName(font_color), EditorStringName(Editor));
|
|
|
+
|
|
|
+ Ref<Font> light_font = get_theme_font(SNAME("main"), EditorStringName(EditorFonts));
|
|
|
+ int light_font_size = get_theme_font_size(SNAME("main_size"), EditorStringName(EditorFonts));
|
|
|
+
|
|
|
// - Checkbox.
|
|
|
Ref<Texture2D> checkbox = _get_checkbox();
|
|
|
if (checkbox.is_valid()) {
|
|
|
+ const String checkbox_text = TTR("On");
|
|
|
+ Size2 label_size = light_font->get_string_size(checkbox_text, HORIZONTAL_ALIGNMENT_LEFT, -1.0f, light_font_size);
|
|
|
Point2 checkbox_position;
|
|
|
+ Point2 label_position;
|
|
|
if (rtl) {
|
|
|
- checkbox_position.x = margin_start;
|
|
|
+ label_position.x = margin_start;
|
|
|
+ checkbox_position.x = margin_start + label_size.width + 2 * EDSCALE;
|
|
|
} else {
|
|
|
- checkbox_position.x = get_size().width - (margin_end + checkbox->get_width());
|
|
|
+ label_position.x = get_size().width - (margin_end + label_size.width);
|
|
|
+ checkbox_position.x = label_position.x - checkbox->get_width() - 2 * EDSCALE;
|
|
|
}
|
|
|
checkbox_position.y = (header_height - checkbox->get_height()) / 2;
|
|
|
- check_rect = Rect2(checkbox_position.x, checkbox_position.y, checkbox->get_width(), checkbox->get_height());
|
|
|
+ label_position.y = light_font->get_ascent(light_font_size) + (header_height - label_size.height) / 2.0;
|
|
|
+
|
|
|
+ check_rect = Rect2(checkbox_position.x, 0, checkbox->get_width() + label_size.width + 2 * EDSCALE, header_height);
|
|
|
|
|
|
+ Color check_font_color = font_color;
|
|
|
Color checkbox_color(1, 1, 1);
|
|
|
if (check_hover) {
|
|
|
checkbox_color.r *= 1.2;
|
|
|
checkbox_color.g *= 1.2;
|
|
|
checkbox_color.b *= 1.2;
|
|
|
+ check_font_color = checked ? get_theme_color(SNAME("font_hover_pressed_color"), EditorStringName(Editor)) : get_theme_color(SNAME("font_hover_color"), EditorStringName(Editor));
|
|
|
+ } else if (checked) {
|
|
|
+ check_font_color = get_theme_color(SNAME("font_pressed_color"), EditorStringName(Editor));
|
|
|
}
|
|
|
+
|
|
|
draw_texture(checkbox, checkbox_position, checkbox_color);
|
|
|
- margin_end += checkbox->get_width() + 4 * EDSCALE;
|
|
|
+ draw_string(light_font, label_position, checkbox_text, HORIZONTAL_ALIGNMENT_LEFT, -1.0f, light_font_size, check_font_color, TextServer::JUSTIFICATION_NONE);
|
|
|
+ margin_end += label_size.width + checkbox->get_width() + 6 * EDSCALE;
|
|
|
}
|
|
|
|
|
|
int available = get_size().width - (margin_start + margin_end);
|
|
@@ -1891,22 +1911,10 @@ void EditorInspectorSection::_notification(int p_what) {
|
|
|
String num_revertable_str;
|
|
|
int num_revertable_width = 0;
|
|
|
|
|
|
- bool folded = foldable && !object->editor_is_section_unfolded(section);
|
|
|
-
|
|
|
- Ref<Font> font = get_theme_font(SNAME("bold"), EditorStringName(EditorFonts));
|
|
|
- int font_size = get_theme_font_size(SNAME("bold_size"), EditorStringName(EditorFonts));
|
|
|
- Color font_color;
|
|
|
- if (object->has_method("_get_property_warning")) {
|
|
|
- font_color = get_theme_color(String(object->call("_get_property_warning", related_enable_property)).is_empty() ? SceneStringName(font_color) : SNAME("warning_color"), EditorStringName(Editor));
|
|
|
- } else {
|
|
|
- font_color = get_theme_color(SceneStringName(font_color), EditorStringName(Editor));
|
|
|
- }
|
|
|
-
|
|
|
+ bool folded = (foldable || hide_feature) && !object->editor_is_section_unfolded(section);
|
|
|
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"), EditorStringName(EditorFonts));
|
|
|
- int light_font_size = get_theme_font_size(SNAME("main_size"), EditorStringName(EditorFonts));
|
|
|
Color light_font_color = get_theme_color(SNAME("font_disabled_color"), EditorStringName(Editor));
|
|
|
|
|
|
// Can we fit the long version of the revertable count text?
|
|
@@ -1934,6 +1942,9 @@ void EditorInspectorSection::_notification(int p_what) {
|
|
|
if (rtl) {
|
|
|
text_offset.x = margin_end;
|
|
|
}
|
|
|
+ if (object->has_method("_get_property_warning") && !String(object->call("_get_property_warning", related_enable_property)).is_empty()) {
|
|
|
+ font_color = get_theme_color(SNAME("warning_color"), EditorStringName(Editor));
|
|
|
+ }
|
|
|
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);
|
|
|
}
|
|
@@ -2084,7 +2095,7 @@ void EditorInspectorSection::gui_input(const Ref<InputEvent> &p_event) {
|
|
|
|
|
|
Ref<InputEventKey> k = p_event;
|
|
|
if (k.is_valid() && k->is_pressed()) {
|
|
|
- if (foldable && has_children_to_show && k->is_action("ui_accept", true)) {
|
|
|
+ if (foldable && has_children_to_show && !(checkable && !checked && hide_feature) && k->is_action("ui_accept", true)) {
|
|
|
accept_event();
|
|
|
|
|
|
bool should_unfold = !object->editor_is_section_unfolded(section);
|
|
@@ -2108,12 +2119,16 @@ void EditorInspectorSection::gui_input(const Ref<InputEvent> &p_event) {
|
|
|
|
|
|
accept_event();
|
|
|
|
|
|
- if (check_rect.has_point(mb->get_position())) {
|
|
|
+ if (checkable && check_rect.has_point(mb->get_position())) {
|
|
|
checked = !checked;
|
|
|
emit_signal(SNAME("section_toggled_by_user"), related_enable_property, checked);
|
|
|
- unfold();
|
|
|
+ if (checked) {
|
|
|
+ unfold();
|
|
|
+ } else if (hide_feature) {
|
|
|
+ fold();
|
|
|
+ }
|
|
|
} else if (foldable) {
|
|
|
- bool should_unfold = has_children_to_show && !object->editor_is_section_unfolded(section);
|
|
|
+ bool should_unfold = has_children_to_show && !(checkable && !checked && hide_feature) && !object->editor_is_section_unfolded(section);
|
|
|
if (should_unfold) {
|
|
|
unfold();
|
|
|
} else {
|
|
@@ -2151,7 +2166,7 @@ void EditorInspectorSection::_accessibility_action_expand(const Variant &p_data)
|
|
|
}
|
|
|
|
|
|
void EditorInspectorSection::unfold() {
|
|
|
- if (!foldable) {
|
|
|
+ if (!foldable && !hide_feature) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -2163,7 +2178,7 @@ void EditorInspectorSection::unfold() {
|
|
|
}
|
|
|
|
|
|
void EditorInspectorSection::fold() {
|
|
|
- if (!foldable) {
|
|
|
+ if (!foldable && !hide_feature) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -2187,23 +2202,32 @@ void EditorInspectorSection::reset_timer() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void EditorInspectorSection::set_checkable(const String &p_related_check_property) {
|
|
|
+void EditorInspectorSection::set_checkable(const String &p_related_check_property, bool p_hide_feature) {
|
|
|
if (checkable == !p_related_check_property.is_empty()) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+ hide_feature = p_hide_feature;
|
|
|
checkable = !p_related_check_property.is_empty();
|
|
|
related_enable_property = p_related_check_property;
|
|
|
queue_redraw();
|
|
|
-}
|
|
|
|
|
|
-void EditorInspectorSection::set_checked(bool p_checked) {
|
|
|
- if (checked == p_checked) {
|
|
|
- return;
|
|
|
+ if (InspectorDock::get_singleton()) {
|
|
|
+ if (checkable) {
|
|
|
+ InspectorDock::get_inspector_singleton()->connect("property_edited", callable_mp(this, &EditorInspectorSection::_property_edited));
|
|
|
+ } else {
|
|
|
+ InspectorDock::get_inspector_singleton()->disconnect("property_edited", callable_mp(this, &EditorInspectorSection::_property_edited));
|
|
|
+ }
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
+void EditorInspectorSection::set_checked(bool p_checked) {
|
|
|
checked = p_checked;
|
|
|
- queue_redraw();
|
|
|
+ if (hide_feature && !checked) {
|
|
|
+ fold();
|
|
|
+ } else {
|
|
|
+ unfold();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
bool EditorInspectorSection::has_revertable_properties() const {
|
|
@@ -2222,6 +2246,17 @@ void EditorInspectorSection::property_can_revert_changed(const String &p_path, b
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+void EditorInspectorSection::_property_edited(const String &p_property) {
|
|
|
+ if (!related_enable_property.is_empty() && p_property == related_enable_property) {
|
|
|
+ bool valid = false;
|
|
|
+ Variant value_checked = object->get(related_enable_property, &valid);
|
|
|
+
|
|
|
+ if (valid) {
|
|
|
+ set_checked(value_checked.operator bool());
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
void EditorInspectorSection::_bind_methods() {
|
|
|
ClassDB::bind_method(D_METHOD("setup", "section", "label", "object", "bg_color", "foldable", "indent_depth", "level"), &EditorInspectorSection::setup, DEFVAL(0), DEFVAL(1));
|
|
|
ClassDB::bind_method(D_METHOD("get_vbox"), &EditorInspectorSection::get_vbox);
|
|
@@ -2247,6 +2282,10 @@ EditorInspectorSection::~EditorInspectorSection() {
|
|
|
if (!vbox_added) {
|
|
|
memdelete(vbox);
|
|
|
}
|
|
|
+
|
|
|
+ if (checkable && InspectorDock::get_singleton()) {
|
|
|
+ InspectorDock::get_inspector_singleton()->disconnect("property_edited", callable_mp(this, &EditorInspectorSection::_property_edited));
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////
|
|
@@ -3461,8 +3500,10 @@ void EditorInspector::update_tree() {
|
|
|
String filter = search_box ? search_box->get_text() : "";
|
|
|
String group;
|
|
|
String group_base;
|
|
|
+ EditorInspectorSection *group_togglable_property = nullptr;
|
|
|
String subgroup;
|
|
|
String subgroup_base;
|
|
|
+ EditorInspectorSection *subgroup_togglable_property = nullptr;
|
|
|
int section_depth = 0;
|
|
|
bool disable_favorite = false;
|
|
|
VBoxContainer *category_vbox = nullptr;
|
|
@@ -3473,6 +3514,7 @@ void EditorInspector::update_tree() {
|
|
|
HashMap<VBoxContainer *, HashMap<String, VBoxContainer *>> vbox_per_path;
|
|
|
HashMap<String, EditorInspectorArray *> editor_inspector_array_per_prefix;
|
|
|
HashMap<String, HashMap<String, LocalVector<EditorProperty *>>> favorites_to_add;
|
|
|
+ HashMap<String, EditorInspectorSection *> togglable_editor_inspector_sections;
|
|
|
|
|
|
Color sscolor = get_theme_color(SNAME("prop_subsection"), EditorStringName(Editor));
|
|
|
bool sub_inspectors_enabled = EDITOR_GET("interface/inspector/open_resources_in_current_inspector");
|
|
@@ -3496,6 +3538,7 @@ void EditorInspector::update_tree() {
|
|
|
if (p.usage & PROPERTY_USAGE_SUBGROUP) {
|
|
|
// Setup a property sub-group.
|
|
|
subgroup = p.name;
|
|
|
+ subgroup_togglable_property = nullptr;
|
|
|
|
|
|
Vector<String> hint_parts = p.hint_string.split(",");
|
|
|
subgroup_base = hint_parts[0];
|
|
@@ -3510,6 +3553,7 @@ void EditorInspector::update_tree() {
|
|
|
} else if (p.usage & PROPERTY_USAGE_GROUP) {
|
|
|
// Setup a property group.
|
|
|
group = p.name;
|
|
|
+ group_togglable_property = nullptr;
|
|
|
|
|
|
Vector<String> hint_parts = p.hint_string.split(",");
|
|
|
group_base = hint_parts[0];
|
|
@@ -3521,6 +3565,7 @@ void EditorInspector::update_tree() {
|
|
|
|
|
|
subgroup = "";
|
|
|
subgroup_base = "";
|
|
|
+ subgroup_togglable_property = nullptr;
|
|
|
|
|
|
continue;
|
|
|
|
|
@@ -3528,8 +3573,10 @@ void EditorInspector::update_tree() {
|
|
|
// Setup a property category.
|
|
|
group = "";
|
|
|
group_base = "";
|
|
|
+ group_togglable_property = nullptr;
|
|
|
subgroup = "";
|
|
|
subgroup_base = "";
|
|
|
+ subgroup_togglable_property = nullptr;
|
|
|
section_depth = 0;
|
|
|
disable_favorite = false;
|
|
|
|
|
@@ -3710,6 +3757,7 @@ void EditorInspector::update_tree() {
|
|
|
// Keep it, this is used pretty often.
|
|
|
} else {
|
|
|
subgroup = ""; // The prefix changed, we are no longer in the subgroup.
|
|
|
+ subgroup_togglable_property = nullptr;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -3721,7 +3769,9 @@ void EditorInspector::update_tree() {
|
|
|
// Keep it, this is used pretty often.
|
|
|
} else {
|
|
|
group = ""; // The prefix changed, we are no longer in the group.
|
|
|
+ group_togglable_property = nullptr;
|
|
|
subgroup = "";
|
|
|
+ subgroup_togglable_property = nullptr;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -4034,9 +4084,7 @@ void EditorInspector::update_tree() {
|
|
|
F = dd->class_list.find(F->value.inherits);
|
|
|
}
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- if (use_doc_hints) {
|
|
|
// `|` separators used in `EditorHelpBit`.
|
|
|
if (theme_item_name.is_empty()) {
|
|
|
if (p.name.contains("shader_parameter/")) {
|
|
@@ -4063,9 +4111,15 @@ void EditorInspector::update_tree() {
|
|
|
Variant value_checked = object->get(p.name, &valid);
|
|
|
|
|
|
if (valid) {
|
|
|
- last_created_section->set_checkable(p.name);
|
|
|
+ last_created_section->set_checkable(p.name, p.hint_string == "feature");
|
|
|
last_created_section->set_checked(value_checked.operator bool());
|
|
|
|
|
|
+ if (p.name.begins_with(group_base)) {
|
|
|
+ group_togglable_property = last_created_section;
|
|
|
+ } else {
|
|
|
+ subgroup_togglable_property = last_created_section;
|
|
|
+ }
|
|
|
+
|
|
|
if (use_doc_hints) {
|
|
|
last_created_section->set_tooltip_text(doc_tooltip_text);
|
|
|
}
|
|
@@ -4149,19 +4203,6 @@ void EditorInspector::update_tree() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- Node *section_search = current_vbox->get_parent();
|
|
|
- while (section_search) {
|
|
|
- EditorInspectorSection *section = Object::cast_to<EditorInspectorSection>(section_search);
|
|
|
- if (section) {
|
|
|
- ep->connect("property_can_revert_changed", callable_mp(section, &EditorInspectorSection::property_can_revert_changed));
|
|
|
- }
|
|
|
- section_search = section_search->get_parent();
|
|
|
- if (Object::cast_to<EditorInspector>(section_search)) {
|
|
|
- // Skip sub-resource inspectors.
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
if (p.name.begins_with("metadata/")) {
|
|
|
Variant _default = Variant();
|
|
|
if (node != nullptr) {
|
|
@@ -4184,8 +4225,30 @@ void EditorInspector::update_tree() {
|
|
|
if (ep && ep->is_favoritable() && current_favorites.has(p.name)) {
|
|
|
ep->favorited = true;
|
|
|
favorites_to_add[group][subgroup].push_back(ep);
|
|
|
+
|
|
|
+ if (group_togglable_property) {
|
|
|
+ togglable_editor_inspector_sections[group] = group_togglable_property;
|
|
|
+ }
|
|
|
+ if (subgroup_togglable_property) {
|
|
|
+ togglable_editor_inspector_sections[group + "/" + subgroup] = subgroup_togglable_property;
|
|
|
+ }
|
|
|
} else {
|
|
|
current_vbox->add_child(editors[i].property_editor);
|
|
|
+
|
|
|
+ if (ep) {
|
|
|
+ Node *section_search = current_vbox->get_parent();
|
|
|
+ while (section_search) {
|
|
|
+ EditorInspectorSection *section = Object::cast_to<EditorInspectorSection>(section_search);
|
|
|
+ if (section) {
|
|
|
+ ep->connect("property_can_revert_changed", callable_mp(section, &EditorInspectorSection::property_can_revert_changed));
|
|
|
+ }
|
|
|
+ section_search = section_search->get_parent();
|
|
|
+ if (Object::cast_to<EditorInspector>(section_search)) {
|
|
|
+ // Skip sub-resource inspectors.
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
if (ep) {
|
|
@@ -4248,6 +4311,23 @@ void EditorInspector::update_tree() {
|
|
|
parent_vbox = section->get_vbox();
|
|
|
section->setup("", section_name, object, sscolor, false);
|
|
|
section->set_tooltip_text(tooltip);
|
|
|
+
|
|
|
+ if (togglable_editor_inspector_sections.has(section_name)) {
|
|
|
+ EditorInspectorSection *corresponding_section = togglable_editor_inspector_sections.get(section_name);
|
|
|
+
|
|
|
+ bool valid = false;
|
|
|
+ Variant value_checked = object->get(corresponding_section->related_enable_property, &valid);
|
|
|
+ if (valid) {
|
|
|
+ section->section = corresponding_section->section;
|
|
|
+ section->set_checkable(corresponding_section->related_enable_property, corresponding_section->hide_feature);
|
|
|
+ section->set_checked(value_checked.operator bool());
|
|
|
+ if (use_doc_hints) {
|
|
|
+ section->set_tooltip_text(corresponding_section->get_tooltip_text());
|
|
|
+ }
|
|
|
+
|
|
|
+ section->connect("section_toggled_by_user", callable_mp(this, &EditorInspector::_section_toggled_by_user));
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
for (const KeyValue<String, LocalVector<EditorProperty *>> &KV2 : KV.value) {
|
|
@@ -4268,11 +4348,41 @@ void EditorInspector::update_tree() {
|
|
|
vbox = section->get_vbox();
|
|
|
section->setup("", section_name, object, sscolor, false);
|
|
|
section->set_tooltip_text(tooltip);
|
|
|
+
|
|
|
+ if (togglable_editor_inspector_sections.has(KV.key + "/" + section_name)) {
|
|
|
+ EditorInspectorSection *corresponding_section = togglable_editor_inspector_sections.get(KV.key + "/" + section_name);
|
|
|
+
|
|
|
+ bool valid = false;
|
|
|
+ Variant value_checked = object->get(corresponding_section->related_enable_property, &valid);
|
|
|
+ if (valid) {
|
|
|
+ section->section = corresponding_section->section;
|
|
|
+ section->set_checkable(corresponding_section->related_enable_property, corresponding_section->hide_feature);
|
|
|
+ section->set_checked(value_checked.operator bool());
|
|
|
+ if (use_doc_hints) {
|
|
|
+ section->set_tooltip_text(corresponding_section->get_tooltip_text());
|
|
|
+ }
|
|
|
+
|
|
|
+ section->connect("section_toggled_by_user", callable_mp(this, &EditorInspector::_section_toggled_by_user));
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
for (EditorProperty *ep : KV2.value) {
|
|
|
vbox->add_child(ep);
|
|
|
|
|
|
+ Node *section_search = vbox->get_parent();
|
|
|
+ while (section_search) {
|
|
|
+ EditorInspectorSection *section = Object::cast_to<EditorInspectorSection>(section_search);
|
|
|
+ if (section) {
|
|
|
+ ep->connect("property_can_revert_changed", callable_mp(section, &EditorInspectorSection::property_can_revert_changed));
|
|
|
+ }
|
|
|
+ section_search = section_search->get_parent();
|
|
|
+ if (Object::cast_to<EditorInspector>(section_search)) {
|
|
|
+ // Skip sub-resource inspectors.
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
// Now that it's inside the tree, do the setup.
|
|
|
ep->update_property();
|
|
|
ep->_update_flags();
|