2026-08-03 00:16:12 +08:00
|
|
|
import base64
|
2026-07-14 22:22:58 +08:00
|
|
|
from pathlib import Path
|
|
|
|
|
|
2026-07-14 16:41:14 +08:00
|
|
|
from PySide6.QtCore import QCoreApplication, QThread, QSize, Qt
|
2026-08-03 00:16:12 +08:00
|
|
|
from PySide6.QtGui import QScreen, QPixmap, QPainter, QPalette, QIcon, QColor, QImage
|
|
|
|
|
from PySide6.QtWidgets import QMainWindow, QApplication, QWidget, QDialog
|
2026-07-10 23:27:21 +08:00
|
|
|
|
|
|
|
|
|
2026-08-03 00:16:12 +08:00
|
|
|
def move_window_to_center(window: QMainWindow | QDialog) -> None:
|
2026-07-10 23:27:21 +08:00
|
|
|
main_screen = QApplication.primaryScreen()
|
|
|
|
|
center = QScreen.availableGeometry(main_screen).center()
|
|
|
|
|
geometry = window.frameGeometry()
|
|
|
|
|
geometry.moveCenter(center)
|
|
|
|
|
window.move(geometry.topLeft())
|
2026-07-12 22:43:34 +08:00
|
|
|
|
|
|
|
|
def is_main_thread() -> bool:
|
|
|
|
|
app = QCoreApplication.instance()
|
2026-07-14 16:41:14 +08:00
|
|
|
return app is not None and QThread.currentThread() == app.thread()
|
|
|
|
|
|
2026-07-14 22:22:58 +08:00
|
|
|
# ======================== AI generated ========================
|
2026-07-14 16:41:14 +08:00
|
|
|
def recolor_standard_icon(widget, standard_pixmap, size=24):
|
|
|
|
|
source_icon = widget.style().standardIcon(standard_pixmap)
|
|
|
|
|
source = source_icon.pixmap(QSize(size, size))
|
|
|
|
|
|
|
|
|
|
result = QPixmap(source.size())
|
|
|
|
|
result.fill(Qt.GlobalColor.transparent)
|
|
|
|
|
|
|
|
|
|
painter = QPainter(result)
|
|
|
|
|
painter.drawPixmap(0, 0, source)
|
|
|
|
|
painter.setCompositionMode(
|
|
|
|
|
QPainter.CompositionMode.CompositionMode_SourceIn
|
|
|
|
|
)
|
|
|
|
|
painter.fillRect(
|
|
|
|
|
result.rect(),
|
|
|
|
|
widget.palette().color(QPalette.ColorRole.ButtonText),
|
|
|
|
|
)
|
|
|
|
|
painter.end()
|
|
|
|
|
|
2026-07-14 22:22:58 +08:00
|
|
|
return QIcon(result)
|
|
|
|
|
|
|
|
|
|
def recolor_pixmap(
|
|
|
|
|
path: str | Path,
|
|
|
|
|
color: QColor | None = None,
|
|
|
|
|
) -> QPixmap:
|
|
|
|
|
source = QPixmap(str(path))
|
|
|
|
|
|
|
|
|
|
if source.isNull():
|
|
|
|
|
raise FileNotFoundError(f"Unable to load image: {path}")
|
|
|
|
|
|
|
|
|
|
if color is None:
|
|
|
|
|
color = QApplication.palette().color(
|
|
|
|
|
QPalette.ColorRole.ButtonText
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
result = QPixmap(source.size())
|
|
|
|
|
result.setDevicePixelRatio(source.devicePixelRatio())
|
|
|
|
|
result.fill(Qt.GlobalColor.transparent)
|
|
|
|
|
|
|
|
|
|
painter = QPainter(result)
|
|
|
|
|
painter.drawPixmap(0, 0, source)
|
|
|
|
|
painter.setCompositionMode(
|
|
|
|
|
QPainter.CompositionMode.CompositionMode_SourceIn
|
|
|
|
|
)
|
|
|
|
|
painter.fillRect(result.rect(), color)
|
|
|
|
|
painter.end()
|
|
|
|
|
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def recolor_icon(
|
|
|
|
|
path: str | Path,
|
|
|
|
|
color: QColor | None = None,
|
|
|
|
|
) -> QIcon:
|
|
|
|
|
return QIcon(recolor_pixmap(path, color))
|
|
|
|
|
|
|
|
|
|
def is_light_theme(widget=None) -> bool:
|
|
|
|
|
palette = (
|
|
|
|
|
widget.palette()
|
|
|
|
|
if widget is not None
|
|
|
|
|
else QApplication.palette()
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
color = palette.color(QPalette.ColorRole.Window)
|
|
|
|
|
|
|
|
|
|
luminance = (
|
|
|
|
|
0.2126 * color.redF()
|
|
|
|
|
+ 0.7152 * color.greenF()
|
|
|
|
|
+ 0.0722 * color.blueF()
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
return luminance >= 0.5
|
|
|
|
|
|
2026-08-01 00:47:41 +08:00
|
|
|
def add_icon_padding(icon: QIcon, icon_size=32, padding=6) -> QIcon:
|
|
|
|
|
source = icon.pixmap(icon_size, icon_size)
|
|
|
|
|
|
|
|
|
|
canvas_size = icon_size + padding * 2
|
|
|
|
|
canvas = QPixmap(canvas_size, canvas_size)
|
|
|
|
|
canvas.fill(Qt.GlobalColor.transparent)
|
|
|
|
|
|
|
|
|
|
painter = QPainter(canvas)
|
|
|
|
|
painter.drawPixmap(padding, padding, source)
|
|
|
|
|
painter.end()
|
|
|
|
|
|
|
|
|
|
return QIcon(canvas)
|
|
|
|
|
|
2026-08-03 00:16:12 +08:00
|
|
|
def data_url_to_qt_image(data_url: str) -> QImage:
|
|
|
|
|
try:
|
|
|
|
|
header, encoded_data = data_url.split(",", 1)
|
|
|
|
|
except ValueError:
|
|
|
|
|
raise ValueError("Not a valid data url")
|
|
|
|
|
|
|
|
|
|
if ";base64" not in header:
|
|
|
|
|
raise ValueError("Unsupported data url. Supported data urls are base64")
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
image_data = base64.b64decode(encoded_data, validate=True)
|
|
|
|
|
except ValueError as error:
|
|
|
|
|
raise ValueError("Invalid image data") from error
|
|
|
|
|
|
|
|
|
|
image = QImage.fromData(image_data)
|
|
|
|
|
|
|
|
|
|
if image.isNull():
|
|
|
|
|
raise ValueError("Qt does not support this image")
|
|
|
|
|
|
|
|
|
|
return image
|
|
|
|
|
|
2026-07-14 22:22:58 +08:00
|
|
|
# ======================== AI generated END ========================
|