The `status_label` displays what is currently going on with the game. It reflects the current operation running on it or if it requires special attention (update, needs verification etc) The `tooltip_label` displays hover information such as what happens if a part of the widget is clicked or in the case of the launch button if the game can run (without version check, offline etc) The context menu on the widgets will be updated and populated according to the installation state of the game. Since the context menu was revised the shortcut creation code was revised too to make it more compact. the `create_desktop_link` and `get_rare_executable` functions are moved from `rare.utils.misc` to `rare.utils.paths` to avoid cyclical imports and better grouping. Two functions are added, `desktop_link_path` to uniformly calculate the path of the shortcut and `desktop_links_supported` which checks if Rare supports creating shortcuts on the current platform. `desktop_links_supported` should be used as safeguard before `desktop_link_path`. Desktop links are currently untested on Windows but if `shortcut.Description` works as expected, it should be good to go.
160 lines
6.2 KiB
Python
160 lines
6.2 KiB
Python
from logging import getLogger
|
|
|
|
from PyQt5.QtCore import Qt, QEvent, QRect
|
|
from PyQt5.QtGui import (
|
|
QPalette,
|
|
QBrush,
|
|
QPaintEvent,
|
|
QPainter,
|
|
QLinearGradient,
|
|
QPixmap,
|
|
QImage,
|
|
QResizeEvent,
|
|
)
|
|
|
|
from rare.models.game import RareGame
|
|
from rare.utils.misc import get_size
|
|
from rare.widgets.image_widget import ImageWidget
|
|
from .game_widget import GameWidget
|
|
from .list_widget import ListWidget
|
|
|
|
logger = getLogger("ListGameWidget")
|
|
|
|
|
|
class ListGameWidget(GameWidget):
|
|
def __init__(self, rgame: RareGame, parent=None):
|
|
super().__init__(rgame, parent)
|
|
self.setObjectName(f"{rgame.app_name}")
|
|
self.ui = ListWidget()
|
|
self.ui.setupUi(self)
|
|
|
|
self.ui.title_label.setText(self.rgame.app_title)
|
|
self.ui.launch_btn.clicked.connect(self._launch)
|
|
self.ui.launch_btn.setVisible(self.rgame.is_installed)
|
|
self.ui.install_btn.clicked.connect(self._install)
|
|
self.ui.install_btn.setVisible(not self.rgame.is_installed)
|
|
|
|
self.ui.launch_btn.setEnabled(self.rgame.can_launch)
|
|
|
|
self.ui.launch_btn.setText(
|
|
self.tr("Launch") if not self.rgame.is_origin else self.tr("Link/Play")
|
|
)
|
|
self.ui.developer_text.setText(self.rgame.developer)
|
|
# self.version_label.setVisible(self.is_installed)
|
|
if self.rgame.igame:
|
|
self.ui.version_text.setText(self.rgame.version)
|
|
self.ui.size_text.setText(get_size(self.rgame.install_size) if self.rgame.install_size else "")
|
|
|
|
self.update_state()
|
|
|
|
# lk: "connect" the buttons' enter/leave events to this widget
|
|
self.installEventFilter(self)
|
|
self.ui.launch_btn.installEventFilter(self)
|
|
self.ui.install_btn.installEventFilter(self)
|
|
|
|
def enterEvent(self, a0: QEvent = None) -> None:
|
|
if a0 is not None:
|
|
a0.accept()
|
|
self.ui.tooltip_label.setVisible(True)
|
|
|
|
def leaveEvent(self, a0: QEvent = None) -> None:
|
|
if a0 is not None:
|
|
a0.accept()
|
|
self.ui.tooltip_label.setVisible(False)
|
|
|
|
# def game_started(self, app_name):
|
|
# if app_name == self.rgame.app_name:
|
|
# self.game_running = True
|
|
# # self.update_text()
|
|
# self.ui.launch_btn.setDisabled(True)
|
|
|
|
# def game_finished(self, app_name, error):
|
|
# if app_name != self.rgame.app_name:
|
|
# return
|
|
# super().game_finished(app_name, error)
|
|
# # self.update_text(None)
|
|
# self.ui.launch_btn.setDisabled(False)
|
|
|
|
"""
|
|
Painting and progress overrides.
|
|
Let them live here until a better alternative is divised.
|
|
|
|
The list widget and these painting functions can be
|
|
refactored to be used in downloads and/or dlcs
|
|
"""
|
|
|
|
def event(self, e: QEvent) -> bool:
|
|
if e.type() == QEvent.LayoutRequest:
|
|
if self.progress_label.isVisible():
|
|
width = int(self._pixmap.width() / self._pixmap.devicePixelRatioF())
|
|
origin = self.width() - width
|
|
fill_rect = QRect(origin, 0, width, self.sizeHint().height())
|
|
self.progress_label.setGeometry(fill_rect)
|
|
return ImageWidget.event(self, e)
|
|
|
|
def resizeEvent(self, a0: QResizeEvent) -> None:
|
|
if self.progress_label.isVisible():
|
|
width = int(self._pixmap.width() / self._pixmap.devicePixelRatioF())
|
|
origin = self.width() - width
|
|
fill_rect = QRect(origin, 0, width, self.sizeHint().height())
|
|
self.progress_label.setGeometry(fill_rect)
|
|
ImageWidget.resizeEvent(self, a0)
|
|
|
|
def prepare_pixmap(self, pixmap: QPixmap) -> QPixmap:
|
|
device: QImage = QImage(
|
|
pixmap.size().width() * 3,
|
|
int(self.sizeHint().height() * pixmap.devicePixelRatioF()) + 1,
|
|
QImage.Format_ARGB32_Premultiplied
|
|
)
|
|
painter = QPainter(device)
|
|
brush = QBrush(pixmap)
|
|
painter.fillRect(device.rect(), brush)
|
|
# the gradient could be cached and reused as it is expensive
|
|
gradient = QLinearGradient(0, 0, device.width(), 0)
|
|
gradient.setColorAt(0.15, Qt.transparent)
|
|
gradient.setColorAt(0.5, Qt.black)
|
|
gradient.setColorAt(0.85, Qt.transparent)
|
|
painter.setCompositionMode(QPainter.CompositionMode_DestinationIn)
|
|
painter.fillRect(device.rect(), gradient)
|
|
painter.end()
|
|
ret = QPixmap.fromImage(device)
|
|
ret.setDevicePixelRatio(pixmap.devicePixelRatioF())
|
|
return ret
|
|
|
|
def setPixmap(self, pixmap: QPixmap) -> None:
|
|
# lk: trade some possible delay and start-up time
|
|
# lk: for faster rendering. Gradients are expensive
|
|
# lk: so pre-generate the image
|
|
super(ListGameWidget, self).setPixmap(self.prepare_pixmap(pixmap))
|
|
|
|
def paint_image_cover(self, painter: QPainter, a0: QPaintEvent) -> None:
|
|
painter.setOpacity(self._opacity)
|
|
color = self.palette().color(QPalette.Background).darker(75)
|
|
painter.fillRect(self.rect(), color)
|
|
brush = QBrush(self._pixmap)
|
|
brush.setTransform(self._transform)
|
|
width = int(self._pixmap.width() / self._pixmap.devicePixelRatioF())
|
|
origin = self.width() - width
|
|
painter.setBrushOrigin(origin, 0)
|
|
fill_rect = QRect(origin, 0, width, self.height())
|
|
painter.fillRect(fill_rect, brush)
|
|
|
|
def progressPixmap(self, color: QPixmap, gray: QPixmap, progress: int) -> QPixmap:
|
|
# lk: so about that +1 after the in convertion, casting to int rounds down
|
|
# lk: and that can create a weird line at the bottom, add 1 to round up.
|
|
device = QPixmap(
|
|
color.size().width(),
|
|
int(self.sizeHint().height() * color.devicePixelRatioF()) + 1,
|
|
)
|
|
painter = QPainter(device)
|
|
painter.setRenderHint(QPainter.SmoothPixmapTransform, self._smooth_transform)
|
|
painter.setCompositionMode(QPainter.CompositionMode_Source)
|
|
prog_h = (device.height() * progress // 100)
|
|
brush = QBrush(gray)
|
|
painter.fillRect(device.rect().adjusted(0, 0, 0, -prog_h), brush)
|
|
brush.setTexture(color)
|
|
painter.fillRect(device.rect().adjusted(0, device.height() - prog_h, 0, 0), brush)
|
|
painter.end()
|
|
device.setDevicePixelRatio(color.devicePixelRatioF())
|
|
return device
|