2025-03-12 12:55:21 +01:00

154 lines
5.1 KiB
Python

from PyQt6.QtWidgets import QWidget, QVBoxLayout, QLabel, QScrollArea, QTableView
from PyQt6.QtCore import QAbstractTableModel, QModelIndex, Qt
import numpy as np
from cpdctrl.led_script import LedScript
import time
import datetime
class TimeLeft(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.t_end = None
self.setLayout(QVBoxLayout())
self.layout().addWidget(QLabel("Time left"))
self.w_time_left = QLabel("N.A.")
self.layout().addWidget(self.w_time_left)
self.w_end_time = QLabel("N.A.")
self.layout().addWidget(self.w_end_time)
def set_end_time(self, t_end: float):
"""
Set the end time
Parameters
----------
t_end
The end time in seconds since epoch
"""
self.t_end = t_end
self.w_end_time.setText(
datetime.datetime.fromtimestamp(t_end).strftime("%Y-%m-%d %H:%M:%S")
)
def update_time(self, t_now: float):
"""
Update the time left display
Parameters
----------
t_now
The current time in seconds since epoch
"""
if self.t_end is None: raise RuntimeError("Update called before end time was set")
# convert to format <days>d, <hours>h, <minutes>m, <seconds>s
print(self.t_end, t_now, self.t_end - t_now)
sign = 1 if self.t_end > t_now else -1
time_left = abs(int(self.t_end - t_now))
days = sign * int(time_left / (24 * 3600))
time_left %= (24 * 3600)
hours = sign * int(time_left / 3600)
time_left %= 3600
minutes = sign * int(time_left / 60)
time_left %= 60
seconds = sign * int(time_left)
self.w_time_left.setText(f"{days}d, {hours:02}h, {minutes:02}m, {seconds:02}s")
class LedScriptTableModel(QAbstractTableModel):
"""
A table model for the led script.
It only allows editing values that are in the future
"""
def __init__(self, led_script: LedScript, parent=None):
super().__init__(parent)
self.led_script = led_script
self.indices = [i[0] for i in LedScript.ARRAY_DTYPE]
self.dt = 0
def rowCount(self, parent=None):
return self.led_script.script[self.indices[0]].shape[0]
def columnCount(self, parent=None):
return len(self.indices)
def data(self, index: QModelIndex, role: int):
if role == Qt.ItemDataRole.DisplayRole:
return str(self.led_script.script[self.indices[index.column()]][index.row()])
def headerData(self, section: int, orientation: Qt.Orientation, role: int):
if role == Qt.ItemDataRole.DisplayRole:
if orientation == Qt.Orientation.Horizontal:
return self.indices[section]
else:
return str(section)
def setData(self, index: QModelIndex, value, role: int):
if role == Qt.ItemDataRole.EditRole:
self.led_script.script[self.indices[index.column()]][index.row()] = value
return True
return False
def addRows(self, rowCount: int, parent: QModelIndex):
self.beginInsertRows(parent, self.rowCount(), self.rowCount() + rowCount - 1)
for i in self.indices:
np.append(self.led_script.script[i], np.zeros((rowCount, self.led_script.script[i].shape[1])), axis=0)
self.endInsertRows()
def removeRows(self, row: int, count: int, parent: QModelIndex):
self.beginRemoveRows(parent, row, row + count - 1)
rows = [i for i in range(row, row+count)]
for i in self.indices:
np.delete(self.led_script.script[i], rows, axis=0)
self.endRemoveRows()
def flags(self, index: QModelIndex):
flags = Qt.ItemFlag.ItemIsSelectable
if index.row() >= self.led_script.get_current_index(self.dt):
flags |= Qt.ItemFlag.ItemIsEnabled
if index.column() in [0, 2]:
flags |= Qt.ItemFlag.ItemIsEditable
return flags
class LedScriptViewer(QWidget):
def __init__(self, led_script: LedScript, parent=None):
super().__init__(parent)
self.led_script = None
self.model = LedScriptTableModel(led_script, self)
self.l_vbox = QVBoxLayout()
self.setLayout(self.l_vbox)
self.l_vbox.addWidget(QLabel("You may edit the dt and led values of future rows."))
self.w_scroll = QScrollArea()
self.l_vbox.addWidget(self.w_scroll)
self.w_table = QTableView(self)
self.w_table.setModel(self.model)
self.w_table.show()
self.w_scroll.setWidget(self.w_table)
self.w_scroll.setWidgetResizable(True)
self.w_scroll.setFixedHeight(200)
self.w_time_left = TimeLeft(self)
self.l_vbox.addWidget(self.w_time_left)
self.l_vbox.addStretch(1)
def set_script(self, led_script: LedScript):
self.model = LedScriptTableModel(led_script, self)
self.w_table.setModel(self.model)
self.w_table.show()
def set_relative_time(self, t: float):
pass
raise NotImplementedError()
def update_time(self, t_now: float):
self.w_time_left.update_time(t_now)