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:
parent
72f7131be1
commit
28038feb04
|
@ -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));
|
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;
|
FileSystemDock *FileSystemDock::singleton = nullptr;
|
||||||
|
|
||||||
Ref<Texture2D> FileSystemDock::_get_tree_item_icon(bool p_is_valid, String p_file_type) {
|
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() {
|
void FileSystemDock::_rename_operation_confirm() {
|
||||||
if (!tree->is_anything_selected()) {
|
String new_name;
|
||||||
return;
|
|
||||||
}
|
|
||||||
TreeItem *s = tree->get_selected();
|
TreeItem *s = tree->get_selected();
|
||||||
int col_index = tree->get_selected_column();
|
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();
|
String old_name = to_rename.is_file ? to_rename.path.get_file() : to_rename.path.left(-1).get_file();
|
||||||
|
|
||||||
bool rename_error = false;
|
bool rename_error = false;
|
||||||
|
@ -1607,10 +1697,12 @@ void FileSystemDock::_rename_operation_confirm() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restores Tree to restore original names.
|
// Restore original name.
|
||||||
if (rename_error) {
|
if (rename_error && tree->has_focus()) {
|
||||||
s->set_text(col_index, old_name);
|
s->set_text(col_index, old_name);
|
||||||
return;
|
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;
|
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;
|
} break;
|
||||||
|
|
||||||
case FILE_RENAME: {
|
case FILE_RENAME: {
|
||||||
if (tree->is_anything_selected() && !p_selected.is_empty()) {
|
if (!p_selected.is_empty()) {
|
||||||
// Set to_rename variable for callback execution.
|
// Set to_rename variable for callback execution.
|
||||||
to_rename.path = p_selected[0];
|
to_rename.path = p_selected[0];
|
||||||
to_rename.is_file = !to_rename.path.ends_with("/");
|
to_rename.is_file = !to_rename.path.ends_with("/");
|
||||||
|
if (to_rename.path == "res://") {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Edit node in Tree.
|
if (tree->has_focus()) {
|
||||||
tree->grab_focus();
|
// Edit node in Tree.
|
||||||
tree->edit_selected(true);
|
tree->edit_selected(true);
|
||||||
|
|
||||||
if (to_rename.is_file) {
|
if (to_rename.is_file) {
|
||||||
String name = to_rename.path.get_file();
|
String name = to_rename.path.get_file();
|
||||||
tree->set_editor_selection(0, name.rfind("."));
|
tree->set_editor_selection(0, name.rfind("."));
|
||||||
} else {
|
} else {
|
||||||
String name = to_rename.path.left(-1).get_file(); // Removes the "/" suffix for folders.
|
String name = to_rename.path.left(-1).get_file(); // Removes the "/" suffix for folders.
|
||||||
tree->set_editor_selection(0, name.length());
|
tree->set_editor_selection(0, name.length());
|
||||||
|
}
|
||||||
|
} else if (files->has_focus()) {
|
||||||
|
files->edit_selected();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
@ -3337,6 +3435,7 @@ FileSystemDock::FileSystemDock() {
|
||||||
files->connect("gui_input", callable_mp(this, &FileSystemDock::_file_list_gui_input));
|
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("multi_selected", callable_mp(this, &FileSystemDock::_file_multi_selected));
|
||||||
files->connect("empty_clicked", callable_mp(this, &FileSystemDock::_file_list_empty_clicked));
|
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_custom_minimum_size(Size2(0, 15 * EDSCALE));
|
||||||
files->set_allow_rmb_select(true);
|
files->set_allow_rmb_select(true);
|
||||||
file_list_vb->add_child(files);
|
file_list_vb->add_child(files);
|
||||||
|
|
|
@ -57,7 +57,24 @@ class FileSystemTree : public Tree {
|
||||||
};
|
};
|
||||||
|
|
||||||
class FileSystemList : public ItemList {
|
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 {
|
class FileSystemDock : public VBoxContainer {
|
||||||
|
|
Loading…
Reference in New Issue