diff --git a/doc/classes/TreeItem.xml b/doc/classes/TreeItem.xml index 78a703c213a..8f0c1f5cf05 100644 --- a/doc/classes/TreeItem.xml +++ b/doc/classes/TreeItem.xml @@ -223,6 +223,13 @@ Returns the [Color] modulating the column's icon. + + + + + Returns the given column's icon overlay [Texture2D]. + + @@ -662,6 +669,14 @@ Modulates the given column's icon with [param modulate]. + + + + + + Sets the given cell's icon overlay [Texture2D]. The cell has to be in [constant CELL_MODE_ICON] mode, and icon has to be set. Overlay is drawn on top of icon, in the bottom left corner. + + diff --git a/drivers/unix/dir_access_unix.cpp b/drivers/unix/dir_access_unix.cpp index a4208829b7d..e4bad880837 100644 --- a/drivers/unix/dir_access_unix.cpp +++ b/drivers/unix/dir_access_unix.cpp @@ -397,12 +397,18 @@ Error DirAccessUnix::rename(String p_path, String p_new_path) { } p_path = fix_path(p_path); + if (p_path.ends_with("/")) { + p_path = p_path.left(-1); + } if (p_new_path.is_relative_path()) { p_new_path = get_current_dir().path_join(p_new_path); } p_new_path = fix_path(p_new_path); + if (p_new_path.ends_with("/")) { + p_new_path = p_new_path.left(-1); + } return ::rename(p_path.utf8().get_data(), p_new_path.utf8().get_data()) == 0 ? OK : FAILED; } @@ -413,6 +419,9 @@ Error DirAccessUnix::remove(String p_path) { } p_path = fix_path(p_path); + if (p_path.ends_with("/")) { + p_path = p_path.left(-1); + } struct stat flags = {}; if ((stat(p_path.utf8().get_data(), &flags) != 0)) { @@ -432,6 +441,9 @@ bool DirAccessUnix::is_link(String p_file) { } p_file = fix_path(p_file); + if (p_file.ends_with("/")) { + p_file = p_file.left(-1); + } struct stat flags = {}; if ((lstat(p_file.utf8().get_data(), &flags) != 0)) { @@ -447,6 +459,9 @@ String DirAccessUnix::read_link(String p_file) { } p_file = fix_path(p_file); + if (p_file.ends_with("/")) { + p_file = p_file.left(-1); + } char buf[256]; memset(buf, 0, 256); diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index f7e81b329c2..8bf2fcbbda1 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -216,6 +216,7 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory // Set custom folder color (if applicable). bool has_custom_color = assigned_folder_colors.has(lpath); Color custom_color = has_custom_color ? folder_colors[assigned_folder_colors[lpath]] : Color(); + Ref da = DirAccess::create(DirAccess::ACCESS_RESOURCES); if (has_custom_color) { subdirectory_item->set_icon_modulate(0, editor_is_dark_theme ? custom_color : custom_color * ITEM_COLOR_SCALE); @@ -237,6 +238,10 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory subdirectory_item->set_text(0, dname); subdirectory_item->set_structured_text_bidi_override(0, TextServer::STRUCTURED_TEXT_FILE); subdirectory_item->set_icon(0, get_editor_theme_icon(SNAME("Folder"))); + if (da->is_link(lpath)) { + subdirectory_item->set_icon_overlay(0, get_editor_theme_icon(SNAME("LinkOverlay"))); + subdirectory_item->set_tooltip_text(0, vformat(TTR("Link to: %s"), da->read_link(lpath))); + } subdirectory_item->set_selectable(0, true); subdirectory_item->set_metadata(0, lpath); if (!p_select_in_favorites && (current_path == lpath || ((display_mode != DISPLAY_MODE_TREE_ONLY) && current_path.get_base_dir() == lpath))) { @@ -309,6 +314,10 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory file_item->set_text(0, fi.name); file_item->set_structured_text_bidi_override(0, TextServer::STRUCTURED_TEXT_FILE); file_item->set_icon(0, _get_tree_item_icon(!fi.import_broken, fi.type, fi.icon_path)); + if (da->is_link(file_metadata)) { + file_item->set_icon_overlay(0, get_editor_theme_icon(SNAME("LinkOverlay"))); + file_item->set_tooltip_text(0, vformat(TTR("Link to: %s"), da->read_link(file_metadata))); + } file_item->set_icon_max_width(0, icon_size); Color parent_bg_color = subdirectory_item->get_custom_bg_color(0); if (has_custom_color) { diff --git a/editor/icons/LinkOverlay.svg b/editor/icons/LinkOverlay.svg new file mode 100644 index 00000000000..b263f94c0b6 --- /dev/null +++ b/editor/icons/LinkOverlay.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index edd25d1d5c7..d00a5821cf0 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -62,8 +62,15 @@ void TreeItem::Cell::draw_icon(const RID &p_where, const Point2 &p_pos, const Si if (icon_region == Rect2i()) { icon->draw_rect_region(p_where, Rect2(p_pos, dsize), Rect2(Point2(), icon->get_size()), p_color); + if (icon_overlay.is_valid()) { + Vector2 offset = icon->get_size() - icon_overlay->get_size(); + icon_overlay->draw_rect_region(p_where, Rect2(p_pos + offset, dsize), Rect2(Point2(), icon_overlay->get_size()), p_color); + } } else { icon->draw_rect_region(p_where, Rect2(p_pos, dsize), icon_region, p_color); + if (icon_overlay.is_valid()) { + icon_overlay->draw_rect_region(p_where, Rect2(p_pos, dsize), icon_region, p_color); + } } } @@ -477,6 +484,24 @@ Ref TreeItem::get_icon(int p_column) const { return cells[p_column].icon; } +void TreeItem::set_icon_overlay(int p_column, const Ref &p_icon_overlay) { + ERR_FAIL_INDEX(p_column, cells.size()); + + if (cells[p_column].icon_overlay == p_icon_overlay) { + return; + } + + cells.write[p_column].icon_overlay = p_icon_overlay; + cells.write[p_column].cached_minimum_size_dirty = true; + + _changed_notify(p_column); +} + +Ref TreeItem::get_icon_overlay(int p_column) const { + ERR_FAIL_INDEX_V(p_column, cells.size(), Ref()); + return cells[p_column].icon_overlay; +} + void TreeItem::set_icon_region(int p_column, const Rect2 &p_icon_region) { ERR_FAIL_INDEX(p_column, cells.size()); @@ -1633,6 +1658,9 @@ void TreeItem::_bind_methods() { ClassDB::bind_method(D_METHOD("set_icon", "column", "texture"), &TreeItem::set_icon); ClassDB::bind_method(D_METHOD("get_icon", "column"), &TreeItem::get_icon); + ClassDB::bind_method(D_METHOD("set_icon_overlay", "column", "texture"), &TreeItem::set_icon_overlay); + ClassDB::bind_method(D_METHOD("get_icon_overlay", "column"), &TreeItem::get_icon_overlay); + ClassDB::bind_method(D_METHOD("set_icon_region", "column", "region"), &TreeItem::set_icon_region); ClassDB::bind_method(D_METHOD("get_icon_region", "column"), &TreeItem::get_icon_region); diff --git a/scene/gui/tree.h b/scene/gui/tree.h index 45187086854..17ea31a733f 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -60,6 +60,7 @@ private: TreeCellMode mode = TreeItem::CELL_MODE_STRING; Ref icon; + Ref icon_overlay; Rect2i icon_region; String text; String xl_text; @@ -257,6 +258,9 @@ public: void set_icon(int p_column, const Ref &p_icon); Ref get_icon(int p_column) const; + void set_icon_overlay(int p_column, const Ref &p_icon_overlay); + Ref get_icon_overlay(int p_column) const; + void set_icon_region(int p_column, const Rect2 &p_icon_region); Rect2 get_icon_region(int p_column) const;