Permits the renaming of files and folders inline for items in the FileSystemDock.

This is a continuation of: https://github.com/godotengine/godot/pull/76794 which didn't consider  DISPLAY_MODE_SPLIT.
Fixes: https://github.com/godotengine/godot/issues/77527 and https://github.com/godotengine/godot-proposals/issues/4933
This commit is contained in:
Wiwip 2023-05-26 17:04:14 -04:00
parent 72f7131be1
commit 28038feb04
2 changed files with 134 additions and 18 deletions

View File

@ -76,6 +76,94 @@ Control *FileSystemList::make_custom_tooltip(const String &p_text) const {
return FileSystemDock::get_singleton()->create_tooltip_for_path(get_item_metadata(idx));
}
void FileSystemList::_line_editor_submit(String p_text) {
popup_editor->hide();
emit_signal(SNAME("item_edited"));
queue_redraw();
}
bool FileSystemList::edit_selected() {
ERR_FAIL_COND_V_MSG(!is_anything_selected(), false, "No item selected.");
int s = get_current();
ensure_current_is_visible();
Rect2 rect;
Rect2 popup_rect;
Vector2 ofs;
Vector2 icon_size = get_item_icon(s)->get_size();
// Handles the different icon modes (TOP/LEFT).
switch (get_icon_mode()) {
case ItemList::ICON_MODE_LEFT:
rect = get_item_rect(s, true);
ofs = Vector2(0, Math::floor((MAX(line_editor->get_minimum_size().height, rect.size.height) - rect.size.height) / 2));
popup_rect.position = get_screen_position() + rect.position - ofs;
popup_rect.size = rect.size;
// Adjust for icon position and size.
popup_rect.size.x -= icon_size.x;
popup_rect.position.x += icon_size.x;
break;
case ItemList::ICON_MODE_TOP:
rect = get_item_rect(s, false);
popup_rect.position = get_screen_position() + rect.position;
popup_rect.size = rect.size;
// Adjust for icon position and size.
popup_rect.size.y -= icon_size.y;
popup_rect.position.y += icon_size.y;
break;
}
popup_editor->set_position(popup_rect.position);
popup_editor->set_size(popup_rect.size);
String name = get_item_text(s);
line_editor->set_text(name);
line_editor->select(0, name.rfind("."));
popup_editor->popup();
popup_editor->child_controls_changed();
line_editor->grab_focus();
return true;
}
String FileSystemList::get_edit_text() {
return line_editor->get_text();
}
void FileSystemList::_text_editor_popup_modal_close() {
if (Input::get_singleton()->is_key_pressed(Key::ESCAPE) ||
Input::get_singleton()->is_key_pressed(Key::KP_ENTER) ||
Input::get_singleton()->is_key_pressed(Key::ENTER)) {
return;
}
_line_editor_submit(line_editor->get_text());
}
void FileSystemList::_bind_methods() {
ADD_SIGNAL(MethodInfo("item_edited"));
}
FileSystemList::FileSystemList() {
popup_editor = memnew(Popup);
add_child(popup_editor);
popup_editor_vb = memnew(VBoxContainer);
popup_editor_vb->add_theme_constant_override("separation", 0);
popup_editor_vb->set_anchors_and_offsets_preset(PRESET_FULL_RECT);
popup_editor->add_child(popup_editor_vb);
line_editor = memnew(LineEdit);
line_editor->set_v_size_flags(SIZE_EXPAND_FILL);
popup_editor_vb->add_child(line_editor);
line_editor->connect("text_submitted", callable_mp(this, &FileSystemList::_line_editor_submit));
popup_editor->connect("popup_hide", callable_mp(this, &FileSystemList::_text_editor_popup_modal_close));
}
FileSystemDock *FileSystemDock::singleton = nullptr;
Ref<Texture2D> FileSystemDock::_get_tree_item_icon(bool p_is_valid, String p_file_type) {
@ -1581,13 +1669,15 @@ void FileSystemDock::_folder_removed(String p_folder) {
}
void FileSystemDock::_rename_operation_confirm() {
if (!tree->is_anything_selected()) {
return;
}
String new_name;
TreeItem *s = tree->get_selected();
int col_index = tree->get_selected_column();
String new_name = s->get_text(col_index);
new_name = new_name.strip_edges();
if (tree->has_focus()) {
new_name = s->get_text(col_index).strip_edges();
} else if (files->has_focus()) {
new_name = files->get_edit_text().strip_edges();
}
String old_name = to_rename.is_file ? to_rename.path.get_file() : to_rename.path.left(-1).get_file();
bool rename_error = false;
@ -1607,10 +1697,12 @@ void FileSystemDock::_rename_operation_confirm() {
}
}
// Restores Tree to restore original names.
if (rename_error) {
// Restore original name.
if (rename_error && tree->has_focus()) {
s->set_text(col_index, old_name);
return;
} else if (rename_error && files->has_focus()) {
return;
}
String old_path = to_rename.path.ends_with("/") ? to_rename.path.left(-1) : to_rename.path;
@ -2032,21 +2124,27 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
} break;
case FILE_RENAME: {
if (tree->is_anything_selected() && !p_selected.is_empty()) {
if (!p_selected.is_empty()) {
// Set to_rename variable for callback execution.
to_rename.path = p_selected[0];
to_rename.is_file = !to_rename.path.ends_with("/");
if (to_rename.path == "res://") {
break;
}
// Edit node in Tree.
tree->grab_focus();
tree->edit_selected(true);
if (tree->has_focus()) {
// Edit node in Tree.
tree->edit_selected(true);
if (to_rename.is_file) {
String name = to_rename.path.get_file();
tree->set_editor_selection(0, name.rfind("."));
} else {
String name = to_rename.path.left(-1).get_file(); // Removes the "/" suffix for folders.
tree->set_editor_selection(0, name.length());
if (to_rename.is_file) {
String name = to_rename.path.get_file();
tree->set_editor_selection(0, name.rfind("."));
} else {
String name = to_rename.path.left(-1).get_file(); // Removes the "/" suffix for folders.
tree->set_editor_selection(0, name.length());
}
} else if (files->has_focus()) {
files->edit_selected();
}
}
} break;
@ -3337,6 +3435,7 @@ FileSystemDock::FileSystemDock() {
files->connect("gui_input", callable_mp(this, &FileSystemDock::_file_list_gui_input));
files->connect("multi_selected", callable_mp(this, &FileSystemDock::_file_multi_selected));
files->connect("empty_clicked", callable_mp(this, &FileSystemDock::_file_list_empty_clicked));
files->connect("item_edited", callable_mp(this, &FileSystemDock::_rename_operation_confirm));
files->set_custom_minimum_size(Size2(0, 15 * EDSCALE));
files->set_allow_rmb_select(true);
file_list_vb->add_child(files);

View File

@ -57,7 +57,24 @@ class FileSystemTree : public Tree {
};
class FileSystemList : public ItemList {
virtual Control *make_custom_tooltip(const String &p_text) const;
GDCLASS(FileSystemList, ItemList);
VBoxContainer *popup_editor_vb = nullptr;
Popup *popup_editor = nullptr;
LineEdit *line_editor = nullptr;
virtual Control *make_custom_tooltip(const String &p_text) const override;
void _line_editor_submit(String p_text);
void _text_editor_popup_modal_close();
protected:
static void _bind_methods();
public:
bool edit_selected();
String get_edit_text();
FileSystemList();
};
class FileSystemDock : public VBoxContainer {