From 0bc15be1f67ec5eac944cc5e159db196375dffa6 Mon Sep 17 00:00:00 2001 From: Dummerle <44114474+Dummerle@users.noreply.github.com> Date: Wed, 5 Jan 2022 15:44:29 +0100 Subject: [PATCH] Fix Icon error for Ubuntu LTS, which uses QtAwesome 0.4.4 --- rare/components/dialogs/uninstall_dialog.py | 2 +- rare/components/tabs/__init__.py | 4 +- .../tabs/downloads/dl_queue_widget.py | 2 +- .../components/tabs/games/cloud_save_utils.py | 53 +++++++++----- .../tabs/games/game_info/game_settings.py | 2 +- .../game_widgets/installed_icon_widget.py | 2 +- .../game_widgets/installed_list_widget.py | 2 +- rare/components/tabs/games/head_bar.py | 6 +- rare/components/tabs/settings/rpc.py | 9 +-- .../tabs/settings/ubisoft_activation.py | 2 +- rare/components/tabs/shop/game_info.py | 6 +- rare/components/tabs/shop/game_widgets.py | 2 +- rare/components/tabs/shop/wishlist.py | 2 +- rare/components/tabs/tab_utils.py | 7 +- rare/utils/extra_widgets.py | 73 ++++++++++--------- rare/utils/utils.py | 35 ++++++--- 16 files changed, 120 insertions(+), 89 deletions(-) diff --git a/rare/components/dialogs/uninstall_dialog.py b/rare/components/dialogs/uninstall_dialog.py index 9a9afb9c..13caab00 100644 --- a/rare/components/dialogs/uninstall_dialog.py +++ b/rare/components/dialogs/uninstall_dialog.py @@ -8,9 +8,9 @@ from PyQt5.QtWidgets import ( QHBoxLayout, QPushButton, ) -from qtawesome import icon from legendary.models.game import Game +from rare.utils.utils import icon class UninstallDialog(QDialog): diff --git a/rare/components/tabs/__init__.py b/rare/components/tabs/__init__.py index bf48e3c5..29e8bcd5 100644 --- a/rare/components/tabs/__init__.py +++ b/rare/components/tabs/__init__.py @@ -1,6 +1,5 @@ from PyQt5.QtCore import QSize from PyQt5.QtWidgets import QMenu, QTabWidget, QWidget, QWidgetAction, QShortcut -from qtawesome import icon from rare import shared from rare.components.tabs.account import MiniWidget @@ -10,6 +9,7 @@ from rare.components.tabs.settings import SettingsTab from rare.components.tabs.settings.debug import DebugSettings from rare.components.tabs.shop import Shop from rare.components.tabs.tab_utils import MainTabBar, TabButtonWidget +from rare.utils.utils import icon class TabWidget(QTabWidget): @@ -56,7 +56,7 @@ class TabWidget(QTabWidget): self.mini_widget = MiniWidget() account_action = QWidgetAction(self) account_action.setDefaultWidget(self.mini_widget) - account_button = TabButtonWidget("mdi.account-circle", "Account") + account_button = TabButtonWidget("mdi.account-circle", "Account", fallback_icon="fa.user") account_button.setMenu(QMenu()) account_button.menu().addAction(account_action) self.tabBar().setTabButton( diff --git a/rare/components/tabs/downloads/dl_queue_widget.py b/rare/components/tabs/downloads/dl_queue_widget.py index 8b3d823d..d507de20 100644 --- a/rare/components/tabs/downloads/dl_queue_widget.py +++ b/rare/components/tabs/downloads/dl_queue_widget.py @@ -9,9 +9,9 @@ from PyQt5.QtWidgets import ( QPushButton, QWidget, ) -from qtawesome import icon from rare.utils.models import InstallQueueItemModel +from rare.utils.utils import icon logger = getLogger("QueueWidget") diff --git a/rare/components/tabs/games/cloud_save_utils.py b/rare/components/tabs/games/cloud_save_utils.py index a2da20aa..78353332 100644 --- a/rare/components/tabs/games/cloud_save_utils.py +++ b/rare/components/tabs/games/cloud_save_utils.py @@ -1,15 +1,17 @@ import datetime +import sys from dataclasses import dataclass from logging import getLogger from typing import Union, List from PyQt5.QtCore import QObject, pyqtSignal, QRunnable, QThreadPool, Qt, QSettings -from PyQt5.QtWidgets import QDialog, QMessageBox, QSizePolicy, QLayout -from qtawesome import icon +from PyQt5.QtWidgets import QDialog, QMessageBox, QSizePolicy, QLayout, QApplication +from legendary.core import LegendaryCore from legendary.models.game import SaveGameStatus, InstalledGame, SaveGameFile from rare import shared from rare.ui.components.dialogs.sync_save_dialog import Ui_SyncSaveDialog +from rare.utils.utils import icon logger = getLogger("Cloud Saves") @@ -76,11 +78,11 @@ class CloudSaveDialog(QDialog, Ui_SyncSaveDialog): CANCEL = 0 def __init__( - self, - igame: InstalledGame, - dt_local: datetime.datetime, - dt_remote: datetime.datetime, - newer: str, + self, + igame: InstalledGame, + dt_local: datetime.datetime, + dt_remote: datetime.datetime, + newer: str, ): super(CloudSaveDialog, self).__init__() self.setupUi(self) @@ -101,8 +103,8 @@ class CloudSaveDialog(QDialog, Ui_SyncSaveDialog): elif newer == "local": self.local_gb.setTitle(self.local_gb.title() + new_text) - self.icon_local.setPixmap(icon("mdi.harddisk").pixmap(128, 128)) - self.icon_remote.setPixmap(icon("mdi.cloud-outline").pixmap(128, 128)) + self.icon_local.setPixmap(icon("mdi.harddisk", "fa.desktop").pixmap(128, 128)) + self.icon_remote.setPixmap(icon("mdi.cloud-outline", "ei.cloud").pixmap(128, 128)) self.upload_button.clicked.connect(lambda: self.btn_clicked(self.UPLOAD)) self.download_button.clicked.connect(lambda: self.btn_clicked(self.DOWNLOAD)) @@ -168,16 +170,16 @@ class CloudSaveUtils(QObject): logger.info(f"Set save path of {igame.title} to {savepath}") elif not ignore_settings: # sync on startup if ( - QMessageBox.question( - None, - "Warning", - self.tr( - "Could not compute cloud save path. Please set it in Game settings manually. \nDo you want to launch {} anyway?" - ).format(igame.title), - QMessageBox.Yes | QMessageBox.No, - QMessageBox.No, - ) - == QMessageBox.Yes + QMessageBox.question( + None, + "Warning", + self.tr( + "Could not compute cloud save path. Please set it in Game settings manually. \nDo you want to launch {} anyway?" + ).format(igame.title), + QMessageBox.Yes | QMessageBox.No, + QMessageBox.No, + ) + == QMessageBox.Yes ): return False else: @@ -313,3 +315,16 @@ class CloudSaveUtils(QObject): self.tr("Syncing with cloud failed: \n ") + error_message, ) self.sync_finished.emit(app_name) + + +def test_dialog(): + app = QApplication(sys.argv) + core = LegendaryCore() + dlg = CloudSaveDialog(core.get_installed_list()[0], datetime.datetime.now(), + datetime.datetime.strptime("2021,1", "%Y,%M"), "local") + dlg.show() + app.exec_() + + +if __name__ == '__main__': + test_dialog() diff --git a/rare/components/tabs/games/game_info/game_settings.py b/rare/components/tabs/games/game_info/game_settings.py index e051e929..ff7bf701 100644 --- a/rare/components/tabs/games/game_info/game_settings.py +++ b/rare/components/tabs/games/game_info/game_settings.py @@ -12,7 +12,6 @@ from PyQt5.QtWidgets import ( QPushButton, QSizePolicy, ) -from qtawesome import icon from legendary.core import LegendaryCore from legendary.models.game import InstalledGame, Game @@ -20,6 +19,7 @@ from rare.components.tabs.settings.linux import LinuxSettings from rare.ui.components.tabs.games.game_info.game_settings import Ui_GameSettings from rare.utils.extra_widgets import PathEdit from rare.utils.utils import WineResolver, get_raw_save_path +from rare.utils.utils import icon logger = getLogger("GameSettings") diff --git a/rare/components/tabs/games/game_widgets/installed_icon_widget.py b/rare/components/tabs/games/game_widgets/installed_icon_widget.py index fa3068b6..9f958911 100644 --- a/rare/components/tabs/games/game_widgets/installed_icon_widget.py +++ b/rare/components/tabs/games/game_widgets/installed_icon_widget.py @@ -3,12 +3,12 @@ from logging import getLogger from PyQt5.QtCore import QEvent, pyqtSignal, QSize, Qt from PyQt5.QtGui import QMouseEvent from PyQt5.QtWidgets import QVBoxLayout, QHBoxLayout, QPushButton, QLabel -from qtawesome import icon from rare import shared from rare.components.tabs.games.game_widgets.base_installed_widget import ( BaseInstalledWidget, ) +from rare.utils.utils import icon logger = getLogger("GameWidgetInstalled") diff --git a/rare/components/tabs/games/game_widgets/installed_list_widget.py b/rare/components/tabs/games/game_widgets/installed_list_widget.py index ef69a83a..008316a1 100644 --- a/rare/components/tabs/games/game_widgets/installed_list_widget.py +++ b/rare/components/tabs/games/game_widgets/installed_list_widget.py @@ -2,12 +2,12 @@ from logging import getLogger from PyQt5.QtCore import QProcess, pyqtSignal, Qt from PyQt5.QtWidgets import QHBoxLayout, QLabel, QPushButton, QVBoxLayout -from qtawesome import icon from rare.components.tabs.games.game_widgets.base_installed_widget import ( BaseInstalledWidget, ) from rare.utils.utils import get_size +from rare.utils.utils import icon logger = getLogger("GameWidget") diff --git a/rare/components/tabs/games/head_bar.py b/rare/components/tabs/games/head_bar.py index 7652f05c..1448c9f8 100644 --- a/rare/components/tabs/games/head_bar.py +++ b/rare/components/tabs/games/head_bar.py @@ -7,10 +7,10 @@ from PyQt5.QtWidgets import ( QHBoxLayout, QComboBox, ) -from qtawesome import icon from rare import shared from rare.utils.extra_widgets import SelectViewWidget +from rare.utils.utils import icon class GameListHeadBar(QWidget): @@ -62,11 +62,11 @@ class GameListHeadBar(QWidget): self.filter.currentIndexChanged.connect(self.filter_changed) self.layout().addStretch(1) - self.import_game = QPushButton(icon("mdi.import"), self.tr("Import Game")) + self.import_game = QPushButton(icon("mdi.import", "fa.arrow-down"), self.tr("Import Game")) self.import_clicked = self.import_game.clicked self.layout().addWidget(self.import_game) - self.egl_sync = QPushButton(icon("mdi.sync"), self.tr("Sync with EGL")) + self.egl_sync = QPushButton(icon("mdi.sync", "fa.refresh"), self.tr("Sync with EGL")) self.egl_sync_clicked = self.egl_sync.clicked self.layout().addWidget(self.egl_sync) # FIXME: Until it is ready diff --git a/rare/components/tabs/settings/rpc.py b/rare/components/tabs/settings/rpc.py index 03c03a3d..bf51e78c 100644 --- a/rare/components/tabs/settings/rpc.py +++ b/rare/components/tabs/settings/rpc.py @@ -1,14 +1,12 @@ -from PyQt5.QtCore import QSettings, pyqtSignal +from PyQt5.QtCore import QSettings from PyQt5.QtWidgets import QGroupBox from rare.ui.components.tabs.settings.rpc import Ui_RPCSettings class RPCSettings(QGroupBox, Ui_RPCSettings): - update_settings = pyqtSignal() - - def __init__(self): - super(RPCSettings, self).__init__() + def __init__(self, parent): + super(RPCSettings, self).__init__(parent=parent) self.setupUi(self) self.settings = QSettings() @@ -33,4 +31,3 @@ class RPCSettings(QGroupBox, Ui_RPCSettings): def changed(self, i): self.settings.setValue("rpc_enable", i) - self.update_settings.emit() diff --git a/rare/components/tabs/settings/ubisoft_activation.py b/rare/components/tabs/settings/ubisoft_activation.py index 203b50aa..eb123e71 100644 --- a/rare/components/tabs/settings/ubisoft_activation.py +++ b/rare/components/tabs/settings/ubisoft_activation.py @@ -4,10 +4,10 @@ from logging import getLogger from PyQt5.QtCore import QObject, pyqtSignal, QRunnable, QThreadPool, QSize from PyQt5.QtWidgets import QWidget, QLabel, QHBoxLayout, QSizePolicy, QPushButton -from qtawesome import icon from legendary.models.game import Game from rare import shared +from rare.utils.utils import icon logger = getLogger("Ubisoft") diff --git a/rare/components/tabs/shop/game_info.py b/rare/components/tabs/shop/game_info.py index c3201f2f..54e35f26 100644 --- a/rare/components/tabs/shop/game_info.py +++ b/rare/components/tabs/shop/game_info.py @@ -13,12 +13,12 @@ from PyQt5.QtWidgets import ( QTabWidget, QGridLayout, ) -from qtawesome import icon from rare import shared from rare.components.tabs.shop.shop_models import ShopGame from rare.ui.components.tabs.store.shop_game_info import Ui_shop_info from rare.utils.extra_widgets import WaitingSpinner, ImageLabel +from rare.utils.utils import icon logger = logging.getLogger("ShopInfo") @@ -234,10 +234,10 @@ class ShopGameInfo(QWidget, Ui_shop_info): for name, url in self.game.links: if name.lower() == "homepage": - icn = icon("mdi.web", scale_factor=1.5) + icn = icon("mdi.web", "fa.search", scale_factor=1.5) else: try: - icn = icon("mdi." + name.lower(), scale_factor=1.5) + icn = icon("mdi." + name.lower(), "fa." + name.lower(), scale_factor=1.5) except Exception as e: logger.error(str(e)) continue diff --git a/rare/components/tabs/shop/game_widgets.py b/rare/components/tabs/shop/game_widgets.py index eaa719be..9e985a94 100644 --- a/rare/components/tabs/shop/game_widgets.py +++ b/rare/components/tabs/shop/game_widgets.py @@ -5,11 +5,11 @@ from PyQt5.QtCore import pyqtSignal from PyQt5.QtGui import QFont from PyQt5.QtNetwork import QNetworkAccessManager from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QHBoxLayout -from qtawesome import icon from rare.components.tabs.shop.shop_models import ImageUrlModel from rare.ui.components.tabs.store.wishlist_widget import Ui_WishlistWidget from rare.utils.extra_widgets import ImageLabel +from rare.utils.utils import icon logger = logging.getLogger("GameWidgets") diff --git a/rare/components/tabs/shop/wishlist.py b/rare/components/tabs/shop/wishlist.py index d49b2a78..d9b40c4a 100644 --- a/rare/components/tabs/shop/wishlist.py +++ b/rare/components/tabs/shop/wishlist.py @@ -1,11 +1,11 @@ from PyQt5.QtCore import pyqtSignal from PyQt5.QtWidgets import QStackedWidget, QMessageBox -from qtawesome import icon from rare.components.tabs.shop import ShopApiCore from rare.components.tabs.shop.game_widgets import WishlistWidget from rare.ui.components.tabs.store.wishlist import Ui_Wishlist from rare.utils.extra_widgets import WaitingSpinner +from rare.utils.utils import icon class Wishlist(QStackedWidget, Ui_Wishlist): diff --git a/rare/components/tabs/tab_utils.py b/rare/components/tabs/tab_utils.py index 788dc859..8d545352 100644 --- a/rare/components/tabs/tab_utils.py +++ b/rare/components/tabs/tab_utils.py @@ -1,6 +1,7 @@ from PyQt5.QtCore import QSize from PyQt5.QtWidgets import QTabBar, QToolButton -from qtawesome import icon + +from rare.utils.utils import icon class MainTabBar(QTabBar): @@ -25,10 +26,10 @@ class MainTabBar(QTabBar): class TabButtonWidget(QToolButton): - def __init__(self, button_icon: str, tool_tip: str): + def __init__(self, button_icon: str, tool_tip: str, fallback_icon=None): super(TabButtonWidget, self).__init__() self.setText("Icon") self.setPopupMode(QToolButton.InstantPopup) - self.setIcon(icon(button_icon, scale_factor=1.25)) + self.setIcon(icon(button_icon, fallback_icon, scale_factor=1.25)) self.setToolTip(tool_tip) self.setIconSize(QSize(25, 25)) diff --git a/rare/utils/extra_widgets.py b/rare/utils/extra_widgets.py index 3ded2fba..b40dbc65 100644 --- a/rare/utils/extra_widgets.py +++ b/rare/utils/extra_widgets.py @@ -32,10 +32,10 @@ from PyQt5.QtWidgets import ( QStyledItemDelegate, QFileIconProvider, ) -from qtawesome import icon as qta_icon from rare import cache_dir from rare.utils.qt_requests import QtRequestManager +from rare.utils.utils import icon as qta_icon logger = getLogger("ExtraWidgets") @@ -244,22 +244,22 @@ class IndicatorLineEdit(QWidget): 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 + ("mdi.file-cancel", "fa.file-excel-o"), # Unknown + ("mdi.desktop-classic", "fa.desktop"), # Computer + ("mdi.desktop-mac", "fa.desktop"), # Desktop + ("mdi.trash-can", "fa.trash"), # Trashcan + ("mdi.server-network", "fa.server"), # Network + ("mdi.harddisk", "fa.desktop"), # Drive + ("mdi.folder", "fa.folder"), # Folder + ("mdi.file", "fa.file"), # File + ("mdi.cog", "fa.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")}) + for idx, (icn, fallback) in enumerate(self.icons): + self.icon_types.update({idx - 1: qta_icon(icn, fallback, color="#eeeeee")}) def icon(self, info_type): if isinstance(info_type, QFileInfo): @@ -281,21 +281,24 @@ class PathEdit(IndicatorLineEdit): def __init__( self, - path: str = "", - file_type: QFileDialog.FileType = QFileDialog.AnyFile, - type_filter: str = "", - name_filter: str = "", - ph_text: str = "", - edit_func: Callable[[str], Tuple[bool, str]] = None, - save_func: Callable[[str], None] = None, - horiz_policy: QSizePolicy = QSizePolicy.Expanding, - parent=None, + path: str = "", + file_type: QFileDialog.FileType = QFileDialog.AnyFile, + type_filter: str = "", + name_filter: str = "", + ph_text: str = "", + edit_func: Callable[[str], Tuple[bool, str]] = None, + save_func: Callable[[str], None] = None, + horiz_policy: QSizePolicy = QSizePolicy.Expanding, + parent=None, ): - self.compl_model.setOptions( - QFileSystemModel.DontWatchForChanges - | QFileSystemModel.DontResolveSymlinks - | QFileSystemModel.DontUseCustomDirectoryIcons - ) + try: + self.compl_model.setOptions( + QFileSystemModel.DontWatchForChanges + | QFileSystemModel.DontResolveSymlinks + | QFileSystemModel.DontUseCustomDirectoryIcons + ) + except AttributeError as e: # Error on Ubuntu + logger.warning(e) self.compl_model.setIconProvider(PathEditIconProvider()) self.compl_model.setRootPath(path) self.completer.setModel(self.compl_model) @@ -381,7 +384,7 @@ class SideTabWidget(QTabWidget): self.setDocumentMode(True) self.setTabPosition(QTabWidget.West) if show_back: - self.addTab(QWidget(), qta_icon("mdi.keyboard-backspace"), self.tr("Back")) + self.addTab(QWidget(), qta_icon("mdi.keyboard-backspace", "ei.backward"), self.tr("Back")) self.tabBarClicked.connect(self.back_func) def back_func(self, tab): @@ -417,12 +420,12 @@ class SelectViewWidget(QWidget): self.list_view = QPushButton() if icon_view: self.icon_view_button.setIcon( - qta_icon("mdi.view-grid-outline", color="orange") + qta_icon("mdi.view-grid-outline", "ei.th-large", color="orange") ) - self.list_view.setIcon(qta_icon("fa5s.list")) + self.list_view.setIcon(qta_icon("fa5s.list", "ei.th-list")) else: - 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.setIcon(qta_icon("mdi.view-grid-outline", "ei.th-large")) + self.list_view.setIcon(qta_icon("fa5s.list", "ei.th-list", color="orange")) self.icon_view_button.clicked.connect(self.icon) self.list_view.clicked.connect(self.list) @@ -437,14 +440,14 @@ class SelectViewWidget(QWidget): return self.icon_view def icon(self): - self.icon_view_button.setIcon(qta_icon("mdi.view-grid-outline", color="orange")) - self.list_view.setIcon(qta_icon("fa5s.list")) + self.icon_view_button.setIcon(qta_icon("mdi.view-grid-outline", "ei.th-large", color="orange")) + self.list_view.setIcon(qta_icon("fa5s.list", "ei.th-list")) self.icon_view = False self.toggled.emit() def list(self): - 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.setIcon(qta_icon("mdi.view-grid-outline", "ei.th-large")) + self.list_view.setIcon(qta_icon("fa5s.list", "ei.th-list", color="orange")) self.icon_view = True self.toggled.emit() diff --git a/rare/utils/utils.py b/rare/utils/utils.py index c1cff184..8b37dcfb 100644 --- a/rare/utils/utils.py +++ b/rare/utils/utils.py @@ -86,14 +86,14 @@ def download_image(game, force=False): # Download for image in game.metadata["keyImages"]: if ( - image["type"] == "DieselGameBoxTall" - or image["type"] == "DieselGameBoxLogo" - or image["type"] == "Thumbnail" + image["type"] == "DieselGameBoxTall" + or image["type"] == "DieselGameBoxLogo" + or image["type"] == "Thumbnail" ): if image["type"] not in json_data.keys(): json_data[image["type"]] = None if json_data[image["type"]] != image["md5"] or not os.path.isfile( - f"{image_dir}/{game.app_name}/{image['type']}.png" + f"{image_dir}/{game.app_name}/{image['type']}.png" ): # Download json_data[image["type"]] = image["md5"] @@ -311,7 +311,7 @@ def create_desktop_link(app_name, core: LegendaryCore, type_of_link="desktop") - if os.path.exists(p := os.path.join(image_dir, igame.app_name, "Thumbnail.png")): icon = p elif os.path.exists( - p := os.path.join(image_dir, igame.app_name, "DieselGameBoxLogo.png") + p := os.path.join(image_dir, igame.app_name, "DieselGameBoxLogo.png") ): icon = p else: @@ -467,13 +467,13 @@ class WineResolver(QRunnable): @pyqtSlot() def run(self): if "WINEPREFIX" not in self.wine_env or not os.path.exists( - self.wine_env["WINEPREFIX"] + self.wine_env["WINEPREFIX"] ): # pylint: disable=E1136 self.signals.result_ready[str].emit(str()) return if not os.path.exists(self.wine_binary) or not os.path.exists( - self.winepath_binary + self.winepath_binary ): # pylint: disable=E1136 self.signals.result_ready[str].emit(str()) @@ -531,14 +531,29 @@ def get_raw_save_path(game: Game): if game.supports_cloud_saves: return ( game.metadata.get("customAttributes", {}) - .get("CloudSaveFolder", {}) - .get("value") + .get("CloudSaveFolder", {}) + .get("value") ) def get_default_platform(app_name): if platform.system() != "Darwin" or app_name not in shared.api_results.mac_games: return "Windows" - else: return "Mac" + + +def icon(icn_str: str, fallback: str = None, **kwargs): + try: + return qtawesome.icon(icn_str, **kwargs) + except Exception as e: + if not fallback: + logger.warning(str(e) + " " + icn_str) + if fallback: + try: + return qtawesome.icon(fallback, **kwargs) + except Exception as e: + logger.error(str(e)) + if kwargs.get("color"): + kwargs["color"] = "red" + return qtawesome.icon("ei.error", **kwargs)