Exemplo n.º 1
0
 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())
Exemplo n.º 2
0
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())
Exemplo n.º 3
0
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()
Exemplo n.º 4
0
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()
Exemplo n.º 5
0
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()
Exemplo n.º 6
0
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])
Exemplo n.º 7
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_()
Exemplo n.º 8
0
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
Exemplo n.º 9
0
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 ()
Exemplo n.º 10
0
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
Exemplo n.º 11
0
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()
        """
Exemplo n.º 12
0
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()
Exemplo n.º 13
0
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))
Exemplo n.º 14
0
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()
Exemplo n.º 15
0
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))
Exemplo n.º 16
0
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)
Exemplo n.º 17
0
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)
Exemplo n.º 18
0
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
Exemplo n.º 19
0
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()
Exemplo n.º 20
0
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()
Exemplo n.º 21
0
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)