Browse Source

Merge pull request #58842 from IgorKordiukiewicz/save-as-scene-visual-feedback

Added visual feedback when drag and dropping from scene tree to filesystem
Rémi Verschelde 3 years ago
parent
commit
1fbd498307
2 changed files with 129 additions and 0 deletions
  1. 122 0
      editor/filesystem_dock.cpp
  2. 7 0
      editor/filesystem_dock.h

+ 122 - 0
editor/filesystem_dock.cpp

@@ -396,12 +396,25 @@ void FileSystemDock::_notification(int p_what) {
 					}
 				} else if ((String(dd["type"]) == "files") || (String(dd["type"]) == "files_and_dirs") || (String(dd["type"]) == "resource")) {
 					tree->set_drop_mode_flags(Tree::DROP_MODE_ON_ITEM | Tree::DROP_MODE_INBETWEEN);
+				} else if ((String(dd["type"]) == "nodes")) {
+					holding_branch = true;
+					TreeItem *item = tree->get_next_selected(tree->get_root());
+					while (item) {
+						tree_items_selected_on_drag_begin.push_back(item);
+						item = tree->get_next_selected(item);
+					}
+					list_items_selected_on_drag_begin = files->get_selected_items();
 				}
 			}
 		} break;
 
 		case NOTIFICATION_DRAG_END: {
 			tree->set_drop_mode_flags(0);
+
+			if (holding_branch) {
+				holding_branch = false;
+				_reselect_items_selected_on_drag_begin(true);
+			}
 		} break;
 
 		case NOTIFICATION_THEME_CHANGED: {
@@ -2647,8 +2660,79 @@ void FileSystemDock::_file_multi_selected(int p_index, bool p_selected) {
 	call_deferred(SNAME("_update_import_dock"));
 }
 
+void FileSystemDock::_tree_mouse_exited() {
+	if (holding_branch) {
+		_reselect_items_selected_on_drag_begin();
+	}
+}
+
+void FileSystemDock::_reselect_items_selected_on_drag_begin(bool reset) {
+	TreeItem *selected_item = tree->get_next_selected(tree->get_root());
+	if (selected_item) {
+		selected_item->deselect(0);
+	}
+	if (!tree_items_selected_on_drag_begin.is_empty()) {
+		bool reselected = false;
+		for (TreeItem *item : tree_items_selected_on_drag_begin) {
+			if (item->get_tree()) {
+				item->select(0);
+				reselected = true;
+			}
+		}
+
+		if (reset) {
+			tree_items_selected_on_drag_begin.clear();
+		}
+
+		if (!reselected) {
+			// If couldn't reselect the items selected on drag begin, select the "res://" item.
+			tree->get_root()->get_child(1)->select(0);
+		}
+	}
+
+	files->deselect_all();
+	if (!list_items_selected_on_drag_begin.is_empty()) {
+		for (const int idx : list_items_selected_on_drag_begin) {
+			files->select(idx, false);
+		}
+
+		if (reset) {
+			list_items_selected_on_drag_begin.clear();
+		}
+	}
+}
+
 void FileSystemDock::_tree_gui_input(Ref<InputEvent> p_event) {
 	Ref<InputEventKey> key = p_event;
+
+	Ref<InputEventMouseMotion> mm = p_event;
+	if (mm.is_valid()) {
+		TreeItem *item = tree->get_item_at_position(mm->get_position());
+		if (item && holding_branch) {
+			String fpath = item->get_metadata(0);
+			while (!fpath.ends_with("/") && fpath != "res://" && item->get_parent()) { // Find the parent folder tree item.
+				item = item->get_parent();
+				fpath = item->get_metadata(0);
+			}
+
+			TreeItem *deselect_item = tree->get_next_selected(tree->get_root());
+			while (deselect_item) {
+				deselect_item->deselect(0);
+				deselect_item = tree->get_next_selected(deselect_item);
+			}
+			item->select(0);
+
+			if (display_mode == DisplayMode::DISPLAY_MODE_SPLIT) {
+				files->deselect_all();
+				// Try to select the corresponding file list item.
+				const int files_item_idx = files->find_metadata(fpath);
+				if (files_item_idx != -1) {
+					files->select(files_item_idx);
+				}
+			}
+		}
+	}
+
 	if (key.is_valid() && key->is_pressed() && !key->is_echo()) {
 		if (ED_IS_SHORTCUT("filesystem_dock/duplicate", p_event)) {
 			_tree_rmb_option(FILE_DUPLICATE);
@@ -2669,6 +2753,43 @@ void FileSystemDock::_tree_gui_input(Ref<InputEvent> p_event) {
 }
 
 void FileSystemDock::_file_list_gui_input(Ref<InputEvent> p_event) {
+	Ref<InputEventMouseMotion> mm = p_event;
+	if (mm.is_valid() && holding_branch) {
+		const int item_idx = files->get_item_at_position(mm->get_position());
+		if (item_idx != -1) {
+			files->deselect_all();
+			String fpath = files->get_item_metadata(item_idx);
+			if (fpath.ends_with("/") || fpath == "res://") {
+				files->select(item_idx);
+			}
+
+			TreeItem *deselect_item = tree->get_next_selected(tree->get_root());
+			while (deselect_item) {
+				deselect_item->deselect(0);
+				deselect_item = tree->get_next_selected(deselect_item);
+			}
+
+			// Try to select the corresponding tree item.
+			TreeItem *tree_item = tree->get_item_with_text(files->get_item_text(item_idx));
+			if (tree_item) {
+				tree_item->select(0);
+			} else {
+				// Find parent folder.
+				fpath = fpath.substr(0, fpath.rfind("/") + 1);
+				if (fpath.size() > String("res://").size()) {
+					fpath = fpath.left(fpath.size() - 2); // Remove last '/'.
+					const int slash_idx = fpath.rfind("/");
+					fpath = fpath.substr(slash_idx + 1, fpath.size() - slash_idx - 1);
+				}
+
+				tree_item = tree->get_item_with_text(fpath);
+				if (tree_item) {
+					tree_item->select(0);
+				}
+			}
+		}
+	}
+
 	Ref<InputEventKey> key = p_event;
 	if (key.is_valid() && key->is_pressed() && !key->is_echo()) {
 		if (ED_IS_SHORTCUT("filesystem_dock/duplicate", p_event)) {
@@ -2932,6 +3053,7 @@ FileSystemDock::FileSystemDock() {
 	tree->connect("empty_rmb", callable_mp(this, &FileSystemDock::_tree_rmb_empty));
 	tree->connect("nothing_selected", callable_mp(this, &FileSystemDock::_tree_empty_selected));
 	tree->connect("gui_input", callable_mp(this, &FileSystemDock::_tree_gui_input));
+	tree->connect("mouse_exited", callable_mp(this, &FileSystemDock::_tree_mouse_exited));
 
 	file_list_vb = memnew(VBoxContainer);
 	file_list_vb->set_v_size_flags(SIZE_EXPAND_FILL);

+ 7 - 0
editor/filesystem_dock.h

@@ -185,6 +185,13 @@ private:
 	ItemList *files;
 	bool import_dock_needs_update;
 
+	bool holding_branch = false;
+	Vector<TreeItem *> tree_items_selected_on_drag_begin;
+	PackedInt32Array list_items_selected_on_drag_begin;
+
+	void _tree_mouse_exited();
+	void _reselect_items_selected_on_drag_begin(bool reset = false);
+
 	Ref<Texture2D> _get_tree_item_icon(bool p_is_valid, String p_file_type);
 	bool _create_tree(TreeItem *p_parent, EditorFileSystemDirectory *p_dir, Vector<String> &uncollapsed_paths, bool p_select_in_favorites, bool p_unfold_path = false);
 	Vector<String> _compute_uncollapsed_paths();