def run(self): timer = QTimer() timer.start(self.time_length) while timer.remainingTime() > 0: self.timerVal.emit(timer.remainingTime()) time.sleep(0.05) self.timerVal.emit(timer.remainingTime())
class Planta(QObject): senal_update = None def __init__(self, tipo, *args, **kwargs): super().__init__(*args, **kwargs) self.tipo = tipo self.timer = QTimer() self.timer.start(100) self.init_gui() def init_gui(self): while self.timer.remainingTime() > 0: print(self.timer.remainingTime())
class Countdown(): def __init__(self): self.timer_main = QTimer() self.timer_sec = QTimer() self.timer_main.setSingleShot(True) self.interval = 30 self.timer_sec.setInterval(1000) self.callback_end = None self.callback_update = None self.timer_main.timeout.connect(self.end_signal_emitted) self.timer_sec.timeout.connect(self.update_signal_emitted) def start(self): ''' Start the countdown ''' self.timer_main.start(self.interval * 1000) self.timer_sec.start() self.update_signal_emitted() def end_signal_emitted(self): ''' Stop countdown and run callback_end function ''' self.stop() if self.callback_end is not None: self.callback_end() def update_signal_emitted(self): ''' Run callback_update function ''' if self.callback_update is not None: remaining_time = self.timer_main.remainingTime() if remaining_time != -1: self.callback_update(int(round(remaining_time / 1000))) def stop(self): ''' Stop the countdown ''' self.timer_main.stop() self.timer_sec.stop() def is_active(self): ''' Returns the state of the countdown ''' return self.timer_main.isActive()
class SystemTrayIcon(QtWidgets.QSystemTrayIcon): """ GUI CLASS FOR WORKOUT ALERT Author: ORIGINAL CODE FROM THE INTERWEBS EDITED BY JIN JEONGKYUN Date: 2020-04-29 """ def __init__(self, icon, parent=None): QtWidgets.QSystemTrayIcon.__init__(self, icon, parent) self.timer = QTimer(self) self.timer.setInterval(2000000) self.timer.start() self.timer.timeout.connect(self.timeout) menu = QtWidgets.QMenu(parent) exitAction = menu.addAction("Exit") exitAction.triggered.connect(lambda: exit()) viewWorkouts = menu.addAction("View Workout List") viewWorkouts.triggered.connect(lambda: ShowAlert('list')) showTimeLeft = menu.addAction("Show Time Left") showTimeLeft.triggered.connect( lambda: ctypes.windll.user32.MessageBoxW( 0, str(math.floor(self.timer.remainingTime() / 1000)) + " SECS", 1 )) self.setContextMenu(menu) def exit(self): QtCore.QCoreApplication.exit() def timeout(self): sender = self.sender() if id(sender) == id(self.timer): ShowAlert()
class Ronda(QObject): senal_paso_correcto = pyqtSignal(list) senal_actualizar_combo = pyqtSignal(int) senal_actualizar_combo_maximo = pyqtSignal(int) senal_actualizar_progreso = pyqtSignal(int) senal_actualizar_aprobacion = pyqtSignal(int) senal_paso_correcto = pyqtSignal(set) senal_calcular_estadisticas = pyqtSignal(int, int, int, int, bool) senal_activar_boton_jugar_solo = pyqtSignal(bool) senal_despintar_zona_captura = pyqtSignal() senal_pintar_tecla = pyqtSignal(str) senal_activar_boton_comenzar = pyqtSignal() senal_desactivar_opciones = pyqtSignal(bool) def __init__(self, duracion=10, tiempo_entre_pasos=0.1, aprobacion_necesaria=0, ruta_cancion=path.join(*p.CANCIONES["Shingeki"])): super().__init__() url = QUrl() url = url.fromLocalFile("cancion_1.wav") content = QMediaContent(url) self.__dificultad = "" self.cancion = QMediaPlayer() self.cancion.setMedia(content) self.esta_pausada = False self.__duracion = duracion self.__tiempo_entre_pasos = tiempo_entre_pasos self.aprobacion_necesaria = aprobacion_necesaria self.puntaje = 0 self.aprobacion = 0 self.__combo = 0 self.__combo_maximo = 0 self.pasos_correctos = 0 self.pasos_incorrectos = 0 self.pasos_generados = set() self.nivel_comenzado = False self.flechas_capturadas = { "normal": 0, "x2": 0, "dorada": 0, "hielo": 0, } self.rect_zona_captura = QRect(20, 550, 200, 50) # generador de pasos self.generador_pasos = GeneradorPasos(self.tiempo_entre_pasos, ronda=self) # Timer duracion self.timer = QTimer() self.timer.setInterval(self.duracion * 1000) self.timer.timeout.connect(self.terminar) # Timer barras de progreso self.timer_barras = QTimer() self.timer_barras.setInterval(p.TASA_REFRESCO * 1000) self.timer_barras.timeout.connect(self.actualizar_progreso_aprobacion) @property def dificultad(self): return self.__dificultad @dificultad.setter def dificultad(self, string): self.__dificultad = string if string == "Principiante": self.generador_pasos.pasos_dobles = False self.generador_pasos.pasos_triples = False elif string == "Aficionado": self.generador_pasos.pasos_dobles = True self.generador_pasos.pasos_triples = False elif string == "Maestro Cumbia": self.generador_pasos.pasos_dobles = True self.generador_pasos.pasos_triples = True @property def combo(self): return self.__combo @combo.setter def combo(self, valor): self.__combo = valor # Actualiza el combo maximo if self.combo > self.combo_maximo: self.combo_maximo = self.combo self.senal_actualizar_combo.emit(self.combo) @property def combo_maximo(self): return self.__combo_maximo @combo_maximo.setter def combo_maximo(self, valor): self.__combo_maximo = valor self.senal_actualizar_combo_maximo.emit(self.combo) @property def aprobacion(self): return self.__aprobacion @aprobacion.setter def aprobacion(self, valor): self.__aprobacion = valor self.senal_actualizar_aprobacion.emit(valor) @property def progreso(self): return self.__progreso @progreso.setter def progreso(self, valor): self.__progreso = valor self.senal_actualizar_progreso.emit(valor) @property def tiempo_entre_pasos(self): return self.__tiempo_entre_pasos @tiempo_entre_pasos.setter def tiempo_entre_pasos(self, valor): self.__tiempo_entre_pasos = valor print("Cambiando tiempo entre pasos") print(self.tiempo_entre_pasos) self.generador_pasos.tiempo_entre_pasos = valor @property def duracion(self): return self.__duracion @duracion.setter def duracion(self, valor): self.__duracion = valor self.timer.setInterval(valor * 1000) def comenzar(self): print("Ronda Comenzada") self.reiniciar_estadisticas() self.nivel_comenzado = True self.timer.start() self.timer_barras.start() self.cancion.play() self.generador_pasos.start() self.senal_activar_boton_jugar_solo.emit(True) def pausar(self): self.esta_pausada = True self.generador_pasos.stop() for paso in self.pasos_generados: paso.stop() self.timer_barras.stop() self.cancion.pause() tiempo_restante = self.timer.remainingTime() self.timer.stop() # crea un timer nuevo con el tiempo que quedaba self.timer = QTimer() self.timer.setInterval(tiempo_restante) self.timer.timeout.connect(self.terminar) def reanudar(self): self.esta_pausada = False for paso in self.pasos_generados: paso.start() self.timer.start() self.timer_barras.start() self.generador_pasos.start() self.cancion.play() def terminar(self, interrumpido=False): if interrumpido: self.nivel_interrupido = True else: self.nivel_interrupido = False print("Ronda Terminada") self.nivel_comenzado = False self.timer.stop() self.timer_barras.stop() self.cancion.stop() self.generador_pasos.stop() # Espera a que pasen todas las flechas self.timer_flechas_restantes = QTimer() self.timer_flechas_restantes.setInterval((500 / p.VELOCIDAD_FLECHA) * 1000) self.timer_flechas_restantes.setSingleShot(True) self.timer_flechas_restantes.timeout.connect(self.terminar_2) self.timer_flechas_restantes.start() def terminar_2(self): self.senal_activar_boton_comenzar.emit() self.senal_desactivar_opciones.emit(True) self.calcular_puntaje() self.senal_calcular_estadisticas.emit(self.puntaje, self.combo_maximo, self.pasos_incorrectos, self.aprobacion, self.nivel_interrupido) self.nivel_interrupido = False self.reiniciar_estadisticas() def calcular_puntaje(self): flechas_normales = self.flechas_capturadas["normal"] flechas_x2 = self.flechas_capturadas["x2"] flechas_doradas = self.flechas_capturadas["dorada"] flechas_hielo = self.flechas_capturadas["hielo"] suma_flechas = flechas_normales + (p.MULT_FLECHA_X2 * flechas_x2)\ + (p.MUTL_FLECHA_DORADA * flechas_doradas) + flechas_hielo self.puntaje = self.combo_maximo * suma_flechas * p.PUNTOS_FLECHA def reiniciar_estadisticas(self): self.puntaje = 0 self.aprobacion = 0 self.progreso = 0 self.combo = 0 self.combo_maximo = 0 self.pasos_correctos = 0 self.pasos_incorrectos = 0 self.flechas_capturadas = { "normal": 0, "x2": 0, "dorada": 0, "hielo": 0, } def revisar_teclas(self, teclas): if teclas.issubset({p.FLECHA_DERECHA, p.FLECHA_IZQUIERDA, p.FLECHA_ABAJO, p.FLECHA_ARRIBA}): pasos = self.pasos_en_zona_captura() if pasos: for paso in pasos: paso_correcto = self.revisar_paso(paso, teclas) if paso_correcto: paso.realizado = True self.pasos_correctos += 1 self.combo += 1 else: self.pasos_incorrectos += 1 self.combo = 0 else: # En caso de que no hayan pasos en la zona de captura self.pasos_incorrectos += 1 self.combo = 0 def pasos_en_zona_captura(self): pasos_en_zona = set() pasos = self.pasos_generados for paso in pasos: if paso.rect.intersects(self.rect_zona_captura): pasos_en_zona.add(paso) return(pasos_en_zona) def revisar_paso(self, paso, teclas): """ Determina si un paso es correcto o incorrecto y además realiza las acciones necesarias para las flechas que se encuentran dentro del paso dadas las teclas presionadas """ paso_correcto = False set_true_false = set() # Determinara si se cumplieron todos los pasos for flecha in paso.flechas: flecha_es_correcta = self.revisar_flecha(flecha, teclas) set_true_false.add(flecha_es_correcta) if False in set_true_false: # Caso en que hay flechas incorrectas return False elif len(teclas) > len(paso.flechas): # Caso presiona teclas ademas de las correctas return False elif paso.realizado: # Caso vuelve a capturar el mismo paso return False else: self.senal_paso_correcto.emit(paso.flechas) return True def revisar_flecha(self, flecha, teclas): direcciones = { "derecha": p.FLECHA_DERECHA, "izquierda": p.FLECHA_IZQUIERDA, "arriba": p.FLECHA_ARRIBA, "abajo": p.FLECHA_ABAJO } if direcciones[flecha.direccion] in teclas: flecha.capturar() tipo = flecha.tipo self.flechas_capturadas[f"{tipo}"] += 1 return True else: return False def actualizar_progreso_aprobacion(self): tiempo_restante = self.timer.remainingTime() / 1000 self.progreso = int(((self.duracion - tiempo_restante) / self.duracion) * 100) self.aprobacion = self.calcular_aprobacion() def calcular_aprobacion(self): try: pasos_totales = (self.pasos_correctos + self.pasos_incorrectos) aprobacion = p.MULTIPLCIADOR_APROBACION * \ ((self.pasos_correctos - self.pasos_incorrectos) / pasos_totales) except ZeroDivisionError: aprobacion = 0 return aprobacion def cheat_jugar_solo(self, tiempo): self.timer_solo = QTimer() self.timer_solo.setInterval((p.TASA_REFRESCO * 6) * 1000) self.timer_solo.timeout.connect(self.jugar_solo) self.timer_solo.start() self.timer_cheat = QTimer() self.timer_cheat.setInterval(tiempo * 1000) self.timer_cheat.setSingleShot(True) self.timer_cheat.timeout.connect(self.timer_solo.stop) self.timer_cheat.start() def jugar_solo(self): direccion_a_flecha = {"derecha": p.FLECHA_DERECHA, "izquierda": p.FLECHA_IZQUIERDA, "arriba": p.FLECHA_ARRIBA, "abajo": p.FLECHA_ABAJO} pasos_en_zona = self.pasos_en_zona_captura() teclas_automaticas = set() if pasos_en_zona: for paso in pasos_en_zona: if paso.realizado: continue for flecha in paso.flechas: direccion = flecha.direccion tecla = direccion_a_flecha[direccion] teclas_automaticas.add(tecla) self.revisar_teclas(teclas_automaticas) for tecla in teclas_automaticas: self.senal_pintar_tecla.emit(tecla) print("Emitiendo senal") self.timer_despintar_tecla = QTimer() self.timer_despintar_tecla.setInterval(0.1 * 1000) self.timer_despintar_tecla.setSingleShot(True) self.timer_despintar_tecla.timeout.connect( self.despintar_teclas_para_cheat) self.timer_despintar_tecla.start() teclas_automaticas = set() def despintar_teclas_para_cheat(self): self.senal_despintar_zona_captura.emit()
class TimerWidget(QWidget): def __init__(self): super().__init__() self.initUI() # Инициализируем плеер и плейлист, на котором поставим цикличное воспроизведение self.playlist = QMediaPlaylist(self) self.playlist.setPlaybackMode(QMediaPlaylist.Loop) self.player = QMediaPlayer() # Создадим пустую ссылку, чтобы программа не крашилась, если пользователь не выберет мелодию self.url = QUrl() # Подскажем для чего кнопка self.lbl = QLabel('Выберите мелодию для таймера:', self) self.lbl.move(165, 100) # Кнопка для выбора файла с мелодией self.btn_getfile = QPushButton('Выбрать файл', self) self.btn_getfile.move(200, 125) self.btn_getfile.resize(100, 50) self.btn_getfile.clicked.connect(self.getfile) # Кнопка старта таймера self.btn_start = QPushButton('Старт', self) self.btn_start.move(225, 225) self.btn_start.resize(50, 50) self.btn_start.clicked.connect(self.start_timer) # Кнопка остановки таймера до того, как он закончит отсчет self.btn_stop = QPushButton('Стоп', self) self.btn_stop.move(250, 225) self.btn_stop.resize(50, 50) self.btn_stop.clicked.connect(self.stop_timer) self.btn_stop.setVisible(False) # Кнопка паузы таймера self.btn_pause = QPushButton('Пауза', self) self.btn_pause.move(200, 225) self.btn_pause.resize(50, 50) self.btn_pause.clicked.connect(self.pause_timer) self.btn_pause.setVisible(False) # Кнопка для продолжения отсчета таймера self.btn_continue = QPushButton('Дальше', self) self.btn_continue.move(200, 225) self.btn_continue.resize(50, 50) self.btn_continue.clicked.connect(self.continue_timer) self.btn_continue.setVisible(False) # Кнопка для выключения таймера, когда он закончит отсчет self.btn_off = QPushButton('Выкл', self) self.btn_off.move(225, 225) self.btn_off.resize(50, 50) self.btn_off.clicked.connect(self.timer_off) self.btn_off.setVisible(False) # Спрашивваем значение таймера self.get_timer = QTimeEdit(self) self.get_timer.move(185, 175) self.get_timer.resize(130, 50) self.get_timer.setFont(QFont('Times', 15, QFont.Bold)) self.get_timer.setDisplayFormat('HH:mm:ss') # Дисплей для вывода таймера self.dsp = QLCDNumber(self) self.dsp.resize(200, 50) self.dsp.move(150, 175) self.dsp.setVisible(False) self.dsp.setDigitCount(8) # Таймер self.nTimer = QTimer() self.nTimer.timeout.connect(self.timer) def initUI(self): self.setGeometry(100, 100, 500, 500) self.setWindowTitle('Таймер') def start_timer(self): # Добавляем мелодию в плеер self.content = QMediaContent(self.url) self.playlist.addMedia(self.content) self.player.setPlaylist(self.playlist) # Выводим начальное значение времени на дисплей self.dsp.display(self.get_timer.time().toString('hh:mm:ss')) # Переводим время в секунды timer = self.get_timer.time() timer_text = timer.toString('hh:mm:ss') timer_int = list(map(lambda x: int(x), timer_text.split(':'))) self.timer_in_sec = timer_int[0]*3600 + timer_int[1]*60 + timer_int[2] # Проверяем не установили ли нулевое значение if self.timer_in_sec == 0: self.timer_timeout() else: # Запускаем таймер self.nTimer.start(1000) # Махинации с показом кнопок self.btn_start.setVisible(False) self.btn_pause.setVisible(True) self.btn_stop.setVisible(True) self.dsp.setVisible(True) self.get_timer.setVisible(False) self.lbl.setVisible(False) self.btn_getfile.setVisible(False) def timer(self): # Функция обновления таймера и дисплея со временем # Делаем обратный отсчет, отнимая каждую секунду единицу из начального значения self.timer_in_sec -= 1 # Переводим целочисленные значения в строку timer_text = list(map(lambda x: str(x), [self.timer_in_sec // 3600, (self.timer_in_sec % 3600) // 60, (self.timer_in_sec % 3600) % 60])) # Если один символ, то к нему добавляется ноль if len(timer_text[0]) == 1: timer_text[0] = '0' + timer_text[0] if len(timer_text[1]) == 1: timer_text[1] = '0' + timer_text[1] if len(timer_text[2]) == 1: timer_text[2] = '0' + timer_text[2] # Объединяем список в формат hh:mm:ss timer_text = ':'.join(timer_text) # Выводим текст со временем на дисплей self.dsp.display(timer_text) # Если таймер дошел до нуля: if self.timer_in_sec == 0: self.timer_timeout() else: # Обновляем таймер self.nTimer.start(1000) def stop_timer(self): # Останавливаем таймер self.nTimer.stop() # Махинации с кнопками self.btn_start.setVisible(True) self.btn_stop.setVisible(False) self.btn_pause.setVisible(False) self.dsp.setVisible(False) self.btn_continue.setVisible(False) self.get_timer.setVisible(True) self.btn_getfile.setVisible(True) self.lbl.setVisible(True) def continue_timer(self): # Продолжаем таймер с того места, где остановились self.nTimer.start(self.inter) # Махинации с показом кнопок self.btn_continue.setVisible(False) self.btn_pause.setVisible(True) def pause_timer(self): # Ловим оставшееся время таймера self.inter = self.nTimer.remainingTime() # Останавливаем таймер и делаем махинации с показом кнопок self.nTimer.stop() self.btn_pause.setVisible(False) self.btn_continue.setVisible(True) def timer_off(self): # Махинации с кнопками self.btn_start.setVisible(True) self.dsp.setVisible(False) self.get_timer.setVisible(True) self.btn_off.setVisible(False) self.btn_getfile.setVisible(True) self.lbl.setVisible(True) # Останавливаем мелодию self.player.stop() def timer_timeout(self): # Останавливаем таймер self.nTimer.stop() # Махинации с кнопками self.get_timer.setVisible(False) self.btn_stop.setVisible(False) self.btn_pause.setVisible(False) self.btn_continue.setVisible(False) self.btn_off.setVisible(True) self.dsp.setVisible(True) self.lbl.setVisible(False) self.btn_getfile.setVisible(False) # Запускаем функцию воспроизведения мелодии self.playmus() def playmus(self): # Воспроизводим мелодию self.player.play() def getfile(self): # Достаем файл с мелодией и сохраняем её путь fname = QFileDialog.getOpenFileName(self, 'Open File', '/home', 'Audio Files (*mp3 *wav)') self.url = QUrl.fromLocalFile(fname[0])
class Hearthstone( QMainWindow ): # the most important variables are defined here with their starting values moneyCount = 1000 rankCount = 25 goldCount = 0 commonCards = 100 rareCards = 25 epicCards = 0 legendaryCards = 0 packCount = 0 adventureCount = 0 freeToPlay = True brawlPlayed = False questPlayed = False welcomeGift = False # the init function of the main class - setting up some sounds and timers that will be used later on, so that they can be used by other functions to not cause an AttributeError ########################################################################## def __init__(self): super(Hearthstone, self).__init__() self.initGUI() self.initMenu() self.theme = QSound("sounds/HearthstoneSoundtrack-MainTitle.wav") self.ping = QSound("sounds/WhatsApp_Original_Message.wav") self.sax = QSound("sounds/EpicSaxGuy-EpicSaxGuyCruzoRemix.wav") self.theme.play() # starting the app out with the hearthstone theme self.theme.setLoops( 100 ) # hopefully nobody will play this long... (does this cause python to crash when I close the application? Possible..) self.moneyTimer = QTimer( self ) # these timers are for use in the pay to win mode -> they make sure money is self.moneyTimer.timeout.connect( self.depleteMoney ) # taken out of the players account and ranks and gold are put in regularly self.rankTimer = QTimer(self) self.rankTimer.timeout.connect(self.increaseRank) self.goldTimer = QTimer(self) self.goldTimer.timeout.connect(self.increaseGold) def initGUI(self): self.popUpFriendsTimer = QTimer(self) self.popUpFriendsTimer.timeout.connect(self.popUpFriends) self.popUpFinancesTimer = QTimer(self) self.popUpFinancesTimer.timeout.connect(self.popUpFinances) self.popUpFriendsTimer.start( 30000 ) # this makes the 'whatsapp messages of friends' pop up, who worry about the player putting too much time into the game try: if self.moneyTimer.isActive( ) == True: # so that the money, rank and gold values keep changing when the player returns to the main screen in pay to win mode self.moneyTimer.stop() self.rankTimer.stop() self.goldTimer.stop() self.moneyTimer.start(10000) self.rankTimer.start(15000) self.goldTimer.start(5000) else: pass except AttributeError: pass # setting up allllll the GUI elements of the main screen and their signal/slot relationships ########################################################################## self.soloBut = QPushButton("Adventure") self.soloBut.setMinimumSize(100, 80) self.soloBut.clicked.connect(self.playAdventure) self.playBut = QPushButton("Play") self.playBut.setMinimumSize(100, 80) self.playBut.clicked.connect(self.play) self.brawlBut = QPushButton("Tavern Brawl") self.brawlBut.setMinimumSize(100, 80) self.brawlBut.clicked.connect(self.playBrawl) self.questBut = QPushButton("Quest") self.questBut.setMinimumSize(50, 80) self.questBut.clicked.connect(self.playQuest) self.shopBut = QPushButton("Shop") self.shopBut.setMinimumSize(50, 80) self.shopBut.clicked.connect(self.showShop) self.packBut = QPushButton("Packs") self.packBut.setMinimumSize(50, 80) self.packScreen = PackOpeningGraph( self.packCount ) # instance of the only other real custom widget class used in this app self.packBut.clicked.connect(self.updatePackOpenings) self.collectionBut = QPushButton("Collection") self.collectionBut.setMinimumSize(50, 80) self.collectionBut.clicked.connect(self.displayCollection) self.workBut = QPushButton("Work for a Month") self.workBut.setMinimumSize(100, 80) self.workBut.clicked.connect(self.work) mainBut_layout = QVBoxLayout() mainBut_layout.addWidget(self.soloBut) mainBut_layout.addStretch(2) mainBut_layout.addWidget(self.playBut) mainBut_layout.addStretch(2) mainBut_layout.addWidget(self.brawlBut) mainBut_layout.addStretch(2) mainBut_layout.addWidget(self.workBut) mainButtons = QGroupBox() mainButtons.setLayout(mainBut_layout) mainButtons.setMaximumSize(300, 370) leftBut_layout = QVBoxLayout() leftBut_layout.addWidget(self.questBut) leftBut_layout.addWidget(self.shopBut) leftButtons = QGroupBox() leftButtons.setLayout(leftBut_layout) leftButtons.setMaximumSize(300, 300) rightBut_layout = QVBoxLayout() rightBut_layout.addWidget(self.packBut) rightBut_layout.addWidget(self.collectionBut) rightButtons = QGroupBox() rightButtons.setLayout(rightBut_layout) rightButtons.setMaximumSize(300, 300) radios_layout = QHBoxLayout() self.f2p = QRadioButton("Free to Play") self.p2w = QRadioButton("Pay to Win") if Hearthstone.freeToPlay == True: self.f2p.setChecked(True) else: self.p2w.setChecked(True) self.f2p.clicked.connect(self.FreeToPlay) self.p2w.clicked.connect(self.PayToWin) radios_layout.addWidget(self.f2p) radios_layout.addStretch(2) radios_layout.addWidget(self.p2w) radiobuttons = QGroupBox() radiobuttons.setLayout(radios_layout) radiobuttons.setMaximumSize(300, 70) self.gold = QLineEdit() self.gold.setEnabled(False) # so that one cannot cheat! self.goldLabel = QLabel("Gold") self.goldLabel.setObjectName("gold") self.money = QLineEdit() self.money.setEnabled(False) self.moneyLabel = QLabel("Money") self.moneyLabel.setObjectName("money") self.rank = QLineEdit() self.rank.setEnabled(False) self.rankLabel = QLabel("Rank") self.rankLabel.setObjectName("rank") money_layout = QHBoxLayout() money_layout.addWidget(self.moneyLabel) money_layout.addWidget(self.money) moneyBox = QGroupBox() moneyBox.setLayout(money_layout) moneyBox.setMaximumSize(300, 70) rank_layout = QHBoxLayout() rank_layout.addWidget(self.rankLabel) rank_layout.addWidget(self.rank) rankBox = QGroupBox() rankBox.setLayout(rank_layout) rankBox.setMaximumSize(300, 70) gold_layout = QHBoxLayout() gold_layout.addWidget(self.goldLabel) gold_layout.addWidget(self.gold) goldBox = QGroupBox() goldBox.setLayout(gold_layout) goldBox.setMaximumSize(300, 70) grid = QGridLayout() grid.addWidget(moneyBox, 0, 0, 1, 2) grid.addWidget(rankBox, 0, 2, 1, 2) grid.addWidget(goldBox, 0, 4, 1, 2) grid.addWidget(mainButtons, 1, 2, 4, 2) grid.addWidget(leftButtons, 3, 0, 2, 1) grid.addWidget(rightButtons, 3, 5, 2, 1) grid.addWidget(radiobuttons, 4, 2, 1, 3) mainScreen = QWidget() mainScreen.setLayout(grid) mainScreen.setObjectName("main") # for the css self.setWindowTitle("Hearthstone") h = qApp.desktop().screenGeometry().height() - 100 w = qApp.desktop().screenGeometry().width() - 350 self.setGeometry(175, 0, w, h) self.setFixedSize(w, h) self.setCentralWidget(mainScreen) self.show() self.updateGoldCount( ) # so the numbers in the line edits up top are always accurate self.updateMoneyCount() self.updateRankCount() def updateGoldCount(self): try: self.gold.setText(str(Hearthstone.goldCount)) except RuntimeError: pass def updateMoneyCount(self): try: self.money.setText(str(Hearthstone.moneyCount)) except RuntimeError: pass def updateRankCount(self): try: if Hearthstone.rankCount <= 0: self.rank.setText( "LEGEND") # In Hearthstone, rank 0 is called legend else: self.rank.setText(str(Hearthstone.rankCount)) except RuntimeError: pass def updatePackOpenings( self ): # this exists so if the player buys 2 packs and only uses one, the next time he visits the open packs screen, he only has one pack left Hearthstone.packCount -= PackOpeningGraph.usedPacks PackOpeningGraph.usedPacks = 0 self.packScreen.show() def Save( self ): # saves all important variable values in text files inside the repository Hearthstone.packCount -= PackOpeningGraph.usedPacks PackOpeningGraph.usedPacks = 0 gold = open("SaveGame/gold.txt", "w") gold.write(str(Hearthstone.goldCount)) gold.close rank = open("SaveGame/rank.txt", "w") rank.write(str(Hearthstone.rankCount)) rank.close money = open("SaveGame/money.txt", "w") money.write(str(Hearthstone.moneyCount)) money.close common = open("SaveGame/common.txt", "w") common.write(str(Hearthstone.commonCards)) common.close rare = open("SaveGame/rare.txt", "w") rare.write(str(Hearthstone.rareCards)) rare.close epic = open("SaveGame/epic.txt", "w") epic.write(str(Hearthstone.epicCards)) epic.close legendary = open("SaveGame/legendary.txt", "w") legendary.write(str(Hearthstone.legendaryCards)) legendary.close packs = open("SaveGame/packs.txt", "w") packs.write(str(Hearthstone.packCount)) packs.close adventures = open("SaveGame/adventures.txt", "w") adventures.write(str(Hearthstone.adventureCount)) adventures.close def Load( self ): # loads all those important values into their respective variables gold = open("SaveGame/gold.txt") Hearthstone.goldCount = int(gold.read()) gold.close rank = open("SaveGame/rank.txt") Hearthstone.rankCount = int(rank.read()) rank.close money = open("SaveGame/money.txt") Hearthstone.moneyCount = int(money.read()) money.close common = open("SaveGame/common.txt") Hearthstone.commonCards = int(common.read()) common.close rare = open("SaveGame/rare.txt") Hearthstone.rareCards = int(rare.read()) rare.close epic = open("SaveGame/epic.txt") Hearthstone.epicCards = int(epic.read()) epic.close legendary = open("SaveGame/legendary.txt") Hearthstone.legendaryCards = int(legendary.read()) legendary.close packs = open("SaveGame/packs.txt") Hearthstone.packCount = int(packs.read()) packs.close adventures = open("SaveGame/adventures.txt") Hearthstone.adventureCount = int(adventures.read()) adventures.close self.updateGoldCount() # so that the loaded numbers are showing self.updateMoneyCount() self.updateRankCount() self.packScreen = PackOpeningGraph( self.packCount ) # it used to not show the loaded packs at first, I thought this might help..it didnt hurt, so... self.update( ) # always good to throw this in from time to time I heard... self.initGUI( ) # just to make really sure all is loaded, load up the main screen again def initMenu( self ): # this sets up the menu bar at the very top of the screen and allows the player to save and load self.menubar = self.menuBar() saveAct = QAction("Save Game", self) loadAct = QAction("Load Game", self) saveAct.triggered.connect(self.Save) loadAct.triggered.connect(self.Load) self.makeMenu = self.menubar.addMenu("Save") self.makeMenu.addAction(saveAct) self.makeMenu.addAction(loadAct) def displayCollection( self ): # shows the player the numbers of cards of different rarities they have in a pop up window Hearthstone.commonCards += PackOpeningGraph.commonCards # adds all cards obtained through pack openings to the cards already in the players collection Hearthstone.rareCards += PackOpeningGraph.rareCards Hearthstone.epicCards += PackOpeningGraph.epicCards Hearthstone.legendaryCards += PackOpeningGraph.legendaryCards PackOpeningGraph.commonCards = 0 # empties the variables for cards obtained through pack openings so that they arent constantly added on PackOpeningGraph.rareCards = 0 PackOpeningGraph.epicCards = 0 PackOpeningGraph.legendaryCards = 0 text = "Your collection: \nCommon: %d\nRare: %d\nEpic: %d\nLEGENDARY: %d\n" % ( Hearthstone.commonCards, Hearthstone.rareCards, Hearthstone.epicCards, Hearthstone.legendaryCards) collectionPopUp = QMessageBox() collectionPopUp.setText(text) collectionPopUp.exec_() # shows the pop up window # the window for playing an adventure ########################################################################## def playAdventure(self): if Hearthstone.adventureCount >= 1: # you have to have bought at least one adventure! self.adventureTimer = QTimer(self) self.adventureTimer.setSingleShot(True) self.adventureTimer.timeout.connect(self.initGUI) self.helpTimer = QTimer(self) self.helpTimer.timeout.connect( self.updateProgressBar ) # these timers are for the progress bar self.adventureProgress = QProgressBar() self.adventureProgress.setInvertedAppearance(True) self.adventureProgress.setMinimum(0) if self.f2p.isChecked() == True: self.adventureProgress.setMaximum(25000) elif self.p2w.isChecked() == True: self.adventureProgress.setMaximum( 5000) # in pay to win mode, everything is a lot faster else: pass self.progressLabel = QLabel( "Playing adventure.\nAcquiring:\n25 common cards\n15 rare cards\n10 epic cards\n5 legendary cards" ) if Hearthstone.freeToPlay == False: self.progressLabel.setStyleSheet( """ QLabel { font-size: 18px; color: white; text-align : center; font-family: "Apple Chancery"; }""" ) # so it looks different in pay to win mode - the white was most important for being readable with a background picture adventure_layout = QVBoxLayout() adventure_layout.addWidget(self.progressLabel) adventure_layout.addWidget(self.adventureProgress) adventureScreen = QWidget() adventureScreen.setLayout(adventure_layout) adventureScreen.setObjectName("adventure") self.setWindowTitle("Adventure") h = qApp.desktop().screenGeometry().height() - 550 w = qApp.desktop().screenGeometry().width() - 1000 self.setGeometry(20, 20, w, h) self.setFixedSize(w, h) self.setCentralWidget(adventureScreen) self.update() Hearthstone.commonCards += 25 Hearthstone.rareCards += 15 Hearthstone.epicCards += 10 Hearthstone.legendaryCards += 5 Hearthstone.adventureCount -= 1 # what a deal! if self.f2p.isChecked() == True: self.adventureTimer.start(25000) elif self.p2w.isChecked() == True: self.adventureTimer.start(5000) # faster... else: pass self.helpTimer.start(100) else: self.displayWarning() def updateProgressBar( self ): # updates the progress bars progress depending on the helpTimer if (self.adventureTimer.remainingTime()) >= 1: self.adventureProgress.setValue( self.adventureTimer.remainingTime()) else: pass def displayWarning( self): # in the case that the player should have 0 adventures text = "You must purchase an adventure first. Navigate to the shop to purchase an adventure!" warningPopUp = QMessageBox() warningPopUp.setText(text) warningPopUp.exec_() # a lot of this is very similar to the playAdventure function ########################################################################## def playBrawl(self): if Hearthstone.brawlPlayed == False: self.brawlTimer = QTimer(self) self.brawlTimer.setSingleShot(True) self.brawlTimer.timeout.connect(self.initGUI) self.brawlHelpTimer = QTimer(self) self.brawlHelpTimer.timeout.connect(self.updateBrawlProgressBar) self.waitTilWednesday = QTimer(self) self.waitTilWednesday.setSingleShot(True) self.waitTilWednesday.timeout.connect( self.resetBrawl ) # this is so the player cannot immediately play tavern brawl again, just like in the original self.brawlProgress = QProgressBar() self.brawlProgress.setInvertedAppearance(True) self.brawlProgress.setMinimum(0) if self.f2p.isChecked() == True: self.brawlProgress.setMaximum(25000) elif self.p2w.isChecked() == True: self.brawlProgress.setMaximum(5000) else: pass self.brawlProgressLabel = QLabel( "Playing Tavern Brawl.\nAcquiring a card pack.") if Hearthstone.freeToPlay == False: self.brawlProgressLabel.setStyleSheet(""" QLabel { font-size: 18px; color: white; text-align : center; font-family: "Apple Chancery"; }""") brawl_layout = QVBoxLayout() brawl_layout.addWidget(self.brawlProgressLabel) brawl_layout.addWidget(self.brawlProgress) brawlScreen = QWidget() brawlScreen.setLayout(brawl_layout) brawlScreen.setObjectName("brawl") self.setWindowTitle("Tavern Brawl") h = qApp.desktop().screenGeometry().height() - 500 w = qApp.desktop().screenGeometry().width() - 1000 self.setGeometry(20, 20, w, h) self.setFixedSize(w, h) self.setCentralWidget(brawlScreen) self.update() Hearthstone.packCount += 1 Hearthstone.brawlPlayed = True if self.f2p.isChecked() == True: self.brawlTimer.start(25000) elif self.p2w.isChecked() == True: self.brawlTimer.start(5000) else: pass self.brawlHelpTimer.start(100) self.waitTilWednesday.start(100000) else: self.displayBrawlWarning() def updateBrawlProgressBar(self): if (self.brawlTimer.remainingTime()) >= 1: self.brawlProgress.setValue(self.brawlTimer.remainingTime()) else: pass def displayBrawlWarning(self): text = "It is not time for a new Tavern Brawl yet! Wait until Wednesday!" warningPopUp = QMessageBox() warningPopUp.setText(text) warningPopUp.exec_() def resetBrawl(self): Hearthstone.brawlPlayed = False # resets the brawl so it can be played again after the timer waitTilWednesday has run out # a lot of this is similar to the last two functions, especially playBrawl ########################################################################## def playQuest(self): if Hearthstone.questPlayed == False: self.questTimer = QTimer(self) self.questTimer.setSingleShot(True) self.questTimer.timeout.connect(self.initGUI) self.questHelpTimer = QTimer(self) self.questHelpTimer.timeout.connect(self.updateQuestProgressBar) self.waitTilTomorrow = QTimer(self) self.waitTilTomorrow.setSingleShot(True) self.waitTilTomorrow.timeout.connect(self.resetQuest) self.questProgress = QProgressBar() self.questProgress.setInvertedAppearance(True) self.questProgress.setMinimum(0) if self.f2p.isChecked() == True: self.questProgress.setMaximum(25000) elif self.p2w.isChecked() == True: self.questProgress.setMaximum(5000) else: pass questGold = choice([40, 50, 60, 80, 100]) self.questProgressLabel = QLabel( "Playing Quest.\nAcquiring %d gold." % questGold) if Hearthstone.freeToPlay == False: self.questProgressLabel.setStyleSheet(""" QLabel { font-size: 18px; color: white; text-align : center; font-family: "Apple Chancery"; }""") quest_layout = QVBoxLayout() quest_layout.addWidget(self.questProgressLabel) quest_layout.addWidget(self.questProgress) questScreen = QWidget() questScreen.setLayout(quest_layout) questScreen.setObjectName("quest") self.setWindowTitle("Quest") h = qApp.desktop().screenGeometry().height() - 500 w = qApp.desktop().screenGeometry().width() - 1000 self.setGeometry(20, 20, w, h) self.setFixedSize(w, h) self.setCentralWidget(questScreen) self.update() Hearthstone.goldCount += questGold Hearthstone.questPlayed = True if self.f2p.isChecked() == True: self.questTimer.start(25000) elif self.p2w.isChecked() == True: self.questTimer.start(5000) else: pass self.questHelpTimer.start(100) self.waitTilTomorrow.start(50000) else: self.displayQuestWarning() def updateQuestProgressBar(self): if (self.questTimer.remainingTime()) >= 1: self.questProgress.setValue(self.questTimer.remainingTime()) else: pass def displayQuestWarning(self): text = "It is not time for a new Quest yet! Wait until tomorrow!" warningPopUp = QMessageBox() warningPopUp.setText(text) warningPopUp.exec_() def resetQuest(self): Hearthstone.questPlayed = False # still some is similar to the last 3 ########################################################################## def play(self): Hearthstone.commonCards += PackOpeningGraph.commonCards Hearthstone.rareCards += PackOpeningGraph.rareCards Hearthstone.epicCards += PackOpeningGraph.epicCards Hearthstone.legendaryCards += PackOpeningGraph.legendaryCards # same as in displayCollection -> adds all previously acquired cards to the players collection PackOpeningGraph.commonCards = 0 PackOpeningGraph.rareCards = 0 PackOpeningGraph.epicCards = 0 PackOpeningGraph.legendaryCards = 0 self.playTimer = QTimer(self) self.playTimer.setSingleShot(True) self.playTimer.timeout.connect(self.initGUI) self.playTimer.timeout.connect(self.displayDecision) self.playHelpTimer = QTimer(self) self.playHelpTimer.timeout.connect(self.updatePlayProgressBar) self.playProgress = QProgressBar() self.playProgress.setInvertedAppearance(True) self.playProgress.setMinimum(0) if self.f2p.isChecked() == True: self.playProgress.setMaximum(25000) elif self.p2w.isChecked() == True: self.playProgress.setMaximum(5000) else: pass self.playProgressLabel = QLabel( "Playing a game versus\nan online opponent.") if Hearthstone.freeToPlay == False: self.playProgressLabel.setStyleSheet(""" QLabel { font-size: 18px; color: white; text-align : center; font-family: "Apple Chancery"; }""") play_layout = QVBoxLayout() play_layout.addWidget(self.playProgressLabel) play_layout.addWidget(self.playProgress) playScreen = QWidget() playScreen.setLayout(play_layout) playScreen.setObjectName("play") self.setWindowTitle("Ranked Game") h = qApp.desktop().screenGeometry().height() - 500 w = qApp.desktop().screenGeometry().width() - 1000 self.setGeometry(20, 20, w, h) self.setFixedSize(w, h) self.setCentralWidget(playScreen) self.update() self.chance = (Hearthstone.rankCount + 25) + Hearthstone.legendaryCards + ( Hearthstone.epicCards * 0.25) if self.chance >= 99: # a calculation for the players percentage chance of winning self.chance = 98 else: pass dieThrow = randint(0, 99) if self.chance >= dieThrow: # setting up the possible outcomes of the game if Hearthstone.rankCount == 0: self.decision = "victorious" Hearthstone.goldCount += 10 else: Hearthstone.rankCount -= 1 self.decision = "victorious" Hearthstone.goldCount += 10 else: if Hearthstone.rankCount == 25: # cannot fall 'lower', numerically higher, than 25 self.decision = "defeated" else: Hearthstone.rankCount += 1 self.decision = "defeated" if self.f2p.isChecked() == True: self.playTimer.start(25000) elif self.p2w.isChecked() == True: self.playTimer.start(5000) else: pass self.playHelpTimer.start(100) def updatePlayProgressBar(self): if (self.playTimer.remainingTime()) >= 1: self.playProgress.setValue(self.playTimer.remainingTime()) else: pass def displayDecision(self): text = "You were %s!" % self.decision if self.decision == "defeated": text = text + "\nBetter luck next time!\nMaybe you need more legendary cards." else: text = text + "\nGreat job!\nYou must have a large collection of powerful, expensive cards." warningPopUp = QMessageBox() warningPopUp.setText(text) warningPopUp.exec_() # still similar... ########################################################################## def work(self): self.workTimer = QTimer(self) self.workTimer.setSingleShot(True) self.workTimer.timeout.connect(self.initGUI) self.workHelpTimer = QTimer(self) self.workHelpTimer.timeout.connect(self.updateWorkProgressBar) self.workProgress = QProgressBar() self.workProgress.setInvertedAppearance(True) self.workProgress.setMinimum(0) if self.f2p.isChecked() == True: self.workProgress.setMaximum(250000) elif self.p2w.isChecked() == True: self.workProgress.setMaximum( 500000) # this actually takes longer in pay to win mode! else: pass self.workProgressLabel = QLabel("Working.\nAcquiring 1000 Dollars") work_layout = QVBoxLayout() work_layout.addWidget(self.workProgressLabel) work_layout.addWidget(self.workProgress) workScreen = QWidget() workScreen.setLayout(work_layout) workScreen.setObjectName("work") self.setWindowTitle("Work") h = qApp.desktop().screenGeometry().height() - 500 w = qApp.desktop().screenGeometry().width() - 1000 self.setGeometry(20, 20, w, h) self.setFixedSize(w, h) self.setCentralWidget(workScreen) self.update() Hearthstone.moneyCount += 1000 if self.f2p.isChecked() == True: self.workTimer.start(250000) elif self.p2w.isChecked() == True: self.workTimer.start(500000) else: pass self.workHelpTimer.start(100) def updateWorkProgressBar(self): if (self.workTimer.remainingTime()) >= 1: self.workProgress.setValue(self.workTimer.remainingTime()) else: pass # sets up the shop and its GUI elements ########################################################################## def showShop(self): if Hearthstone.freeToPlay == True: self.buyPackBut = QPushButton("Only 100 Gold") self.buyPacksBut = QPushButton("Only 100 Dollars") self.buyAdventureBut = QPushButton("Only 3.500 Gold") self.buyAdventureMoneyBut = QPushButton("Or 350 Dollars") else: self.buyPackBut = QPushButton("Discounted: 50 Gold") self.buyPacksBut = QPushButton("Discounted: 50 Dollars") self.buyAdventureBut = QPushButton("Discounted: 1000 Gold") self.buyAdventureMoneyBut = QPushButton("Or 100 Dollars") self.buyPackBut.setObjectName("pack") self.buyPacksBut.setObjectName("packs") self.buyAdventureBut.setObjectName("adventuregold") self.buyAdventureMoneyBut.setObjectName( "adventuremoney") # all for css self.buyPackLabel = QLabel("1 Card-Pack") if Hearthstone.freeToPlay == False: # guess i could have done this just like above...oops self.buyPackLabel.setStyleSheet(""" QLabel { font-size: 18px; color: white; font-family: "Apple Chancery"; }""") self.buyPacksLabel = QLabel("50 Card-Packs") if Hearthstone.freeToPlay == False: self.buyPacksLabel.setStyleSheet(""" QLabel { font-size: 18px; color: white; font-family: "Apple Chancery"; }""") self.buyAdventureLabel = QLabel("1 Adventure") if Hearthstone.freeToPlay == False: self.buyAdventureLabel.setStyleSheet(""" QLabel { font-size: 18px; color: white; font-family: "Apple Chancery"; }""") self.buyPackBut.clicked.connect(self.buyPack) self.buyPacksBut.clicked.connect(self.buyPacks) self.buyAdventureBut.clicked.connect(self.buyAdventure) self.buyAdventureMoneyBut.clicked.connect(self.buyAdventureMoney) self.backLink = QPushButton("Go Back") self.backLink.setMaximumSize(100, 50) self.backLink.clicked.connect(self.initGUI) PackBox1 = QHBoxLayout() PackBox1.addWidget(self.buyPackLabel) PackBox1.addStretch(1) PackBox1.addWidget(self.buyPackBut) PackBox2 = QHBoxLayout() PackBox2.addWidget(self.buyPacksLabel) PackBox2.addStretch(1) PackBox2.addWidget(self.buyPacksBut) AdventureBox = QHBoxLayout() AdventureBox.addWidget(self.buyAdventureLabel) AdventureBox.addStretch(1) AdventureBox.addWidget(self.buyAdventureBut) AdventureBox.addStretch(1) AdventureBox.addWidget(self.buyAdventureMoneyBut) ShopLayout = QVBoxLayout() ShopLayout.addItem(PackBox1) ShopLayout.addStretch(2) ShopLayout.addItem(PackBox2) ShopLayout.addStretch(2) ShopLayout.addItem(AdventureBox) ShopLayout.addStretch(1) ShopLayout.addWidget(self.backLink) shopScreen = QWidget() shopScreen.setLayout(ShopLayout) shopScreen.setObjectName("shop") self.setWindowTitle("Shop") h = qApp.desktop().screenGeometry().height() - 500 w = qApp.desktop().screenGeometry().width() - 900 self.setGeometry(20, 20, w, h) self.setFixedSize(w, h) self.setCentralWidget(shopScreen) self.update() def buyAdventure( self ): # all the possibilities when one wants to buy and adventure with gold, inluding current mode if Hearthstone.freeToPlay == True: if Hearthstone.goldCount >= 3500: Hearthstone.goldCount -= 3500 Hearthstone.adventureCount += 1 else: text = "You don't have enough gold!" warningPopUp = QMessageBox() warningPopUp.setText(text) warningPopUp.exec_() else: if Hearthstone.goldCount >= 1000: Hearthstone.goldCount -= 1000 Hearthstone.adventureCount += 1 else: text = "You don't have enough gold!" warningPopUp = QMessageBox() warningPopUp.setText(text) warningPopUp.exec_() def buyAdventureMoney(self): # same as above with money instead of gold if Hearthstone.freeToPlay == True: if Hearthstone.moneyCount >= 350: Hearthstone.moneyCount -= 350 Hearthstone.adventureCount += 1 else: text = "You don't have enough money!" warningPopUp = QMessageBox() warningPopUp.setText(text) warningPopUp.exec_() else: if Hearthstone.moneyCount >= 100: Hearthstone.moneyCount -= 100 Hearthstone.adventureCount += 1 else: text = "You don't have enough money!" warningPopUp = QMessageBox() warningPopUp.setText(text) warningPopUp.exec_() def buyPack(self): # same as two above except with a pack if Hearthstone.freeToPlay == True: if Hearthstone.goldCount >= 100: Hearthstone.goldCount -= 100 Hearthstone.packCount += 1 else: text = "You don't have enough gold!" warningPopUp = QMessageBox() warningPopUp.setText(text) warningPopUp.exec_() else: if Hearthstone.goldCount >= 50: Hearthstone.goldCount -= 50 Hearthstone.packCount += 1 else: text = "You don't have enough gold!" warningPopUp = QMessageBox() warningPopUp.setText(text) warningPopUp.exec_() def buyPacks(self): # same as above, just with 50 packs and money if Hearthstone.freeToPlay == True: if Hearthstone.moneyCount >= 100: Hearthstone.moneyCount -= 100 Hearthstone.packCount += 50 else: text = "You don't have enough money!" warningPopUp = QMessageBox() warningPopUp.setText(text) warningPopUp.exec_() else: if Hearthstone.moneyCount >= 50: Hearthstone.moneyCount -= 50 Hearthstone.packCount += 50 else: text = "You don't have enough money!" warningPopUp = QMessageBox() warningPopUp.setText(text) warningPopUp.exec_() # the function that starts the craziness that is pay to win mode ########################################################################## def PayToWin(self): if Hearthstone.moneyCount > 0: # only possible if the player has at least some money if Hearthstone.freeToPlay == True: # and the mode is not yet engaged Hearthstone.freeToPlay = False self.popUpFriendsTimer.stop() self.popUpFinancesTimer.start( 17500 ) # starts the pop up messages regarding a defficiency of finances on the players end styleSheet = open("css/p2w.css") # opens the main stlyesheet qApp.setStyleSheet(styleSheet.read()) styleSheet.close() self.theme.stop() self.sax.play( ) # changes the music - FOR YOUR INFORMATION: THIS MUSIC IS COMMONLY PLAYED IN THE HEARTHSTONE COMMUNITY, self.sax.setLoops( 100 ) # WHEN IMPRESSIVE FEATS SUCH AS MASSIVE COMBOS ARE SHOWN! THAT IS WHY I CHOSE IT TO REPRESENT if Hearthstone.welcomeGift == False: # THE PLAYER WHO SPENDS MONEY ON THE GAME TO BE AS GOOD AS POSSIBLE text = "Congratulations for chosing to\nspend your money on this game!\nHave 5 complimentary adventures for your commitment." congratsPopUp = QMessageBox() congratsPopUp.setGeometry(500, 500, 500, 500) congratsPopUp.setText(text) congratsPopUp.exec_() Hearthstone.adventureCount += 5 # the first time a player enters pay to win mode, he gets 5 adventures Hearthstone.welcomeGift = True else: pass Hearthstone.moneyCount -= 100 # so there can't be gold farming, 100 dollars are subtracted immediately upon selection of pay to win mode self.updateMoneyCount() self.moneyTimer.start( 10000 ) # starts the constant subtraction/addition of values self.goldTimer.start(5000) self.rankTimer.start(15000) else: pass else: self.f2p.setChecked(True) def depleteMoney(self): try: Hearthstone.moneyCount -= 100 if Hearthstone.moneyCount <= 0: # this happens when the player runs out of money before pressing the free to play button again self.moneyTimer.stop( ) # everything changes back into free to play mode self.rankTimer.stop() self.goldTimer.stop() self.popUpFriendsTimer.start(30000) self.popUpFinancesTimer.stop() qApp.setStyleSheet("") self.sax.stop() self.theme.play() self.theme.setLoops(100) Hearthstone.moneyCount = 0 Hearthstone.freeToPlay = True self.f2p.setChecked(True) self.initGUI self.update() text = "It seems that you have run out of money...\nToo bad that we had to set you\nback to the free-to-play status." warningPopUp = QMessageBox() warningPopUp.setText(text) warningPopUp.exec_() else: pass self.updateMoneyCount() self.update() except RuntimeError: # I had some errors when the player was still in another window than the main screen when they ran out of money.. self.popUpFriendsTimer.start(30000) self.popUpFinancesTimer.stop() qApp.setStyleSheet("") self.sax.stop() self.theme.play() self.theme.setLoops(100) self.moneyTimer.stop() self.rankTimer.stop() self.goldTimer.stop() Hearthstone.moneyCount = 0 Hearthstone.freeToPlay = True text = "It seems that you have run out of money...\nToo bad that we had to set you\nback to the free-to-play status." warningPopUp = QMessageBox() warningPopUp.setText(text) warningPopUp.exec_() def increaseRank(self): Hearthstone.rankCount -= 1 self.updateRankCount() self.update() def increaseGold(self): Hearthstone.goldCount += 100 self.updateGoldCount() self.update() # this connects to the free to play button being pressed and does basically all that depleteMoney does, when the player runs out of money ########################################################################## def FreeToPlay(self): if Hearthstone.moneyCount <= 0: self.moneyTimer.stop() self.rankTimer.stop() self.goldTimer.stop() else: pass self.popUpFriendsTimer.start(30000) self.popUpFinancesTimer.stop() qApp.setStyleSheet("") self.sax.stop() self.theme.play() self.theme.setLoops(100) try: self.moneyTimer.stop() self.rankTimer.stop() self.goldTimer.stop() Hearthstone.freeToPlay = True self.f2p.setChecked(True) text = "We are sad to see you\ngo back to that place.\nCome back some time." byePopUp = QMessageBox() byePopUp.setText(text) byePopUp.exec_() self.initGUI self.update() except AttributeError: pass # randomly selects one of the 10 / 7 messages and makes them pop up ########################################################################## def popUpFriends(self): message = randint(0, 9) messages = [ "Hey dude, why aren't you at the hockey game?", "Come on out here, man!", "This is your mother. You have not come out of your room for 3 days. What are you doing in there?!", "I miss you, we should hang out again some time!", "Haven't seen you at school in some time, are you on vacation or something?", "You are playing Hearthstone again, aren't you?", "The concert last night was awesome! Why didn't you come again?", "Dude! Did you sleep through the exam this morning?!", "The weather is nice out, want to go for a hike?", "Last chance! If you want to come with me to Spain tomorrow, you gotta decide NOW!" ] self.ping.play() text = messages[message] self.friendPopUp = QMessageBox() self.friendPopUp.setText(text) self.friendPopUp.setWindowTitle("New Message") self.friendPopUp.setGeometry(0, 0, 300, 200) self.friendPopUp.setObjectName("friend") self.friendPopUp.exec_() def popUpFinances(self): message = randint(0, 6) messages = [ "Your credit card has been denied due to insuficcient funds.", "Dude, I like you, but I need you to pay the rent on time. Don't let me down..", "WHERE'S MY MONEY?!", "Hey, just checking in about the 12$ you're still owing me. I'd appreciate them back.", "Dear customer, you just went over the limit of your bank account. Thus it was closed until further notice.", "Dear, I'm so glad your mom and I can support you going to college. I hope the money lasts the month!", "Hey, just wanted to inform you that the interest for last month's loan went up to 8%, because I still don't have the money from you.." ] self.ping.play() text = messages[message] self.financePopUp = QMessageBox() self.financePopUp.setText(text) self.financePopUp.setWindowTitle("New Message") self.financePopUp.setGeometry(0, 0, 300, 200) self.financePopUp.setObjectName("finance") self.financePopUp.exec_()
class StopwatchWidget(QWidget): def __init__(self): super().__init__() self.initUI() # Кнопка старта секундомера self.btn_start = QPushButton('Старт', self) self.btn_start.move(225, 50) self.btn_start.resize(50, 50) self.btn_start.clicked.connect(self.start) # Кнопка паузы self.btn_pause = QPushButton('Пауза', self) self.btn_pause.move(225, 50) self.btn_pause.resize(50, 50) self.btn_pause.setVisible(False) self.btn_pause.clicked.connect(self.pause) # Кнопка для продолжения секундомера self.btn_continue = QPushButton('Продолжить', self) self.btn_continue.move(200, 50) self.btn_continue.resize(100, 50) self.btn_continue.setVisible(False) self.btn_continue.clicked.connect(self.timer_continue) # Кнопка сохранения результата секундомера self.btn_split = QPushButton('Split', self) self.btn_split.move(150, 50) self.btn_split.resize(50, 50) self.btn_split.setVisible(False) self.btn_split.clicked.connect(self.spliting) # Сброс секундомера и его значений self.btn_drop = QPushButton('Сброс', self) self.btn_drop.move(300, 50) self.btn_drop.resize(50, 50) self.btn_drop.setVisible(False) self.btn_drop.clicked.connect(self.drop) # Дисплей для вывода времени self.dsp = QLCDNumber(self) self.dsp.move(150, 0) self.dsp.resize(200, 50) self.dsp.setDigitCount(13) self.dsp.display('00:00:00.000') # Список со значениями секундомера self.lst_times = QListWidget(self) self.lst_times.move(125, 100) self.lst_times.resize(250, 300) # Таймер self.nTimer = QTimer() self.nTimer.timeout.connect(self.repeatTime) def initUI(self): self.setGeometry(100, 100, 500, 500) self.setWindowTitle('Секундомер') def start(self): # Инициализируем при старте первое значение в списке self.num = 1 # Устанавливаем всё значение времени на ноль self.time_in_ms = 0 self.time_in_s = 0 self.time_in_m = 0 self.time_in_h = 0 # Махинация с показом кнопок self.btn_drop.setVisible(True) self.btn_split.setVisible(True) self.btn_pause.setVisible(True) # Запускаем таймер на 1 мс self.nTimer.start(1) def repeatTime(self): # При каждом тике таймера кол-во мс в секундомере увеличивается на 1, остальные значения правильно форматируются self.time_in_ms += 1 if self.time_in_ms == 1000: self.time_in_s += 1 self.time_in_ms = 0 if self.time_in_s == 60: self.time_in_m += 1 self.time_in_s = 0 if self.time_in_m == 60: self.time_in_h += 1 self.time_in_m = 0 # Переводим их в строку ms = str(self.time_in_ms) s = str(self.time_in_s) m = str(self.time_in_m) h = str(self.time_in_h) # Форматируем значения к виду hh:mm:ss.mss if len(s) == 1: s = '0' + s if len(m) == 1: m = '0' + m if len(h) == 1: h = '0' + h if len(ms) == 1: ms = '00' + ms if len(ms) == 2: ms = '0' + ms # Сохраняем в едином виде и показываем в дисплее self.time = h + ":" + m + ':' + s + '.' + ms self.dsp.display(self.time) def drop(self): # Останавливаем таймер и сбрасываем время на дисплее self.nTimer.stop() self.dsp.display('00:00:00.000') # Махинации с показом кнопок self.btn_pause.setVisible(False) self.btn_split.setVisible(False) self.btn_drop.setVisible(False) self.btn_start.setVisible(True) self.btn_continue.setVisible(False) # Сбрасываем список значений и устанавливаем, что следующее значение будет первым self.lst_times.clear() self.num = 1 def pause(self): # Сохраняем на чем остановился таймер self.inter = self.nTimer.remainingTime() self.nTimer.stop() # Махинация с показом кнопок self.btn_continue.setVisible(True) self.btn_pause.setVisible(False) def timer_continue(self): # Запускаем с того места, на котором остановили self.nTimer.start(self.inter) # Махинации с покахом кнопок self.btn_pause.setVisible(True) self.btn_continue.setVisible(False) def spliting(self): # Сохраняем данное значение времени в списке self.lst_times.addItem(str(self.num) + '. ' + self.time) # Делаем следующее значение на один больше, чем предыдущее self.num += 1
class Lecteur : """Classe permettant la lecture des fichiers. S'initialise avec la fenêtre.""" def __init__ (self, window): self.window = window self.timer = QTimer () self.timer.setSingleShot (True) self.reading = False self.paused_time_save = None self.data = [] self.heure_debut = None def read_messages (self, nom_fichier) : """Méthode utilisée pour lire les fichiers contenants des messages, et executer les messages comme s'ils avaient envoyés par Ivy. /!\\ Les commandes de l'interface ne seront pas envoyées avec ce mode.""" if not self.reading : self.reading = "MSG" with open (nom_fichier, 'r') as file : self.data = file.readlines () self.heure_debut = time () self.data = self.data [3:] self.data.reverse () temps_message = int (self.data [-1].split ()[0]) self.timer.timeout.connect (self.read_msg) self.timer.start (temps_message) else : self.timer.start (self.paused_time_save) def read_msg(self): """Méthode utilisée pour lire le message à la fin de self.data /!\\ Si ce message est une commande de l'interface, elle ne sera pas envoyée.""" if len (self.data) == 0: self.timer.timeout.disconnect () self.window.button_play.setChecked (False) self.window.button_play.setStyleSheet ("") self.window.playback_sgnl.emit([-1, 0, 0]) self.reading = False return None line = self.data.pop (-1) try: words = line.split () self.timer.start( (int(self.data[-1].split()[0]) - int(words[0])) if len (self.data)!= 0 else 1) self.window.playback_sgnl.emit([1, len(self.data), 1]) rid, message, sender = words[3], words[2], words[1] if message == 'PosReport': x, y, z = words[4], words[5], words[6] self.window.backend.radio.on_posreg ("Lecteur", rid, x, y, z) elif message == "ActuatorReport": sid, val =words[4], words[5] self.window.backend.radio.on_captreg ("Lecteur", rid, sid, val) elif message == 'ActuatorDecl': sid, mini, maxi, step, droits, unit = words[4], words[5], words[6], words[7], words[8], words[9] self.window.backend.radio.on_actudecl ("Lecteur", rid, sid, mini, maxi, step, droits, unit) elif sender == 'Interface': if message in ('PosCmd', 'PosCmdOrient'): x, y, theta = words[4], words[5], (words[6] if len(words)==7 else None) if self.window.inspecteur.check_robot(words[3]): anc_texte = self.window.inspecteur.find(rid).qlineedit_pos_cmd.text() texte = "{:04d} : {:04d}".format (int(float(x)), int(float(y))) if theta is not None: texte += " : {:03d}".format (int (float(theta)/3.141592654*180)) else : texte += anc_texte[10:] self.window.inspecteur.find(rid).qlineedit_pos_cmd.setText(texte) elif message == "ActuatorCmd": sid, valeur = words[4], words[5] eqp_display = self.window.inspecteur.find(rid,sid) if eqp_display is not None and isinstance(eqp_display, ACT): eqp_display.updt_cmd(valeur) except Exception as bug: print ("La ligne [{}] pose un problème.\n{}".format (line, bug)) self.timer.start (1) def read_commands (self, nom_fichier): """Méthode utilisée pour lire un fichier contenant des commandes de l'interface.""" if self.reading: self.timer.start (self.paused_time_save) else : self.reading = "CMD" with open (nom_fichier, 'r') as file: self.data = file.readlines ()[3:] self.data.reverse () temps_commande = int (self.data [-1].split ()[0]) self.timer.timeout.connect (self.read_cmd) self.timer.start (temps_commande) def read_cmd (self): """Méthode appelée pour envoyer la dernière commande de self.data""" if len (self.data) == 0: self.timer.timeout.disconnect () self.window.button_play.setChecked (False) self.window.button_play.setStyleSheet ("") self.window.playback_sgnl.emit([-1, 0, 0]) self.reading = False return None line = self.data.pop (-1) try : words = line.split() self.timer.start( (int(self.data[-1].split()[0]) - int(words[0])) if len (self.data) != 0 else 1) self.window.playback_sgnl.emit([1, len(self.data), 0]) rid = words[2] if words [1] in ('PosCmd', 'PosCmdOrient'): x, y, theta = words[3], words[4], (words[5] if len(words) == 6 else None) if self.window.backend.annu.check_robot(rid): anc_texte = self.window.inspecteur.find(rid).qlineedit_pos_cmd.text() texte = "{:04d} : {:04d}".format (int(float (x)), int(float(y))) if theta is not None: texte += " : {:03d}".format (int(float(theta)/3.141592654*180)) else : texte += anc_texte[10:] self.window.inspecteur.find(rid).qlineedit_pos_cmd.setText(texte) self.window.backend.sendposcmd_robot (rid, (x, y, (float(theta) if len (words) == 6 else None))) elif words [1] == 'Shutdown' : self.window.backend.stopandforget_robot (rid) elif words [1] == "Emergency" : self.window.backend.emergency_stop_robot (rid) elif words [1] == "ActuatorsRequest": self.window.backend.send_descr_cmd (rid) elif words [1] == "SpeedCmd": self.window.backend.send_speed_cmd (rid, words [3], words [4], float (words [5])) elif words [1] == "ActuatorCmd" : sid, val = words [3], words [4] self.window.backend.sendeqpcmd (rid, sid, val) eqp_display = self.window.inspecteur.find (rid,sid) if eqp_display is not None and isinstance(eqp_display, ACT): eqp_display.updt_cmd (val) except Exception as bug: print ("La ligne [{}] pose un problème.\n{}".format (line, bug)) self.timer.start (1) def on_play_button (self): """Message appelé après un appui sur le bouton play. Appelle la bonne fonction de lecture de fichier.""" path = self.window.settings_dict["Enregistrement/Playback (Dernière Lecture)"] if path not in (None, ""): if "essages" in path : self.window.button_play.setChecked (True) self.window.button_play.setStyleSheet ("background-color: red") self.read_messages (path) self.window.playback_sgnl.emit([0, 0, 1]) elif "ommand" in path : self.window.button_play.setChecked (True) self.window.button_play.setStyleSheet ("background-color: red") self.read_commands (path) self.window.playback_sgnl.emit([0, 0, 0]) def on_stop_button (self): """Méthode appelée par un appui du bouton stop. Arrête la lecture du fichier.""" if self.reading == "MSG": self.timer.timeout.disconnect () elif self.reading == "CMD": self.timer.timeout.disconnect () self.window.playback_sgnl.emit([-1, 0, 0]) self.reading = False def on_pause_button (self): """Méthode appelée par un appui du bouton pause. Met la lecture du fichier en pause.""" self.paused_time_save = self.timer.remainingTime () self.window.playback_sgnl.emit([-2, 0, 0]) self.timer.stop ()
class ControllerGUITab(QWidget): LEFT_COLUMN_MAX_WIDTH = 400 # This signal tells the global tab if is not possible to start dosing for this tab # False is sent out when the dosing vectors are incorrect or when the process is already started dosingSignal = pyqtSignal(bool) # This just signals if saving was enabled/disabled by the user in the tab, so the global tab can update itself savingSignal = pyqtSignal(bool) # Signal when a sample is ready for the combined plot sampleReady = pyqtSignal(int, np.float16) def __init__(self, controller: Controller): super().__init__() # Create the master layout outerLayout = QHBoxLayout() self.graph = None self.controller = controller self.temperatureController = None self.tempControllerGroup = None self.sensor1 = None self.sensor2 = None self.sensor1Group = None self.sensor2Group = None self.vorNormalButton = None self.vorClosedButton = None self.vorOpenButton = None self.gasFactorEdit = None self.pvFullScaleEdit = None self.pvSigtypeDropdown = None self.spFullScaleEdit = None self.spSigtypeDropdown = None self.spSourceDropdown = None self.decimalDropdown = None self.measureUnitsDropdown = None self.timebaseDropdown = None self.bufferSizeEdit = None self.intervalEdit = None self.setpointEdit = None self.setpointUnitsLabel = None self.saveCsvButton = None self.sensor1Timer = None self.sensor1SampleIntervalEdit = None self.sensor1BufferSizeEdit = None self.sensor2Timer = None self.sensor2SampleIntervalEdit = None self.sensor2BufferSizeEdit = None self.temperatureSlider = None self.temperatureLabel = None self.tempReadoutLabel = None self.rangeLowEdit = None self.rangeHighEdit = None self.rampingCheckbox = None self.gradientEdit = None self.tempControlButton = None self.dosingTimesEdit = None self.dosingTimes = None self.dosingValuesEdit = None self.dosingValues = None self.dosingUnitsLabel = None self.dosingLabel = None self.dosingVorStateLabel = None self.dosingControlButton = None self.dosingEnabled = False # Data buffers self.sampleBufferSize = 64 self.samplesPV = RingBuffer(capacity=self.sampleBufferSize, dtype=np.float16) self.samplesTotalizer = RingBuffer(capacity=self.sampleBufferSize, dtype=np.float32) self.sampleTimestamps = RingBuffer(capacity=self.sampleBufferSize, dtype=datetime) # Nest the inner layouts into the outer layout outerLayout.addLayout(self.create_left_column()) outerLayout.addLayout(self.create_right_column()) # Set the window's main layout self.setLayout(outerLayout) # Generic timer that calls generic_update every second # Used to update a few labels self.genericTimer = QTimer() self.genericTimer.timeout.connect(self.update_generic) self.genericTimer.start(1000) self.graphTimer = QTimer() self.graphTimer.timeout.connect(self.update_plot) self.graphTimer.start(int(60 * 1000 * float(self.intervalEdit.text()))) self.dosingValue = None self.dosingTimer = QTimer() self.dosingTimer.timeout.connect(self.dosing_process) self.csvFile = None self.csvIterator = 1 self.defaultStyleSheet = QLineEdit().styleSheet() # Current dosing value, used to set the setpoint edit # text correctly after a process shutdown self.spValue = 1.0 # Get initial dosing values from the text inside self.dosingValues = [ float(x) for x in self.dosingValuesEdit.text().split(sep=',') if x.strip() != '' ] self.dosingTimes = [ float(x) * 60 * 1000 for x in self.dosingTimesEdit.text().split(sep=',') if x.strip() != '' ] self.dosingValues.reverse() self.dosingTimes.reverse() def get_measurement(self): # Proper implementation that gets the data from the device over serial current, total, timestamp = self.controller.get_measurements() if total is not None: self.samplesTotalizer.append(total) self.samplesPV.append(current) self.sampleTimestamps.append(timestamp) self.sampleReady.emit(self.controller.channel, current) # Save samples to a csv file, named after the current time and controller number it is coming from # After this function saving is continued by update_plot function, which calls append_to_csv def save_to_csv_start(self): # If saving is invoked from global tab while it is already enabled, close the old file, # so no sensor data will be lost and it will be closed properly if self.csvFile is not None: self.save_to_csv_stop() filename = datetime.now().strftime( f"controller{self.controller.channel}_%Y-%m-%d_%H-%M-%S.csv") self.csvFile = open(filename, 'w') self.csvFile.write( f"Gas factor:{self.controller.get_gas()}\tDecimal point:{self.controller.get_decimal_point()},\tUnits:{self.controller.get_measurement_units()}/{self.controller.get_time_base()}\n" ) self.csvFile.write("{:<15} {:^18} {:>19}\n".format( "Measurement", "Totalizer", "Time of measurement")) for i in range(0, len(self.samplesPV) - 1): self.csvFile.write("{:<15},{:^18},{:>19}\n".format( self.samplesPV[len(self.samplesPV) - 1], self.samplesTotalizer[len(self.samplesPV) - 1], self.sampleTimestamps[len(self.samplesPV) - 1].strftime("%Y/%m/%d,%H:%M:%S"))) self.saveCsvButton.clicked.disconnect() self.saveCsvButton.clicked.connect(self.save_to_csv_stop) self.saveCsvButton.setText("Stop saving to CSV") self.savingSignal.emit(True) def append_to_csv(self): # check if file is bigger than ~8MB if self.csvFile.tell() > 8192000: name = re.sub( r"(|_[0-9]+).csv", f"_{self.csvIterator}.csv", self.csvFile.name.split("\\")[ len(self.csvFile.name.split("\\")) - 1]) self.csvIterator += 1 self.append_sensor() self.csvFile.close() self.csvFile = open(name, 'w') self.csvFile.write("{:<15},{:^18},{:>19}\n".format( self.samplesPV[len(self.samplesPV) - 1], self.samplesTotalizer[len(self.samplesPV) - 1], self.sampleTimestamps[len(self.samplesPV) - 1].strftime("%Y/%m/%d,%H:%M:%S"))) def save_to_csv_stop(self): self.append_sensor() self.csvFile.close() self.csvFile = None self.saveCsvButton.clicked.disconnect() self.saveCsvButton.clicked.connect(self.save_to_csv_start) self.saveCsvButton.setText("Start saving to CSV") self.csvIterator = 1 self.savingSignal.emit(False) def append_sensor(self): # if available, append data from sensors if self.sensor1 is not None and len(self.sensor1.buffer) > 0: self.csvFile.write(f"Sensor 1 header: {self.sensor1.header}\n") for i in range(0, len(self.sensor1.buffer)): self.csvFile.write(str(self.sensor1.buffer[i])) self.sensor1.buffer.clear() self.csvFile.write('\n') if self.sensor2 is not None and len(self.sensor2.buffer) > 0: self.csvFile.write(f"Sensor 2 header: {self.sensor2.header}\n") for i in range(0, len(self.sensor2.buffer)): self.csvFile.write(str(self.sensor2.buffer[i])) self.sensor2.buffer.clear() # Handler functions for UI elements # TODO: react to returned value from functions def update_vor_normal(self): if self.vorNormalButton.isChecked(): # disable other buttons to clarify which VOR state is active self.vorClosedButton.setChecked(False) self.vorOpenButton.setChecked(False) self.controller.set_valve_override(Controller.VOR_OPTION_NORMAL) self.dosingVorStateLabel.setText("VOR is normal") self.dosingVorStateLabel.setStyleSheet("color: green;") def update_vor_closed(self): if self.vorClosedButton.isChecked(): self.vorNormalButton.setChecked(False) self.vorOpenButton.setChecked(False) self.controller.set_valve_override(Controller.VOR_OPTION_CLOSED) self.dosingVorStateLabel.setText("VOR is closed") self.dosingVorStateLabel.setStyleSheet("color: red;") def update_vor_open(self): if self.vorOpenButton.isChecked(): self.vorClosedButton.setChecked(False) self.vorNormalButton.setChecked(False) self.controller.set_valve_override(Controller.VOR_OPTION_OPEN) self.dosingVorStateLabel.setText("VOR is open") self.dosingVorStateLabel.setStyleSheet("color: red;") def update_gas_factor(self): self.controller.set_gas_factor(float(self.gasFactorEdit.text())) def update_pv_full_scale(self): self.controller.set_pv_full_scale(float(self.pvFullScaleEdit.text())) def update_pv_signal_type(self): self.controller.set_pv_signal_type( self.pvSigtypeDropdown.currentText()) def update_sp_full_scale(self): self.controller.set_sp_full_scale(float(self.spFullScaleEdit.text())) def update_sp_signal_type(self): self.controller.set_sp_signal_type( self.spSigtypeDropdown.currentText()) def update_source(self): self.controller.set_source(self.spSourceDropdown.currentText()) def update_decimal_point(self): self.controller.set_decimal_point(self.decimalDropdown.currentText()) def update_measure_units(self): if self.dosingUnitsLabel is not None: self.dosingUnitsLabel.setText( f"{self.measureUnitsDropdown.currentText()}/{self.timebaseDropdown.currentText()}" ) if self.setpointUnitsLabel is not None: self.setpointUnitsLabel.setText( f"{self.measureUnitsDropdown.currentText()}/{self.timebaseDropdown.currentText()}" ) self.controller.set_measurement_units( self.measureUnitsDropdown.currentText()) def update_time_base(self): if self.dosingUnitsLabel is not None: self.dosingUnitsLabel.setText( f"{self.measureUnitsDropdown.currentText()}/{self.timebaseDropdown.currentText()}" ) if self.setpointUnitsLabel is not None: self.setpointUnitsLabel.setText( f"{self.measureUnitsDropdown.currentText()}/{self.timebaseDropdown.currentText()}" ) self.controller.set_time_base(self.timebaseDropdown.currentText()) def update_buffer_size(self): self.change_buffer_size(int(self.bufferSizeEdit.text())) self.sampleBufferSize = int(self.bufferSizeEdit.text()) def update_graph_timer(self): self.graphTimer.setInterval( float(self.intervalEdit.text()) * 60 * 1000) def update_setpoint(self): value = float(self.setpointEdit.text()) self.controller.set_setpoint(value) def update_sensor1_timer(self): self.sensor1Timer.setInterval( float(self.sensor1SampleIntervalEdit.text()) * 60 * 1000) def update_sensor1_buffer(self): self.sensor1.change_buffer_size(int(self.sensor1BufferSizeEdit.text())) def update_sensor2_timer(self): self.sensor2Timer.setInterval( float(self.sensor2SampleIntervalEdit.text()) * 60 * 1000) def update_sensor2_buffer(self): self.sensor2.change_buffer_size(int(self.sensor2BufferSizeEdit.text())) def update_temperature(self): self.temperatureController.set_temperature( float(self.temperatureSlider.value())) self.temperatureLabel.setText(self.temperatureSlider.value()) def update_range_low(self): newTemp = self.temperatureController.set_range_low( float(self.rangeLowEdit.text())) self.temperatureSlider.setMinimum(float(self.rangeLowEdit.text())) self.temperatureSlider.setValue(newTemp) def update_range_high(self): newTemp = self.temperatureController.set_range_high( float(self.rangeHighEdit.text())) self.temperatureSlider.setMaximum(float(self.rangeHighEdit.text())) self.temperatureSlider.setValue(newTemp) def update_ramping_enable(self): if self.rampingCheckbox.isChecked(): self.temperatureController.ramping_on() else: self.temperatureController.ramping_off() def update_gradient(self): self.temperatureController.set_gradient(float()) def update_temp_control_enable(self): if self.tempControlButton.isChecked(): self.temperatureController.ramping_on() self.tempControlButton.setText("Disable output") else: self.temperatureController.ramping_off() self.tempControlButton.setText("Enable output") def update_dosing_vectors(self): self.dosingValues = [ float(x) for x in self.dosingValuesEdit.text().split(sep=',') if x.strip() != '' ] self.dosingTimes = [ float(x) * 1000 * 60 for x in self.dosingTimesEdit.text().split(sep=',') if x.strip() != '' ] # Since we will be using pop() to get the next values, we reverse the arrays self.dosingValues.reverse() self.dosingTimes.reverse() if len(self.dosingTimes) != len(self.dosingValues) or len( self.dosingTimes) * len(self.dosingValues) == 0: self.dosingTimesEdit.setStyleSheet("color: red;") self.dosingValuesEdit.setStyleSheet("color: red;") self.dosingControlButton.setEnabled(False) self.dosingSignal.emit(True) else: self.dosingTimesEdit.setStyleSheet(self.defaultStyleSheet) self.dosingValuesEdit.setStyleSheet(self.defaultStyleSheet) self.dosingControlButton.setEnabled(True) self.dosingSignal.emit(False) def update_dosing_state(self): if self.dosingControlButton.isChecked(): self.dosingValuesEdit.setEnabled(False) self.dosingValuesEdit.setStyleSheet("color: grey") self.dosingTimesEdit.setEnabled(False) self.dosingTimesEdit.setStyleSheet("color: grey") self.dosingControlButton.setText("Disable dosing") self.setpointEdit.setEnabled(False) self.dosingEnabled = True self.dosingSignal.emit(True) # Set VOR to normal for dosing self.vorNormalButton.setChecked(True) self.update_vor_normal() self.dosing_process() else: self.dosingValuesEdit.setEnabled(True) self.dosingValuesEdit.setStyleSheet(self.defaultStyleSheet) self.dosingTimesEdit.setEnabled(True) self.dosingTimesEdit.setStyleSheet(self.defaultStyleSheet) self.dosingControlButton.setText("Enable dosing") self.setpointEdit.setEnabled(True) self.dosingEnabled = False self.end_dosing_process() # This function sets the setpoint to those values that were set when "Enable dosing" was pressed # and iterates over them def dosing_process(self): self.spValue = self.dosingValues.pop() spTime = self.dosingTimes.pop() self.setpointEdit.setText(f"{str(self.spValue)} - dosing is enabled") self.controller.set_setpoint(self.spValue) if len(self.dosingTimes) == 0: self.dosingTimer.timeout.disconnect() self.dosingTimer.singleShot(spTime, self.end_dosing_process) self.dosingTimer.setInterval(spTime) self.dosingTimer.start() def update_generic(self): if self.dosingTimer.isActive() and len(self.dosingValues) > 0: if self.dosingTimer.remainingTime() / 1000 > 60: self.dosingLabel.setText( f"{int(self.dosingTimer.remainingTime() / (1000 * 60))} minutes {int(self.dosingTimer.remainingTime() / 1000) % 60} seconds until next dosing value: {self.dosingValues[-1]}" ) else: self.dosingLabel.setText( f"{int(self.dosingTimer.remainingTime() / 1000)} seconds until next dosing value: {self.dosingValues[-1]}" ) elif self.dosingTimer.isActive() and len(self.dosingValues) == 0: self.dosingLabel.setText( f"{int(self.dosingTimer.remainingTime() / 1000)} seconds until end of process" ) else: self.dosingLabel.setText("Dosing disabled") if self.temperatureController is not None: self.tempReadoutLabel.setText( f"Readout: {self.temperatureController.read_temperature()} ℃") else: self.tempReadoutLabel.setText("Readout: None ℃") def end_dosing_process(self): self.dosingControlButton.setChecked(False) self.dosingControlButton.setText("Enable dosing") self.dosingLabel.setText("Dosing disabled") self.dosingTimer.stop() # Since all the values have been popped and the text is unchanged, we fill the vectors again self.dosingValues = [ float(x) for x in self.dosingValuesEdit.text().split(sep=',') if x.strip() != '' ] self.dosingTimes = [ float(x) * 60 * 1000 for x in self.dosingTimesEdit.text().split(sep=',') if x.strip() != '' ] self.dosingValues.reverse() self.dosingTimes.reverse() # Remove the string portion from setpoint field self.setpointEdit.setText(str(self.spValue)) # Unlock the setpoint and dosing values/times fields self.setpointEdit.setEnabled(True) self.dosingValuesEdit.setEnabled(True) self.dosingTimesEdit.setEnabled(True) # Return to normal stylesheet self.dosingValuesEdit.setStyleSheet(self.defaultStyleSheet) self.dosingTimesEdit.setStyleSheet(self.defaultStyleSheet) # reconnect the dosing_process function to the timer self.dosingTimer.timeout.connect(self.dosing_process) # Set the setpoint to 0 and close valve at the end self.controller.set_setpoint(0) self.setpointEdit.setText("0") self.vorClosedButton.setChecked(True) self.dosingSignal.emit(False) self.update_vor_closed() def update_plot(self): self.graph.clear() self.get_measurement() self.graph.plot(self.samplesPV, pen=pyqtgraph.mkPen((255, 127, 0), width=1.25), symbolBrush=(255, 127, 0), symbolPen=pyqtgraph.mkPen((255, 127, 0)), symbol='o', symbolSize=5, name="symbol ='o'") if self.csvFile is not None: self.append_to_csv() def update_sensor1_group(self): if self.sensor1Group.isChecked(): dg = SensorConfigDialog() dg.accepted.connect(self.connect_sensor1) # if unsuccessful, disable the temperature controller group if dg.exec_() == 0: self.sensor1Group.setChecked(False) else: self.sensor1.close() self.sensor1Timer.stop() self.sensor1 = None # connect to sensor instance 1 using values returned by the dialog def connect_sensor1(self, values): self.sensor1 = Sensor(comport=values['port'], baudrate=values['baudrate'], databits=values['databits'], parity=values['paritybits'], stopbits=values['stopbits'], dataHeader=values['header']) self.sensor1Timer = QTimer() self.sensor1Timer.setInterval( float(self.sensor1SampleIntervalEdit.text()) * 1000 * 60) self.sensor1Timer.timeout.connect(self.sensor1_get_data) self.sensor1Timer.start() # Wrapper function to handle exceptions from GUI level def sensor1_get_data(self): try: self.sensor1.getData() except SerialException as se: dg = QErrorMessage() dg.setWindowIcon(QIcon(':/icon.png')) dg.setWindowTitle("Sensor 1 Exception") filename = datetime.now().strftime("sensor1_%Y-%m-%d_%H-%M-%S.csv") dumpFile = open(filename, 'w') dumpFile.write(f"Sensor 1 header: {self.sensor1.header}\n") for i in range(0, len(self.sensor1.buffer)): self.csvFile.write(str(self.sensor1.buffer[i])) dumpFile.close() self.sensor1Group.setChecked(False) self.update_sensor1_group() dg.showMessage(f"Sensor 1 has encountered an exception: {se}") dg.exec_() def update_sensor2_group(self): if self.sensor2Group.isChecked(): dg = SensorConfigDialog() dg.accepted.connect(self.connect_sensor2) # if unsuccessful, disable the temperature controller group if dg.exec_() == 0: self.sensor2Group.setChecked(False) else: self.sensor2.close() self.sensor2Timer.stop() self.sensor2 = None # connect to sensor instance 2 using values returned by the dialog def connect_sensor2(self, values): self.sensor2 = Sensor(comport=values['port'], baudrate=values['baudrate'], databits=values['databits'], parity=values['paritybits'], stopbits=values['stopbits'], dataHeader=values['header']) self.sensor2Timer = QTimer() self.sensor2Timer.setInterval( float(self.sensor2SampleIntervalEdit.text()) * 1000 * 60) self.sensor2Timer.timeout.connect(self.sensor2_get_data) self.sensor2Timer.start() # Wrapper function to handle exceptions from GUI level def sensor2_get_data(self): try: self.sensor2.getData() except SerialException as se: dg = QErrorMessage() dg.setWindowIcon(QIcon(':/icon.png')) dg.setWindowTitle("Sensor 2 Exception") filename = datetime.now().strftime("sensor2_%Y-%m-%d_%H-%M-%S.csv") dumpFile = open(filename, 'w') dumpFile.write(f"Sensor 2 header: {self.sensor2.header}\n") for i in range(0, len(self.sensor2.buffer)): self.csvFile.write(str(self.sensor2.buffer[i])) dumpFile.close() self.sensor2Group.setChecked(False) self.update_sensor2_group() dg.showMessage(f"Sensor 2 has encountered an exception: {se}") dg.exec_() def update_temperature_group(self): if self.tempControllerGroup.isChecked(): dg = AR6X2ConfigDialog() dg.accepted.connect(self.connect_temp_controller) # if unsuccessful, disable the temperature controller group if dg.exec_() == 0: self.tempControllerGroup.setChecked(False) else: self.temperatureController = None self.tempControlButton.setText("Enable output") # Connect to the AR6X2 controller using given parameters def connect_temp_controller(self, values): self.temperatureController = AR6X2(port=values['port'], address=values['address']) def create_left_column(self): # Create a vertical layout for the left column leftColumnLayout = QVBoxLayout() # Valve override group vorGroup = QGroupBox("Valve override") vorLayout = QHBoxLayout() self.vorNormalButton = QPushButton("Normal") self.vorNormalButton.setMinimumWidth(50) self.vorNormalButton.setFixedHeight(75) self.vorNormalButton.setCheckable(True) self.vorNormalButton.clicked.connect(self.update_vor_normal) self.vorClosedButton = QPushButton("Closed") self.vorClosedButton.setMinimumWidth(50) self.vorClosedButton.setFixedHeight(75) self.vorClosedButton.setCheckable(True) self.vorClosedButton.clicked.connect(self.update_vor_closed) self.vorOpenButton = QPushButton("Open") self.vorOpenButton.setMinimumWidth(50) self.vorOpenButton.setFixedHeight(75) self.vorOpenButton.setCheckable(True) self.vorOpenButton.clicked.connect(self.update_vor_open) vorState = self.controller.get_valve_override() if vorState == "Normal": self.vorNormalButton.setChecked(True) self.vorClosedButton.setChecked(False) self.vorOpenButton.setChecked(False) elif vorState == "Closed": self.vorNormalButton.setChecked(False) self.vorClosedButton.setChecked(True) self.vorOpenButton.setChecked(False) elif vorState == "Open": self.vorNormalButton.setChecked(False) self.vorClosedButton.setChecked(False) self.vorOpenButton.setChecked(True) else: raise ValueError(f"Unexpected vor state: {vorState}") vorLayout.addWidget(self.vorNormalButton) vorLayout.addWidget(self.vorClosedButton) vorLayout.addWidget(self.vorOpenButton) vorGroup.setLayout(vorLayout) vorGroup.setMaximumWidth(ControllerGUITab.LEFT_COLUMN_MAX_WIDTH) leftColumnLayout.addWidget(vorGroup, alignment=Qt.AlignTop) # Process configuration group processGroup = QGroupBox("Process configuration") processLayout = QFormLayout() self.gasFactorEdit = QLineEdit() self.gasFactorEdit.setValidator( QRegExpValidator(QRegExp("[0-9]{1,3}(|\\.[0-9]{1,3})"))) self.gasFactorEdit.editingFinished.connect(self.update_gas_factor) self.gasFactorEdit.setText("{:.5f}".format(self.controller.get_gas())) self.pvFullScaleEdit = QLineEdit() self.pvFullScaleEdit.setValidator( QRegExpValidator(QRegExp("(-|)[0-9]{1,3}(|\\.[0-9]{1,3})"))) self.pvFullScaleEdit.editingFinished.connect(self.update_pv_full_scale) self.pvFullScaleEdit.setText(str(self.controller.get_pv_full_scale())) self.pvSigtypeDropdown = QComboBox() self.pvSigtypeDropdown.addItems(Controller.INPUT_PORT_TYPES.keys()) self.pvSigtypeDropdown.currentTextChanged.connect( self.update_pv_signal_type) self.pvSigtypeDropdown.setCurrentText( str(self.controller.get_pv_signal_type())) self.spFullScaleEdit = QLineEdit() self.spFullScaleEdit.setValidator( QRegExpValidator(QRegExp("(-|)[0-9]{1,3}(|\\.[0-9]{1,3})"))) self.spFullScaleEdit.editingFinished.connect(self.update_sp_full_scale) self.spFullScaleEdit.setText(str(self.controller.get_sp_full_scale())) self.spSigtypeDropdown = QComboBox() self.spSigtypeDropdown.addItems(Controller.OUTPUT_PORT_TYPES.keys()) self.spSigtypeDropdown.currentTextChanged.connect( self.update_sp_signal_type) self.spSigtypeDropdown.setCurrentText( str(self.controller.get_sp_signal_type())) self.spSourceDropdown = QComboBox() self.spSourceDropdown.addItems(Controller.SP_SOURCES.keys()) self.spSourceDropdown.currentTextChanged.connect(self.update_source) self.spSourceDropdown.setCurrentText(str(self.controller.get_source())) self.decimalDropdown = QComboBox() self.decimalDropdown.addItems(Controller.DECIMAL_POINTS.keys()) self.decimalDropdown.currentTextChanged.connect( self.update_decimal_point) self.decimalDropdown.setCurrentText( str(self.controller.get_decimal_point())) self.measureUnitsDropdown = QComboBox() self.measureUnitsDropdown.addItems(Controller.MEASUREMENT_UNITS.keys()) self.measureUnitsDropdown.currentTextChanged.connect( self.update_measure_units) self.measureUnitsDropdown.setCurrentText( str(self.controller.get_measurement_units())) self.timebaseDropdown = QComboBox() self.timebaseDropdown.addItems(Controller.RATE_TIME_BASE.keys()) self.timebaseDropdown.currentTextChanged.connect(self.update_time_base) self.timebaseDropdown.setCurrentText( str(self.controller.get_time_base())) processLayout.addRow(QLabel("Gas factor"), self.gasFactorEdit) processLayout.addRow(QLabel("PV Full Scale"), self.pvFullScaleEdit) processLayout.addRow(QLabel("PV Signal Type"), self.pvSigtypeDropdown) processLayout.addRow(QLabel("SP Full Scale"), self.spFullScaleEdit) processLayout.addRow(QLabel("SP Signal Type"), self.spSigtypeDropdown) processLayout.addRow(QLabel("Setpoint source"), self.spSourceDropdown) processLayout.addRow(QLabel("Decimal point"), self.decimalDropdown) processLayout.addRow(QLabel("Measurement units"), self.measureUnitsDropdown) processLayout.addRow(QLabel("Time base"), self.timebaseDropdown) processGroup.setLayout(processLayout) processGroup.setMaximumWidth(ControllerGUITab.LEFT_COLUMN_MAX_WIDTH) leftColumnLayout.addWidget(processGroup, alignment=Qt.AlignTop) leftColumnLayout.setStretch(1, 100) runtimeGroup = QGroupBox("Runtime options") runtimeLayout = QVBoxLayout() layout = QHBoxLayout() self.bufferSizeEdit = QLineEdit() self.bufferSizeEdit.setText("64") self.bufferSizeEdit.setValidator(QIntValidator()) self.bufferSizeEdit.editingFinished.connect(self.update_buffer_size) layout.addWidget(QLabel("Sample buffer size")) layout.addWidget(self.bufferSizeEdit) layout.addWidget(QLabel("samples")) runtimeLayout.addLayout(layout) layout = QHBoxLayout() self.intervalEdit = QLineEdit() self.intervalEdit.setText("1") self.intervalEdit.setValidator( QRegExpValidator(QRegExp("[0-9]*(|\\.[0-9]*)"))) self.intervalEdit.editingFinished.connect(self.update_graph_timer) layout.addWidget(QLabel("Data update interval")) layout.addWidget(self.intervalEdit) layout.addWidget(QLabel("minutes")) runtimeLayout.addLayout(layout) layout = QHBoxLayout() self.setpointEdit = QLineEdit() self.setpointEdit.setValidator( QRegExpValidator(QRegExp("[0-9]*(|\\.[0-9]*)"))) self.setpointEdit.editingFinished.connect(self.update_setpoint) self.setpointEdit.setText(str(self.controller.get_setpoint())) self.setpointUnitsLabel = QLabel( f"{self.measureUnitsDropdown.currentText()}/{self.timebaseDropdown.currentText()}" ) layout.addWidget(QLabel("Setpoint")) layout.addWidget(self.setpointEdit) layout.addWidget(self.setpointUnitsLabel) runtimeLayout.addLayout(layout) layout = QHBoxLayout() manualMeasureButton = QPushButton("Get measurement") manualMeasureButton.clicked.connect(self.update_plot) self.saveCsvButton = QPushButton("Start saving to CSV") self.saveCsvButton.clicked.connect(self.save_to_csv_start) layout.addWidget(manualMeasureButton) layout.addWidget(self.saveCsvButton) runtimeLayout.addLayout(layout) runtimeGroup.setLayout(runtimeLayout) runtimeGroup.setMaximumWidth(ControllerGUITab.LEFT_COLUMN_MAX_WIDTH) runtimeGroup.setFixedHeight(150) leftColumnLayout.addWidget(runtimeGroup, alignment=Qt.AlignBottom) return leftColumnLayout def create_right_column(self): # Create layouts and elements for the right column, including graph and sensor/temperature control/dosing groups rightColumnLayout = QVBoxLayout() rightInnerGrid = QGridLayout() # Creation of sensor 1 and sub-elements self.sensor1Group = QGroupBox("Sensor 1") self.sensor1Group.setCheckable(True) self.sensor1Group.setChecked(False) self.sensor1Group.clicked.connect(self.update_sensor1_group) sensor1Layout = QVBoxLayout() layout = QHBoxLayout() self.sensor1SampleIntervalEdit = QLineEdit() self.sensor1SampleIntervalEdit.setValidator( QRegExpValidator(QRegExp("[0-9]*(|\\.[0-9]*)"))) self.sensor1SampleIntervalEdit.setFixedWidth(100) self.sensor1SampleIntervalEdit.editingFinished.connect( self.update_sensor1_timer) self.sensor1SampleIntervalEdit.setText("1") label = QLabel('Sampling interval') label.setFixedWidth(90) layout.addWidget(label) layout.addWidget(self.sensor1SampleIntervalEdit) layout.addWidget(QLabel('minutes')) layout.setStretch(2, 10) sensor1Layout.addLayout(layout) layout = QHBoxLayout() self.sensor1BufferSizeEdit = QLineEdit() self.sensor1BufferSizeEdit.setValidator(QIntValidator()) self.sensor1BufferSizeEdit.setFixedWidth(100) self.sensor1BufferSizeEdit.editingFinished.connect( self.update_sensor1_buffer) self.sensor1BufferSizeEdit.setText("64") label = QLabel('Buffer size') label.setFixedWidth(90) layout.addWidget(label) layout.addWidget(self.sensor1BufferSizeEdit) layout.addWidget(QLabel('samples')) layout.setStretch(2, 10) sensor1Layout.addLayout(layout) self.sensor1Group.setLayout(sensor1Layout) # Creation of sensor 2 and sub-elements self.sensor2Group = QGroupBox("Sensor 2") self.sensor2Group.setCheckable(True) self.sensor2Group.setChecked(False) self.sensor2Group.clicked.connect(self.update_sensor2_group) sensor2Layout = QVBoxLayout() layout = QHBoxLayout() self.sensor2SampleIntervalEdit = QLineEdit() self.sensor2SampleIntervalEdit.setValidator( QRegExpValidator(QRegExp("[0-9]*(|\\.[0-9]*)"))) self.sensor2SampleIntervalEdit.setFixedWidth(100) self.sensor2SampleIntervalEdit.editingFinished.connect( self.update_sensor2_timer) self.sensor2SampleIntervalEdit.setText("1") label = QLabel('Sampling interval') label.setFixedWidth(90) layout.addWidget(label) layout.addWidget(self.sensor2SampleIntervalEdit) layout.addWidget(QLabel('minutes')) layout.setStretch(2, 10) sensor2Layout.addLayout(layout) layout = QHBoxLayout() self.sensor2BufferSizeEdit = QLineEdit() self.sensor2BufferSizeEdit.setValidator(QIntValidator()) self.sensor2BufferSizeEdit.setFixedWidth(100) self.sensor2BufferSizeEdit.editingFinished.connect( self.update_sensor2_buffer) self.sensor2BufferSizeEdit.setText("64") label = QLabel('Buffer size') label.setFixedWidth(90) layout.addWidget(label) layout.addWidget(self.sensor2BufferSizeEdit) layout.addWidget(QLabel('samples')) layout.setStretch(2, 10) sensor2Layout.addLayout(layout) self.sensor2Group.setLayout(sensor2Layout) self.tempControllerGroup = QGroupBox("Temperature controller") self.tempControllerGroup.setCheckable(True) self.tempControllerGroup.setEnabled( False) # Disabled functionality as it is untested self.tempControllerGroup.setChecked(False) self.tempControllerGroup.clicked.connect(self.update_temperature_group) tempControllerLayout = QVBoxLayout() layout = QHBoxLayout() self.temperatureSlider = QSlider(Qt.Horizontal) self.temperatureSlider.setMinimumWidth(95) self.temperatureSlider.setMaximumWidth(1000) self.temperatureSlider.setMinimum(-199.9) self.temperatureSlider.setMaximum(850.0) self.temperatureSlider.setValue(100) self.temperatureSlider.sliderMoved.connect(self.update_temperature) self.temperatureLabel = QLabel("100") layout.addWidget(QLabel("Temperature"), alignment=Qt.AlignLeft) layout.addWidget(self.temperatureSlider, alignment=Qt.AlignLeft) layout.addWidget(self.temperatureLabel, alignment=Qt.AlignLeft) layout.addWidget(QLabel("℃"), alignment=Qt.AlignLeft) layout.setStretch(3, 200) tempControllerLayout.addLayout(layout) # these edits have validators, but input still has to be capped layout = QHBoxLayout() self.rangeLowEdit = QLineEdit() self.rangeLowEdit.setMinimumWidth(30) self.rangeLowEdit.setMaximumWidth(60) self.rangeLowEdit.setText("-199.9") self.rangeLowEdit.setValidator( QRegExpValidator( QRegExp("(-[0-9]{1,3}\\.[0-9]|[0-9]{1,3}\\.[0-9|[0-9]{1,4})"))) self.rangeLowEdit.editingFinished.connect(self.update_range_low) self.rangeHighEdit = QLineEdit() self.rangeHighEdit.setMinimumWidth(30) self.rangeHighEdit.setMaximumWidth(60) self.rangeHighEdit.setText("850.0") self.rangeHighEdit.setValidator( QRegExpValidator( QRegExp("(-[0-9]{1,3}\\.[0-9]|[0-9]{1,3}\\.[0-9|[0-9]{1,4})"))) self.rangeHighEdit.editingFinished.connect(self.update_range_high) layout.addWidget(QLabel("Range")) layout.addWidget(self.rangeLowEdit, alignment=Qt.AlignLeft) layout.addWidget(self.rangeHighEdit, alignment=Qt.AlignLeft) layout.addWidget(QLabel("℃")) layout.setStretch(3, 10) tempControllerLayout.addLayout(layout) self.rampingCheckbox = QCheckBox() self.rampingCheckbox.stateChanged.connect(self.update_ramping_enable) self.tempReadoutLabel = QLabel("Readout: None ℃") layout = QHBoxLayout() layout.addWidget(QLabel("Ramping"), alignment=Qt.AlignLeft) layout.addWidget(self.rampingCheckbox, alignment=Qt.AlignLeft) layout.addWidget(self.tempReadoutLabel, alignment=Qt.AlignBottom) layout.setStretch(1, 10) tempControllerLayout.addLayout(layout) layout = QHBoxLayout() self.gradientEdit = QLineEdit() self.gradientEdit.setMinimumWidth(30) self.gradientEdit.setMaximumWidth(60) self.gradientEdit.setText("0.1") # default value from the datasheet self.gradientEdit.editingFinished.connect(self.update_gradient) self.tempControlButton = QPushButton("Enable output") self.tempControlButton.setCheckable(True) self.tempControlButton.clicked.connect(self.update_temp_control_enable) layout.addWidget(QLabel("Gradient"), alignment=Qt.AlignLeft) layout.addWidget(self.gradientEdit, alignment=Qt.AlignLeft) layout.addWidget(QLabel("℃/min")) layout.addWidget(self.tempControlButton, alignment=Qt.AlignBottom) layout.setStretch(2, 10) tempControllerLayout.addLayout(layout) self.tempControllerGroup.setLayout(tempControllerLayout) self.tempControllerGroup.setMinimumWidth(200) self.tempControllerGroup.setFixedHeight(150) dosingGroup = QGroupBox("Dosing control") dosingGroup.setCheckable(False) dosingLayout = QVBoxLayout() layout = QHBoxLayout() self.dosingTimesEdit = QLineEdit() self.dosingTimesEdit.setMinimumWidth(160) self.dosingTimesEdit.setText("1, 1, 1.5") self.dosingTimesEdit.setValidator( QRegExpValidator(QRegExp("(([0-9]+|[0-9]+\\.[0-9]+),(| ))+"))) self.dosingTimesEdit.textChanged.connect(self.update_dosing_vectors) label = QLabel("Times") label.setFixedWidth(55) layout.addWidget(label) layout.addWidget(self.dosingTimesEdit) layout.addWidget(QLabel("minutes")) dosingLayout.addLayout(layout) layout = QHBoxLayout() self.dosingValuesEdit = QLineEdit() self.dosingValuesEdit.setMinimumWidth(160) self.dosingValuesEdit.setText("1.0, 2.0, 5.0") self.dosingValuesEdit.setValidator( QRegExpValidator(QRegExp("(([0-9]+|[0-9]+\\.[0-9]+),(| ))+"))) self.dosingValuesEdit.textChanged.connect(self.update_dosing_vectors) label = QLabel("Setpoints") label.setFixedWidth(55) self.dosingUnitsLabel = QLabel( f"{self.measureUnitsDropdown.currentText()}/{self.timebaseDropdown.currentText()}" ) layout.addWidget(label) layout.addWidget(self.dosingValuesEdit) layout.addWidget(self.dosingUnitsLabel) dosingLayout.addLayout(layout) self.dosingLabel = QLabel("Dosing disabled") self.dosingVorStateLabel = QLabel( f"VOR is {self.controller.get_valve_override().lower()}") if "normal" in self.dosingVorStateLabel.text(): self.dosingVorStateLabel.setStyleSheet("color: green") else: self.dosingVorStateLabel.setStyleSheet("color: red") self.dosingControlButton = QPushButton("Start dosing") self.dosingControlButton.setCheckable(True) self.dosingControlButton.clicked.connect(self.update_dosing_state) dosingLayout.addWidget(self.dosingLabel, alignment=Qt.AlignLeft) layout = QHBoxLayout() layout.addWidget(self.dosingVorStateLabel, alignment=Qt.AlignLeft) layout.addWidget(self.dosingControlButton, alignment=Qt.AlignRight) dosingLayout.addLayout(layout) # finally, assign the layout to the group dosingGroup.setLayout(dosingLayout) dosingGroup.setMinimumWidth(200) dosingGroup.setFixedHeight(150) rightInnerGrid.addWidget(self.sensor1Group, 0, 0) rightInnerGrid.addWidget(self.sensor2Group, 0, 1) rightInnerGrid.addWidget(self.tempControllerGroup, 1, 0) rightInnerGrid.addWidget(dosingGroup, 1, 1) rightInnerGrid.setColumnStretch(0, 100) rightInnerGrid.setColumnStretch(1, 100) self.graph = PlotWidget() self.graph.getPlotItem().showGrid(x=True, y=True, alpha=1) if "qdarkstyle" in sys.modules: self.graph.setBackground((25, 35, 45)) rightColumnLayout.addWidget(self.graph) rightColumnLayout.addLayout(rightInnerGrid) return rightColumnLayout # function to change the amount of stored samples without losing previously gathered samples def change_buffer_size(self, value): if value > self.sampleBufferSize: newBufPV = RingBuffer(capacity=value, dtype=np.float16) newBufTotal = RingBuffer(capacity=value, dtype=np.float32) newTimestampBuf = RingBuffer(capacity=value, dtype=datetime) newBufPV.extend(self.samplesPV) newBufTotal.extend(self.samplesTotalizer) newTimestampBuf.extend(self.sampleTimestamps) self.samplesPV = newBufPV self.samplesTotalizer = newBufTotal self.sampleTimestamps = newTimestampBuf elif value < self.sampleBufferSize: newBufPV = RingBuffer(capacity=value, dtype=np.float16) newBufTotal = RingBuffer(capacity=value, dtype=np.float32) newTimestampBuf = RingBuffer(capacity=value, dtype=datetime) newBufPV.extend(self.samplesPV[:-value]) newBufTotal.extend(self.samplesTotalizer[:-value]) newTimestampBuf.extend(self.sampleTimestamps[:-value]) self.samplesPV = newBufPV self.samplesTotalizer = newBufTotal self.sampleTimestamps = newTimestampBuf
class Window(QWidget): temptime = 0 time = 0 totalDuration = 0 subtitleIndex = 1 qp = QPainter() def __init__(self): super().__init__() self.title = "Video Editor" self.display() self.initUI() self.toolbar() self.timeLine() self.createButtons() self.timeMarks() self.importBox() self.importPreviewBox() self.timer = QTimer(self) self.subtitleTimer = QTimer(self) self.subStopTimer = QTimer(self) # Video player creation, move to own definition later self.mediaPlayer = QMediaPlayer(self) self.audioPlayer = QMediaPlayer(self) self.videoWidget = QVideoWidget(self) self.videoWidget.setGeometry(700, 20, 600, 400) self.mediaPlayer.setVideoOutput(self.videoWidget) self.mediaPlayer.durationChanged.connect(self.durationChanged) self.mediaPlayer.positionChanged.connect(self.positionChanged) self.videoWidget.setAspectRatioMode(Qt.KeepAspectRatio) self.show() def initUI(self): self.setWindowTitle(self.title) self.setGeometry(100, 50, 1700, 900) # Creates the box for the import list, default box def importBox(self): self.importBoxLabel = QLabel(self) self.importBoxLabel.setStyleSheet("border: 2px solid black") self.importBoxLabel.setGeometry(20, 20, 300, 400) # Creates the actual box containing the list of imports def importBoxList(self, fname): Model.importList.append(QPushButton("", self)) Model.importList[len(Model.videoList) - 1].setStyleSheet("border: 2px solid black") Model.importList[len(Model.videoList) - 1].setText( str(len(Model.importList)) + ". " + str(fname)) Model.importList[len(Model.videoList) - 1].setGeometry( 20, 20 + (20 * (len(Model.videoList) - 1)), 300, 20) Model.importList[len(Model.videoList) - 1].clicked.connect( partial(self.importClicked, len(Model.videoList) - 1)) Model.importList[len(Model.videoList) - 1].show() # Creates the box containing the list of imporsts def importAudioList(self, aname): Model.importAudioList.append(QPushButton("", self)) Model.importAudioList[len(Model.audioList) - 1].setStyleSheet("border: 2px solid black") Model.importAudioList[len(Model.audioList) - 1].setText( str(len(Model.importAudioList)) + ". " + str(aname)) Model.importAudioList[len(Model.audioList) - 1].setGeometry( 320, 20 + (20 * (len(Model.audioList) - 1)), 300, 20) Model.importAudioList[len(Model.audioList) - 1].clicked.connect( partial(self.importAudioClicked, len(Model.audioList) - 1)) Model.importAudioList[len(Model.audioList) - 1].show() # Creates a box for the preview of each import. TODO: show the thumbnail of each import and details. def importPreviewBox(self): self.previewBox = QLabel(self) self.previewBox.setStyleSheet("Border: 2px solid black") self.previewBox.setGeometry(320, 20, 300, 400) def display(self): self.displayLabel = QLabel(self) self.displayLabel.setStyleSheet("border: 2px solid black") self.displayLabel.setGeometry(700, 20, 600, 400) def toolbar(self): self.toolbarLabel = QLabel(self) self.toolbarLabel.setStyleSheet("border: 2px solid black") self.toolbarLabel.setGeometry(20, 450, 1400, 100) def timeLine(self): self.timeLineLabel = QLabel(self) self.timeLineLabel.setStyleSheet("border: 2px solid black") self.timeLineLabel.setGeometry(20, 585, 1400, 130) # Timeline for subtitles self.subTimeLineLabel = QLabel(self) self.subTimeLineLabel.setStyleSheet("border: 2px solid black") self.subTimeLineLabel.setGeometry(20, 790, 1400, 50) # Timeline for audio self.audioTimeLine = QLabel(self) self.audioTimeLine.setStyleSheet("border: 2px solid black") self.audioTimeLine.setGeometry(20, 720, 1400, 60) # Calculates total duration and convers milliseconds to seconds def durationChanged(self, duration): self.positionSlider.setRange(0, duration) if Window.totalDuration == 0: self.playTimeLabel = QLabel(self) Window.totalDuration += duration self.seconds = int(math.floor((duration / 1000) % 60)) self.minutes = int(math.floor((duration / 60000) % 60)) self.hours = int(math.floor((duration / 3600000) % 24)) self.playTimeLabel.setText( str(self.hours) + ":" + str(self.minutes) + ":" + str(self.seconds)) self.playTimeLabel.setStyleSheet( "font-size: 40px; alignment:center-align") self.playTimeLabel.move(450, 500) self.playTimeLabel.show() # Creates all buttons needed def createButtons(self): # List Titles self.videoTitle = QLabel(self) self.videoTitle.setText("Video List") self.videoTitle.move(20, 0) self.audioTitle = QLabel(self) self.audioTitle.setText("Audio List") self.audioTitle.move(320, 0) # Play button self.playButton = QPushButton("Play", self) self.playButton.setStyleSheet("background-color: gray") self.playButton.move(700, 500) self.playButton.setEnabled(False) self.playButton.clicked.connect(self.play) # Import files button self.importButton = QPushButton("Import Videos", self) self.importButton.setStyleSheet("background-color: gray") self.importButton.move(30, 460) self.importButton.clicked.connect(self.importFunction) # Import audio button self.importAudioButton = QPushButton("Import Audio", self) self.importAudioButton.setStyleSheet("background-color: gray") self.importAudioButton.move(30, 490) self.importAudioButton.clicked.connect(self.importAudioFunction) self.addSubtitleButton = QPushButton("Add Subtitles", self) self.addSubtitleButton.setStyleSheet("background-color: gray") self.addSubtitleButton.move(800, 500) self.addSubtitleButton.clicked.connect(self.addSubtitles) # Move to timeline button self.moveButton = QPushButton("Video to Timeline", self) self.moveButton.setStyleSheet("background-color: gray") self.moveButton.move(300, 460) self.moveButton.clicked.connect(self.showOnTimeLine) self.moveButton.setEnabled(False) self.moveButton.setHidden(True) # Move audio to timeline self.moveAudio = QPushButton("Audio to Timeline", self) self.moveAudio.setStyleSheet("background-color:gray") self.moveAudio.move(300, 490) self.moveAudio.clicked.connect(self.createAudioThumbs) self.moveAudio.setEnabled(False) self.moveAudio.setHidden(True) self.saveVideo = QPushButton("Save Video", self) self.saveVideo.setStyleSheet("background-color:gray") self.saveVideo.move(500, 470) self.saveVideo.clicked.connect(self.exportFile) self.saveVideo.setEnabled(False) self.moveOn = QPushButton("Move video", self) self.moveOn.setStyleSheet("background-color:gray") self.moveOn.move(300, 460) self.moveOn.clicked.connect(self.moveOnTimeline) self.moveOn.setEnabled(False) self.moveOn.setHidden(True) self.moveAuOn = QPushButton("Move audio", self) self.moveAuOn.setStyleSheet("background-color:gray") self.moveAuOn.move(300, 490) self.moveAuOn.clicked.connect(self.moveAudioOnTime) self.moveAuOn.setEnabled(False) self.moveAuOn.setHidden(True) # Qlineedit self.positioningRequest = QLineEdit(self) self.positioningRequest.setPlaceholderText("Enter Position(seconds)") self.positioningRequest.move(150, 460) self.positioningRequest.resize(150, 25) self.positioningRequest.setEnabled(False) self.audioPosition = QLineEdit(self) self.audioPosition.setPlaceholderText("Enter Position(seconds)") self.audioPosition.move(150, 490) self.audioPosition.resize(150, 25) self.audioPosition.setEnabled(False) self.positionSlider = QSlider(Qt.Horizontal, self) self.positionSlider.setRange(0, 0) self.positionSlider.sliderMoved.connect(self.setPosition) self.positionSlider.setGeometry(20, 585, 1400, 130) # Time line tracker def positionChanged(self, position): self.positionSlider.setValue(position / 40) self.positionSlider.show() def setPosition(self, position): self.mediaPlayer.setPosition(position) # Creates labels/buttons, as the thumbnails of each video imported def moveOnTimeline(self): position = int(self.positioningRequest.text()) currentIndex = Model.currentVidTimeLineIndex Model.buttonList[currentIndex].move(20 + (position) * 5.5, 585) Model.positionarray[currentIndex].timepos = position self.update() Model.od = sorted(Model.positionarray, key=lambda x: x.timepos) # Allows users to move audio files to time line def moveAudioOnTime(self): Model.soundPosition = int(self.audioPosition.text()) currentAudioIndex = Model.currentAudioTimeIndex Model.audioThumbList[currentAudioIndex].move( 20 + (Model.soundPosition) * 5.5, 720) self.update() # Creates the thumnail of an audio file in the time line def createAudioThumbs(self): Model.audioThumbList.append( QPushButton(str(Model.audioCurrent + 1), self)) Model.soundPosition = int(self.audioPosition.text()) self.audioDuration = self.mediaPlayer.duration() #Added minutes self.audioSeconds = int(round((self.audioDuration / 1000))) Model.audioThumbList[len(Model.audioThumbList) - 1].resize( (self.audioSeconds * 5.5), 60) Model.audioThumbList[len(Model.audioThumbList) - 1].setStyleSheet( "border: 1px solid black;color:red") Model.audioThumbList[len(Model.audioThumbList) - 1].move( 20 + (Model.soundPosition) * 5.5, 720) Model.audioThumbList[len(Model.audioThumbList) - 1].show() Model.audioThumbList[len(Model.audioThumbList) - 1].clicked.connect( partial(self.audioTimeLineClicked, len(Model.audioThumbList) - 1)) self.update() self.moveAudio.setEnabled(False) # Shows the labels we see in time line def showOnTimeLine(self): Model.videoDuration = self.mediaPlayer.duration() Model.buttonList.append(QPushButton(str(Model.current + 1), self)) self.position = int(self.positioningRequest.text()) Window.totalDuration += self.position * 1000 Model.positionarray.append( positionObject(self.position, Model.current, Model.videoDuration)) Model.od = sorted(Model.positionarray, key=lambda x: x.timepos) print(Model.od) vidSeconds = int(round((Model.videoDuration / 1000) % 60)) Model.buttonList[len(Model.buttonList) - 1].resize((vidSeconds * 5.5), 130) Model.buttonList[len(Model.buttonList) - 1].setStyleSheet("border: 1px solid black; color:red") Model.buttonList[len(Model.buttonList) - 1].move( 20 + (self.position) * 5.5, 585) Model.buttonList[len(Model.buttonList) - 1].clicked.connect( partial(self.timelinetoVid, len(Model.buttonList) - 1)) Model.buttonList[len(Model.buttonList) - 1].show() # Writes to a text file to create a list for the ffmpeg comman #self.file = open(r'bin/text.txt','a+') #windows self.file = open(r'bin\text.txt', 'w+') #abpath = os.path.abspath("./empty.mp4") #windows abpath = os.path.abspath(r'.\empty.avi') self.getDelays() if len(Model.delayTimes) > 0: self.file.write("file '" + str(abpath) + "'\n" + "duration " + str(Model.delayTimes[Model.i]) + "\n") Model.i += 1 self.file.write("file '" + str(Model.videoList[Model.current]) + "'\n") self.file.close() self.moveButton.setEnabled(False) self.playButton.setEnabled(True) self.saveVideo.setEnabled(True) self.update() # Plays/pauses the media files depending on the state def play(self): if Model.timelineState == False: if self.mediaPlayer.state() != QMediaPlayer.PlayingState: self.mediaPlayer.play() self.playButton.setText("Pause") else: self.mediaPlayer.pause() self.playButton.setText("Play") # Starts the timer at the last paused time instead of starting at the totalDuration each time. if Model.timelineState == True: if Model.pausedTime == 0: if self.timer.isActive() != True: if Model.tempIndex == len(Model.od): Model.tempIndex = 0 if Model.tempIndex < len(Model.od) - 1: if ((Model.od[Model.tempIndex + 1].timepos * 1000) - Model.od[Model.tempIndex].duration) < 0: Model.additionalduration = 0 Model.additionalduration = ( Model.od[Model.tempIndex + 1].timepos * 1000) - Model.od[Model.tempIndex].duration else: Model.additionalduration = 0 self.timer.start(Model.od[Model.tempIndex].duration + Model.additionalduration) print("Subtitle Duration: " + str(Model.subtitleDuration)) print("Subtitle Start: " + str(Model.subtitleStart)) self.subtitleTimer.start( Model.subtitleStart[Model.subtitleIndex] + Model.subtitleDuration[Model.subtitleIndex]) print("Timer: " + str(self.timer.remainingTime())) print("Sub Timer: " + str(self.subtitleTimer.remainingTime())) self.mediaPlayer.play() if Model.subtitleIndex < len(Model.subList): self.subtitleTimer.timeout.connect(self.playSubtitles) if len(Model.audioList) != 0 and Model.soundPosition != 0: self.timer.singleShot((Model.soundPosition * 1000), self.playAudio) if len(Model.audioList) != 0 and Model.soundPosition == 0: self.timer.singleShot(Model.soundPosition * 1000, self.playAudio) self.timer.timeout.connect(self.playNext) self.playButton.setText("Pause") else: self.mediaPlayer.pause() self.audioPlayer.pause() self.playButton.setText("Play") Model.pausedTime = self.timer.remainingTime() Model.subTimePause = self.subtitleTimer.remainingTime() self.subtitleTimer.stop() self.timer.stop() else: print("AUSD") if self.audioPlayer.state() == QMediaPlayer.PlayingState: self.audioPlayer.pause() else: self.audioPlayer.play() if self.timer.isActive() != True: self.timer.start(Model.pausedTime) self.subtitleTimer.start(Model.subTimePause) self.mediaPlayer.play() self.playButton.setText("Pause") else: self.mediaPlayer.pause() self.playButton.setText("Play") Model.pausedTime = self.timer.remainingTime() self.timer.stop() Model.subTimePause = self.subtitleTimer.remainingTime() self.subtitleTimer.stop() Model.subList[Model.subtitleIndex - 1].setHidden(True) # Plays the next video in the time line def playNext(self): Model.tempIndex += 1 if Model.tempIndex < len(Model.od): self.mediaPlayer.setMedia( QMediaContent( QUrl.fromLocalFile( Model.videoList[Model.od[Model.tempIndex].index]))) self.mediaPlayer.play() else: print("video done") self.timer.stop() def playAudio(self): self.audioPlayer.play() def stopall(self): self.timer.stop() self.mediaPlayer.stop() self.audioPlayer.stop() # Shows the first subtitle but never hides it def playSubtitles(self): if Model.subtitleIndex == 0: Model.subList[Model.subtitleIndex].setHidden(False) if Model.subtitleIndex < len(Model.subList) - 1: Model.subList[Model.subtitleIndex].setHidden(False) Model.subList[Model.subtitleIndex - 1].setHidden(True) Model.subtitleIndex += 1 # Import function to get the urls needed to display in the mediaplayer widget def importFunction(self): #Model.fname, _ = QFileDialog.getOpenFileName(self, 'Open file', '../desktop','All files(*.jpeg *.mp4 *.mov);;Image files(*.jpeg);;Video Files(*.mp4 *.mov)') #windows Model.fname, _ = QFileDialog.getOpenFileName( self, 'Open file', '..\desktop', 'All files(*.jpeg *.mp4 *.mov);;Image files(*.jpeg);;Video Files(*.mp4 *.mov)' ) if Model.fname != '': Model.videoList.append(Model.fname) fi = QFileInfo(Model.fname) base = fi.completeBaseName() self.importBoxList(base) # Imports audio files that are searched on local drive def importAudioFunction(self): #Model.aname, _ = QFileDialog.getOpenFileName(self, 'Open audio file', '../desktop','All audio files(*.mp3 *.wav)') #windows Model.aname, _ = QFileDialog.getOpenFileName( self, 'Open audio file', '..\desktop', 'All audio files(*.mp3 *.wav)') if Model.aname != '': Model.audioList.append(Model.aname) fi = QFileInfo(Model.aname) base = fi.completeBaseName() self.importAudioList(base) # When audio in time line is clicked, allows users to play whatever is on time line def audioTimeLineClicked(self, index): Model.tempIndex = 0 Model.timelineState = True self.cleanImportLists() self.cleanTimeline() Model.audioThumbList[index].setStyleSheet( "border: 2px solid red;color:red") if len(Model.buttonList) > 0: self.mediaPlayer.setMedia( QMediaContent( QUrl.fromLocalFile( Model.videoList[Model.od[Model.tempIndex].index]))) self.audioPlayer.setMedia( QMediaContent(QUrl.fromLocalFile( Model.audioList[Model.tempIndex]))) self.hideTimeButtons() self.hideImportButtons() self.moveAuOn.setEnabled(True) self.moveAuOn.setHidden(False) self.enabelSlider() self.timer.stop() #clicking each label on the timeline leads here. currently loads video from videourl contained in videoList def timelinetoVid(self, index): #self.mediaPlayer.setMedia(QMediaContent(QUrl.fromLocalFile(Model.videoList[index]))) n = 0 #self.playButton.setEnabled(True) Model.tempIndex = 0 # Highlighting Model.timelineState = True self.cleanImportLists() self.cleanTimeline() Model.buttonList[index].setStyleSheet( "border: 2px solid red;color:red") Model.currentVidTimeLineIndex = index self.hideImportButtons() self.hideTimeButtons() self.moveOn.setEnabled(True) self.moveOn.setHidden(False) self.timer.stop() self.playButton.setEnabled(True) if len(Model.audioThumbList) > 0: self.audioPlayer.setMedia( QMediaContent( QUrl.fromLocalFile(Model.audioList[Model.tempIndex]))) self.mediaPlayer.setMedia( QMediaContent( QUrl.fromLocalFile( Model.videoList[Model.od[Model.tempIndex].index]))) if Model.od[0].timepos != 0: self.mediaPlayer.setMedia( QMediaContent(QUrl.fromLocalFile(r"blackvid.mp4"))) self.enabelSlider() # Gets the delays between videos to use for ffmpeg def getDelays(self): if Model.i < len(Model.od) - 1: Model.delayTimes.append(Model.od[Model.i + 1].timepos - ((Model.od[Model.i].duration) / 1000 + Model.od[Model.i].timepos)) # Allows user to save and compile all the media files into one. def exportFile(self): # FFMPEG command, runs the application from the OS to concactenate media files. TODO: fix the usage of different format/codec files #ffmpeg_command = ["ffmpeg","-y","-f","concat","-safe","0","-i",r"bin/text.txt","-vf","scale=1280:720","-acodec","copy",r"bin/output.mp4"] #windows mode ffmpeg_command = [ "ffmpeg", "-y", "-f", "concat", "-safe", "0", "-i", r"bin\text.txt", "-vf", "scale=1280:720", "-acodec", "copy", r"bin\output.mp4" ] p = subprocess.call(ffmpeg_command, stdout=subprocess.PIPE) ffmpeg_audio = [ "ffmpeg", "-y", "-i", r"bin\output.mp4", "-i", str(Model.audioList[0]), "-map", "0:0", "-map", "1:0", "-c:v", "copy", "-preset", "ultrafast", "-async", "1", r"bin\needSubs.mp4" ] a = subprocess.call(ffmpeg_audio, stdout=subprocess.PIPE) ffmpeg_subtitles = [ "ffmpeg", "-y", "-i", r"bin\needSubs.mp4", "-i", r"bin\subtitles.srt", "-c:v", "libx264", "-ar", "44100", "-ac", "2", "-ab", "128k", "-strict", "-2", "-c:s", "mov_text", "-map", "0", "-map", "1", r"bin\finalVid.mp4" ] s = subprocess.Popen(ffmpeg_subtitles, stdout=subprocess.PIPE) # Highlighting for each item clicked on importlist def importClicked(self, index): Model.importBoxState = 0 Model.timelineState = False self.cleanImportLists() self.cleanTimeline() Model.importList[index].setStyleSheet("border: 2px solid red") self.hideImportButtons() self.hideTimeButtons() self.mediaPlayer.setMedia( QMediaContent(QUrl.fromLocalFile(Model.videoList[index]))) self.playButton.setEnabled(True) self.moveButton.setEnabled(True) self.moveButton.setHidden(False) self.positioningRequest.setEnabled(True) self.positionSlider.setEnabled(True) Model.current = index self.enableMove() self.positionSlider.setEnabled(True) # Highlights each audio file clicked def importAudioClicked(self, index): Model.timelineState = False Model.importBoxState = 1 self.cleanImportLists() self.cleanTimeline() self.hideImportButtons() self.hideTimeButtons() self.positionSlider.setEnabled(True) Model.importAudioList[index].setStyleSheet("border: 2px solid red") self.mediaPlayer.setMedia( QMediaContent(QUrl.fromLocalFile(Model.audioList[index]))) #mixer.music.load(Model.audioList[index]) self.playButton.setEnabled(True) self.moveAudio.setEnabled(True) self.audioPosition.setEnabled(True) self.moveAudio.setHidden(False) Model.audioCurrent = index self.enableAudio() self.positionSlider.setEnabled(True) # Cleans up highlighting so only one is highlighted def cleanImportLists(self): for i in range(len(Model.importList)): Model.importList[i].setStyleSheet("border: 2px solid black") for i in range(len(Model.importAudioList)): Model.importAudioList[i].setStyleSheet("border: 2px solid black") self.setFocus() def cleanTimeline(self): for i in range(len(Model.buttonList)): Model.buttonList[i].setStyleSheet("border: 2px solid black") for i in range(len(Model.audioThumbList)): Model.audioThumbList[i].setStyleSheet("Border:2px solid black") self.setFocus() # Creates the time markers for time line def timeMarks(self): self.markers = QLabel(self) self.markers.setGeometry(20, 555, 1400, 30) self.markers.setStyleSheet("border: 2px solid black") self.markValue = 0 while self.markValue <= 250: self.markerLabel = QLabel(self) if self.markValue == 0: self.markerLabel.move(20, 555) else: self.markerLabel.move(20 + (self.markValue * 5.5), 555) if (self.markValue % 60 == 0): self.markerLabel.setText("|" + str(self.markValue / 60) + "0" + "\n" + "|") else: self.markerLabel.setText("\n" + "|") self.markerLabel.setStyleSheet("font: 15px; color: purple") self.markValue += 5 self.markValue = 0 while self.markValue <= 250: self.markerLabel = QLabel(self) if self.markValue == 0: self.markerLabel.move(20, 710) else: self.markerLabel.move(20 + (self.markValue * 5.5), 710) self.markerLabel.setText("|") self.markerLabel.setStyleSheet("font: 15px; color: purple") self.markValue += 5 self.markValue = 0 while self.markValue <= 250: self.markerLabel = QLabel(self) if self.markValue == 0: self.markerLabel.move(20, 780) else: self.markerLabel.move(20 + (self.markValue * 5.5), 780) self.markerLabel.setText("|") self.markerLabel.setStyleSheet("font: 15px; color: purple") self.markValue += 5 # Creates a new window with a text box to enter subtitles def addSubtitles(self): self.root = Tk() self.entry = Entry(self.root) self.timePosition = Entry(self.root) self.subLength = Entry(self.root) instructions = Label(self.root, text="Please enter the text for the subtitles:") text = Label(self.root, text="Time you wish to insert subtitle:") length = Label(self.root, text="Duration of subtitles:") self.root.title("Add Subtitles") self.root.geometry("400x300+500+200") addButton = Button(self.root, text="Create Subtitle", command=self.printSubtitles) closeButton = Button(self.root, text="Cancel", command=self.destroySecondWindow) self.entry.pack() self.timePosition.pack() self.subLength.pack() closeButton.pack() addButton.pack() instructions.pack() text.pack() length.pack() instructions.place(x="80", y="10") self.entry.place(x="20", y="50", height="30", width="360") text.place(x="100", y="100") self.timePosition.place(x="150", y="130", height="30", width="100") length.place(x="150", y="170") self.subLength.place(x="150", y="200", height="30", width="100") closeButton.place(x="300", y="230") addButton.place(x="30", y="230") self.root.mainloop() # Prints the text entered in the textbox in the second window def printSubtitles(self): # Labels of subtitles that show on preview Model.subList.append(QLabel(self)) Model.subList[len(Model.subList) - 1].setStyleSheet("border: 2px solid transparent") Model.subList[len(Model.subList) - 1].setAlignment(Qt.AlignCenter) Model.subList[len(Model.subList) - 1].setGeometry(740, 350, 500, 50) self.subtitleLabel = QLabel(self) Model.subtitleList.append(self.entry.get()) Model.subList[len(Model.subList) - 1].setText(self.entry.get()) Model.subtitleButtonList.append( QPushButton(str(Model.subtitleList[len(Model.subtitleList) - 1]), self)) self.subtitleDuration = int(self.subLength.get()) # List of subtitle's duration Model.subtitleDuration.append(self.subtitleDuration * 1000) Model.subtitleButtonList[len(Model.subtitleList) - 1].resize( (self.subtitleDuration * 9), 50) Model.subtitleButtonList[len(Model.subtitleList) - 1].setStyleSheet("border: 2px solid black") # When subtitles start subPosition = int(self.timePosition.get()) Model.subtitleStart.append(subPosition * 1000) Model.subtitleButtonList[len(Model.subtitleList) - 1].move( 24 + (subPosition) * 11, 790) Model.subtitleButtonList[len(Model.subtitleList) - 1].show() #self.subtitleFile = open(r"bin/subtitles.srt", "a+") # Window self.subtitleFile = open(r"bin\subtitles.srt", "a+") subtitleIndex = 1 self.subtitleFile.write(str(Window.subtitleIndex) + "\n") Window.subtitleIndex += 1 if subPosition < 10: self.subtitleFile.write("00:00:0" + str(subPosition) + ",000 --> ") if self.subtitleDuration + subPosition < 10: self.subtitleFile.write("00:00:0" + str(self.subtitleDuration + subPosition) + ",000\n") if self.subtitleDuration + subPosition >= 10 and self.subtitleDuration + subPosition < 100: self.subtitleFile.write("00:00:" + str(self.subtitleDuration + subPosition) + ",000\n") if subPosition >= 10 and subPosition <= 59: self.subtitleFile.write("00:00:" + str(subPosition) + ",000 --> ") if self.subtitleDuration + subPosition >= 60 and self.subtitleDuration + subPosition < 600: minutes = int((self.subtitleDuration + subPosition) / 60) seconds = (self.subtitleDuration + subPosition) % 60 if seconds < 10: self.subtitleFile.write("00:0" + str(minutes) + ":0" + str(seconds) + ",000\n") else: self.subtitleFile.write("00:0" + str(minutes) + ":" + str(seconds) + ",000\n") else: self.subtitleFile.write("00:00:" + str(self.subtitleDuration + subPosition) + ",000\n") self.subtitleFile.write(self.entry.get() + ("\n" * 2)) self.subtitleFile.close() self.destroySecondWindow() def hideTimeButtons(self): self.moveButton.setHidden(True) self.moveButton.setEnabled(False) self.moveAudio.setHidden(True) self.moveAudio.setEnabled(False) def hideImportButtons(self): self.moveOn.setHidden(True) self.moveOn.setEnabled(False) self.moveAuOn.setHidden(True) self.moveAuOn.setEnabled(False) def enableMove(self): self.moveButton.setEnabled(True) def enableAudio(self): self.moveAudio.setEnabled(True) def enabelSlider(self): self.positionSlider.setEnabled(True) # Destroys the second window def destroySecondWindow(self): self.root.destroy() # Deletes videolist file on exit @atexit.register def goodbye(): #file = open('bin/text.txt','w+') #windows file = open('bin\text.txt', 'w+') file.truncate() """
class Kamatis(QApplication): __application_name = 'Kamatis' __desktop_file_entry = '''\ [Desktop Entry] Version=1.0 Type=Application Name={0} GenericName={0} Comment=Launch {0} Icon={1} Categories=Utility;Qt; Exec={1} Terminal=false '''.format(__application_name, __application_name.lower()) state_changed = pyqtSignal(str) period_changed = pyqtSignal(str) timer_updated = pyqtSignal(str) period_progressed = pyqtSignal(int) NO_SOUND_VALS = ( 'NO_SOUND', 'SEPARATOR', 'CHOOSE', ) def __init__(self, *args): super(Kamatis, self).__init__(*args) self.setOrganizationName('Fumisoft') self.setApplicationName(self.__application_name) self.setQuitOnLastWindowClosed(False) self.__setup_logging() self.__player = QMediaPlayer(self) self.__period_steps = 12 self.period_changed.connect(self.__start_timer) self.period_changed.connect(self.__start_progress_timer) self.__work_timer = QTimer(self) self.__work_timer.setSingleShot(True) self.__work_timer.timeout.connect(self.__start_break) self.__work_timer.timeout.connect(self.__play_sound) self.__break_timer = QTimer(self) self.__break_timer.setSingleShot(True) self.__break_timer.timeout.connect(self.__start_work) self.__break_timer.timeout.connect(self.__play_sound) self.__progress_timer = QTimer(self) self.__progress_timer.setSingleShot(True) self.__progress_timer.timeout.connect(self.__start_progress_timer) self.__saved_settings = QSettingsManager() self.__load_default_settings() self.settings = ConfigManager() self.settings.set_defaults(self.__saved_settings.as_dict()) self.settings_window = SettingsWindow() self.settings_window.settings_set.connect(self.__apply_settings) self.__tray_icon = TrayIcon(self) self.__tray_icon.show() self.__init_state() def __setup_logging(self): logging.root.setLevel(logging.WARNING) formatter = logging.Formatter( '%(levelname)-8s %(asctime)s [%(module)s:%(funcName)s:%(lineno)s] ' '%(message)s') try: location_type = QStandardPaths.AppLocalDataLocation except AttributeError: # AppLocalDataLocation was only added in Qt 5.4. DataLocation # returns the same value as AppLocalDataLocation but is deprecated # in newer Qt versions. # https://doc.qt.io/qt-5/qstandardpaths.html#StandardLocation-enum location_type = QStandardPaths.DataLocation data_dir = QStandardPaths.standardLocations(location_type)[0] console_handler = logging.StreamHandler(sys.stdout) console_handler.setFormatter(formatter) logging.root.addHandler(console_handler) isdir = util.makedirs(data_dir) if isdir: log_file = os.path.join( data_dir, '{}.log'.format(self.__application_name.lower())) file_handler = logging.FileHandler(log_file) file_handler.setFormatter(formatter) logging.root.addHandler(file_handler) def __init_state(self): self.__apply_settings() self.__set_state('STOPPED') self.__period_counter = 0 self.__progress = -1 def __set_state(self, new_state): self.__state = new_state self.state_changed.emit(new_state) def __set_period(self, new_period): self.__period = new_period length = self.__saved_settings.get(new_period.replace(' ', '_')) # Length is saved in minutes but QTimer accepts milliseconds. self.__timer_length = length * 60 * 1000 self.period_changed.emit(new_period) def __load_default_settings(self): location_type = QStandardPaths.MusicLocation music_dir = QStandardPaths.standardLocations(location_type)[0] self.default_sound_entries = [ ('No sounds', 'NO_SOUND'), (None, 'SEPARATOR'), ('Choose...', 'CHOOSE'), ] self.sound_settings = { 'search_dir': music_dir, 'sound_entries': self.default_sound_entries, } self.default_settings = { 'chosen_sound': 'NO_SOUND', 'work': 25, 'short_break': 5, 'long_break': 15, 'cycle': 4, 'autostart': True, } self.__saved_settings.set_defaults(self.sound_settings) self.__saved_settings.set_defaults(self.default_settings) def __apply_settings(self): self.__set_autostart() self.__load_sound_file() self.__set_cycle_length() def __set_autostart(self): autostart_dir = os.path.expanduser('~/.config/autostart') file_name = '{}.desktop'.format(self.__application_name.lower()) file_path = os.path.join(autostart_dir, file_name) if self.__saved_settings.get('autostart'): action = 'create' success = self.__create_autostart_entry(autostart_dir, file_path) else: action = 'remove' success = self.__remove_autostart_entry(file_path) if not success: template = 'Cannot {} autostart file. See log for more info.' message = template.format(action) self.__tray_icon.showMessage( self.__application_name, message, QSystemTrayIcon.Warning, ) def __create_autostart_entry(self, autostart_dir, file_path): isdir = util.makedirs(autostart_dir) if not isdir: return False try: with open(file_path, 'w') as f: f.write(dedent(self.__desktop_file_entry)) except: logging.warning('Cannot create autostart file.', exc_info=True) return False return True def __remove_autostart_entry(self, file_path): success = True try: os.unlink(file_path) except OSError as err: if err.errno == 2: # File does not exist, ignore. pass else: logging.warning('Cannot remove autostart file.', exc_info=True) success = False except: logging.warning('Cannot remove autostart file.', exc_info=True) success = False return success def __load_sound_file(self): sound_file_path = self.__saved_settings.get('chosen_sound') if sound_file_path in self.NO_SOUND_VALS: sound_file_path = '' media_content = QMediaContent(QUrl.fromLocalFile(sound_file_path)) self.__player.setMedia(media_content) def __set_cycle_length(self): self.__cycle_length = self.__saved_settings.get('cycle') def __start_work(self): self.__current_timer = self.__work_timer self.__set_period('work') def __start_break(self): self.__current_timer = self.__break_timer if self.__period_counter < self.__cycle_length: self.__period_counter += 1 self.__set_period('short break') else: self.__period_counter = 0 self.__set_period('long break') def __start_timer(self, period): message = '{} started'.format(period.capitalize()) self.__current_timer.setInterval(self.__timer_length) self.__current_timer.start() self.timer_updated.emit(message) def __pause_timer(self): message = '{} paused'.format(self.__period.capitalize()) self.__remaining = self.__current_timer.remainingTime() self.__progress_remaining = self.__progress_timer.remainingTime() self.__current_timer.stop() self.__progress_timer.stop() self.timer_updated.emit(message) def __resume_timer(self): message = '{} resumed'.format(self.__period.capitalize()) self.__current_timer.setInterval(self.__remaining) self.__current_timer.start() self.__progress_timer.setInterval(self.__progress_remaining) self.__progress_timer.start() self.timer_updated.emit(message) def __play_sound(self): self.__player.play() def __start_progress_timer(self, *args): self.__progress = (self.__progress + 1) % self.__period_steps self.period_progressed.emit(self.__progress) progress_length = int(self.__timer_length / self.__period_steps) self.__progress_timer.setInterval(progress_length) self.__progress_timer.start() def save_settings(self): new_settings = self.settings.as_dict() self.__saved_settings.set_many(new_settings) def save_sound_settings(self): for key in self.sound_settings.keys(): self.__saved_settings.set(key, self.settings.get(key)) def start(self): self.__set_state('RUNNING') self.__start_work() def pause(self): self.__set_state('PAUSED') self.__pause_timer() def resume(self): self.__set_state('RUNNING') self.__resume_timer() def reset(self): message = 'Current session stopped. Will reset on restart.' self.__current_timer.stop() self.__progress_timer.stop() self.__init_state() self.__tray_icon.showMessage(self.__application_name, message) def skip(self): message = 'Skipping to the next period.' self.__current_timer.setInterval(0) self.__progress_timer.setInterval(0) self.__current_timer.start() self.__progress_timer.start() if self.__state == 'PAUSED': self.__set_state('RUNNING') self.__progress = -1 self.__tray_icon.showMessage(self.__application_name, message) def get_remaining_time(self): if self.__state == 'PAUSED': return self.__remaining return self.__current_timer.remainingTime()
class locker(QWidget, Ui_locker): locked = pyqtSignal() unlocked = pyqtSignal() lockChanged = pyqtSignal(bool) def __init__(self, parent=None): QWidget.__init__(self, parent) self.setupUi(self) self._btnText = None self._words = None self._target = None self._blackout = [] self.timer = QTimer(self) self.timer.setSingleShot(True) self.timer.timeout.connect(self.unlock) self.timer.stop() self.timerSec = QTimer(self) self.timerSec.setInterval(500) self.timerSec.timeout.connect(self.updateBtnText) self.timerSec.stop() self.rbtnWordTarget.toggled.connect(self.spnWordTarget.setVisible) self.rbtnTimeTarget.toggled.connect(self.spnTimeTarget.setVisible) self.rbtnWordTarget.setChecked(True) self.spnTimeTarget.setVisible(False) self.btnLock.clicked.connect(self.lock) def lock(self): # Block others screens desktop = qApp.desktop() self._blackout.clear() if desktop.screenCount() > 1: for d in range(desktop.screenCount()): if desktop.screenNumber(self) != d: w = QWidget() w.setStyleSheet("background: black;") w.move(desktop.screenGeometry(d).topLeft()) w.showFullScreen() self._blackout.append(w) if self.rbtnWordTarget.isChecked(): self._target = self._words + self.spnWordTarget.value() elif self.rbtnTimeTarget.isChecked(): self.timer.setInterval(self.spnTimeTarget.value() * 1000 * 60) self.timer.start() self.timerSec.start() self.updateBtnText() self.setEnabled(False) self.locked.emit() self.lockChanged.emit(True) def unlock(self): # Remove black screens self._blackout.clear() self.setEnabled(True) self.btnLock.setText(self._btnText) self.timer.stop() self.timerSec.stop() self._target = None self.unlocked.emit() self.lockChanged.emit(False) def isLocked(self): return not self.isEnabled() def setWordCount(self, wc): self._words = wc if self.isLocked(): self.updateBtnText() if self._words >= self._target: self.unlock() def updateBtnText(self): if not self._btnText: self._btnText = self.btnLock.text() # Time locked if self.timer.remainingTime() != -1: t = self.timer.remainingTime() t = int(t / 1000) if t > 60 * 60: text = self.tr("~{} h.").format(str(int(t / 60 / 60))) elif t > 60 * 5: text = self.tr("~{} mn.").format(str(int(t / 60))) elif t > 60: mn = int(t / 60) sec = t - 60 * mn text = self.tr("{}:{}").format(str(mn), str(sec)) else: text = self.tr("{} s.").format(str(t)) self.btnLock.setText(self.tr("{} remaining").format( text)) # Word locked elif self._target is not None: self.btnLock.setText(self.tr("{} words remaining").format( self._target - self._words))
class PrinterOutputDevice(QObject, OutputDevice): def __init__(self, device_id, parent = None): super().__init__(device_id = device_id, parent = parent) self._container_registry = ContainerRegistry.getInstance() self._target_bed_temperature = 0 self._bed_temperature = 0 self._num_extruders = 1 self._hotend_temperatures = [0] * self._num_extruders self._target_hotend_temperatures = [0] * self._num_extruders self._material_ids = [""] * self._num_extruders self._hotend_ids = [""] * self._num_extruders self._progress = 0 self._head_x = 0 self._head_y = 0 self._head_z = 0 self._connection_state = ConnectionState.closed self._connection_text = "" self._time_elapsed = 0 self._time_total = 0 self._job_state = "" self._job_name = "" self._error_text = "" self._accepts_commands = True self._preheat_bed_timeout = 900 # Default time-out for pre-heating the bed, in seconds. self._preheat_bed_timer = QTimer() # Timer that tracks how long to preheat still. self._preheat_bed_timer.setSingleShot(True) self._preheat_bed_timer.timeout.connect(self.cancelPreheatBed) self._printer_state = "" self._printer_type = "unknown" self._camera_active = False self._monitor_view_qml_path = "" self._monitor_component = None self._monitor_item = None self._qml_context = None def requestWrite(self, nodes, file_name = None, filter_by_machine = False, file_handler = None): raise NotImplementedError("requestWrite needs to be implemented") ## Signals # Signal to be emitted when bed temp is changed bedTemperatureChanged = pyqtSignal() # Signal to be emitted when target bed temp is changed targetBedTemperatureChanged = pyqtSignal() # Signal when the progress is changed (usually when this output device is printing / sending lots of data) progressChanged = pyqtSignal() # Signal to be emitted when hotend temp is changed hotendTemperaturesChanged = pyqtSignal() # Signal to be emitted when target hotend temp is changed targetHotendTemperaturesChanged = pyqtSignal() # Signal to be emitted when head position is changed (x,y,z) headPositionChanged = pyqtSignal() # Signal to be emitted when either of the material ids is changed materialIdChanged = pyqtSignal(int, str, arguments = ["index", "id"]) # Signal to be emitted when either of the hotend ids is changed hotendIdChanged = pyqtSignal(int, str, arguments = ["index", "id"]) # Signal that is emitted every time connection state is changed. # it also sends it's own device_id (for convenience sake) connectionStateChanged = pyqtSignal(str) connectionTextChanged = pyqtSignal() timeElapsedChanged = pyqtSignal() timeTotalChanged = pyqtSignal() jobStateChanged = pyqtSignal() jobNameChanged = pyqtSignal() errorTextChanged = pyqtSignal() acceptsCommandsChanged = pyqtSignal() printerStateChanged = pyqtSignal() printerTypeChanged = pyqtSignal() # Signal to be emitted when some drastic change occurs in the remaining time (not when the time just passes on normally). preheatBedRemainingTimeChanged = pyqtSignal() @pyqtProperty(QObject, constant=True) def monitorItem(self): # Note that we specifically only check if the monitor component is created. # It could be that it failed to actually create the qml item! If we check if the item was created, it will try to # create the item (and fail) every time. if not self._monitor_component: self._createMonitorViewFromQML() return self._monitor_item def _createMonitorViewFromQML(self): path = QUrl.fromLocalFile(self._monitor_view_qml_path) # Because of garbage collection we need to keep this referenced by python. self._monitor_component = QQmlComponent(Application.getInstance()._engine, path) # Check if the context was already requested before (Printer output device might have multiple items in the future) if self._qml_context is None: self._qml_context = QQmlContext(Application.getInstance()._engine.rootContext()) self._qml_context.setContextProperty("OutputDevice", self) self._monitor_item = self._monitor_component.create(self._qml_context) if self._monitor_item is None: Logger.log("e", "QQmlComponent status %s", self._monitor_component.status()) Logger.log("e", "QQmlComponent error string %s", self._monitor_component.errorString()) @pyqtProperty(str, notify=printerTypeChanged) def printerType(self): return self._printer_type @pyqtProperty(str, notify=printerStateChanged) def printerState(self): return self._printer_state @pyqtProperty(str, notify = jobStateChanged) def jobState(self): return self._job_state def _updatePrinterType(self, printer_type): if self._printer_type != printer_type: self._printer_type = printer_type self.printerTypeChanged.emit() def _updatePrinterState(self, printer_state): if self._printer_state != printer_state: self._printer_state = printer_state self.printerStateChanged.emit() def _updateJobState(self, job_state): if self._job_state != job_state: self._job_state = job_state self.jobStateChanged.emit() @pyqtSlot(str) def setJobState(self, job_state): self._setJobState(job_state) def _setJobState(self, job_state): Logger.log("w", "_setJobState is not implemented by this output device") @pyqtSlot() def startCamera(self): self._camera_active = True self._startCamera() def _startCamera(self): Logger.log("w", "_startCamera is not implemented by this output device") @pyqtSlot() def stopCamera(self): self._camera_active = False self._stopCamera() def _stopCamera(self): Logger.log("w", "_stopCamera is not implemented by this output device") @pyqtProperty(str, notify = jobNameChanged) def jobName(self): return self._job_name def setJobName(self, name): if self._job_name != name: self._job_name = name self.jobNameChanged.emit() ## Gives a human-readable address where the device can be found. @pyqtProperty(str, constant = True) def address(self): Logger.log("w", "address is not implemented by this output device.") ## A human-readable name for the device. @pyqtProperty(str, constant = True) def name(self): Logger.log("w", "name is not implemented by this output device.") return "" @pyqtProperty(str, notify = errorTextChanged) def errorText(self): return self._error_text ## Set the error-text that is shown in the print monitor in case of an error def setErrorText(self, error_text): if self._error_text != error_text: self._error_text = error_text self.errorTextChanged.emit() @pyqtProperty(bool, notify = acceptsCommandsChanged) def acceptsCommands(self): return self._accepts_commands ## Set a flag to signal the UI that the printer is not (yet) ready to receive commands def setAcceptsCommands(self, accepts_commands): if self._accepts_commands != accepts_commands: self._accepts_commands = accepts_commands self.acceptsCommandsChanged.emit() ## Get the bed temperature of the bed (if any) # This function is "final" (do not re-implement) # /sa _getBedTemperature implementation function @pyqtProperty(float, notify = bedTemperatureChanged) def bedTemperature(self): return self._bed_temperature ## Set the (target) bed temperature # This function is "final" (do not re-implement) # /param temperature new target temperature of the bed (in deg C) # /sa _setTargetBedTemperature implementation function @pyqtSlot(int) def setTargetBedTemperature(self, temperature): self._setTargetBedTemperature(temperature) if self._target_bed_temperature != temperature: self._target_bed_temperature = temperature self.targetBedTemperatureChanged.emit() ## The total duration of the time-out to pre-heat the bed, in seconds. # # \return The duration of the time-out to pre-heat the bed, in seconds. @pyqtProperty(int, constant = True) def preheatBedTimeout(self): return self._preheat_bed_timeout ## The remaining duration of the pre-heating of the bed. # # This is formatted in M:SS format. # \return The duration of the time-out to pre-heat the bed, formatted. @pyqtProperty(str, notify = preheatBedRemainingTimeChanged) def preheatBedRemainingTime(self): if not self._preheat_bed_timer.isActive(): return "" period = self._preheat_bed_timer.remainingTime() if period <= 0: return "" minutes, period = divmod(period, 60000) #60000 milliseconds in a minute. seconds, _ = divmod(period, 1000) #1000 milliseconds in a second. if minutes <= 0 and seconds <= 0: return "" return "%d:%02d" % (minutes, seconds) ## Time the print has been printing. # Note that timeTotal - timeElapsed should give time remaining. @pyqtProperty(float, notify = timeElapsedChanged) def timeElapsed(self): return self._time_elapsed ## Total time of the print # Note that timeTotal - timeElapsed should give time remaining. @pyqtProperty(float, notify=timeTotalChanged) def timeTotal(self): return self._time_total @pyqtSlot(float) def setTimeTotal(self, new_total): if self._time_total != new_total: self._time_total = new_total self.timeTotalChanged.emit() @pyqtSlot(float) def setTimeElapsed(self, time_elapsed): if self._time_elapsed != time_elapsed: self._time_elapsed = time_elapsed self.timeElapsedChanged.emit() ## Home the head of the connected printer # This function is "final" (do not re-implement) # /sa _homeHead implementation function @pyqtSlot() def homeHead(self): self._homeHead() ## Home the head of the connected printer # This is an implementation function and should be overriden by children. def _homeHead(self): Logger.log("w", "_homeHead is not implemented by this output device") ## Home the bed of the connected printer # This function is "final" (do not re-implement) # /sa _homeBed implementation function @pyqtSlot() def homeBed(self): self._homeBed() ## Home the bed of the connected printer # This is an implementation function and should be overriden by children. # /sa homeBed def _homeBed(self): Logger.log("w", "_homeBed is not implemented by this output device") ## Protected setter for the bed temperature of the connected printer (if any). # /parameter temperature Temperature bed needs to go to (in deg celsius) # /sa setTargetBedTemperature def _setTargetBedTemperature(self, temperature): Logger.log("w", "_setTargetBedTemperature is not implemented by this output device") ## Pre-heats the heated bed of the printer. # # \param temperature The temperature to heat the bed to, in degrees # Celsius. # \param duration How long the bed should stay warm, in seconds. @pyqtSlot(float, float) def preheatBed(self, temperature, duration): Logger.log("w", "preheatBed is not implemented by this output device.") ## Cancels pre-heating the heated bed of the printer. # # If the bed is not pre-heated, nothing happens. @pyqtSlot() def cancelPreheatBed(self): Logger.log("w", "cancelPreheatBed is not implemented by this output device.") ## Protected setter for the current bed temperature. # This simply sets the bed temperature, but ensures that a signal is emitted. # /param temperature temperature of the bed. def _setBedTemperature(self, temperature): if self._bed_temperature != temperature: self._bed_temperature = temperature self.bedTemperatureChanged.emit() ## Get the target bed temperature if connected printer (if any) @pyqtProperty(int, notify = targetBedTemperatureChanged) def targetBedTemperature(self): return self._target_bed_temperature ## Set the (target) hotend temperature # This function is "final" (do not re-implement) # /param index the index of the hotend that needs to change temperature # /param temperature The temperature it needs to change to (in deg celsius). # /sa _setTargetHotendTemperature implementation function @pyqtSlot(int, int) def setTargetHotendTemperature(self, index, temperature): self._setTargetHotendTemperature(index, temperature) if self._target_hotend_temperatures[index] != temperature: self._target_hotend_temperatures[index] = temperature self.targetHotendTemperaturesChanged.emit() ## Implementation function of setTargetHotendTemperature. # /param index Index of the hotend to set the temperature of # /param temperature Temperature to set the hotend to (in deg C) # /sa setTargetHotendTemperature def _setTargetHotendTemperature(self, index, temperature): Logger.log("w", "_setTargetHotendTemperature is not implemented by this output device") @pyqtProperty("QVariantList", notify = targetHotendTemperaturesChanged) def targetHotendTemperatures(self): return self._target_hotend_temperatures @pyqtProperty("QVariantList", notify = hotendTemperaturesChanged) def hotendTemperatures(self): return self._hotend_temperatures ## Protected setter for the current hotend temperature. # This simply sets the hotend temperature, but ensures that a signal is emitted. # /param index Index of the hotend # /param temperature temperature of the hotend (in deg C) def _setHotendTemperature(self, index, temperature): if self._hotend_temperatures[index] != temperature: self._hotend_temperatures[index] = temperature self.hotendTemperaturesChanged.emit() @pyqtProperty("QVariantList", notify = materialIdChanged) def materialIds(self): return self._material_ids @pyqtProperty("QVariantList", notify = materialIdChanged) def materialNames(self): result = [] for material_id in self._material_ids: if material_id is None: result.append(i18n_catalog.i18nc("@item:material", "No material loaded")) continue containers = self._container_registry.findInstanceContainers(type = "material", GUID = material_id) if containers: result.append(containers[0].getName()) else: result.append(i18n_catalog.i18nc("@item:material", "Unknown material")) return result ## List of the colours of the currently loaded materials. # # The list is in order of extruders. If there is no material in an # extruder, the colour is shown as transparent. # # The colours are returned in hex-format AARRGGBB or RRGGBB # (e.g. #800000ff for transparent blue or #00ff00 for pure green). @pyqtProperty("QVariantList", notify = materialIdChanged) def materialColors(self): result = [] for material_id in self._material_ids: if material_id is None: result.append("#00000000") #No material. continue containers = self._container_registry.findInstanceContainers(type = "material", GUID = material_id) if containers: result.append(containers[0].getMetaDataEntry("color_code")) else: result.append("#00000000") #Unknown material. return result ## Protected setter for the current material id. # /param index Index of the extruder # /param material_id id of the material def _setMaterialId(self, index, material_id): if material_id and material_id != "" and material_id != self._material_ids[index]: Logger.log("d", "Setting material id of hotend %d to %s" % (index, material_id)) self._material_ids[index] = material_id self.materialIdChanged.emit(index, material_id) @pyqtProperty("QVariantList", notify = hotendIdChanged) def hotendIds(self): return self._hotend_ids ## Protected setter for the current hotend id. # /param index Index of the extruder # /param hotend_id id of the hotend def _setHotendId(self, index, hotend_id): if hotend_id and hotend_id != self._hotend_ids[index]: Logger.log("d", "Setting hotend id of hotend %d to %s" % (index, hotend_id)) self._hotend_ids[index] = hotend_id self.hotendIdChanged.emit(index, hotend_id) elif not hotend_id: Logger.log("d", "Removing hotend id of hotend %d.", index) self._hotend_ids[index] = None self.hotendIdChanged.emit(index, None) ## Let the user decide if the hotends and/or material should be synced with the printer # NB: the UX needs to be implemented by the plugin def materialHotendChangedMessage(self, callback): Logger.log("w", "materialHotendChangedMessage needs to be implemented, returning 'Yes'") callback(QMessageBox.Yes) ## Attempt to establish connection def connect(self): raise NotImplementedError("connect needs to be implemented") ## Attempt to close the connection def close(self): raise NotImplementedError("close needs to be implemented") @pyqtProperty(bool, notify = connectionStateChanged) def connectionState(self): return self._connection_state ## Set the connection state of this output device. # /param connection_state ConnectionState enum. def setConnectionState(self, connection_state): if self._connection_state != connection_state: self._connection_state = connection_state self.connectionStateChanged.emit(self._id) @pyqtProperty(str, notify = connectionTextChanged) def connectionText(self): return self._connection_text ## Set a text that is shown on top of the print monitor tab def setConnectionText(self, connection_text): if self._connection_text != connection_text: self._connection_text = connection_text self.connectionTextChanged.emit() ## Ensure that close gets called when object is destroyed def __del__(self): self.close() ## Get the x position of the head. # This function is "final" (do not re-implement) @pyqtProperty(float, notify = headPositionChanged) def headX(self): return self._head_x ## Get the y position of the head. # This function is "final" (do not re-implement) @pyqtProperty(float, notify = headPositionChanged) def headY(self): return self._head_y ## Get the z position of the head. # In some machines it's actually the bed that moves. For convenience sake we simply see it all as head movements. # This function is "final" (do not re-implement) @pyqtProperty(float, notify = headPositionChanged) def headZ(self): return self._head_z ## Update the saved position of the head # This function should be called when a new position for the head is received. def _updateHeadPosition(self, x, y ,z): position_changed = False if self._head_x != x: self._head_x = x position_changed = True if self._head_y != y: self._head_y = y position_changed = True if self._head_z != z: self._head_z = z position_changed = True if position_changed: self.headPositionChanged.emit() ## Set the position of the head. # In some machines it's actually the bed that moves. For convenience sake we simply see it all as head movements. # This function is "final" (do not re-implement) # /param x new x location of the head. # /param y new y location of the head. # /param z new z location of the head. # /param speed Speed by which it needs to move (in mm/minute) # /sa _setHeadPosition implementation function @pyqtSlot("long", "long", "long") @pyqtSlot("long", "long", "long", "long") def setHeadPosition(self, x, y, z, speed = 3000): self._setHeadPosition(x, y , z, speed) ## Set the X position of the head. # This function is "final" (do not re-implement) # /param x x position head needs to move to. # /param speed Speed by which it needs to move (in mm/minute) # /sa _setHeadx implementation function @pyqtSlot("long") @pyqtSlot("long", "long") def setHeadX(self, x, speed = 3000): self._setHeadX(x, speed) ## Set the Y position of the head. # This function is "final" (do not re-implement) # /param y y position head needs to move to. # /param speed Speed by which it needs to move (in mm/minute) # /sa _setHeadY implementation function @pyqtSlot("long") @pyqtSlot("long", "long") def setHeadY(self, y, speed = 3000): self._setHeadY(y, speed) ## Set the Z position of the head. # In some machines it's actually the bed that moves. For convenience sake we simply see it all as head movements. # This function is "final" (do not re-implement) # /param z z position head needs to move to. # /param speed Speed by which it needs to move (in mm/minute) # /sa _setHeadZ implementation function @pyqtSlot("long") @pyqtSlot("long", "long") def setHeadZ(self, z, speed = 3000): self._setHeadY(z, speed) ## Move the head of the printer. # Note that this is a relative move. If you want to move the head to a specific position you can use # setHeadPosition # This function is "final" (do not re-implement) # /param x distance in x to move # /param y distance in y to move # /param z distance in z to move # /param speed Speed by which it needs to move (in mm/minute) # /sa _moveHead implementation function @pyqtSlot("long", "long", "long") @pyqtSlot("long", "long", "long", "long") def moveHead(self, x = 0, y = 0, z = 0, speed = 3000): self._moveHead(x, y, z, speed) ## Implementation function of moveHead. # /param x distance in x to move # /param y distance in y to move # /param z distance in z to move # /param speed Speed by which it needs to move (in mm/minute) # /sa moveHead def _moveHead(self, x, y, z, speed): Logger.log("w", "_moveHead is not implemented by this output device") ## Implementation function of setHeadPosition. # /param x new x location of the head. # /param y new y location of the head. # /param z new z location of the head. # /param speed Speed by which it needs to move (in mm/minute) # /sa setHeadPosition def _setHeadPosition(self, x, y, z, speed): Logger.log("w", "_setHeadPosition is not implemented by this output device") ## Implementation function of setHeadX. # /param x new x location of the head. # /param speed Speed by which it needs to move (in mm/minute) # /sa setHeadX def _setHeadX(self, x, speed): Logger.log("w", "_setHeadX is not implemented by this output device") ## Implementation function of setHeadY. # /param y new y location of the head. # /param speed Speed by which it needs to move (in mm/minute) # /sa _setHeadY def _setHeadY(self, y, speed): Logger.log("w", "_setHeadY is not implemented by this output device") ## Implementation function of setHeadZ. # /param z new z location of the head. # /param speed Speed by which it needs to move (in mm/minute) # /sa _setHeadZ def _setHeadZ(self, z, speed): Logger.log("w", "_setHeadZ is not implemented by this output device") ## Get the progress of any currently active process. # This function is "final" (do not re-implement) # /sa _getProgress # /returns float progress of the process. -1 indicates that there is no process. @pyqtProperty(float, notify = progressChanged) def progress(self): return self._progress ## Set the progress of any currently active process # /param progress Progress of the process. def setProgress(self, progress): if self._progress != progress: self._progress = progress self.progressChanged.emit()
class locker(QWidget, Ui_locker): locked = pyqtSignal() unlocked = pyqtSignal() lockChanged = pyqtSignal(bool) def __init__(self, parent=None): QWidget.__init__(self, parent) self.setupUi(self) self._btnText = None self._words = None self._target = None self._blackout = [] self.timer = QTimer(self) self.timer.setSingleShot(True) self.timer.timeout.connect(self.unlock) self.timer.stop() self.timerSec = QTimer(self) self.timerSec.setInterval(500) self.timerSec.timeout.connect(self.updateBtnText) self.timerSec.stop() self.rbtnWordTarget.toggled.connect(self.spnWordTarget.setVisible) self.rbtnTimeTarget.toggled.connect(self.spnTimeTarget.setVisible) self.rbtnWordTarget.setChecked(True) self.spnTimeTarget.setVisible(False) self.btnLock.clicked.connect(self.lock) def lock(self): # Block others screens desktop = qApp.desktop() self._blackout.clear() if desktop.screenCount() > 1: for d in range(desktop.screenCount()): if desktop.screenNumber(self) != d: w = QWidget() w.setStyleSheet("background: black;") w.move(desktop.screenGeometry(d).topLeft()) w.showFullScreen() self._blackout.append(w) if self.rbtnWordTarget.isChecked(): self._target = self._words + self.spnWordTarget.value() elif self.rbtnTimeTarget.isChecked(): self.timer.setInterval(self.spnTimeTarget.value() * 1000 * 60) self.timer.start() self.timerSec.start() self.updateBtnText() self.setEnabled(False) self.locked.emit() self.lockChanged.emit(True) def unlock(self): # Remove black screens self._blackout.clear() self.setEnabled(True) self.btnLock.setText(self._btnText) self.timer.stop() self.timerSec.stop() self._target = None self.unlocked.emit() self.lockChanged.emit(False) def isLocked(self): return not self.isEnabled() def setWordCount(self, wc): self._words = wc if self.isLocked(): self.updateBtnText() if self._words >= self._target: self.unlock() def updateBtnText(self): if not self._btnText: self._btnText = self.btnLock.text() # Time locked if self.timer.remainingTime() != -1: t = self.timer.remainingTime() t = int(t / 1000) if t > 60 * 60: text = self.tr("~{} h.").format(str(int(t / 60 / 60))) elif t > 60 * 5: text = self.tr("~{} mn.").format(str(int(t / 60))) elif t > 60: mn = int(t / 60) sec = t - 60 * mn text = self.tr("{}:{}").format(str(mn), str(sec)) else: text = self.tr("{} s.").format(str(t)) self.btnLock.setText(self.tr("{} remaining").format(text)) # Word locked elif self._target is not None: self.btnLock.setText( self.tr("{} words remaining").format(self._target - self._words))
class PlanetCallbackWatcher(QObject): """ Callback QObject watcher for `planet.api.dispatch` async operations. Creates a Qt signal interface for registered callback. To use, see `dispatch_callback()` below. """ responseRegistered = pyqtSignal('PyQt_PyObject') responseRegisteredWithId = pyqtSignal(str, 'PyQt_PyObject') responseCancelled = pyqtSignal() responseCancelledWithId = pyqtSignal(str) responseTimedOut = pyqtSignal(int) # response timeout in seconds responseTimedOutWithId = pyqtSignal(str, int) # timeout in seconds responseFinished = pyqtSignal('PyQt_PyObject') responseFinishedWithId = pyqtSignal(str, 'PyQt_PyObject') timerShouldStop = pyqtSignal() def __init__(self, parent: Optional[QObject] = None, timeout: int = RESPONSE_TIMEOUT, watcher_id: Optional[str] = None): """ :param parent: QObject parent :param timeout: Network timeout for request through receiving complete response, in seconds :param watcher_id: Id for watcher, usually an item id """ super().__init__(parent=parent) self._response: Optional[api_models.Response] = None # For `requests` timeout, since none is set in planet.api dispatcher self._timeout = timeout self._timeout_ms = timeout * 1000 self._timer = QTimer() self._timer.setInterval(self._timeout_ms) # noinspection PyUnresolvedReferences self._timer.timeout.connect(self._response_timed_out) # Signal bounce, for when this obj directly called from dispatch thread self.timerShouldStop.connect(self._stop_timer) self._id = watcher_id def id(self) -> str: return self._id def register_response(self, response) -> Optional[api_models.Response]: if response: self._response = response log.debug('Watcher registered response') self._start_timer() self.responseRegistered.emit(response) self.responseRegisteredWithId.emit(self._id, response) return response else: log.debug('No response to register') return None @pyqtSlot() @pyqtSlot(str) def cancel_response(self, item_key: Optional[str] = None) -> None: if item_key and item_key != self._id: return if self._response: self._stop_timer() self._response.cancel() log.debug('Watcher registered response cancelled') self.responseFinished.emit(None) self.responseFinishedWithId.emit(self._id, None) else: log.debug('No registered response to cancel') self.responseCancelled.emit() self.responseCancelledWithId.emit(self._id) def _start_timer(self) -> None: self._timer.start() log.debug('Watcher timer started') def time_remaining(self) -> int: remaining = self._timer.remainingTime() if remaining > 0: return int(remaining / 1000) # in seconds return remaining def _stop_timer(self) -> None: self._timer.stop() log.debug('Watcher timer stopped') @pyqtSlot() def _response_timed_out(self) -> None: self.cancel_response() log.debug(f'Watcher response timed out after {self._timeout} seconds') self.responseTimedOut.emit(self._timeout) self.responseTimedOutWithId.emit(self._id, self._timeout) @pyqtSlot('PyQt_PyObject') def emit_finished(self, body) -> None: self.timerShouldStop.emit() self.responseFinished.emit(body) self.responseFinishedWithId.emit(self._id, body)
class my_Time_Timer(QWidget, Ui_Time_timer): def __init__(self): super(my_Time_Timer, self).__init__() self.setupUi(self) # Options_timetimer 선언하기 self.options = options_timetimer() self.setMinimumSize(self.options.timer_size, self.options.timer_size) self.setMaximumSize(self.options.timer_size, self.options.timer_size) # time_remain 초기값 설정 self.time_remain = 3000 # 기본값 50분 = 3000sec self.timer_status_start = False # False 는 대기중 True 는 실행중 # 마우스이벤트 self.is_pressed = 0 # 초기값으로는 Time_label 숨김 self.label_hour.hide() self.label_min.hide() self.label_sec.hide() # 테두리 없는 창 모드 배경 투명으로 self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint) self.setAttribute(Qt.WA_TranslucentBackground) # Validator - lineedit self.line_edit_hour.setValidator(QtGui.QIntValidator( 0, 60, self)) # 0 ~ 60까지의 정수 self.line_edit_min.setValidator(QtGui.QIntValidator( 0, 60, self)) # 0 ~ 60까지의 정수 self.line_edit_sec.setValidator(QtGui.QIntValidator( 0, 60, self)) # 0 ~ 60까지의 정수 # 기능추가 : 분, 초 입력란에 60이상의 정수 입력 시 시, 분으로 변환해주는 기능 추가 필요 # ---------- 타이머 모음 --------- self.timer = QTimer(self) self.timer.timeout.connect(self.timeout_timer_end) self.timer_sec = QTimer(self) self.timer_sec.timeout.connect(self.timeout_timer) self.timer_mouse_movement = QTimer(self) self.timer_mouse_movement.timeout.connect(self.timeout_mouse_movement) self.timer_mouse_movement.start(2000) self.timer_move = QTimer(self) self.timer_move.timeout.connect(self.timeout_move) # --------시그널 보내 시그널 보내 찌릿찌릿찌릿찘-------- # face_update 관련 시그널 self.line_edit_hour.textChanged.connect(self.face_update) self.line_edit_min.textChanged.connect(self.face_update) self.line_edit_sec.textChanged.connect(self.face_update) self.line_edit_hour.editingFinished.connect(self.face_update) self.line_edit_min.editingFinished.connect(self.face_update) self.line_edit_sec.editingFinished.connect(self.face_update) # buttons 관련 시그널 self.btn_start_stop.clicked.connect(self.fn_btn_start_stop) self.btn_close.clicked.connect(QCoreApplication.instance().quit) self.btn_options.clicked.connect(self.fn_btn_options) # 옵션 설정 관련 시그널 self.options.slider_timer_size.valueChanged.connect( self.window_size_update) self.options.slider_opacity.valueChanged.connect( self.timer_opacity_update) self.options.btn_select_color_timer.clicked.connect( self.color_picker_bg) self.options.btn_select_color_text.clicked.connect( self.color_picker_text) self.options.rad_timer_direction_cw.clicked.connect( self.timer_direction_change) self.options.rad_timer_direction_ccw.clicked.connect( self.timer_direction_change) self.options.rad_text_visible.clicked.connect( self.text_visibility_change) self.options.rad_text_invisible.clicked.connect( self.text_visibility_change) self.options.rad_text_visible.clicked.connect(self.mouseMoveEvent) self.options.rad_text_invisible.clicked.connect(self.mouseMoveEvent) self.options.rad_mov_no.clicked.connect(self.timer_movement_change) self.options.rad_mov_cont.clicked.connect(self.timer_movement_change) self.options.check_box_always_on_top.stateChanged.connect( self.stays_on_top) def stays_on_top(self): if self.options.check_box_always_on_top.isChecked(): self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint) self.show() else: self.setWindowFlags(Qt.FramelessWindowHint) self.show() def timer_movement_change(self): if self.options.rad_mov_no.isChecked(): self.options.timer_movement = 0 elif self.options.rad_mov_cont.isChecked(): self.options.timer_movement = 1 def text_visibility_change(self): if self.options.rad_text_visible.isChecked(): self.options.text_visibility = 1 else: self.options.text_visibility = 0 self.update() def timer_direction_change(self): if self.options.rad_timer_direction_cw.isChecked(): self.options.timer_direction = 1 else: self.options.timer_direction = -1 self.update() def color_picker_bg(self): if self.options.check_box_always_on_top.isChecked(): self.setWindowFlags(Qt.FramelessWindowHint) self.show() self.options.setWindowFlags(self.windowFlags() & ~Qt.WindowStaysOnTopHint & ~Qt.FramelessWindowHint) self.options.show() color_diag = QColorDialog(self) color = color_diag.getColor() if color: self.options.timer_color = list(color.getRgb()) self.options.btn_select_color_timer.setStyleSheet( "color: white; background-color:rgb({r},{g},{b});".format( r=str(self.options.timer_color[0]), g=str(self.options.timer_color[1]), b=str(self.options.timer_color[2]))) self.update() self.options.setWindowFlags(Qt.WindowStaysOnTopHint) self.options.show() if self.options.check_box_always_on_top.isChecked(): self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint) self.show() def color_picker_text(self): color = QColorDialog.getColor() if color: self.options.text_color = list(color.getRgb()) self.options.btn_select_color_text.setStyleSheet( "color: white; background-color:rgb({r},{g},{b});".format( r=str(self.options.text_color[0]), g=str(self.options.text_color[1]), b=str(self.options.text_color[2]))) self.label_hour.setStyleSheet("color:rgb({r},{g},{b});".format( r=str(self.options.text_color[0]), g=str(self.options.text_color[1]), b=str(self.options.text_color[2]))) self.label_min.setStyleSheet("color:rgb({r},{g},{b});".format( r=str(self.options.text_color[0]), g=str(self.options.text_color[1]), b=str(self.options.text_color[2]))) self.label_sec.setStyleSheet("color:rgb({r},{g},{b});".format( r=str(self.options.text_color[0]), g=str(self.options.text_color[1]), b=str(self.options.text_color[2]))) self.line_edit_hour.setStyleSheet("color:rgb({r},{g},{b});".format( r=str(self.options.text_color[0]), g=str(self.options.text_color[1]), b=str(self.options.text_color[2]))) self.line_edit_min.setStyleSheet("color:rgb({r},{g},{b});".format( r=str(self.options.text_color[0]), g=str(self.options.text_color[1]), b=str(self.options.text_color[2]))) self.line_edit_sec.setStyleSheet("color:rgb({r},{g},{b});".format( r=str(self.options.text_color[0]), g=str(self.options.text_color[1]), b=str(self.options.text_color[2]))) self.label.setStyleSheet("color:rgb({r},{g},{b});".format( r=str(self.options.text_color[0]), g=str(self.options.text_color[1]), b=str(self.options.text_color[2]))) self.label_2.setStyleSheet("color:rgb({r},{g},{b});".format( r=str(self.options.text_color[0]), g=str(self.options.text_color[1]), b=str(self.options.text_color[2]))) self.update() def window_size_update(self): self.setMinimumSize(self.options.timer_size, self.options.timer_size) self.setMaximumSize(self.options.timer_size, self.options.timer_size) self.update() def timer_opacity_update(self): self.timeout_mouse_movement() self.update() def fn_btn_options(self): self.options.show() def timeout_timer_end(self): self.time_remain = 3000 self.fn_btn_start_stop() remain_hour = self.time_remain // 3600 remain_min = (self.time_remain - (self.time_remain // 3600) * 3600) // 60 remain_sec = (self.time_remain - (self.time_remain // 3600) * 3600) % 60 str_remain_hour = '{0:02d}'.format(remain_hour) str_remain_min = '{0:02d}'.format(remain_min) str_remain_sec = '{0:02d}'.format(remain_sec) # 남아있는 시, 분, 초 구해서 label 에 입력 self.label_hour.setText(str_remain_hour) self.label_min.setText(str_remain_min) self.label_sec.setText(str_remain_sec) # label 값을 line_edit 에 입력 self.line_edit_hour.setText(str_remain_hour) self.line_edit_min.setText(str_remain_min) self.line_edit_sec.setText(str_remain_sec) self.update() def timeout_move(self): if self.options.timer_movement == 1: # 현재 screen 의 geometry 상태 screen_width = self.screen().geometry().width() screen_height = self.screen().geometry().height() screen_pos_x = self.screen().geometry().x() screen_pos_y = self.screen().geometry().y() widget_pos_x = self.pos().x() - screen_pos_x widget_pos_y = self.pos().y() - screen_pos_y if self.options.timer_movement_dir_x == 1: if widget_pos_x + self.options.timer_size >= screen_width: self.options.timer_movement_dir_x = -1 else: if widget_pos_x <= 0: self.options.timer_movement_dir_x = 1 if self.options.timer_movement_dir_y == 1: if widget_pos_y + self.options.timer_size >= screen_height: self.options.timer_movement_dir_y = -1 else: if widget_pos_y <= 0: self.options.timer_movement_dir_y = 1 x = self.window().pos().x() y = self.window().pos().y() self.move(x + 1 * self.options.timer_movement_dir_x, y + 1 * self.options.timer_movement_dir_y) elif self.options.timer_movement == 2: # 불연속 움직임 모드 pass def timeout_timer(self): self.time_remain = int(round(self.timer.remainingTime() / 1000, 0)) remain_hour = self.time_remain // 3600 remain_min = (self.time_remain - (self.time_remain // 3600) * 3600) // 60 remain_sec = (self.time_remain - (self.time_remain // 3600) * 3600) % 60 str_remain_hour = '{0:02d}'.format(remain_hour) str_remain_min = '{0:02d}'.format(remain_min) str_remain_sec = '{0:02d}'.format(remain_sec) # 남아있는 시, 분, 초 구해서 label 에 입력 self.label_hour.setText(str_remain_hour) self.label_min.setText(str_remain_min) self.label_sec.setText(str_remain_sec) # label 값을 line_edit 에 입력 self.line_edit_hour.setText(str_remain_hour) self.line_edit_min.setText(str_remain_min) self.line_edit_sec.setText(str_remain_sec) self.update() def timeout_mouse_movement(self): self.setWindowOpacity(self.options.timer_opacity) self.btn_start_stop.hide() # start stop 버튼 숨기기 self.btn_options.hide() # options 버튼 숨기기 self.btn_close.hide() # close 버튼 숨기기 if self.options.text_visibility == 0: self.hide_colon() self.hide_label() self.hide_line_edit() # hide colon self.timer_mouse_movement.stop() def opacity_reset(self): self.setWindowOpacity(1) def face_update(self): if not self.timer_status_start: # 대기중일 경우 # line edit 에서 가져온 값들을 정수화 if len(self.line_edit_hour.text()) == 0: remain_hour = 0 else: remain_hour = int(self.line_edit_hour.text()) if len(self.line_edit_min.text()) == 0: remain_min = 0 else: remain_min = int(self.line_edit_min.text()) if len(self.line_edit_sec.text()) == 0: remain_sec = 0 else: remain_sec = int(self.line_edit_sec.text()) str_remain_hour = '{0:02d}'.format(remain_hour) str_remain_min = '{0:02d}'.format(remain_min) str_remain_sec = '{0:02d}'.format(remain_sec) # 남아있는 시, 분, 초 구해서 label 에 입력 self.label_hour.setText(str_remain_hour) self.label_min.setText(str_remain_min) self.label_sec.setText(str_remain_sec) # label 값을 line_edit 에 입력 self.line_edit_hour.setText(str_remain_hour) self.line_edit_min.setText(str_remain_min) self.line_edit_sec.setText(str_remain_sec) self.time_remain = int(remain_hour * 3600 + remain_min * 60 + remain_sec) # 실행중일 경우는 뭐 그냥 업데이트만 self.update() def fn_btn_start_stop(self): if self.timer_status_start: # 타이머 실행중인 상황 self.show_line_edit() self.hide_label() self.btn_start_stop.setText("Start") self.timer.stop() self.timer_sec.stop() self.timer_move.stop() self.timer_status_start = False else: # 타이머 대기중인 상황 # 실행하면 두개 타이머를 동시에 실행 # timer 는 time_remain 만큼 # timer_sec 은 1초 self.timer.start(self.time_remain * 1000) self.timer_sec.start(1000) self.timer_move.start(20) self.hide_line_edit() self.show_label() self.btn_start_stop.setText("Stop") self.timer_status_start = True def hide_label(self): self.label_hour.hide() self.label_min.hide() self.label_sec.hide() def show_label(self): self.label_hour.show() self.label_min.show() self.label_sec.show() def hide_line_edit(self): self.line_edit_hour.hide() self.line_edit_min.hide() self.line_edit_sec.hide() def show_line_edit(self): self.line_edit_hour.show() self.line_edit_min.show() self.line_edit_sec.show() def hide_colon(self): self.label.hide() self.label_2.hide() def show_colon(self): self.label.show() self.label_2.show() # Widget 의 전체 크기를 결정 # def sizeHint(self): # return QSize(self.options.timer_size, self.options.timer_size) # # return QSize(500, 500) def paintEvent(self, event): qp = QtGui.QPainter() rect = QRect(0, 0, self.options.timer_size, self.options.timer_size) qp.begin(self) # QPainter 그리기 시작 qp.setRenderHint(QtGui.QPainter.Antialiasing) # Antialiasing 적용 # 남은시간 파이 그리기 qp.setPen(Qt.NoPen) qp.setBrush( QtGui.QColor(self.options.timer_color[0], self.options.timer_color[1], self.options.timer_color[2], 255)) # qp.drawEllipse(0, 0, 300, 300) # qp.setPen(Qt.blue) # qp.drawLine(self.time_remain,10,100,40) # qp.setPen(QtGui.QColor(0, 0, 0, 0)) # Pie 그릴 때 펜 색 투명 # drawPie(QRect, StartAngle, SpanAngle) 1/16deg 씩 움직임ㅇㅇㅇ qp.drawPie( rect, 90 * 16, int(self.time_remain / 10 * 16) * self.options.timer_direction) # 파이의 빈공간 칠하기 qp.setBrush(QtGui.QColor(0, 0, 0, 1)) qp.drawPie( rect, 90 * 16, 360 * 16 - int(self.time_remain / 10 * 16 * self.options.timer_direction * -1)) # qp.drawPie(rect, 0, 180*16) qp.end() def mousePressEvent(self, event): self.offset = event.pos() self.is_pressed = 1 def mouseReleaseEvent(self, event): self.is_pressed = 0 def mouseMoveEvent(self, event): self.setWindowOpacity(1) self.timer_mouse_movement.start(3000) self.btn_start_stop.show() # start stop 버튼 보이기 self.btn_options.show() # options 버튼 보이기 self.btn_close.show() # close 버튼 보이기 self.show_colon() if not self.timer_status_start: self.show_line_edit() else: self.show_label() if self.is_pressed == 1: x = event.globalX() y = event.globalY() x_w = self.offset.x() y_w = self.offset.y() self.move(x - x_w, y - y_w)
class Player(QGraphicsPixmapItem): def __init__(self, playerName, playerCar , keybed, width): self.playerName = playerName self.Car = playerCar self.qpix = QPixmap(('PNG/Car_' + playerCar + '_Main_Positions/Car_' + playerCar + '_01')) self.qpix = self.qpix.scaled(width, width * 1.5) self.keybed = keybed super(Player, self).__init__(self.qpix) self.lives = 3 self.effect = QGraphicsColorizeEffect() self.effect.setColor(QColor(189, 189, 189)) self.effect.setStrength(0.5) self.effect.setEnabled(False) self.setGraphicsEffect(self.effect) self.key_notifier = KeyNotifier() self.key_notifier.key_signal.connect(self.movePlayer) self.safeTimer = QTimer() self.safeTimer.timeout.connect(self.makeKillable) self.killable = True self.safeTimerRemaining = 0 self.touchesplayer = False self.notMoving = QTimer() self.notMoving.timeout.connect(self.enableMoving) self.canMove = True self.notMovingRemaining = 0 self.networkcode = None def die(self): if self.killable == True: self.lives = self.lives - 1 print("Player: {}, Lives: {}".format(self.playerName, self.lives)) if self.lives == 0: self.key_notifier.die() self.hide() self.killable = False # died three times already, no need to count lives anymore else: self.makeUnkillable() # calls timer def getLives(self): return self.lives def keyPressEvent(self, event): self.key_notifier.add_key(event.key()) def keyReleaseEvent(self, event): self.key_notifier.rem_key(event.key()) def setNetworkCode(self, networkCode): self.networkcode = networkCode def movePlayer(self, key): # if it's not killable, means player died and cannot move index = 0 if key == self.keybed[0]: if self.pos().x() + 15 <= 790: self.moveBy(15, 0) self.checkifCollision(key) elif key == self.keybed[1]: if self.pos().y() + 15 <= 530: self.moveBy(0, 15) self.checkifCollision(key) index = 1 elif key == self.keybed[2]: if self.pos().y() - 15 >= 0: self.moveBy(0, -15) self.checkifCollision(key) index = 2 elif key == self.keybed[3]: if self.pos().x() - 15 >= 150: self.moveBy(-15, 0) self.checkifCollision(key) index = 3 # TODO send position to host. if self.networkcode is not None: if isinstance(self.networkcode, NetworkClientCode): self.networkcode.sendplayerPosition(self.playerName, self.x(), self.y(), index) else: self.networkcode.broadcastMovement(self.playerName, self.x(), self.y(), index) def checkifCollision(self, key): touchedplayer = self.doesitTouch() if self.touchesplayer: if key == self.keybed[0]: self.moveBy(-15, 0) if touchedplayer.pos().x() + 30 <= 790: touchedplayer.moveBy(30, 0) elif key == self.keybed[1]: self.moveBy(0, -15) if touchedplayer.pos().y() + 30 <= 530: touchedplayer.moveBy(0, 30) elif key == self.keybed[2]: self.moveBy(0, 15) if touchedplayer.pos().y() - 30 >= 0: touchedplayer.moveBy(0, -30) elif key == self.keybed[3]: self.moveBy(15, 0) if touchedplayer.pos().x() - 30 >= 150: touchedplayer.moveBy(-30, 0) def doesitTouch(self): collidingPlayers = list(filter(lambda x: isinstance(x, Player), self.collidingItems())) if len(collidingPlayers) != 0: self.touchesplayer = True return collidingPlayers[0] else: self.touchesplayer = False def resetLives(self): self.lives = 3 self.effect.setEnabled(False) self.killable = True self.canMove = True self.safeTimerRemaining = 0 self.notMovingRemaining = 0 def activateThreads(self): if self.safeTimerRemaining != 0: self.safeTimer.start(self.safeTimerRemaining) # resuming timers self.safeTimerRemaining = 0 if self.notMovingRemaining != 0: self.notMoving.start(self.notMovingRemaining) self.notMoving = 0 if self.killable and self.canMove: self.key_notifier.start() def stopThread(self): if self.safeTimer.isActive(): self.safeTimerRemaining = self.safeTimer.remainingTime() #pausing timers self.safeTimer.stop() if self.notMoving.isActive(): self.notMovingRemaining = self.notMoving.remainingTime() self.notMoving.stop() self.key_notifier.die() def makeUnkillable(self): self.killable = False self.safeTimer.start(5000) # After 5 seconds, calls makeKillable. self.effect.setColor(QColor(189, 189, 189)) self.effect.setEnabled(True) def makeKillable(self): self.effect.setEnabled(False) self.safeTimer.stop() self.killable = True def addLife(self): if self.lives < 4: # lives limited to 4 self.lives += 1 print("Player: {}, Lives: {}".format(self.playerName, self.lives)) def disableMoving(self): self.key_notifier.die() self.canMove = False self.effect.setColor(QColor(255, 210, 117)) self.effect.setEnabled(True) self.notMoving.start(2000) def enableMoving(self): if self.killable: self.effect.setEnabled(False) self.effect.setColor(QColor(189, 189, 189)) self.notMoving.stop() self.canMove = True self.key_notifier.start() def getNameCar(self): return self.playerName, self.Car
class InputManager: __instance = None def __init__(self): if not InputManager.__instance: self.ui_manager = UIManager.get_instance() self.radio_stations_manager = RadioStationsManager() self.player = None self.playlist = None self.probe = None self.load_state() if not self.playlist: self.init_state() self.init_signals() def init_signals(self): self.player.durationChanged.connect(self.duration_changed_slot) self.player.positionChanged.connect(self.position_changed_slot) self.player.currentMediaChanged.connect( self.current_media_changed_slot) self.player.stateChanged.connect(self.state_changed_slot) def set_position(self, new_pos): self.ui_manager.set_position_slider_value(new_pos) self.player.setPosition(new_pos) def get_duration(self): return self.player.duration() def get_position(self): return self.player.position() def duration_changed_slot(self, duration): self.ui_manager.set_position_slider_max_value(duration) def position_changed_slot(self, position): self.ui_manager.set_position_slider_value(position) def get_volume(self): return self.player.volume() def set_volume(self, value): self.ui_manager.set_volume_slider_value(value) self.player.setVolume(value) def current_media_changed_slot(self): self.ui_manager.sync_row(self.get_media_position()) def state_changed_slot(self, new_state): if new_state == QMediaPlayer.StoppedState or new_state == QMediaPlayer.PausedState: self.ui_manager.change_play_btn_state(False) else: self.ui_manager.change_play_btn_state(True) def next_media(self): self.playlist.next() def previous_media(self): self.playlist.previous() @classmethod def get_instance(cls, *args, **kwargs): if not cls.__instance: cls.__instance = InputManager(*args, **kwargs) return cls.__instance def init_state(self): self.player = QMediaPlayer() self.playlist = QMediaPlaylist() self.probe = QAudioProbe() self.probe.setSource(self.player) self.probe_connected = False self.timer = QTimer() self.timer.setInterval(100) self.timer.setSingleShot(True) self.recent_files_manager = RecentFilesManager() self.ui_manager.set_output(self.player) self.player.setPlaylist(self.playlist) def load_state(self): file = QFile("file.dat") file.open(QIODevice.ReadOnly) in_stream = QDataStream(file) cur_playlist = QVariant() in_stream >> cur_playlist self.playlist = cur_playlist.value() def get_radio_stations(self, limit=None, category=None): stations = self.radio_stations_manager.get_all_stations( limit, category) return stations def get_radio_categories(self): categories = self.radio_stations_manager.get_all_categories() return categories def save_state(self): file = QFile("file.dat") file.open(QIODevice.WriteOnly) out = QDataStream(file) out << QVariant(self.current_playlist) def add_folder(self, path: str): files = get_dir_files(path) for file in files: self.add_media(path + "/" + file, get_format(file)) def add_file(self, filename: str): format = get_format(filename) if format != FILE_FORMAT.INVALID: return self.add_media(filename, format) raise RuntimeError("Invalid file format") def add_media(self, filename: str, format: FILE_FORMAT): url = QUrl.fromLocalFile( filename) if format != FILE_FORMAT.URL else QUrl(filename) content = QMediaContent(url) self.ui_manager.append_playlist(url.fileName(), format) self.recent_files_manager.write_recent_file(url.path()) self.ui_manager.init_recent_files() self.playlist.addMedia(content) def set_media_position(self, pos): self.playlist.setCurrentIndex(pos) def get_media_position(self): return self.playlist.currentIndex() def get_current_format(self): position = self.get_media_position() if position == -1: return None item = self.ui_manager.get_list_item(self.get_media_position()) return item.data(PlaylistItemDataRole.FORMAT) def play(self): format = self.get_current_format() if format is None: return self.ui_manager.change_play_btn_state(True) if format == FILE_FORMAT.AUDIO: self.probe.audioBufferProbed.connect(self.process_buffer) self.probe_connected = True else: self.probe_connected = False self.ui_manager.show_video() self.player.play() def pause(self): self.player.pause() def stop(self): self.player.stop() def is_muted(self): return self.player.isMuted() def is_paused(self): return self.player.state() in (QMediaPlayer.StoppedState, QMediaPlayer.PausedState) def mute(self, toggle): self.ui_manager.change_mute_state(toggle, self.get_volume()) self.player.setMuted(toggle) def get_playback_rate(self): return self.player.playbackRate() def set_playback_rate(self, value): self.player.setPlaybackRate(value) def process_buffer(self, buffer): if not self.probe_connected: return if not self.timer.isActive(): self.timer.start() else: if self.timer.remainingTime() == 0: data = buffer.data() chunked = chunk(list(data.asarray(buffer.byteCount())), 12) to_visualizer = [int(sum(e) // 12 // 75) for e in chunked] self.show_visualization(to_visualizer) def show_visualization(self, to_visualizer): self.ui_manager.update_equalizer(to_visualizer) def get_audio_devices(self): return QAudioDeviceInfo.availableDevices(QAudio.AudioOutput) def get_recent_files(self): return self.recent_files_manager.get_recent_files() def clear_recent_files(self): return self.recent_files_manager.clear_recent_files() def exit(self): self.ui_manager.exit()
class PrinterOutputDevice(QObject, OutputDevice): def __init__(self, device_id, parent = None): super().__init__(device_id = device_id, parent = parent) self._container_registry = ContainerRegistry.getInstance() self._target_bed_temperature = 0 self._bed_temperature = 0 self._num_extruders = 1 self._hotend_temperatures = [0] * self._num_extruders self._target_hotend_temperatures = [0] * self._num_extruders self._material_ids = [""] * self._num_extruders self._hotend_ids = [""] * self._num_extruders self._progress = 0 self._head_x = 0 self._head_y = 0 self._head_z = 0 self._connection_state = ConnectionState.closed self._connection_text = "" self._time_elapsed = 0 self._time_total = 0 self._job_state = "" self._job_name = "" self._error_text = "" self._accepts_commands = True self._preheat_bed_timeout = 900 # Default time-out for pre-heating the bed, in seconds. self._preheat_bed_timer = QTimer() # Timer that tracks how long to preheat still. self._preheat_bed_timer.setSingleShot(True) self._preheat_bed_timer.timeout.connect(self.cancelPreheatBed) self._printer_state = "" self._printer_type = "unknown" self._camera_active = False def requestWrite(self, nodes, file_name = None, filter_by_machine = False, file_handler = None): raise NotImplementedError("requestWrite needs to be implemented") ## Signals # Signal to be emitted when bed temp is changed bedTemperatureChanged = pyqtSignal() # Signal to be emitted when target bed temp is changed targetBedTemperatureChanged = pyqtSignal() # Signal when the progress is changed (usually when this output device is printing / sending lots of data) progressChanged = pyqtSignal() # Signal to be emitted when hotend temp is changed hotendTemperaturesChanged = pyqtSignal() # Signal to be emitted when target hotend temp is changed targetHotendTemperaturesChanged = pyqtSignal() # Signal to be emitted when head position is changed (x,y,z) headPositionChanged = pyqtSignal() # Signal to be emitted when either of the material ids is changed materialIdChanged = pyqtSignal(int, str, arguments = ["index", "id"]) # Signal to be emitted when either of the hotend ids is changed hotendIdChanged = pyqtSignal(int, str, arguments = ["index", "id"]) # Signal that is emitted every time connection state is changed. # it also sends it's own device_id (for convenience sake) connectionStateChanged = pyqtSignal(str) connectionTextChanged = pyqtSignal() timeElapsedChanged = pyqtSignal() timeTotalChanged = pyqtSignal() jobStateChanged = pyqtSignal() jobNameChanged = pyqtSignal() errorTextChanged = pyqtSignal() acceptsCommandsChanged = pyqtSignal() printerStateChanged = pyqtSignal() printerTypeChanged = pyqtSignal() # Signal to be emitted when some drastic change occurs in the remaining time (not when the time just passes on normally). preheatBedRemainingTimeChanged = pyqtSignal() @pyqtProperty(str, notify=printerTypeChanged) def printerType(self): return self._printer_type @pyqtProperty(str, notify=printerStateChanged) def printerState(self): return self._printer_state @pyqtProperty(str, notify = jobStateChanged) def jobState(self): return self._job_state def _updatePrinterType(self, printer_type): if self._printer_type != printer_type: self._printer_type = printer_type self.printerTypeChanged.emit() def _updatePrinterState(self, printer_state): if self._printer_state != printer_state: self._printer_state = printer_state self.printerStateChanged.emit() def _updateJobState(self, job_state): if self._job_state != job_state: self._job_state = job_state self.jobStateChanged.emit() @pyqtSlot(str) def setJobState(self, job_state): self._setJobState(job_state) def _setJobState(self, job_state): Logger.log("w", "_setJobState is not implemented by this output device") @pyqtSlot() def startCamera(self): self._camera_active = True self._startCamera() def _startCamera(self): Logger.log("w", "_startCamera is not implemented by this output device") @pyqtSlot() def stopCamera(self): self._camera_active = False self._stopCamera() def _stopCamera(self): Logger.log("w", "_stopCamera is not implemented by this output device") @pyqtProperty(str, notify = jobNameChanged) def jobName(self): return self._job_name def setJobName(self, name): if self._job_name != name: self._job_name = name self.jobNameChanged.emit() ## Gives a human-readable address where the device can be found. @pyqtProperty(str, constant = True) def address(self): Logger.log("w", "address is not implemented by this output device.") ## A human-readable name for the device. @pyqtProperty(str, constant = True) def name(self): Logger.log("w", "name is not implemented by this output device.") return "" @pyqtProperty(str, notify = errorTextChanged) def errorText(self): return self._error_text ## Set the error-text that is shown in the print monitor in case of an error def setErrorText(self, error_text): if self._error_text != error_text: self._error_text = error_text self.errorTextChanged.emit() @pyqtProperty(bool, notify = acceptsCommandsChanged) def acceptsCommands(self): return self._accepts_commands ## Set a flag to signal the UI that the printer is not (yet) ready to receive commands def setAcceptsCommands(self, accepts_commands): if self._accepts_commands != accepts_commands: self._accepts_commands = accepts_commands self.acceptsCommandsChanged.emit() ## Get the bed temperature of the bed (if any) # This function is "final" (do not re-implement) # /sa _getBedTemperature implementation function @pyqtProperty(float, notify = bedTemperatureChanged) def bedTemperature(self): return self._bed_temperature ## Set the (target) bed temperature # This function is "final" (do not re-implement) # /param temperature new target temperature of the bed (in deg C) # /sa _setTargetBedTemperature implementation function @pyqtSlot(int) def setTargetBedTemperature(self, temperature): self._setTargetBedTemperature(temperature) if self._target_bed_temperature != temperature: self._target_bed_temperature = temperature self.targetBedTemperatureChanged.emit() ## The total duration of the time-out to pre-heat the bed, in seconds. # # \return The duration of the time-out to pre-heat the bed, in seconds. @pyqtProperty(int, constant = True) def preheatBedTimeout(self): return self._preheat_bed_timeout ## The remaining duration of the pre-heating of the bed. # # This is formatted in M:SS format. # \return The duration of the time-out to pre-heat the bed, formatted. @pyqtProperty(str, notify = preheatBedRemainingTimeChanged) def preheatBedRemainingTime(self): if not self._preheat_bed_timer.isActive(): return "" period = self._preheat_bed_timer.remainingTime() if period <= 0: return "" minutes, period = divmod(period, 60000) #60000 milliseconds in a minute. seconds, _ = divmod(period, 1000) #1000 milliseconds in a second. if minutes <= 0 and seconds <= 0: return "" return "%d:%02d" % (minutes, seconds) ## Time the print has been printing. # Note that timeTotal - timeElapsed should give time remaining. @pyqtProperty(float, notify = timeElapsedChanged) def timeElapsed(self): return self._time_elapsed ## Total time of the print # Note that timeTotal - timeElapsed should give time remaining. @pyqtProperty(float, notify=timeTotalChanged) def timeTotal(self): return self._time_total @pyqtSlot(float) def setTimeTotal(self, new_total): if self._time_total != new_total: self._time_total = new_total self.timeTotalChanged.emit() @pyqtSlot(float) def setTimeElapsed(self, time_elapsed): if self._time_elapsed != time_elapsed: self._time_elapsed = time_elapsed self.timeElapsedChanged.emit() ## Home the head of the connected printer # This function is "final" (do not re-implement) # /sa _homeHead implementation function @pyqtSlot() def homeHead(self): self._homeHead() ## Home the head of the connected printer # This is an implementation function and should be overriden by children. def _homeHead(self): Logger.log("w", "_homeHead is not implemented by this output device") ## Home the bed of the connected printer # This function is "final" (do not re-implement) # /sa _homeBed implementation function @pyqtSlot() def homeBed(self): self._homeBed() ## Home the bed of the connected printer # This is an implementation function and should be overriden by children. # /sa homeBed def _homeBed(self): Logger.log("w", "_homeBed is not implemented by this output device") ## Protected setter for the bed temperature of the connected printer (if any). # /parameter temperature Temperature bed needs to go to (in deg celsius) # /sa setTargetBedTemperature def _setTargetBedTemperature(self, temperature): Logger.log("w", "_setTargetBedTemperature is not implemented by this output device") ## Pre-heats the heated bed of the printer. # # \param temperature The temperature to heat the bed to, in degrees # Celsius. # \param duration How long the bed should stay warm, in seconds. @pyqtSlot(float, float) def preheatBed(self, temperature, duration): Logger.log("w", "preheatBed is not implemented by this output device.") ## Cancels pre-heating the heated bed of the printer. # # If the bed is not pre-heated, nothing happens. @pyqtSlot() def cancelPreheatBed(self): Logger.log("w", "cancelPreheatBed is not implemented by this output device.") ## Protected setter for the current bed temperature. # This simply sets the bed temperature, but ensures that a signal is emitted. # /param temperature temperature of the bed. def _setBedTemperature(self, temperature): if self._bed_temperature != temperature: self._bed_temperature = temperature self.bedTemperatureChanged.emit() ## Get the target bed temperature if connected printer (if any) @pyqtProperty(int, notify = targetBedTemperatureChanged) def targetBedTemperature(self): return self._target_bed_temperature ## Set the (target) hotend temperature # This function is "final" (do not re-implement) # /param index the index of the hotend that needs to change temperature # /param temperature The temperature it needs to change to (in deg celsius). # /sa _setTargetHotendTemperature implementation function @pyqtSlot(int, int) def setTargetHotendTemperature(self, index, temperature): self._setTargetHotendTemperature(index, temperature) if self._target_hotend_temperatures[index] != temperature: self._target_hotend_temperatures[index] = temperature self.targetHotendTemperaturesChanged.emit() ## Implementation function of setTargetHotendTemperature. # /param index Index of the hotend to set the temperature of # /param temperature Temperature to set the hotend to (in deg C) # /sa setTargetHotendTemperature def _setTargetHotendTemperature(self, index, temperature): Logger.log("w", "_setTargetHotendTemperature is not implemented by this output device") @pyqtProperty("QVariantList", notify = targetHotendTemperaturesChanged) def targetHotendTemperatures(self): return self._target_hotend_temperatures @pyqtProperty("QVariantList", notify = hotendTemperaturesChanged) def hotendTemperatures(self): return self._hotend_temperatures ## Protected setter for the current hotend temperature. # This simply sets the hotend temperature, but ensures that a signal is emitted. # /param index Index of the hotend # /param temperature temperature of the hotend (in deg C) def _setHotendTemperature(self, index, temperature): if self._hotend_temperatures[index] != temperature: self._hotend_temperatures[index] = temperature self.hotendTemperaturesChanged.emit() @pyqtProperty("QVariantList", notify = materialIdChanged) def materialIds(self): return self._material_ids @pyqtProperty("QVariantList", notify = materialIdChanged) def materialNames(self): result = [] for material_id in self._material_ids: if material_id is None: result.append(i18n_catalog.i18nc("@item:material", "No material loaded")) continue containers = self._container_registry.findInstanceContainers(type = "material", GUID = material_id) if containers: result.append(containers[0].getName()) else: result.append(i18n_catalog.i18nc("@item:material", "Unknown material")) return result ## List of the colours of the currently loaded materials. # # The list is in order of extruders. If there is no material in an # extruder, the colour is shown as transparent. # # The colours are returned in hex-format AARRGGBB or RRGGBB # (e.g. #800000ff for transparent blue or #00ff00 for pure green). @pyqtProperty("QVariantList", notify = materialIdChanged) def materialColors(self): result = [] for material_id in self._material_ids: if material_id is None: result.append("#00000000") #No material. continue containers = self._container_registry.findInstanceContainers(type = "material", GUID = material_id) if containers: result.append(containers[0].getMetaDataEntry("color_code")) else: result.append("#00000000") #Unknown material. return result ## Protected setter for the current material id. # /param index Index of the extruder # /param material_id id of the material def _setMaterialId(self, index, material_id): if material_id and material_id != "" and material_id != self._material_ids[index]: Logger.log("d", "Setting material id of hotend %d to %s" % (index, material_id)) self._material_ids[index] = material_id self.materialIdChanged.emit(index, material_id) @pyqtProperty("QVariantList", notify = hotendIdChanged) def hotendIds(self): return self._hotend_ids ## Protected setter for the current hotend id. # /param index Index of the extruder # /param hotend_id id of the hotend def _setHotendId(self, index, hotend_id): if hotend_id and hotend_id != self._hotend_ids[index]: Logger.log("d", "Setting hotend id of hotend %d to %s" % (index, hotend_id)) self._hotend_ids[index] = hotend_id self.hotendIdChanged.emit(index, hotend_id) elif not hotend_id: Logger.log("d", "Removing hotend id of hotend %d.", index) self._hotend_ids[index] = None self.hotendIdChanged.emit(index, None) ## Let the user decide if the hotends and/or material should be synced with the printer # NB: the UX needs to be implemented by the plugin def materialHotendChangedMessage(self, callback): Logger.log("w", "materialHotendChangedMessage needs to be implemented, returning 'Yes'") callback(QMessageBox.Yes) ## Attempt to establish connection def connect(self): raise NotImplementedError("connect needs to be implemented") ## Attempt to close the connection def close(self): raise NotImplementedError("close needs to be implemented") @pyqtProperty(bool, notify = connectionStateChanged) def connectionState(self): return self._connection_state ## Set the connection state of this output device. # /param connection_state ConnectionState enum. def setConnectionState(self, connection_state): if self._connection_state != connection_state: self._connection_state = connection_state self.connectionStateChanged.emit(self._id) @pyqtProperty(str, notify = connectionTextChanged) def connectionText(self): return self._connection_text ## Set a text that is shown on top of the print monitor tab def setConnectionText(self, connection_text): if self._connection_text != connection_text: self._connection_text = connection_text self.connectionTextChanged.emit() ## Ensure that close gets called when object is destroyed def __del__(self): self.close() ## Get the x position of the head. # This function is "final" (do not re-implement) @pyqtProperty(float, notify = headPositionChanged) def headX(self): return self._head_x ## Get the y position of the head. # This function is "final" (do not re-implement) @pyqtProperty(float, notify = headPositionChanged) def headY(self): return self._head_y ## Get the z position of the head. # In some machines it's actually the bed that moves. For convenience sake we simply see it all as head movements. # This function is "final" (do not re-implement) @pyqtProperty(float, notify = headPositionChanged) def headZ(self): return self._head_z ## Update the saved position of the head # This function should be called when a new position for the head is received. def _updateHeadPosition(self, x, y ,z): position_changed = False if self._head_x != x: self._head_x = x position_changed = True if self._head_y != y: self._head_y = y position_changed = True if self._head_z != z: self._head_z = z position_changed = True if position_changed: self.headPositionChanged.emit() ## Set the position of the head. # In some machines it's actually the bed that moves. For convenience sake we simply see it all as head movements. # This function is "final" (do not re-implement) # /param x new x location of the head. # /param y new y location of the head. # /param z new z location of the head. # /param speed Speed by which it needs to move (in mm/minute) # /sa _setHeadPosition implementation function @pyqtSlot("long", "long", "long") @pyqtSlot("long", "long", "long", "long") def setHeadPosition(self, x, y, z, speed = 3000): self._setHeadPosition(x, y , z, speed) ## Set the X position of the head. # This function is "final" (do not re-implement) # /param x x position head needs to move to. # /param speed Speed by which it needs to move (in mm/minute) # /sa _setHeadx implementation function @pyqtSlot("long") @pyqtSlot("long", "long") def setHeadX(self, x, speed = 3000): self._setHeadX(x, speed) ## Set the Y position of the head. # This function is "final" (do not re-implement) # /param y y position head needs to move to. # /param speed Speed by which it needs to move (in mm/minute) # /sa _setHeadY implementation function @pyqtSlot("long") @pyqtSlot("long", "long") def setHeadY(self, y, speed = 3000): self._setHeadY(y, speed) ## Set the Z position of the head. # In some machines it's actually the bed that moves. For convenience sake we simply see it all as head movements. # This function is "final" (do not re-implement) # /param z z position head needs to move to. # /param speed Speed by which it needs to move (in mm/minute) # /sa _setHeadZ implementation function @pyqtSlot("long") @pyqtSlot("long", "long") def setHeadZ(self, z, speed = 3000): self._setHeadY(z, speed) ## Move the head of the printer. # Note that this is a relative move. If you want to move the head to a specific position you can use # setHeadPosition # This function is "final" (do not re-implement) # /param x distance in x to move # /param y distance in y to move # /param z distance in z to move # /param speed Speed by which it needs to move (in mm/minute) # /sa _moveHead implementation function @pyqtSlot("long", "long", "long") @pyqtSlot("long", "long", "long", "long") def moveHead(self, x = 0, y = 0, z = 0, speed = 3000): self._moveHead(x, y, z, speed) ## Implementation function of moveHead. # /param x distance in x to move # /param y distance in y to move # /param z distance in z to move # /param speed Speed by which it needs to move (in mm/minute) # /sa moveHead def _moveHead(self, x, y, z, speed): Logger.log("w", "_moveHead is not implemented by this output device") ## Implementation function of setHeadPosition. # /param x new x location of the head. # /param y new y location of the head. # /param z new z location of the head. # /param speed Speed by which it needs to move (in mm/minute) # /sa setHeadPosition def _setHeadPosition(self, x, y, z, speed): Logger.log("w", "_setHeadPosition is not implemented by this output device") ## Implementation function of setHeadX. # /param x new x location of the head. # /param speed Speed by which it needs to move (in mm/minute) # /sa setHeadX def _setHeadX(self, x, speed): Logger.log("w", "_setHeadX is not implemented by this output device") ## Implementation function of setHeadY. # /param y new y location of the head. # /param speed Speed by which it needs to move (in mm/minute) # /sa _setHeadY def _setHeadY(self, y, speed): Logger.log("w", "_setHeadY is not implemented by this output device") ## Implementation function of setHeadZ. # /param z new z location of the head. # /param speed Speed by which it needs to move (in mm/minute) # /sa _setHeadZ def _setHeadZ(self, z, speed): Logger.log("w", "_setHeadZ is not implemented by this output device") ## Get the progress of any currently active process. # This function is "final" (do not re-implement) # /sa _getProgress # /returns float progress of the process. -1 indicates that there is no process. @pyqtProperty(float, notify = progressChanged) def progress(self): return self._progress ## Set the progress of any currently active process # /param progress Progress of the process. def setProgress(self, progress): if self._progress != progress: self._progress = progress self.progressChanged.emit()
class TimerListWidget(Base): def __init__(self, observer: Observer, name: str, foreground_color="#ffffff", parent=None, item: TimerListItem=None): super().__init__(observer, name) self.parent = parent self.item = item self.observer = observer self.foreground_color = foreground_color self.setStyleSheet("QLabel { color : " + self.foreground_color + "; font: 30pt;}") self.hbox_layout = QHBoxLayout() self.timer_name = QLabel(self.item.get_name()) self.timer_value = QLabel(self.item.get_start_value_as_str()) self.start_button_state = False # Is active self.check_timer = QTimer(self) self.check_timer.setInterval(100) # .1 seconds self.check_timer.timeout.connect(lambda: self.update_count_down()) self.count_down_timer = QTimer(self) self.count_down_timer.setInterval(item.get_start_value_as_int()) self.count_down_timer.timeout.connect(lambda: self.count_down_end()) self.gui_button_builder = GuiButtonBuilder() self.gui_button_builder.set_color(foreground_color) self.gui_button_builder.set_size(30, 60) self.delete_button = self.gui_button_builder.create_button("Delete", Gui_Element.BUTTON_FULL_CIRCLE_TEXT) self.delete_button.clicked.connect(lambda: self.remove_item()) self.start_pause_button = self.gui_button_builder.create_button("Start", Gui_Element.BUTTON_FULL_CIRCLE_TEXT) self.start_pause_button.clicked.connect(lambda: self.start_button_pressed()) self.hbox_layout.addWidget(self.timer_name) self.hbox_layout.addWidget(self.timer_value) self.hbox_layout.addWidget(self.start_pause_button) self.hbox_layout.addWidget(self.delete_button) self.setLayout(self.hbox_layout) def set_observer(self, observer: Observer): self.observer = observer def remove_item(self): row = self.parent.row(self.item) self.parent.takeItem(row) self.check_timer.stop() self.count_down_timer.stop() del self.item del self def start_button_pressed(self): if self.start_button_state: self.start_button_state = False self.start_pause_button.setText("Stop") self.start_pause_button.setLayout() self.check_timer.stop() self.count_down_timer.stop() else: self.start_button_state = True self.start_pause_button.setText("Start") self.check_timer.start() self.count_down_timer.start() def update_count_down(self): millis = self.count_down_timer.remainingTime() if millis < 0: self.timer_value.setText("00:00:00") return seconds = (millis / 1000) % 60 seconds = int(seconds) minutes = (millis / (1000 * 60)) % 60 minutes = int(minutes) hours = (millis / (1000 * 60 * 60)) % 24 string = "%02d:%02d:%02d" % (hours, minutes, seconds) self.timer_value.setText(string) def count_down_end(self): self.count_down_timer.stop() msg = { "subscreen_name": "TimerOverview", "msg": self.timer_name.text() + " expired" } self.observer.update_from_subscreen(msg)