1
0
Fork 0
mirror of synced 2024-07-02 21:20:54 +12:00
Rare/rare/components/tabs/games/game_widgets/library_widget.py
loathingKernel 1721677e33 GameWidget: Implement reactive and interactive labels
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.
2023-02-07 13:41:59 +02:00

124 lines
4.9 KiB
Python

from typing import Optional, Tuple, List
from PyQt5.QtCore import Qt, QRect, QEvent
from PyQt5.QtGui import QPainter, QPixmap, QResizeEvent, QFontMetrics, QImage, QBrush, QColor
from PyQt5.QtWidgets import QLabel
from rare.widgets.image_widget import ImageWidget
class ProgressLabel(QLabel):
def __init__(self, parent=None):
super(ProgressLabel, self).__init__(parent=parent)
self.setObjectName(type(self).__name__)
self.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
self.setFrameStyle(QLabel.StyledPanel)
def setGeometry(self, a0: QRect) -> None:
fm = QFontMetrics(self.font())
rect = fm.boundingRect(f" {self.text()} ")
rect.moveCenter(a0.center())
super(ProgressLabel, self).setGeometry(rect)
@staticmethod
def calculateColors(image: QImage) -> Tuple[QColor, QColor]:
color: List[int] = [0, 0, 0]
# take the two diagonals of the center square section
min_d = min(image.width(), image.height())
origin_w = (image.width() - min_d) // 2
origin_h = (image.height() - min_d) // 2
for x, y in zip(range(origin_w, min_d), range(origin_h, min_d)):
pixel = image.pixelColor(x, y).getRgb()
color = list(map(lambda t: sum(t) // 2, zip(pixel[0:3], color)))
# take the V component of the HSV color
fg_color = QColor(0, 0, 0) if QColor(*color).value() < 127 else QColor(255, 255, 255)
bg_color = QColor(*map(lambda c: 255 - c, color))
return bg_color, fg_color
def setStyleSheetColors(self, bg: QColor, fg: QColor, brd: QColor):
sheet = (
f"QLabel#{type(self).__name__} {{"
f"background-color: rgba({bg.red()}, {bg.green()}, {bg.blue()}, 65%);"
f"color: rgb({fg.red()}, {fg.green()}, {fg.blue()});"
f"border-width: 1px;"
f"border-radius: 5%;"
f"border-color: rgb({brd.red()}, {brd.green()}, {brd.blue()});"
f"font-weight: bold;"
f"font-size: 16pt;"
f"}}"
)
self.setStyleSheet(sheet)
class LibraryWidget(ImageWidget):
def __init__(self, parent=None) -> None:
super(LibraryWidget, self).__init__(parent)
self.progress_label = ProgressLabel(self)
self.progress_label.setVisible(False)
self._color_pixmap: Optional[QPixmap] = None
self._gray_pixmap: Optional[QPixmap] = None
# lk: keep percentage to not over-generate the image
self._progress: int = -1
def event(self, e: QEvent) -> bool:
if e.type() == QEvent.LayoutRequest:
self.progress_label.setGeometry(self.rect())
return super(LibraryWidget, self).event(e)
def resizeEvent(self, a0: QResizeEvent) -> None:
if self.progress_label.isVisible():
self.progress_label.setGeometry(self.rect())
super(LibraryWidget, self).resizeEvent(a0)
def progressPixmap(self, color: QPixmap, gray: QPixmap, progress: int) -> QPixmap:
"""
Paints the color image over the gray images based on progress percentage
@param color:
@param gray:
@param progress:
@return:
"""
device = QPixmap(color.size())
painter = QPainter(device)
painter.setRenderHint(QPainter.SmoothPixmapTransform, self._smooth_transform)
painter.setCompositionMode(QPainter.CompositionMode_Source)
# lk: Vertical loading
# 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)
# lk: Horizontal loading
prog_w = device.width() * progress // 100
brush = QBrush(gray)
painter.fillRect(device.rect().adjusted(prog_w, 0, 0, 0), brush)
brush.setTexture(color)
painter.fillRect(device.rect().adjusted(0, 0, prog_w - device.width(), 0), brush)
painter.end()
device.setDevicePixelRatio(color.devicePixelRatioF())
return device
def showProgress(self, color_pm: QPixmap, gray_pm: QPixmap) -> None:
self._color_pixmap = color_pm
self._gray_pixmap = gray_pm
bg_color, fg_color = self.progress_label.calculateColors(color_pm.toImage())
self.progress_label.setStyleSheetColors(bg_color, fg_color, fg_color)
self.progress_label.setVisible(True)
self.progress_label.update()
self.updateProgress(0)
def updateProgress(self, progress: int):
self.progress_label.setText(f"{progress:02}%")
if progress > self._progress:
self._progress = progress
self.setPixmap(self.progressPixmap(self._color_pixmap, self._gray_pixmap, progress))
def hideProgress(self, stopped: bool):
self._color_pixmap = None
self._gray_pixmap = None
self.progress_label.setVisible(stopped)
self._progress = -1