Skip to content

Instantly share code, notes, and snippets.

@UDPSendToFailed
Created December 21, 2023 11:25
Show Gist options
  • Save UDPSendToFailed/71ba1c4def88e2b9edf5950b3ed77922 to your computer and use it in GitHub Desktop.
Save UDPSendToFailed/71ba1c4def88e2b9edf5950b3ed77922 to your computer and use it in GitHub Desktop.
Corsair LCD Tool v0.0.1
import logging
import math
import os
import platform
import queue
import sys
import threading
import time
from dataclasses import dataclass
import cv2
import hid
import numpy as np
import yaml
from PyQt6.QtCore import Qt, QTimer, QPointF, pyqtSignal, QThread, pyqtSlot, QEvent, QRectF
from PyQt6.QtGui import QPixmap, QPainter, QMovie, QIcon, QTransform, QImage, QAction, QPalette, QColor
from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton, QFileDialog, QSlider, QWidget, QGraphicsScene, \
QGraphicsView, QGraphicsPixmapItem, QSystemTrayIcon, QMenu, QStyleFactory, QGraphicsItem, QCheckBox
from openrgb import OpenRGBClient
from openrgb.utils import RGBColor
if os.name == 'nt': # Windows platform
import winshell
elif os.name == 'posix': # Unix/Linux platform
import subprocess
# Set up logging
logging.basicConfig(level=logging.DEBUG) # Adjust the logging level as needed
VID = 0x1b1c # Corsair
PID = 0x0c39 # Corsair LCD Cap for Elite Capellix coolers
@dataclass
class CorsairCommand:
"""Corsair Command"""
opcode: int # 0x02
unknown1: int # 0x05
unknown2: int # 0x40
is_end: bool # 0x00 or 0x01
part_num: int # 0x0000 - 0xffff, little endian
datalen: int # 0x0000 - 0xffff, little endian
data: bytes # datalen bytes + padding up to packet size
HEADER_SIZE = 8
@classmethod
def from_bytes(cls, data):
try:
opcode = data[0]
unknown1 = data[1]
unknown2 = data[2]
is_end = data[3] == 0x01
part_num = int.from_bytes(data[4:6], byteorder='little')
datalen = int.from_bytes(data[6:8], byteorder='little')
payload = data[cls.HEADER_SIZE:cls.HEADER_SIZE + datalen]
return cls(
opcode=opcode,
unknown1=unknown1,
unknown2=unknown2,
is_end=is_end,
part_num=part_num,
datalen=datalen,
data=payload
)
except Exception as e:
logging.error(f"Error parsing CorsairCommand: {e}")
raise
def to_bytes(self):
return bytes([
self.opcode,
self.unknown1,
self.unknown2,
0x01 if self.is_end else 0x00,
]) + \
self.part_num.to_bytes(2, byteorder='little') + \
self.datalen.to_bytes(2, byteorder='little') + \
self.data
@property
def is_start(self):
return self.part_num == 0
@property
def header_size(self):
return self.HEADER_SIZE
@property
def size(self):
return self.header_size + self.datalen
def make_commands(data, opcode=0x02, max_len=1024):
"""Splits data into Corsair commands of max_len bytes"""
real_max_len = max_len - CorsairCommand.HEADER_SIZE
part_num = 0
while data:
if len(data) < real_max_len:
padded_data = data + b'\x00' * (real_max_len - len(data))
else:
padded_data = data[:real_max_len]
datalen = min(real_max_len, len(data))
data = data[real_max_len:]
try:
yield CorsairCommand(
opcode=opcode,
unknown1=0x05,
unknown2=0x40,
is_end=not bool(data),
part_num=part_num,
datalen=datalen,
data=padded_data,
)
except Exception as e:
logging.error(f"Error creating CorsairCommand: {e}")
raise
part_num += 1
class UpdateDeviceThread(QThread):
captureSignal: pyqtSignal = pyqtSignal()
def __init__(self, container, image_previewer):
super().__init__()
self.container = container
self.image_previewer = image_previewer
self.device = hid.device()
try:
self.device.open(VID, PID)
except Exception as e:
logging.error(f"Error opening device: {e}")
raise
QTimer.singleShot(0, self.start_timer)
def start_timer(self):
self.updateLCD_timer = QTimer()
self.updateLCD_timer.timeout.connect(self.updateLCD)
self.updateLCD_timer.start(int(1000 / 30))
def run(self):
self.exec()
@pyqtSlot()
def updateLCD(self):
try:
image = self.image_previewer.captureContainer()
width = image.width()
height = image.height()
ptr = image.bits()
ptr.setsize(height * width * 4)
arr = np.frombuffer(ptr, np.uint8).reshape((height, width, 4))
arr = cv2.resize(arr, (480, 480))
image_data = cv2.imencode('.jpg', arr)[1].tobytes()
self.write_command(image_data)
except Exception as e:
logging.error(f"Error updating LCD: {e}")
def write_command(self, data):
try:
commands = make_commands(data)
for command in commands:
self.device.write(command.to_bytes())
except Exception as e:
logging.error(f"Error writing command to device: {e}")
class NoScrollGraphicsView(QGraphicsView):
def __init__(self, scene, parent=None):
super().__init__(scene, parent)
self.setViewportUpdateMode(QGraphicsView.ViewportUpdateMode.FullViewportUpdate)
def scrollContentsBy(self, dx, dy):
# Override the function and do nothing
pass
def wheelEvent(self, event):
logging.debug("Wheel event detected, but ignored")
pass # Ignore wheel events
class LEDController(QThread):
captureSignal: pyqtSignal = pyqtSignal()
def __init__(self, image_previewer):
super().__init__()
self.image_previewer = image_previewer
self.client = OpenRGBClient()
self.last_rgb_colors = [RGBColor(0, 0, 0)] * 24
QTimer.singleShot(0, self.start_timer)
def start_timer(self):
self.updateLED_timer = QTimer()
self.updateLED_timer.timeout.connect(self.analyze_and_set_colors)
self.updateLED_timer.start(33) # Adjusted for ~30 fps
@pyqtSlot()
def analyze_and_set_colors(self):
try:
image = self.image_previewer.captureContainer()
width = image.width()
height = image.height()
radius = min(width, height) // 2
for i in range(24):
angle = 2 * math.pi * (23 - i) / 24
x = width - int(width / 2 + radius * math.cos(angle))
y = int(height / 2 + radius * math.sin(angle))
color = QColor(image.pixel(x, y))
rgb_color = RGBColor(color.red(), color.green(), color.blue())
self.last_rgb_colors[i] = rgb_color # Directly assign the new color
self.send_color_to_openrgb() # Send color data to OpenRGB
except Exception as e:
logging.error(f"Error updating LED: {e}")
def send_color_to_openrgb(self):
for device in self.client.devices:
if device.name == "Corsair Commander Core":
self.set_device_colors(device)
def set_device_colors(self, device):
try:
for i, rgb_color in enumerate(self.last_rgb_colors):
device.leds[i].set_color(rgb_color)
except Exception as e:
logging.error(f"Error setting color for device {device.name}: {e}")
class ImagePreviewer(QMainWindow):
def __init__(self):
super().__init__()
logging.debug("Initializing ImagePreviewer")
self.pixmapItem = QGraphicsPixmapItem()
self.pixmapItem.setPos(QPointF(0, 0))
self.trayIcon = QSystemTrayIcon(self)
self.trayIcon.setIcon(QIcon('icon.ico'))
self.windowStateHandler = WindowStateHandler(self)
self.controller = LEDController(self)
self.controller.analyze_and_set_colors()
self.currentImagePath = None
self.lastPixmapPos = None
self.lastTransform = None
self.lastSliderValue = None
self.lastSceneRect = None
self.lastScrollBarPos = None
self.setWindowTitle('Corsair LCD Tool')
self.setFixedSize(600, 650) # Extend the window size
self.container = QWidget(self)
self.container.setGeometry(60, 20, 480, 480)
self.container.setStyleSheet("background-color: #282c34; border: 0px")
self.scene = QGraphicsScene(self.container)
self.view = QGraphicsView(self.scene, self.container)
self.view.setGeometry(0, 0, 480, 480)
self.view.setRenderHint(QPainter.RenderHint.Antialiasing)
self.view.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
self.view.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
self.view.setTransformationAnchor(QGraphicsView.ViewportAnchor.AnchorUnderMouse)
self.openButton = QPushButton("Open Image", self)
self.openButton.setGeometry(60, 540, 120, 30)
self.openButton.clicked.connect(self.openImage)
self.trayButton = QPushButton("Minimize to Tray", self)
self.trayButton.setGeometry(240, 540, 120, 30)
self.trayButton.clicked.connect(self.windowStateHandler.minimizeWindow)
self.resetButton = QPushButton("Reset View", self)
self.resetButton.setGeometry(420, 540, 120, 30)
self.resetButton.clicked.connect(self.resetImage)
self.script_path = os.path.join(os.getcwd(), 'asd2.py')
# Get the path to the Python interpreter
self.python_path = sys.executable
if platform.system() == "Windows":
import winshell
# Get the path to the startup folder
self.startup_folder = winshell.startup()
# Get the path to the shortcut
self.shortcut_path = os.path.join(self.startup_folder, 'asd2.lnk')
elif platform.system() == "Linux":
# In Linux, there's no equivalent to the startup folder in Windows.
# You can use crontab or systemd to run scripts at startup.
# Here, we'll use crontab as an example.
# The crontab command to add or remove the script from startup
self.crontab_command = f'@reboot {self.python_path} {self.script_path} &'
self.startupCheckbox = QCheckBox("Run at startup", self) # Add a checkbox
self.startupCheckbox.setGeometry(60, 580, 120, 30) # Position it below the buttons
self.startupCheckbox.stateChanged.connect(self.update_startup)
self.slider = QSlider(Qt.Orientation.Horizontal, self)
self.slider.setGeometry(60, 510, 480, 20)
self.slider.setMinimum(20)
self.slider.setMaximum(180)
self.slider.setValue(100)
self.slider.setDisabled(True)
self.slider.valueChanged.connect(self.scaleImage)
restoreAction = QAction("Restore", self)
restoreAction.triggered.connect(self.showNormal)
quitAction = QAction("Quit", self)
quitAction.triggered.connect(QApplication.quit)
self.trayMenu = QMenu()
self.trayMenu.addAction(restoreAction)
self.trayMenu.addAction(quitAction)
self.trayIcon.setContextMenu(self.trayMenu)
self.setWindowIcon(QIcon('icon.ico'))
self.movie = None
logging.debug("ImagePreviewer initialized")
try:
self.updateDeviceThread = UpdateDeviceThread(self.container, self)
self.updateDeviceThread.start()
self.frames = []
except Exception as e:
logging.error(f"Error initializing ImagePreviewer: {e}")
raise
self.saveStateHandler = saveStateHandler(self)
self.show()
# Set the style for the application
QApplication.instance().setStyle(QStyleFactory.create('Fusion'))
# Set the palette for the application
palette = QPalette()
palette.setColor(QPalette.ColorRole.Window, QColor('#2c313a'))
palette.setColor(QPalette.ColorRole.WindowText, QColor('white'))
palette.setColor(QPalette.ColorRole.Base, QColor('#2c313a'))
palette.setColor(QPalette.ColorRole.AlternateBase, QColor('gray'))
palette.setColor(QPalette.ColorRole.ToolTipBase, QColor('#2c313a'))
palette.setColor(QPalette.ColorRole.ToolTipText, QColor('white'))
palette.setColor(QPalette.ColorRole.Text, QColor('white'))
palette.setColor(QPalette.ColorRole.Button, QColor('#2c313a'))
palette.setColor(QPalette.ColorRole.ButtonText, QColor('white'))
palette.setColor(QPalette.ColorRole.BrightText, QColor('red'))
palette.setColor(QPalette.ColorRole.Link, QColor('#0069c0'))
palette.setColor(QPalette.ColorRole.Highlight, QColor('#0069c0'))
palette.setColor(QPalette.ColorRole.HighlightedText, QColor('black'))
QApplication.instance().setPalette(palette)
self.saveStateHandler.loadImageState()
logging.debug("UI Initialized")
def update_startup(self, state):
print(f"Checkbox state: {state}")
print(f"Script path: {self.script_path}")
if platform.system() == "Windows":
print(f"Shortcut path: {self.shortcut_path}")
if state == 2: # Checkbox is checked
# Create a shortcut in the startup folder
with winshell.shortcut(self.shortcut_path) as shortcut:
shortcut.path = self.script_path
shortcut.description = 'My Python script'
print("Shortcut created.")
else: # Checkbox is unchecked
# Remove the shortcut from the startup folder
if os.path.exists(self.shortcut_path):
os.remove(self.shortcut_path)
print("Shortcut removed.")
elif platform.system() == "Linux":
service_content = f"""[Unit]
Description=My Python script
[Service]
ExecStart={self.python_path} {self.script_path}
[Install]
WantedBy=multi-user.target
"""
service_path = f"/etc/systemd/system/{os.path.basename(self.script_path)}.service"
if state == 2: # Checkbox is checked
# Create a systemd service
with open(service_path, 'w') as f:
f.write(service_content)
subprocess.run(["systemctl", "daemon-reload"], check=True)
subprocess.run(["systemctl", "enable", os.path.basename(self.script_path)], check=True)
print("Systemd service created and enabled.")
else: # Checkbox is unchecked
# Remove the systemd service
if os.path.exists(service_path):
os.remove(service_path)
subprocess.run(["systemctl", "daemon-reload"], check=True)
print("Systemd service removed.")
def openImage(self):
logging.debug("Entering openImage function")
fileName, _ = QFileDialog.getOpenFileName(self, "Open Image", "",
"Images (*.png *.xpm *.jpg *.bmp *.gif)")
if fileName:
logging.debug(f"Opening image file: {fileName}")
self.loadNewImage(fileName)
self.currentImagePath = fileName
self.saveStateHandler.restartsaveImageStateTimer()
def loadNewImage(self, fileName):
logging.debug(f"Loading a new image: {fileName}")
# Clear prior image or gif
self.scene.clear()
# Check if the file is a gif
if fileName.lower().endswith('.gif'):
self.loadNewGif(fileName)
else:
# Stop and delete the old movie if it exists
if self.movie is not None:
self.movie.stop()
self.movie.deleteLater()
self.movie = None
# Load the image as pixmap
pixmap = QPixmap(fileName)
# Create a pixmap item
self.pixmapItem = QGraphicsPixmapItem(pixmap)
# Set pixmap item to be movable
self.pixmapItem.setFlag(QGraphicsItem.GraphicsItemFlag.ItemIsMovable)
# Add pixmap item to the scene
self.scene.addItem(self.pixmapItem)
# Enable the slider
self.slider.setEnabled(True)
def loadNewGif(self, fileName):
# Stop and delete the old movie if it exists
if self.movie is not None:
self.movie.stop()
self.movie.deleteLater()
# Create a new QMovie object
self.movie = QMovie(fileName)
# Create a pixmap item
self.pixmapItem = QGraphicsPixmapItem()
# Set pixmap item to be movable
self.pixmapItem.setFlag(QGraphicsItem.GraphicsItemFlag.ItemIsMovable)
# Add pixmap item to the scene
self.scene.addItem(self.pixmapItem)
# Connect frameChanged signal to set each frame of gif
self.movie.frameChanged.connect(lambda: self.pixmapItem.setPixmap(QPixmap.fromImage(self.movie.currentImage())))
# Start the gif
self.movie.start()
# Enable the slider
self.slider.setEnabled(True)
def resetImage(self):
if self.currentImagePath is not None:
self.loadNewImage(self.currentImagePath)
def scaleImage(self, value):
if self.pixmapItem is not None:
# Reset any existing transformations
self.pixmapItem.resetTransform()
# Calculate the scale factor. The slider's range is 20 to 180,
# so we'll divide by 100 to get a range of 0.2 to 1.8
scale_factor = value / 100.0
# Set the pixmap item's transformation origin point to its center
self.pixmapItem.setTransformOriginPoint(self.pixmapItem.boundingRect().center())
# Scale the pixmap item
self.pixmapItem.setScale(scale_factor)
self.saveStateHandler.restartsaveImageStateTimer()
def captureContainer(self):
try:
pixmap = QPixmap(self.container.size())
self.container.render(pixmap)
return pixmap.toImage()
except Exception as e:
logging.error(f"Error in captureContainer: {e}")
return QImage() # Return an empty QImage in case of an error
def changeEvent(self, event):
self.windowStateHandler.handleWindowStateChange(event)
class saveStateHandler:
def __init__(self, image_previewer):
self.oldPos = None
self.main = image_previewer
self.isFirstLoad = True
self.checkStateTimer = QTimer()
self.checkStateTimer.setInterval(1000)
self.checkStateTimer.timeout.connect(self.checkState)
self.saveImageStateTimer = QTimer()
self.saveImageStateTimer.setInterval(2000)
self.saveImageStateTimer.timeout.connect(self.handleSaveImageStateTimeout)
self.saveImageStateFlag = False
self.oldTransform = None
def loadImageState(self):
logging.debug("Entering loadImageState function")
try:
logging.debug(f"self.isFirstLoad value: {self.isFirstLoad}")
if not self.isFirstLoad:
logging.debug("State has already been loaded. Skipping load.")
return
state_file = 'state.yaml'
if os.path.exists(state_file):
try:
with open(state_file, 'r') as f:
state = yaml.safe_load(f)
logging.debug(f"Loaded state from file: {state}")
if state is not None:
image_path = state.get('lastImagePath', '')
if image_path and os.path.exists(image_path):
self.main.loadNewImage(image_path)
self.main.currentImagePath = image_path
self.main.view.resetTransform()
self.main.scene.setSceneRect(QRectF(*state.get('lastSceneRect')))
self.main.pixmapItem.setPos(QPointF(*state.get('lastPixmapPos')))
self.main.view.setTransform(QTransform().scale(*state.get('lastTransform')))
self.main.slider.setValue(state.get('lastSliderValue'))
self.main.view.horizontalScrollBar().setValue(state.get('lastScrollBarPos')[0])
self.main.view.verticalScrollBar().setValue(state.get('lastScrollBarPos')[1])
self.main.show()
print(f"Loaded state: {state}")
else:
logging.warning(
"State file is empty or image path does not exist. Loading with default settings.")
else:
logging.warning("No state file found. Loading with default settings.")
except yaml.YAMLError as e:
logging.error(
f"Error loading state: Invalid YAML file. Loading with default settings. Error details: {e}")
except Exception as e:
logging.error(f"Error loading state: {e}")
self.isFirstLoad = False
self.checkStateTimer.start()
print('checkStateTimer started')
def saveImageState(self):
try:
# Check if state loading is complete before saving the state
if self.isFirstLoad:
logging.debug("State loading is not complete. Skipping saveImageState.")
return
else:
logging.debug("Saving current state to disk.")
state = {
'lastImagePath': self.main.currentImagePath,
'lastPixmapPos': [self.main.pixmapItem.pos().x(), self.main.pixmapItem.pos().y()],
'lastTransform': [self.main.view.transform().m11(), self.main.view.transform().m22()],
'lastSliderValue': self.main.slider.value(),
'lastSceneRect': [self.main.scene.sceneRect().x(), self.main.scene.sceneRect().y(),
self.main.scene.sceneRect().width(), self.main.scene.sceneRect().height()],
'lastScrollBarPos': [self.main.view.horizontalScrollBar().value(),
self.main.view.verticalScrollBar().value()]
}
with open('state.yaml', 'w') as file:
yaml.dump(state, file)
logging.debug(f"Saved state to disk: {state}")
except Exception as e:
logging.error(f"An error occurred while saving the image state: {e}")
def checkState(self):
try:
newPos = self.main.pixmapItem.pos()
newTransform = self.main.view.transform()
if newPos is not None and newTransform is not None:
if newPos != self.oldPos or newTransform != self.oldTransform:
if not self.isFirstLoad:
self.restartsaveImageStateTimer()
self.oldPos = newPos
self.oldTransform = newTransform
else:
logging.warning("Either pixmap position or view transform is None.")
except Exception as e:
logging.error(f"Error in checkState: {e}")
def handleSaveImageStateTimeout(self):
try:
if self.saveImageStateFlag:
self.saveImageState()
self.saveImageStateFlag = False
except Exception as e:
logging.error(f"Error handling save state timeout: {e}")
def restartsaveImageStateTimer(self):
try:
if self.isFirstLoad:
logging.debug("restartsaveImageStateTimer skipped because isFirstLoad is True.")
return
if self.saveImageStateTimer.isActive():
self.saveImageStateTimer.stop()
self.saveImageStateTimer.start()
self.saveImageStateFlag = True
logging.debug(f"restartsaveImageStateTimer called")
except Exception as e:
logging.error(f"Error in restartsaveImageStateTimer: {e}")
class WindowStateHandler:
def __init__(self, image_previewer):
self.main = image_previewer
self.main.trayIcon.activated.connect(self.handleTrayActivation)
def handleWindowStateChange(self, event):
if event.type() == QEvent.Type.WindowStateChange:
if self.main.windowState() == Qt.WindowState.WindowMinimized:
logging.debug("Window minimized to taskbar. Saving current state.")
self.main.lastPixmapPos = self.main.pixmapItem.pos()
self.main.lastTransform = self.main.view.transform()
self.main.lastSliderValue = self.main.slider.value()
self.main.lastSceneRect = self.main.scene.sceneRect()
self.main.lastScrollBarPos = (
self.main.view.horizontalScrollBar().value(), self.main.view.verticalScrollBar().value())
print(
f"Saved state: Pixmap Position ({self.main.lastPixmapPos.x()}, {self.main.lastPixmapPos.y()}), Transform ({self.main.lastTransform.m11()}, {self.main.lastTransform.m22()}), Slider Value {self.main.lastSliderValue}, Scene Rect {self.main.lastSceneRect.x()}, {self.main.lastSceneRect.y()}, {self.main.lastSceneRect.width()}, {self.main.lastSceneRect.height()}, ScrollBar Position {self.main.lastScrollBarPos}")
elif event.oldState() == Qt.WindowState.WindowMinimized and self.main.lastPixmapPos is not None and self.main.lastTransform is not None and self.main.lastSliderValue is not None and self.main.lastSceneRect is not None and self.main.lastScrollBarPos is not None:
logging.debug("Window restored from taskbar.")
self.main.view.resetTransform()
self.main.scene.setSceneRect(self.main.lastSceneRect)
self.main.pixmapItem.setPos(self.main.lastPixmapPos)
self.main.view.setTransform(self.main.lastTransform)
self.main.slider.setValue(self.main.lastSliderValue)
self.main.view.horizontalScrollBar().setValue(self.main.lastScrollBarPos[0])
self.main.view.verticalScrollBar().setValue(self.main.lastScrollBarPos[1])
self.main.show()
print(
f"Restored state: Pixmap Position ({self.main.lastPixmapPos.x()}, {self.main.lastPixmapPos.y()}), Transform ({self.main.lastTransform.m11()}, {self.main.lastTransform.m22()}), Slider Value {self.main.lastSliderValue}, Scene Rect {self.main.lastSceneRect.x()}, {self.main.lastSceneRect.y()}, {self.main.lastSceneRect.width()}, {self.main.lastSceneRect.height()}, ScrollBar Position {self.main.lastScrollBarPos}")
def handleTrayActivation(self, reason):
if reason == QSystemTrayIcon.ActivationReason.Trigger:
logging.debug("System tray icon activated. Restoring window.")
self.restoreWindow()
def restoreWindow(self):
try:
self.main.show()
self.main.view.resetTransform()
self.main.scene.setSceneRect(self.main.lastSceneRect)
self.main.pixmapItem.setPos(self.main.lastPixmapPos)
self.main.view.setTransform(self.main.lastTransform)
self.main.slider.setValue(self.main.lastSliderValue)
self.main.view.horizontalScrollBar().setValue(self.main.lastScrollBarPos[0])
self.main.view.verticalScrollBar().setValue(self.main.lastScrollBarPos[1])
print(
f"Restored state: Pixmap Position ({self.main.lastPixmapPos.x()}, {self.main.lastPixmapPos.y()}), Transform ({self.main.lastTransform.m11()}, {self.main.lastTransform.m22()}), Slider Value {self.main.lastSliderValue}, Scene Rect {self.main.lastSceneRect.x()}, {self.main.lastSceneRect.y()}, {self.main.lastSceneRect.width()}, {self.main.lastSceneRect.height()}, ScrollBar Position {self.main.lastScrollBarPos}")
self.main.trayIcon.hide()
except Exception as e:
logging.error(f"Error in restoreWindow: {e}")
def minimizeWindow(self):
try:
logging.debug("Minimizing window to system tray. Saving current state.")
self.main.lastPixmapPos = self.main.pixmapItem.pos()
self.main.lastTransform = self.main.view.transform()
self.main.lastSliderValue = self.main.slider.value()
self.main.lastSceneRect = self.main.scene.sceneRect()
self.main.lastScrollBarPos = (
self.main.view.horizontalScrollBar().value(), self.main.view.verticalScrollBar().value())
print(
f"Saved state: Pixmap Position ({self.main.lastPixmapPos.x()}, {self.main.lastPixmapPos.y()}), Transform ({self.main.lastTransform.m11()}, {self.main.lastTransform.m22()}), Slider Value {self.main.lastSliderValue}, Scene Rect {self.main.lastSceneRect.x()}, {self.main.lastSceneRect.y()}, {self.main.lastSceneRect.width()}, {self.main.lastSceneRect.height()}, ScrollBar Position {self.main.lastScrollBarPos}")
self.main.hide()
self.main.trayIcon.show()
except Exception as e:
logging.error(f"Error in minimizeWindow: {e}")
if __name__ == "__main__":
try:
app = QApplication(sys.argv)
window = ImagePreviewer()
window.show()
sys.exit(app.exec())
except Exception as e:
logging.error(f"Error in main: {e}")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment