From 8805dd53257a7ca614e0befa7c9531bc95d93f32 Mon Sep 17 00:00:00 2001 From: Stelios Tsampas Date: Thu, 4 Nov 2021 18:28:29 +0200 Subject: [PATCH] Add path completer for PathEdit. Doesn't enumerate hidden folders right now unless the RootPath is re-set (Through the browse button) --- rare/components/tabs/games/__init__.py | 2 +- .../stylesheets/RareStyle/stylesheet.qss | 2 +- rare/utils/extra_widgets.py | 80 +++++++++++++++---- 3 files changed, 66 insertions(+), 18 deletions(-) diff --git a/rare/components/tabs/games/__init__.py b/rare/components/tabs/games/__init__.py index 524692bb..93f2a7c4 100644 --- a/rare/components/tabs/games/__init__.py +++ b/rare/components/tabs/games/__init__.py @@ -2,9 +2,9 @@ from logging import getLogger from PyQt5.QtCore import QSettings, QObjectCleanupHandler from PyQt5.QtWidgets import QStackedWidget, QVBoxLayout, QWidget +from legendary.models.game import Game, InstalledGame import rare.shared as shared -from legendary.models.game import Game, InstalledGame from rare.components.dialogs.uninstall_dialog import UninstallDialog from rare.ui.components.tabs.games.games_tab import Ui_GamesTab from rare.utils import legendary_utils diff --git a/rare/resources/stylesheets/RareStyle/stylesheet.qss b/rare/resources/stylesheets/RareStyle/stylesheet.qss index 14470b56..bd9adf83 100644 --- a/rare/resources/stylesheets/RareStyle/stylesheet.qss +++ b/rare/resources/stylesheets/RareStyle/stylesheet.qss @@ -254,7 +254,7 @@ QToolButton { border-radius: 2px; padding: 2px; padding-left: 6px; - padding-right: 6px + padding-right: 6px; } QPushButton::menu-indicator { subcontrol-position: right center; diff --git a/rare/utils/extra_widgets.py b/rare/utils/extra_widgets.py index 9fa9a453..321248df 100644 --- a/rare/utils/extra_widgets.py +++ b/rare/utils/extra_widgets.py @@ -5,11 +5,12 @@ from typing import Callable, Tuple import PIL from PIL import Image -from PyQt5.QtCore import Qt, QCoreApplication, QRect, QSize, QPoint, pyqtSignal +from PyQt5.QtCore import Qt, QCoreApplication, QRect, QSize, QPoint, pyqtSignal, QFileInfo from PyQt5.QtGui import QMovie, QPixmap, QFontMetrics from PyQt5.QtWidgets import QLayout, QStyle, QSizePolicy, QLabel, QFileDialog, QHBoxLayout, QWidget, QPushButton, \ - QStyleOptionTab, QStylePainter, QTabBar, QLineEdit, QToolButton, QTabWidget -from qtawesome import icon + QStyleOptionTab, QStylePainter, QTabBar, QLineEdit, QToolButton, QTabWidget, QCompleter, QFileSystemModel, \ + QStyledItemDelegate, QFileIconProvider +from qtawesome import icon as qta_icon from rare import resources_path, cache_dir from rare.utils.qt_requests import QtRequestManager @@ -130,6 +131,7 @@ class IndicatorLineEdit(QWidget): def __init__(self, text: str = "", ph_text: str = "", + completer: QCompleter = None, edit_func: Callable[[str], Tuple[bool, str]] = None, save_func: Callable[[str], None] = None, horiz_policy: QSizePolicy = QSizePolicy.Expanding, @@ -143,10 +145,13 @@ class IndicatorLineEdit(QWidget): self.line_edit.setObjectName("line_edit") self.line_edit.setPlaceholderText(ph_text) self.line_edit.setSizePolicy(horiz_policy, QSizePolicy.Fixed) + if completer is not None: + completer.popup().setItemDelegate(QStyledItemDelegate(self)) + self.line_edit.setCompleter(completer) self.layout.addWidget(self.line_edit) if edit_func is not None: self.indicator_label = QLabel() - self.indicator_label.setPixmap(icon("ei.info-circle", color="gray").pixmap(16, 16)) + self.indicator_label.setPixmap(qta_icon("ei.info-circle", color="gray").pixmap(16, 16)) self.indicator_label.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.layout.addWidget(self.indicator_label) @@ -177,7 +182,7 @@ class IndicatorLineEdit(QWidget): def __indicator(self, res): color = "green" if res else "red" - self.indicator_label.setPixmap(icon("ei.info-circle", color=color).pixmap(16, 16)) + self.indicator_label.setPixmap(qta_icon("ei.info-circle", color=color).pixmap(16, 16)) def __edit(self, text): if self.edit_func is not None: @@ -195,7 +200,43 @@ class IndicatorLineEdit(QWidget): self.save_func(text) +class PathEditIconProvider(QFileIconProvider): + icons = [ + 'mdi.file-cancel', # Unknown + 'mdi.desktop-classic', # Computer + 'mdi.desktop-mac', # Desktop + 'mdi.trash-can', # Trashcan + 'mdi.server-network', # Network + 'mdi.harddisk', # Drive + 'mdi.folder', # Folder + 'mdi.file', # File + 'mdi.cog', # Executable + ] + + def __init__(self): + super(PathEditIconProvider, self).__init__() + self.icon_types = dict() + for idx, icn in enumerate(self.icons): + self.icon_types.update({idx-1: qta_icon(icn, color='#eeeeee')}) + + def icon(self, info_type): + if isinstance(info_type, QFileInfo): + if info_type.isRoot(): + return self.icon_types[4] + if info_type.isDir(): + return self.icon_types[5] + if info_type.isFile(): + return self.icon_types[6] + if info_type.isExecutable(): + return self.icon_types[7] + return self.icon_types[-1] + return self.icon_types[int(info_type)] + + class PathEdit(IndicatorLineEdit): + compl = QCompleter() + compl_model = QFileSystemModel() + def __init__(self, path: str = "", file_type: QFileDialog.FileType = QFileDialog.AnyFile, @@ -206,7 +247,13 @@ class PathEdit(IndicatorLineEdit): save_func: Callable[[str], None] = None, horiz_policy: QSizePolicy = QSizePolicy.Expanding, parent=None): - super(PathEdit, self).__init__(text=path, ph_text=ph_text, + self.compl_model.setOptions(QFileSystemModel.DontWatchForChanges | + QFileSystemModel.DontResolveSymlinks | + QFileSystemModel.DontUseCustomDirectoryIcons) + self.compl_model.setIconProvider(PathEditIconProvider()) + self.compl_model.setRootPath(path) + self.compl.setModel(self.compl_model) + super(PathEdit, self).__init__(text=path, ph_text=ph_text, completer=self.compl, edit_func=edit_func, save_func=save_func, horiz_policy=horiz_policy, parent=parent) self.setObjectName("PathEdit") @@ -237,6 +284,7 @@ class PathEdit(IndicatorLineEdit): if dlg.exec_(): names = dlg.selectedFiles() self.line_edit.setText(names[0]) + self.compl_model.setRootPath(names[0]) class SideTabBar(QTabBar): @@ -280,7 +328,7 @@ class SideTabWidget(QTabWidget): self.setTabBar(SideTabBar()) self.setTabPosition(QTabWidget.West) if show_back: - self.addTab(QWidget(), icon("mdi.keyboard-backspace"), self.tr("Back")) + self.addTab(QWidget(), qta_icon("mdi.keyboard-backspace"), self.tr("Back")) self.tabBarClicked.connect(self.back_func) def back_func(self, tab): @@ -311,11 +359,11 @@ class SelectViewWidget(QWidget): self.icon_view_button = QPushButton() self.list_view = QPushButton() if icon_view: - self.icon_view_button.setIcon(icon("mdi.view-grid-outline", color="orange")) - self.list_view.setIcon(icon("fa5s.list")) + self.icon_view_button.setIcon(qta_icon("mdi.view-grid-outline", color="orange")) + self.list_view.setIcon(qta_icon("fa5s.list")) else: - self.icon_view_button.setIcon(icon("mdi.view-grid-outline")) - self.list_view.setIcon(icon("fa5s.list", color="orange")) + self.icon_view_button.setIcon(qta_icon("mdi.view-grid-outline")) + self.list_view.setIcon(qta_icon("fa5s.list", color="orange")) self.icon_view_button.clicked.connect(self.icon) self.list_view.clicked.connect(self.list) @@ -330,14 +378,14 @@ class SelectViewWidget(QWidget): return self.icon_view def icon(self): - self.icon_view_button.setIcon(icon("mdi.view-grid-outline", color="orange")) - self.list_view.setIcon(icon("fa5s.list")) + self.icon_view_button.setIcon(qta_icon("mdi.view-grid-outline", color="orange")) + self.list_view.setIcon(qta_icon("fa5s.list")) self.icon_view = False self.toggled.emit() def list(self): - self.icon_view_button.setIcon(icon("mdi.view-grid-outline")) - self.list_view.setIcon(icon("fa5s.list", color="orange")) + self.icon_view_button.setIcon(qta_icon("mdi.view-grid-outline")) + self.list_view.setIcon(qta_icon("fa5s.list", color="orange")) self.icon_view = True self.toggled.emit() @@ -401,7 +449,7 @@ class ButtonLineEdit(QLineEdit): super(ButtonLineEdit, self).__init__(parent) self.button = QToolButton(self) - self.button.setIcon(icon(icon_name, color="white")) + self.button.setIcon(qta_icon(icon_name, color="white")) self.button.setStyleSheet('border: 0px; padding: 0px;') self.button.setCursor(Qt.ArrowCursor) self.button.clicked.connect(self.buttonClicked.emit)