示例#1
0
    def show_tray(self):
        if QSystemTrayIcon.isSystemTrayAvailable:
            # create tray menu
            traymenu = QMenu('AyoShalat', self)
            openwin_menu = traymenu.addAction('Show me!')
            openwin_menu.triggered.connect(self.show)

            playazan_menu = traymenu.addAction('Play Azan')
            playazan_menu.triggered.connect(self.playAzan)
            
            stop_azan_menu = traymenu.addAction('Stop Azan')
            stop_azan_menu.triggered.connect(self.stopAzan)

            traymenu.addSeparator()

            exit_menu = traymenu.addAction('Exit')
            exit_menu.triggered.connect(self.exit)

            # create tray icon
            qtray = QSystemTrayIcon(self)

            qtray.setIcon(QIcon(self.icopath))
            qtray.setVisible(True)
            qtray.setContextMenu(traymenu)
            qtray.show()
示例#2
0
文件: pryme2.py 项目: qt4cpp/pryme2
class Pryme2(QWidget):

    notify_request = Signal(str)

    def __init__(self, parent=None):

        super(Pryme2, self).__init__(parent)

        self.timer_instances = (SimpleTimer(), AlarmClock(), PomoTimer())
        self.timer_selection = QComboBox(self)
        for t in self.timer_instances:
            self.timer_selection.addItem(t.name)
        self.timer = self.timer_instances[0]
        self.commitment_textbox = QLineEdit(self)
        self.commitment_textbox.setPlaceholderText(
            'What do you want to commit?')
        self.commitment_textbox.setClearButtonEnabled(True)
        self.commit_done_btn = QPushButton('&Done', self)
        self.start_btn = QPushButton('&Start', self)
        self.abort_btn = QPushButton('&Abort', self)
        self.abort_btn.hide()
        self.pause_btn = QPushButton('&Pause', self)
        self.pause_btn.hide()
        self.resume_btn = QPushButton('&Resume', self)
        self.resume_btn.hide()

        self.tray = QSystemTrayIcon(self)
        self.tray.setIcon(QIcon('pryme-logo.svg'))
        self.tray.show()

        self.set_ui()
        self.set_connection()
        self.show()

    def set_ui(self):
        self.hlayout = QHBoxLayout()
        self.hlayout.addWidget(self.commitment_textbox)
        self.hlayout.addWidget(self.commit_done_btn)
        self.commit_group = QGroupBox('Commitment')
        self.commit_group.setLayout(self.hlayout)

        self.vlayout = QVBoxLayout()
        self.vlayout.addWidget(self.commit_group)
        self.vlayout.addWidget(self.timer_selection)
        self.vlayout.addWidget(self.timer)

        self.bottom_hlayout = QHBoxLayout()
        self.bottom_hlayout.addWidget(self.start_btn)
        self.bottom_hlayout.addWidget(self.abort_btn)
        self.bottom_hlayout.addWidget(self.pause_btn)
        self.bottom_hlayout.addWidget(self.resume_btn)

        self.vlayout.addLayout(self.bottom_hlayout)
        self.setLayout(self.vlayout)

    def set_connection(self):
        self.timer_selection.currentIndexChanged.connect(self.change_timer)
        self.connect_timer()

    def connect_timer(self):
        self.start_btn.clicked.connect(self.timer.start)
        self.abort_btn.clicked.connect(self.timer.abort)
        self.timer.finished.connect(self.notify)
        self.timer.started.connect(self.set_timer_active_ui)
        self.timer.aborted.connect(self.set_timer_deactive_ui)
        self.timer.finished.connect(self.set_timer_deactive_ui)
        if hasattr(self.timer, 'pause'):
            self.pause_btn.clicked.connect(self.timer.pause)
            self.resume_btn.clicked.connect(self.timer.resume)
            self.timer.paused.connect(self.activate_resume_button)

    def disconnect_timer(self):
        self.timer.disconnect(self)
        self.start_btn.disconnect(self.timer)
        self.abort_btn.disconnect(self.timer)
        self.resume_btn.disconnect(self.timer)

    def notify(self):
        title = self.commitment_textbox.text()
        if not title:
            title = 'Time up!'
        message = self.timer.get_notify_message()
        if not message:
            print(message)
            message = 'Time up!'
        self.tray.showMessage(title, message)
        subprocess.Popen(cmd.split())

    def set_ui_enabled(self, enable: bool):
        self.timer_selection.setEnabled(enable)
        self.commitment_textbox.setEnabled(enable)

    def set_timer_active_ui(self):
        self.activate_start_button(False)
        self.set_ui_enabled(False)

    def set_timer_deactive_ui(self):
        self.activate_start_button(True)
        self.set_ui_enabled(True)

    def activate_start_button(self, activate: bool):
        if activate:
            # active start button
            self.start_btn.show()
            self.abort_btn.hide()
            self.pause_btn.hide()
            self.resume_btn.hide()
        else:
            self.abort_btn.show()
            self.start_btn.hide()
            if hasattr(self.timer, 'pause'):
                self.pause_btn.show()
                self.resume_btn.hide()

    def activate_resume_button(self):
        self.pause_btn.hide()
        self.resume_btn.show()

    @Slot(int)
    def change_timer(self, index):
        self.disconnect_timer()
        self.timer.hide()
        self.vlayout.replaceWidget(self.timer, self.timer_instances[index])
        self.timer = self.timer_instances[index]
        self.connect_timer()
        self.timer.show()
示例#3
0
class MainWindow(QMainWindow):
    """Voice Changer main window."""
    def __init__(self, parent=None):
        super(MainWindow, self).__init__()
        self.statusBar().showMessage("Move Dial to Deform Microphone Voice !.")
        self.setWindowTitle(__doc__)
        self.setMinimumSize(240, 240)
        self.setMaximumSize(480, 480)
        self.resize(self.minimumSize())
        self.setWindowIcon(QIcon.fromTheme("audio-input-microphone"))
        self.tray = QSystemTrayIcon(self)
        self.center()
        QShortcut("Ctrl+q", self, activated=lambda: self.close())
        self.menuBar().addMenu("&File").addAction("Quit", lambda: exit())
        self.menuBar().addMenu("Sound").addAction(
            "STOP !", lambda: call('killall rec', shell=True))
        windowMenu = self.menuBar().addMenu("&Window")
        windowMenu.addAction("Hide", lambda: self.hide())
        windowMenu.addAction("Minimize", lambda: self.showMinimized())
        windowMenu.addAction("Maximize", lambda: self.showMaximized())
        windowMenu.addAction("Restore", lambda: self.showNormal())
        windowMenu.addAction("FullScreen", lambda: self.showFullScreen())
        windowMenu.addAction("Center", lambda: self.center())
        windowMenu.addAction("Top-Left", lambda: self.move(0, 0))
        windowMenu.addAction("To Mouse", lambda: self.move_to_mouse_position())
        # widgets
        group0 = QGroupBox("Voice Deformation")
        self.setCentralWidget(group0)
        self.process = QProcess(self)
        self.process.error.connect(
            lambda: self.statusBar().showMessage("Info: Process Killed", 5000))
        self.control = QDial()
        self.control.setRange(-10, 20)
        self.control.setSingleStep(5)
        self.control.setValue(0)
        self.control.setCursor(QCursor(Qt.OpenHandCursor))
        self.control.sliderPressed.connect(
            lambda: self.control.setCursor(QCursor(Qt.ClosedHandCursor)))
        self.control.sliderReleased.connect(
            lambda: self.control.setCursor(QCursor(Qt.OpenHandCursor)))
        self.control.valueChanged.connect(
            lambda: self.control.setToolTip(f"<b>{self.control.value()}"))
        self.control.valueChanged.connect(lambda: self.statusBar().showMessage(
            f"Voice deformation: {self.control.value()}", 5000))
        self.control.valueChanged.connect(self.run)
        self.control.valueChanged.connect(lambda: self.process.kill())
        # Graphic effect
        self.glow = QGraphicsDropShadowEffect(self)
        self.glow.setOffset(0)
        self.glow.setBlurRadius(99)
        self.glow.setColor(QColor(99, 255, 255))
        self.control.setGraphicsEffect(self.glow)
        self.glow.setEnabled(False)
        # Timer to start
        self.slider_timer = QTimer(self)
        self.slider_timer.setSingleShot(True)
        self.slider_timer.timeout.connect(self.on_slider_timer_timeout)
        # an icon and set focus
        QLabel(self.control).setPixmap(
            QIcon.fromTheme("audio-input-microphone").pixmap(32))
        self.control.setFocus()
        QVBoxLayout(group0).addWidget(self.control)
        self.menu = QMenu(__doc__)
        self.menu.addAction(__doc__).setDisabled(True)
        self.menu.setIcon(self.windowIcon())
        self.menu.addSeparator()
        self.menu.addAction(
            "Show / Hide", lambda: self.hide()
            if self.isVisible() else self.showNormal())
        self.menu.addAction("STOP !", lambda: call('killall rec', shell=True))
        self.menu.addSeparator()
        self.menu.addAction("Quit", lambda: exit())
        self.tray.setContextMenu(self.menu)
        self.make_trayicon()

    def run(self):
        """Run/Stop the QTimer."""
        if self.slider_timer.isActive():
            self.slider_timer.stop()
        self.glow.setEnabled(True)
        call('killall rec ; killall play', shell=True)
        self.slider_timer.start(3000)

    def on_slider_timer_timeout(self):
        """Run subprocess to deform voice."""
        self.glow.setEnabled(False)
        value = int(self.control.value()) * 100
        command = f'play -q -V0 "|rec -q -V0 -n -d -R riaa bend pitch {value} "'
        print(f"Voice Deformation Value: {value}")
        print(f"Voice Deformation Command: {command}")
        self.process.start(command)
        if self.isVisible():
            self.statusBar().showMessage("Minimizing to System TrayIcon", 3000)
            print("Minimizing Main Window to System TrayIcon now...")
            sleep(3)
            self.hide()

    def center(self):
        """Center Window on the Current Screen,with Multi-Monitor support."""
        window_geometry = self.frameGeometry()
        mousepointer_position = QApplication.desktop().cursor().pos()
        screen = QApplication.desktop().screenNumber(mousepointer_position)
        centerPoint = QApplication.desktop().screenGeometry(screen).center()
        window_geometry.moveCenter(centerPoint)
        self.move(window_geometry.topLeft())

    def move_to_mouse_position(self):
        """Center the Window on the Current Mouse position."""
        window_geometry = self.frameGeometry()
        window_geometry.moveCenter(QApplication.desktop().cursor().pos())
        self.move(window_geometry.topLeft())

    def make_trayicon(self):
        """Make a Tray Icon."""
        if self.windowIcon() and __doc__:
            self.tray.setIcon(self.windowIcon())
            self.tray.setToolTip(__doc__)
            self.tray.activated.connect(
                lambda: self.hide() if self.isVisible() else self.showNormal())
            return self.tray.show()
示例#4
0
class AyoShalat(QMainWindow):
    # +=========+===============================================+
    # | Method  | Description                                   |
    # +=========+===============================================+
    # | MWL     | Muslim World League                           |
    # +---------+-----------------------------------------------+
    # | ISNA    | Islamic Society of North America              |
    # +---------+-----------------------------------------------+
    # | Egypt   | Egyptian General Authority of Survey          |
    # +---------+-----------------------------------------------+
    # | Makkah  | Umm al-Qura University                        |
    # +---------+-----------------------------------------------+
    # | Karachi | University of Islamic Sciences, Karachi       |
    # +---------+-----------------------------------------------+
    # | Tehran  | Institute of Geophysics, University of Tehran |
    # +---------+-----------------------------------------------+
    # | Jafari  | Shia Ithna Ashari (Jafari)                    |
    # +---------+-----------------------------------------------+

    def __init__(self):
        QMainWindow.__init__(self)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        if os.name == 'nt':
            self.current_directory = str(
                pathlib.Path(__file__).parent.absolute()).replace('\\', '/')
        else:
            self.current_directory = str(
                pathlib.Path(__file__).parent.absolute())

        self.reformat_ui()

        # set clicked
        self.ui.btnPlay.clicked.connect(self.playAzan)
        self.ui.btnStop.clicked.connect(self.stopAzan)
        # self.ui.btnHide.clicked.connect(self.openSetting)
        self.ui.btnHide.clicked.connect(self.hide)
        self.ui.btnExit.clicked.connect(self.do_close)
        self.ui.btnSave.clicked.connect(self.do_save)
        self.ui.btnSetting.clicked.connect(self.show_frame_setting)
        self.ui.btnTimeTable.clicked.connect(self.show_time_table)
        self.ui.ckNotification.toggled.connect(self.toggle_check_notification)

        self.calculation_method_array = [
            'MWL', 'ISNA', 'Egypt', 'Makkah', 'Karachi', 'Tehran', 'Jafari'
        ]
        self.mathhab_array = ['Standard', 'Hanafi']

        # init form setting
        self.ui.frameSetting.setVisible(False)

        # get username of this login user
        # self.myusername = pwd.getpwuid(os.getuid()).pw_name

        # init icon
        self.setting_file = self.current_directory + '/setting.txt'
        self.icopath = self.current_directory + '/icon/masjid.xpm'
        self.setWindowIcon(QIcon(self.icopath))
        self.default_azan = self.current_directory + '/audio/azan.mp3'
        self.default_azan_wav = self.current_directory + '/audio/azan.wav'
        self.default_notif = self.current_directory + '/audio/hayyalashala.mp3'
        self.default_notif_wav = self.current_directory + '/audio/hayyalashala.wav'

        # image dialog
        azandialog = QDialog(self, Qt.FramelessWindowHint)
        azandialog.setWindowTitle("It's time to Shalat")
        self.azanDialog = azandialog
        btnDialog = QPushButton("", self.azanDialog)
        btnDialog.setFlat(True)
        btnDialog.clicked.connect(self.azanDialog.hide)

        # OPEN SETTING ON START
        self.open_setting()

        # init thread
        self.docalc = threading.Thread(target=self.do_calculate,
                                       name="Azan Calculating")
        self.threadAzan = threading.Thread(target=self._playAzan,
                                           name="Play Azan")
        self.threadNotif = threading.Thread(target=self._playNotif,
                                            name="Play Notif")

        self.init_times_new()

        # show times
        self.showTimes()

        # show tray on start
        self.show_tray()

        # ---------------------------------------------------------------------------------------------------------------------

    def do_close(self):
        if QMessageBox().question(self, 'Close', 'Are you sure ?',
                                  QMessageBox.StandardButton.Yes,
                                  QMessageBox.StandardButton.No
                                  ) == QMessageBox.StandardButton.Yes:
            self.qtray.hide()
            self.qtray.deleteLater()
            self.deleteLater()
            os._exit(0)

    def toggle_check_notification(self):
        # toggle enable of txNotification
        if self.ui.ckNotification.isChecked():
            self.ui.txBeforeTime.show()
            self.ui.label_7.show()
        else:
            self.ui.txBeforeTime.hide()
            self.ui.label_7.hide()

    def show_frame_setting(self):
        self.ui.frameSetting.setVisible(True)
        self.ui.frameSetting.raise_()

    def show_time_table(self):
        self.ui.frameSetting.setVisible(False)

    def show_tray(self):
        if QSystemTrayIcon.isSystemTrayAvailable:
            # create tray menu
            traymenu = QMenu('AyoShalat', self)
            openwin_menu = traymenu.addAction('Show me!')
            openwin_menu.triggered.connect(self.show)

            playazan_menu = traymenu.addAction('Play Azan')
            playazan_menu.triggered.connect(self.playAzan)

            stop_azan_menu = traymenu.addAction('Stop Azan')
            stop_azan_menu.triggered.connect(self.stopAzan)

            traymenu.addSeparator()

            exit_menu = traymenu.addAction('Exit')
            exit_menu.triggered.connect(self.do_close)

            # create tray icon
            self.qtray = QSystemTrayIcon(self)

            self.qtray.setIcon(QIcon(self.icopath))
            self.qtray.setVisible(True)
            self.qtray.setContextMenu(traymenu)
            self.qtray.show()

    def do_save(self):
        # save setting to tinydb
        if self.ui.ckStartTray.isChecked():
            is_open_in_tray = 'True'
        else:
            is_open_in_tray = 'False'
        vals = {
            'open_in_tray': is_open_in_tray,
            'latitude': self.ui.txLat.text().strip(),
            'longitude': self.ui.txLong.text().strip(),
            'utc_offset': self.ui.txUtc.text().strip(),
            'calculation_method_index': str(self.ui.cbMethod.currentIndex()),
            'time_format': '24h',
            'mathhab_index': str(self.ui.cbMathhab.currentIndex()),
            'before_pray_time': self.ui.txBeforeTime.text().strip(),
            'enable_notification_before':
            str(self.ui.ckNotification.isChecked()),
            'before_jumah_time': self.ui.txBeforeJumah.text().strip(),
            'enable_jumah_notification': str(self.ui.ckJumah.isChecked()),
        }
        pprint(vals)
        # setting_lines  = self.db.search(self.TinyData.code == 'setting')
        # for setting in setting_lines:

        #     setting['latitude'] = self.ui.txLat.text().strip()
        #     setting['longitude'] = self.ui.txLong.text().strip()
        #     setting['utc_offset'] = self.ui.txUtc.text().strip()
        #     setting['calculation_method_index'] = str(self.ui.cbMethod.currentIndex())
        #     setting['time_format'] = '24h'
        #     setting['mathhab_index'] = str(self.ui.cbMathhab.currentIndex())

        self.db.update(vals, self.TinyData.code == 'setting')

        # reload setting
        self.open_setting()
        self.init_times_new()
        self.showTimes()

    # active_time fajr = 1
    def set_color_prayer_time_frame(self, active_time):
        normal_style = "border-style:solid;border-radius:0px;border-bottom:1px solid whitesmoke;"
        active_style = normal_style + "background-color:rgb(252, 210, 93);"

        normal_style = ".QFrame{" + normal_style + "}"
        active_style = ".QFrame{" + active_style + "}"

        # clear
        self.ui.frameFajr.setStyleSheet(normal_style)
        self.ui.frameDhuhr.setStyleSheet(normal_style)
        self.ui.frameAsr.setStyleSheet(normal_style)
        self.ui.frameMaghrib.setStyleSheet(normal_style)
        self.ui.frameIsya.setStyleSheet(normal_style)

        if active_time == 1:
            self.ui.frameFajr.setStyleSheet(active_style)
        if active_time == 2:
            self.ui.frameDhuhr.setStyleSheet(active_style)
        if active_time == 3:
            self.ui.frameAsr.setStyleSheet(active_style)
        if active_time == 4:
            self.ui.frameMaghrib.setStyleSheet(active_style)
        if active_time == 5:
            self.ui.frameIsya.setStyleSheet(active_style)

    def show_prayer_time_info(self):
        # show current prayer time info
        # get current time
        current_time = datetime.datetime.now()
        now = current_time.strftime("%H:%M")

        # if now == self.time_array['fajr'].strip():
        #     self.ui.lblCurrentWaktu.setText('Subh')
        #     self.set_color_prayer_time_frame(1)
        # elif now == self.time_array['dhuhr'].strip():
        #     self.ui.lblCurrentWaktu.setText('dhuhr')
        #     self.set_color_prayer_time_frame(2)
        # elif now == self.time_array['asr'].strip():
        #     self.ui.lblCurrentWaktu.setText('Asr')
        #     self.set_color_prayer_time_frame(3)
        # elif now == self.time_array['maghrib'].strip():
        #     self.ui.lblCurrentWaktu.setText('Maghrib')
        #     self.set_color_prayer_time_frame(4)
        # elif now == self.time_array['isha'].strip():
        #     self.ui.lblCurrentWaktu.setText('Isya`')
        #     self.set_color_prayer_time_frame(5)

        # subh
        subh = self.time_array['fajr'].strip()
        dhuhr = self.time_array['dhuhr'].strip()
        asr = self.time_array['asr'].strip()
        maghrib = self.time_array['maghrib'].strip()
        isya = self.time_array['isha'].strip()

        subh_date_str = str(current_time.year) + '/' + str(
            current_time.strftime('%m')) + '/' + str(
                current_time.strftime('%d')) + ' ' + subh + ':00'
        subh_date = datetime.datetime.strptime(subh_date_str,
                                               '%Y/%m/%d %H:%M:%S')

        # dhuhr
        dhuhr_date_str = str(current_time.year) + '/' + str(
            current_time.strftime('%m')) + '/' + str(
                current_time.strftime('%d')) + ' ' + dhuhr + ':00'
        dhuhr_date = datetime.datetime.strptime(dhuhr_date_str,
                                                '%Y/%m/%d %H:%M:%S')

        # asr
        asr_date_str = str(current_time.year) + '/' + str(
            current_time.strftime('%m')) + '/' + str(
                current_time.strftime('%d')) + ' ' + asr + ':00'
        asr_date = datetime.datetime.strptime(asr_date_str,
                                              '%Y/%m/%d %H:%M:%S')

        # asr
        maghrib_date_str = str(current_time.year) + '/' + str(
            current_time.strftime('%m')) + '/' + str(
                current_time.strftime('%d')) + ' ' + maghrib + ':00'
        maghrib_date = datetime.datetime.strptime(maghrib_date_str,
                                                  '%Y/%m/%d %H:%M:%S')

        # isya
        isya_date_str = str(current_time.year) + '/' + str(
            current_time.strftime('%m')) + '/' + str(
                current_time.strftime('%d')) + ' ' + isya + ':00'
        isya_date = datetime.datetime.strptime(isya_date_str,
                                               '%Y/%m/%d %H:%M:%S')

        # show upcoming
        if current_time >= subh_date and current_time <= dhuhr_date:
            self.ui.lblUpcomingWaktu.setText("Dhuhr")
            self.ui.lblUpcomingJam.setText(self.time_array['dhuhr'])
            self.ui.lblCurrentWaktu.setText('Subh')
            self.show_remaining_time()
            self.set_color_prayer_time_frame(1)

        if current_time >= dhuhr_date and current_time <= asr_date:
            self.ui.lblUpcomingWaktu.setText("Asr")
            self.ui.lblUpcomingJam.setText(self.time_array['asr'])
            self.ui.lblCurrentWaktu.setText('Duhr')
            self.show_remaining_time()
            self.set_color_prayer_time_frame(2)

        if current_time >= asr_date and current_time <= maghrib_date:
            self.ui.lblUpcomingWaktu.setText("Maghrib")
            self.ui.lblUpcomingJam.setText(self.time_array['maghrib'])
            self.ui.lblCurrentWaktu.setText('Asr')
            self.show_remaining_time()
            self.set_color_prayer_time_frame(3)

        if current_time >= maghrib_date and current_time <= isya_date:
            self.ui.lblUpcomingWaktu.setText("Isya")
            self.ui.lblUpcomingJam.setText(self.time_array['isha'])
            self.ui.lblCurrentWaktu.setText('Maghrib')
            self.show_remaining_time()
            self.set_color_prayer_time_frame(4)

        # if current_time >= isya_date and current_time <= subh_date:
        if current_time >= isya_date:
            self.ui.lblUpcomingWaktu.setText("Subh")
            self.ui.lblUpcomingJam.setText(self.time_array['fajr'])
            self.ui.lblCurrentWaktu.setText('Isya')
            self.show_remaining_time()
            self.set_color_prayer_time_frame(5)

    def show_remaining_time(self):
        current_time = datetime.datetime.now()
        subh = self.time_array['fajr'].strip()
        dhuhr = self.time_array['dhuhr'].strip()
        asr = self.time_array['asr'].strip()
        maghrib = self.time_array['maghrib'].strip()
        isya = self.time_array['isha'].strip()

        subh_date_str = str(current_time.year) + '/' + str(
            current_time.strftime('%m')) + '/' + str(
                current_time.strftime('%d')) + ' ' + subh + ':00'
        subh_date = datetime.datetime.strptime(subh_date_str,
                                               '%Y/%m/%d %H:%M:%S')

        # dhuhr
        dhuhr_date_str = str(current_time.year) + '/' + str(
            current_time.strftime('%m')) + '/' + str(
                current_time.strftime('%d')) + ' ' + dhuhr + ':00'
        dhuhr_date = datetime.datetime.strptime(dhuhr_date_str,
                                                '%Y/%m/%d %H:%M:%S')

        # asr
        asr_date_str = str(current_time.year) + '/' + str(
            current_time.strftime('%m')) + '/' + str(
                current_time.strftime('%d')) + ' ' + asr + ':00'
        asr_date = datetime.datetime.strptime(asr_date_str,
                                              '%Y/%m/%d %H:%M:%S')

        # asr
        maghrib_date_str = str(current_time.year) + '/' + str(
            current_time.strftime('%m')) + '/' + str(
                current_time.strftime('%d')) + ' ' + maghrib + ':00'
        maghrib_date = datetime.datetime.strptime(maghrib_date_str,
                                                  '%Y/%m/%d %H:%M:%S')

        # isya
        isya_date_str = str(current_time.year) + '/' + str(
            current_time.strftime('%m')) + '/' + str(
                current_time.strftime('%d')) + ' ' + isya + ':00'
        isya_date = datetime.datetime.strptime(isya_date_str,
                                               '%Y/%m/%d %H:%M:%S')
        # show upcoming
        if current_time >= subh_date and current_time <= dhuhr_date:
            remaining_hours = int(
                self.get_remaining_second(current_time, dhuhr_date) // 3600)
            remaining_minutes = int(
                (self.get_remaining_second(current_time, dhuhr_date) // 60) %
                60)

        if current_time >= dhuhr_date and current_time <= asr_date:
            remaining_hours = int(
                self.get_remaining_second(current_time, asr_date) // 3600)
            remaining_minutes = int(
                (self.get_remaining_second(current_time, asr_date) // 60) % 60)

        if current_time >= asr_date and current_time <= maghrib_date:
            remaining_hours = int(
                self.get_remaining_second(current_time, maghrib_date) // 3600)
            remaining_minutes = int(
                (self.get_remaining_second(current_time, maghrib_date) // 60) %
                60)

        if current_time >= maghrib_date and current_time <= isya_date:
            remaining_hours = int(
                self.get_remaining_second(current_time, isya_date) // 3600)
            remaining_minutes = int(
                (self.get_remaining_second(current_time, isya_date) // 60) %
                60)

        # if current_time >= isya_date and current_time <= subh_date:
        if current_time >= isya_date or current_time <= subh_date:
            subh_date = subh_date + datetime.timedelta(days=1)
            remaining_hours = int(
                self.get_remaining_second(current_time, subh_date) // 3600)
            remaining_minutes = int(
                (self.get_remaining_second(current_time, subh_date) // 60) %
                60)

        remaining_str = f'{remaining_hours} hours and ' if (
            remaining_hours) else ''
        remaining_str += f'{remaining_minutes} minutes to go'

        self.ui.lblRemaining.setText(remaining_str)

    def do_calculate(self):
        while True:
            time.sleep(1)

            # update time every time
            self.init_times_new()

            self.showTimes()

            self.show_remaining_time()

            # Check Azan Time
            current_time = datetime.datetime.now()
            now = current_time.strftime("%H:%M")
            if now == self.time_array['fajr'].strip(
            ) or now == self.time_array['dhuhr'].strip(
            ) or now == self.time_array['asr'].strip(
            ) or now == self.time_array['maghrib'].strip(
            ) or now == self.time_array['isha'].strip():
                self.playAzan()
                # self.show_current_prayer_time()
                self.show_prayer_time_info()
                time.sleep(60)
            # -----------------------------------------------------------------------

            # checking for jumah notification
            # friday is 4
            if current_time.weekday() == 4:
                if self.enable_jumah_notification:
                    # dhuhr
                    dhuhr_date_str = str(current_time.year) + '/' + str(
                        current_time.strftime('%m')) + '/' + str(
                            current_time.strftime('%d')
                        ) + ' ' + self.time_array['dhuhr'].strip() + ':00'
                    dhuhr_date = datetime.datetime.strptime(
                        dhuhr_date_str, '%Y/%m/%d %H:%M:%S')

                    if self.get_remaining_time(current_time,
                                               dhuhr_date) == int(
                                                   self.before_jumah_time):
                        self.playNotif('Jum`ah')
                        time.sleep(75)

            # checking notification before pray time
            if self.enable_notification_before:

                # subh
                subh_date_str = str(current_time.year) + '/' + str(
                    current_time.strftime('%m')) + '/' + str(
                        current_time.strftime('%d')
                    ) + ' ' + self.time_array['fajr'].strip() + ':00'
                subh_date = datetime.datetime.strptime(subh_date_str,
                                                       '%Y/%m/%d %H:%M:%S')

                # dhuhr
                dhuhr_date_str = str(current_time.year) + '/' + str(
                    current_time.strftime('%m')) + '/' + str(
                        current_time.strftime('%d')
                    ) + ' ' + self.time_array['dhuhr'].strip() + ':00'
                dhuhr_date = datetime.datetime.strptime(
                    dhuhr_date_str, '%Y/%m/%d %H:%M:%S')

                # asr
                asr_date_str = str(current_time.year) + '/' + str(
                    current_time.strftime('%m')) + '/' + str(
                        current_time.strftime('%d')
                    ) + ' ' + self.time_array['asr'].strip() + ':00'
                asr_date = datetime.datetime.strptime(asr_date_str,
                                                      '%Y/%m/%d %H:%M:%S')

                # asr
                maghrib_date_str = str(current_time.year) + '/' + str(
                    current_time.strftime('%m')) + '/' + str(
                        current_time.strftime('%d')
                    ) + ' ' + self.time_array['maghrib'].strip() + ':00'
                maghrib_date = datetime.datetime.strptime(
                    maghrib_date_str, '%Y/%m/%d %H:%M:%S')

                # isya
                isya_date_str = str(current_time.year) + '/' + str(
                    current_time.strftime('%m')) + '/' + str(
                        current_time.strftime('%d')
                    ) + ' ' + self.time_array['isha'].strip() + ':00'
                isya_date = datetime.datetime.strptime(isya_date_str,
                                                       '%Y/%m/%d %H:%M:%S')

                if self.get_remaining_time(current_time, subh_date) == int(
                        self.before_pray_time):
                    self.playNotif('Fajr')
                    time.sleep(75)

                if self.get_remaining_time(current_time, dhuhr_date) == int(
                        self.before_pray_time):
                    self.playNotif('Dhuhr')
                    time.sleep(75)

                if self.get_remaining_time(current_time, asr_date) == int(
                        self.before_pray_time):
                    self.playNotif('Asr')
                    time.sleep(75)

                if self.get_remaining_time(current_time, maghrib_date) == int(
                        self.before_pray_time):
                    self.playNotif('Maghrib')
                    time.sleep(75)

                if self.get_remaining_time(current_time, isya_date) == int(
                        self.before_pray_time):
                    self.playNotif('Isya')
                    time.sleep(75)

    def get_remaining_second(self, time_1, time_2):
        time_delta = (time_2 - time_1)
        return time_delta.total_seconds()  # in seconds

    def get_remaining_time(self, time_1, time_2):
        # in minutes
        return round(self.get_remaining_second(time_1, time_2) / 60)

    def runningme(self):
        # do some stuff
        self.show_prayer_time_info()
        self.docalc.start()

    def showImageAzan(self):
        image_dir = self.current_directory + '/images'
        filename = random.choice(os.listdir(image_dir))

        image_path = image_dir + '/' + filename
        im = Image.open(image_path)
        im_width, im_height = im.size
        im_width -= 75
        im_height -= 75
        self.azanDialog.resize(im_width, im_height)

        im_width -= 10
        im_height -= 10

        print('showing azan dialog')
        btnDialog = self.azanDialog.children()[0]
        btnDialog.setGeometry(5, 5, im_width, im_height)
        styleBg = "border-image: url('" + image_path + \
            "') 0 0 0 0 stretch stretch;"
        btnDialog.setStyleSheet(styleBg)
        self.azanDialog.show()

    def stopAzan(self):
        try:
            self.azanplay.stop()
        except AttributeError as ae:
            print(ae)

    def stopNotif(self):
        self.notifplay.stop()

    def playAzan(self):
        self.threadAzan = threading.Thread(target=self._playAzan,
                                           name="Play Azan")

        self.threadAzan.start()
        self.showImageAzan()

    def playNotif(self, time_string):
        notification.notify(title="It's time to Shalat.",
                            message=str(self.before_pray_time) +
                            " minutes before " + time_string + ' prayer time.',
                            timeout=10)
        self.threadNotif = threading.Thread(target=self._playNotif,
                                            name="Play Notif")

        self.threadNotif.start()

    def _playAzan(self):
        try:
            self.azanplay.stop()
            self.azanplay = AzanPlay(self.default_azan_wav)
            self.azanplay.play()
        except AttributeError:
            self.azanplay = AzanPlay(self.default_azan_wav)
            self.azanplay.play()

    def _playNotif(self):
        try:
            self.notifplay.stop()
            self.notifplay = AzanPlay(self.default_notif_wav)
            self.notifplay.play()
        except AttributeError:
            self.notifplay = AzanPlay(self.default_notif_wav)
            self.notifplay.play()

    def showTimes(self):
        # show label current date name
        self.ui.lblTodayName.setText('Today / ' +
                                     datetime.datetime.now().strftime('%A'))
        self.ui.lblTodayDate.setText(
            datetime.datetime.now().strftime('%d %B %Y / %H:%M'))
        self.ui.lblSunset.setText(self.time_array['sunset'])
        self.ui.lblSunrise.setText(self.time_array['sunrise'])

        # using new calculation module
        self.ui.txFajr.setText(self.time_array['fajr'].strip())
        self.ui.txDhuhr.setText(self.time_array['dhuhr'].strip())
        self.ui.txAshr.setText(self.time_array['asr'].strip())
        self.ui.txMaghrib.setText(self.time_array['maghrib'].strip())
        self.ui.txIsya.setText(self.time_array['isha'].strip())

    def init_times_new(self):
        today = datetime.date.today()
        PT = PrayTimes('MWL')
        times = PT.get_times(today,
                             (float(self.latitude), float(self.longitude)),
                             float(self.utc_offset))
        self.time_array = times

    def open_setting(self):
        # init database
        self.db = TinyDB('ayodb.json')
        self.TinyData = TinyQuery()

        # opening app setting
        try:
            setting_lines = self.db.search(self.TinyData.code == 'setting')[0]
        except IndexError:
            self.init_db()
            setting_lines = self.db.search(self.TinyData.code == 'setting')[0]

        # fileob = open(self.setting_file, 'r')
        # setting_lines = fileob.readlines()
        try:

            # open in tray
            self.open_in_tray = setting_lines['open_in_tray'] or 'False'

            # latitude
            self.latitude = setting_lines['latitude'] or -7.502814765426055

            # longitude
            self.longitude = setting_lines['longitude'] or 112.71057820736571

            # utc
            self.utc_offset = setting_lines['utc_offset'] or 7

            # calculation method
            self.calculation_method_index = int(
                setting_lines['calculation_method_index']) or 0

            self.calculation_method = self.calculation_method_array[int(
                self.calculation_method_index)]

            # time format
            self.time_format = setting_lines['time_format'] or '24h'

            # mathhab
            self.mathhab_index = int(setting_lines['mathhab_index']) or 0

            self.mathhab = self.mathhab_array[int(self.mathhab_index)]

            self.before_pray_time = setting_lines['before_pray_time']
            self.enable_notification_before = strtobool(
                setting_lines['enable_notification_before'])
            self.enable_jumah_notification = strtobool(
                setting_lines['enable_jumah_notification'])
            self.before_jumah_time = setting_lines['before_jumah_time']

            if self.open_in_tray == 'True':
                # self.hide()
                self.ui.ckStartTray.setChecked(True)
            # fileob.close()

            self.ui.txLat.setText(str(self.latitude))
            self.ui.txLong.setText(str(self.longitude))
            self.ui.txUtc.setText(str(self.utc_offset))
            self.ui.txBeforeTime.setText(str(self.before_pray_time))
            self.ui.cbMethod.setCurrentIndex(self.calculation_method_index)
            self.ui.cbMathhab.setCurrentIndex(self.mathhab_index)
            self.ui.ckNotification.setChecked(self.enable_notification_before)
            self.ui.txBeforeJumah.setText(str(self.before_jumah_time))
            self.ui.ckJumah.setChecked(self.enable_jumah_notification)

        except KeyError:
            self.init_db()
            self.open_setting()

    def init_db(self):
        # delete first data
        self.db.remove(self.TinyData.code == 'setting')
        item = {
            'code': 'setting',
            'open_in_tray': 'False',
            'latitude': -7.502814765426055,
            'longitude': 112.71057820736571,
            'utc_offset': 7,
            'calculation_method_index': 0,
            'calculation_method': '',
            'time_format': '24h',
            'mathhab_index': 0,
            'mathhab': '',
            'enable_notification_before': "False",
            'before_pray_time': 0,
            'enable_jumah_notification': "False",
            'before_jumah_time': 0,
        }
        self.db.insert(item)

    # def show_current_prayer_time(self):
    #     current_time = datetime.datetime.now()

    def closeEvent(self, event):
        self.qtray.hide()
        self.qtray.deleteLater()
        self.deleteLater()

    def reformat_ui(self):
        self.ui.txBeforeTime.hide()
        self.ui.label_7.hide()
        self.ui.txBeforeJumah.hide()
        self.ui.label_8.hide()

        icon = QIcon()
        icon.addFile(self.current_directory + u"/icon/masjid.xpm", QSize(),
                     QIcon.Normal, QIcon.Off)
        # MainWindow.setWindowIcon(icon)
        self.ui.centralwidget.setWindowIcon(icon)

        self.ui.frameSetting.setGeometry(QRect(-1, -1, 322, 461))
        self.ui.frameSetting.setStyleSheet(u"#frameSetting{\n"
                                           "	background-image:url('" +
                                           self.current_directory +
                                           "/icon/bg6-3.jpg');\n"
                                           "	background-position:center;\n"
                                           "}\n"
                                           ".QLabel{\n"
                                           "color:white;}\n")

        self.ui.frameDashboardUpper.setGeometry(QRect(-10, -1, 391, 271))
        self.ui.frameDashboardUpper.setStyleSheet(
            u"#frameDashboardUpper{\n"
            "	background-image:url('" + self.current_directory +
            "/icon/bg6-3.jpg');\n"
            "	background-position:center;\n"
            "}")

        self.ui.lblLocation.setStyleSheet(u"#lblLocation{\n"
                                          "	color:white;\n"
                                          "	background-image:url('" +
                                          self.current_directory +
                                          "/icon/location_on-24px.svg');\n"
                                          "background-position:center;\n"
                                          "}")

        self.ui.label_10.setStyleSheet(u".QLabel{\n"
                                       "	background-image:url('" +
                                       self.current_directory +
                                       "/icon/noun_Sea Sunset_395675.svg');\n"
                                       "	background-position:center;\n"
                                       "	background-repeat:no-repeat;\n"
                                       "}")

        self.ui.label_16.setStyleSheet(u".QLabel{\n"
                                       "	background-image:url('" +
                                       self.current_directory +
                                       "/icon/noun_Sunrise _395417.svg');\n"
                                       "	background-position:center;\n"
                                       "	background-repeat:no-repeat;\n"
                                       "}")

        self.ui.frame_4.setStyleSheet(u"#frame_4{\n"
                                      "	background-image:url('" +
                                      self.current_directory +
                                      "/icon/today-24px.svg');\n"
                                      "	background-repeat:no-repeat;\n"
                                      "	background-position:center;\n"
                                      "}")

        self.ui.label_11.setStyleSheet(u"background-image:url('" +
                                       self.current_directory +
                                       "/icon/alarm_on-24px.svg');\n"
                                       "background-repeat:no-repeat;\n"
                                       "background-position:right center;")

        self.ui.label_14.setStyleSheet(u"background-image:url('" +
                                       self.current_directory +
                                       "/icon/alarm_on-24px.svg');\n"
                                       "background-repeat:no-repeat;\n"
                                       "background-position:right center;")

        self.ui.label_17.setStyleSheet(u"background-image:url('" +
                                       self.current_directory +
                                       "/icon/alarm_on-24px.svg');\n"
                                       "background-repeat:no-repeat;\n"
                                       "background-position:right center;")

        self.ui.label_20.setStyleSheet(u"background-image:url('" +
                                       self.current_directory +
                                       "/icon/alarm_on-24px.svg');\n"
                                       "background-repeat:no-repeat;\n"
                                       "background-position:right center;")

        self.ui.label_23.setStyleSheet(u"background-image:url('" +
                                       self.current_directory +
                                       "/icon/alarm_on-24px.svg');\n"
                                       "background-repeat:no-repeat;\n"
                                       "background-position:right center;")

        self.ui.lblIconSetting.setStyleSheet(
            u"background-image:url('" + self.current_directory +
            "/icon/settings-24px-white.svg');\n"
            "background-repeat:no-repeat;\n"
            "background-position:left center;")

        icon1 = QIcon()
        icon1.addFile(self.current_directory + u"/icon/date_range-24px.svg",
                      QSize(), QIcon.Normal, QIcon.On)
        self.ui.btnTimeTable.setIcon(icon1)
        self.ui.btnTimeTable.setCursor(QCursor(Qt.PointingHandCursor))

        icon2 = QIcon()
        icon2.addFile(self.current_directory + u"/icon/settings-24px.svg",
                      QSize(), QIcon.Normal, QIcon.On)
        self.ui.btnSetting.setIcon(icon2)
        self.ui.btnSetting.setCursor(QCursor(Qt.PointingHandCursor))

        icon3 = QIcon()
        icon3.addFile(self.current_directory + u"/icon/hide_source-24px.svg",
                      QSize(), QIcon.Normal, QIcon.On)
        self.ui.btnHide.setIcon(icon3)
        self.ui.btnHide.setCursor(QCursor(Qt.PointingHandCursor))

        icon4 = QIcon()
        icon4.addFile(self.current_directory + u"/icon/exit_to_app-24px.svg",
                      QSize(), QIcon.Normal, QIcon.On)
        self.ui.btnExit.setIcon(icon4)
        self.ui.btnExit.setCursor(QCursor(Qt.PointingHandCursor))

        self.ui.containerSetting.setStyleSheet(
            u".QLineEdit{\n"
            "	border:none;\n"
            "	border-radius:0px;\n"
            "	background-color:whitesmoke;\n"
            "	border-bottom:1px solid gray;\n"
            "}\n"
            ".QLineEdit:focus{\n"
            "	background-color:rgb(255, 186, 97);\n"
            "}\n"
            "#containerSetting{\n"
            "	background-color: rgb(255, 255, 255);\n"
            "	border-radius:10;\n"
            "	border-style:outer;\n"
            "	border:1px solid #cbcbcb;\n"
            "}\n"
            ".QLabel{\n"
            "	color:black;\n"
            "}\n"
            ".QPushButton{\n"
            "	border-radius:2px;\n"
            "	background-color:rgb(0, 85, 127);\n"
            "	color:#fff;\n"
            "}\n"
            ".QPushButton:hover{\n"
            "	background-color:rgb(0, 135, 201);\n"
            "}\n"
            ".QCheckBox{\n"
            "	color:black;\n"
            "}\n"
            "\n"
            ".QComboBox{\n"
            "border:none;\n"
            "	border:none;\n"
            "	border-radius:0px;\n"
            "	background-color:whitesmoke;\n"
            "	border-bottom:1px solid gray;\n"
            "	selection-color: black;\n"
            "      selection-background-color: rgb(255, 186, 97);\n"
            "}\n"
            ".QComboBox:focus{\n"
            "	background-color:rgb(255, 186, 97);\n"
            "}\n"
            "\n"
            ".QComboBox::drop-down:button{\n"
            "	background-color: rgb(234,234,234);\n"
            "	width:25px;\n"
            "background-image:url('" + self.current_directory +
            "/icon/expand_more-24px.svg')\n"
            "}")
示例#5
0
class Window(QDialog):
    def __init__(self, parent=None):
        super(Window, self).__init__(parent)

        self.iconGroupBox = QGroupBox()
        self.iconLabel = QLabel()
        self.iconComboBox = QComboBox()
        self.showIconCheckBox = QCheckBox()

        self.messageGroupBox = QGroupBox()
        self.typeLabel = QLabel()
        self.durationLabel = QLabel()
        self.durationWarningLabel = QLabel()
        self.titleLabel = QLabel()
        self.bodyLabel = QLabel()

        self.typeComboBox = QComboBox()
        self.durationSpinBox = QSpinBox()
        self.titleEdit = QLineEdit()
        self.bodyEdit = QTextEdit()
        self.showMessageButton = QPushButton()

        self.minimizeAction = QAction()
        self.maximizeAction = QAction()
        self.restoreAction = QAction()
        self.quitAction = QAction()

        self.trayIcon = QSystemTrayIcon()
        self.trayIconMenu = QMenu()

        self.createIconGroupBox()
        self.createMessageGroupBox()

        self.iconLabel.setMinimumWidth(self.durationLabel.sizeHint().width())

        self.createActions()
        self.createTrayIcon()

        self.showMessageButton.clicked.connect(self.showMessage)
        self.showIconCheckBox.toggled.connect(self.trayIcon.setVisible)
        self.iconComboBox.currentIndexChanged.connect(self.setIcon)
        self.trayIcon.messageClicked.connect(self.messageClicked)
        self.trayIcon.activated.connect(self.iconActivated)

        self.mainLayout = QVBoxLayout()
        self.mainLayout.addWidget(self.iconGroupBox)
        self.mainLayout.addWidget(self.messageGroupBox)
        self.setLayout(self.mainLayout)

        self.iconComboBox.setCurrentIndex(1)
        self.trayIcon.show()

        self.setWindowTitle("Systray")
        self.resize(400, 300)

    def setVisible(self, visible):
        self.minimizeAction.setEnabled(visible)
        self.maximizeAction.setEnabled(not self.isMaximized())
        self.restoreAction.setEnabled(self.isMaximized() or not visible)
        super().setVisible(visible)

    def closeEvent(self, event):
        if not event.spontaneous() or not self.isVisible():
            return
        if self.trayIcon.isVisible():
            QMessageBox.information(
                self, "Systray",
                "The program will keep running in the system tray. "
                "To terminate the program, choose <b>Quit</b> in the context "
                "menu of the system tray entry.")
            self.hide()
            event.ignore()

    @Slot(int)
    def setIcon(self, index):
        icon = self.iconComboBox.itemIcon(index)
        self.trayIcon.setIcon(icon)
        self.setWindowIcon(icon)
        self.trayIcon.setToolTip(self.iconComboBox.itemText(index))

    @Slot(str)
    def iconActivated(self, reason):
        if reason == QSystemTrayIcon.Trigger:
            pass
        if reason == QSystemTrayIcon.DoubleClick:
            self.iconComboBox.setCurrentIndex(
                (self.iconComboBox.currentIndex() + 1) %
                self.iconComboBox.count())
        if reason == QSystemTrayIcon.MiddleClick:
            self.showMessage()

    @Slot()
    def showMessage(self):
        self.showIconCheckBox.setChecked(True)
        selectedIcon = self.typeComboBox.itemData(
            self.typeComboBox.currentIndex())
        msgIcon = QSystemTrayIcon.MessageIcon(selectedIcon)

        if selectedIcon == -1:  # custom icon
            icon = QIcon(
                self.iconComboBox.itemIcon(self.iconComboBox.currentIndex()))
            self.trayIcon.showMessage(
                self.titleEdit.text(),
                self.bodyEdit.toPlainText(),
                icon,
                self.durationSpinBox.value() * 1000,
            )
        else:
            self.trayIcon.showMessage(
                self.titleEdit.text(),
                self.bodyEdit.toPlainText(),
                msgIcon,
                self.durationSpinBox.value() * 1000,
            )

    @Slot()
    def messageClicked(self):
        QMessageBox.information(
            None, "Systray", "Sorry, I already gave what help I could.\n"
            "Maybe you should try asking a human?")

    def createIconGroupBox(self):
        self.iconGroupBox = QGroupBox("Tray Icon")

        self.iconLabel = QLabel("Icon:")

        self.iconComboBox = QComboBox()
        self.iconComboBox.addItem(QIcon(":/images/bad.png"), "Bad")
        self.iconComboBox.addItem(QIcon(":/images/heart.png"), "Heart")
        self.iconComboBox.addItem(QIcon(":/images/trash.png"), "Trash")

        self.showIconCheckBox = QCheckBox("Show icon")
        self.showIconCheckBox.setChecked(True)

        iconLayout = QHBoxLayout()
        iconLayout.addWidget(self.iconLabel)
        iconLayout.addWidget(self.iconComboBox)
        iconLayout.addStretch()
        iconLayout.addWidget(self.showIconCheckBox)
        self.iconGroupBox.setLayout(iconLayout)

    def createMessageGroupBox(self):
        self.messageGroupBox = QGroupBox("Balloon Message")

        self.typeLabel = QLabel("Type:")

        self.typeComboBox = QComboBox()
        self.typeComboBox.addItem("None", QSystemTrayIcon.NoIcon)
        self.typeComboBox.addItem(
            self.style().standardIcon(QStyle.SP_MessageBoxInformation),
            "Information",
            QSystemTrayIcon.Information,
        )
        self.typeComboBox.addItem(
            self.style().standardIcon(QStyle.SP_MessageBoxWarning),
            "Warning",
            QSystemTrayIcon.Warning,
        )
        self.typeComboBox.addItem(
            self.style().standardIcon(QStyle.SP_MessageBoxCritical),
            "Critical",
            QSystemTrayIcon.Critical,
        )
        self.typeComboBox.addItem(QIcon(), "Custom icon", -1)
        self.typeComboBox.setCurrentIndex(1)

        self.durationLabel = QLabel("Duration:")

        self.durationSpinBox = QSpinBox()
        self.durationSpinBox.setRange(5, 60)
        self.durationSpinBox.setSuffix(" s")
        self.durationSpinBox.setValue(15)

        self.durationWarningLabel = QLabel(
            "(some systems might ignore this hint)")
        self.durationWarningLabel.setIndent(10)

        self.titleLabel = QLabel("Title:")
        self.titleEdit = QLineEdit("Cannot connect to network")
        self.bodyLabel = QLabel("Body:")

        self.bodyEdit = QTextEdit()
        self.bodyEdit.setPlainText(
            "Don't believe me. Honestly, I don't have a clue."
            "\nClick this balloon for details.")

        self.showMessageButton = QPushButton("Show Message")
        self.showMessageButton.setDefault(True)

        messageLayout = QGridLayout()
        messageLayout.addWidget(self.typeLabel, 0, 0)
        messageLayout.addWidget(self.typeComboBox, 0, 1, 1, 2)
        messageLayout.addWidget(self.durationLabel, 1, 0)
        messageLayout.addWidget(self.durationSpinBox, 1, 1)
        messageLayout.addWidget(self.durationWarningLabel, 1, 2, 1, 3)
        messageLayout.addWidget(self.titleLabel, 2, 0)
        messageLayout.addWidget(self.titleEdit, 2, 1, 1, 4)
        messageLayout.addWidget(self.bodyLabel, 3, 0)
        messageLayout.addWidget(self.bodyEdit, 3, 1, 2, 4)
        messageLayout.addWidget(self.showMessageButton, 5, 4)
        messageLayout.setColumnStretch(3, 1)
        messageLayout.setRowStretch(4, 1)
        self.messageGroupBox.setLayout(messageLayout)

    def createActions(self):
        self.minimizeAction = QAction("Minimize", self)
        self.minimizeAction.triggered.connect(self.hide)

        self.maximizeAction = QAction("Maximize", self)
        self.maximizeAction.triggered.connect(self.showMaximized)

        self.restoreAction = QAction("Restore", self)
        self.restoreAction.triggered.connect(self.showNormal)

        self.quitAction = QAction("Quit", self)
        self.quitAction.triggered.connect(qApp.quit)

    def createTrayIcon(self):
        self.trayIconMenu = QMenu(self)
        self.trayIconMenu.addAction(self.minimizeAction)
        self.trayIconMenu.addAction(self.maximizeAction)
        self.trayIconMenu.addAction(self.restoreAction)
        self.trayIconMenu.addSeparator()
        self.trayIconMenu.addAction(self.quitAction)

        self.trayIcon = QSystemTrayIcon(self)
        self.trayIcon.setContextMenu(self.trayIconMenu)
示例#6
0
class Window(QDialog):
    def __init__(self, parent=None):
        super(Window, self).__init__(parent)
        self.createTrayIcon()
        self.createProgramsList()
        self.createCodeEditPage()
        self.logsPage = QTextBrowser()
        self.documentation = QTextBrowser()

        self.tabWidget = QTabWidget()
        self.tabWidget.setIconSize(QSize(64, 64))
        self.tabWidget.addTab(self.programsListPage, QIcon(":/images/Adventure-Map-icon.png"), "Programs")
        self.tabWidget.addTab(self.codeEditPage, QIcon(":/images/Sword-icon.png"), "Edit Program")
        self.tabWidget.addTab(self.logsPage, QIcon(":/images/Spell-Scroll-icon.png"), "Logs")
        self.tabWidget.addTab(self.documentation, QIcon(":/images/Spell-Book-icon.png"), "Documentation")

        self.mainLayout = QVBoxLayout()
        self.mainLayout.addWidget(self.tabWidget)
        self.setLayout(self.mainLayout)

        self.setWindowTitle(APP_NAME)
        self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.Dialog)
        self.resize(800, 600)

        self.systrayHintMsgShowed = False
        self.firstShow = True
        self.fromQuit = False

    def createProgramsList(self):
        self.programsListModel = QStandardItemModel(0, 1, self)
        self.programsList = QListView()
        self.programsList.setModel(self.programsListModel)
        self.programsListPage = QWidget()
        self.programsListLayout = QVBoxLayout()
        self.programsListButtons = QHBoxLayout()
        self.programsListButtonNew = QPushButton("New")
        self.programsListButtonDelete = QPushButton("Delete")
        self.programsListButtonEdit = QPushButton("Edit")
        self.programsListButtonSet = QPushButton("Set")
        self.programsListButtons.addWidget(self.programsListButtonNew)
        self.programsListButtons.addWidget(self.programsListButtonSet)
        self.programsListButtons.addWidget(self.programsListButtonEdit)
        self.programsListButtons.addWidget(self.programsListButtonDelete)
        self.programsListLayout.addLayout(self.programsListButtons)
        self.programsListLayout.addWidget(self.programsList)
        self.programsListPage.setLayout(self.programsListLayout)
        self.programsListButtonNew.clicked.connect(self.newProgram)
        self.programsListButtonEdit.clicked.connect(self.editProgram)
        self.programsListButtonDelete.clicked.connect(self.deleteProgram)
        self.programsListButtonSet.clicked.connect(self.setProgram)

    def createCodeEditPage(self):
        self.codeEditPage = QWidget()
        self.codeEditLayout = QVBoxLayout()
        self.codeEditNameBox = QHBoxLayout()
        self.codeEditNameBoxNameLabel = QLabel("Name:")
        self.codeEditNameBoxNameInput = QLineEdit()
        self.codeEditNameBoxSaveButton = QPushButton("Save")
        self.codeEditNameBoxCancelButton = QPushButton("Cancel")
        self.codeEditNameBox.addWidget(self.codeEditNameBoxNameLabel)
        self.codeEditNameBox.addWidget(self.codeEditNameBoxNameInput)
        self.codeEditNameBox.addWidget(self.codeEditNameBoxSaveButton)
        self.codeEditNameBox.addWidget(self.codeEditNameBoxCancelButton)
        self.codeEdit = QTextEdit()
        self.codeEditLayout.addLayout(self.codeEditNameBox)
        self.codeEditLayout.addWidget(self.codeEdit)
        self.codeEditPage.setLayout(self.codeEditLayout)
        self.codeEditLastCode = ''
        self.codeEditNameBoxSaveButton.clicked.connect(self.saveEditProgram)
        self.codeEditNameBoxCancelButton.clicked.connect(self.cancelEditProgram)

    def showEvent(self, event):
        super().showEvent(event)
        if self.firstShow:
            self.firstShow = False
            self.createWaitDialog()
            self.findKeyboard()

    def closeWaitDialog(self):
        time.sleep(1)
        self.waitDialog.close()

    @Slot()
    def newProgram(self):
        self.showNormal()
        self.tabWidget.setCurrentWidget(self.codeEditPage)
        self.codeEdit.setPlainText("")
        self.codeEditLastCode = ''
        self.codeEditNameBoxNameInput.setText("")
    
    @Slot()
    def editProgram(self):
        selected = self.programsList.selectedIndexes()
        if not selected:
            return
        selected = selected[0].data()
        loadProgram = LoadProgram(self.cmdSocket, selected)
        loadProgram.loaded.connect(self.programLoaded)
        loadProgram.start()
        self.showWaitDialog("Loading program ...")

    @Slot()
    def saveEditProgram(self):
        name = self.codeEditNameBoxNameInput.text()
        program = self.codeEdit.toPlainText()
        if not name:
            return
        editProgramWorker = EditProgram(self.cmdSocket, name, program)
        editProgramWorker.edited.connect(self.programSaved)
        editProgramWorker.start()
        self.showWaitDialog("Saving program ...")

    @Slot()
    def cancelEditProgram(self):
        self.codeEdit.setPlainText(self.codeEditLastCode)

    @Slot()
    def deleteProgram(self):
        selected = self.programsList.selectedIndexes()
        if not selected:
            return
        selected = selected[0].data()
        deleteWorker = DeleteProgram(self.cmdSocket, selected)
        deleteWorker.deleted.connect(self.programDeleted)
        deleteWorker.start()
        self.showWaitDialog("Deleting program ...")

    @Slot()
    def setProgram(self):
        selected = self.programsList.selectedIndexes()
        if not selected:
            return
        selected = selected[0].data()
        setWorker = SetProgram(self.cmdSocket, selected)
        setWorker.setDone.connect(self.programSet)
        setWorker.start()
        self.showWaitDialog("Setting program ...")

    @Slot(str, str)
    def programLoaded(self, name, program):
        self.closeWaitDialog()
        self.tabWidget.setCurrentWidget(self.codeEditPage)
        self.codeEdit.setPlainText(program)
        self.codeEditLastCode = program
        self.codeEditNameBoxNameInput.setText(name)

    @Slot(str)
    def programDeleted(self, name):
        self.updateProgramsList()

    @Slot(str)
    def programSet(self, name):
        self.updateProgramsList()

    @Slot(str)
    def programSaved(self, name):
        self.updateProgramsList()
        self.tabWidget.setCurrentWidget(self.programsListPage)

    def createWaitDialog(self):
        self.waitDialog = QDialog(self)
        self.waitDialogLayout = QHBoxLayout()
        self.waitDialogLabel = QLabel()
        self.waitDialogLayout.addWidget(self.waitDialogLabel)
        self.waitDialog.setLayout(self.waitDialogLayout)
        self.waitDialog.setWindowFlags(Qt.Dialog | Qt.FramelessWindowHint)

    def showWaitDialog(self, text='Please wait...'):
        self.waitDialogLabel.setText(text)
        self.waitDialog.exec_()

    def findKeyboard(self):
        find = ConnectKeyboard()
        find.connected.connect(self.keyboardConnected)
        find.start()
        self.showWaitDialog('Finding and connecting Fruit2Pi Keyboard ...')

    @Slot(BluetoothSocket)
    def keyboardConnected(self, socket):
        self.cmdSocket = socket
        self.updateProgramsList()
    
    def updateProgramsList(self):
        self.listProgram = ListProgram(self.cmdSocket)
        self.listProgram.listed.connect(self.programListUpdated)
        self.listProgram.start()
    
    @Slot(list, str)
    def programListUpdated(self, programs, current_program):
        print(programs)
        print(current_program)
        self.closeWaitDialog()
        self.programsListModel.clear()
        for p in programs:
            item = QStandardItem(p)
            if p == current_program:
                item.setForeground(QBrush(QColor(0, 0, 255, 127)))
            self.programsListModel.appendRow(item)

    def setVisible(self, visible):
        super().setVisible(visible)

    def closeEvent(self, event):
        if self.fromQuit:
            return
        if not event.spontaneous() or not self.isVisible():
            return
        if not self.systrayHintMsgShowed:
            self.systrayHintMsgShowed = True
            icon = QIcon(":/images/yammi-banana-icon.png")
            self.trayIcon.showMessage(APP_NAME,
                                      "Running on background"
                                      "To quit, choose <b>Quit</b> in the icon menu",
                                      icon,
                                      5000
                                      )
        self.hide()
        event.ignore()

    @Slot(str)
    def iconActivated(self, reason):
        print(reason)
        if reason == QSystemTrayIcon.Trigger:
            self.showNormal()
        if reason == QSystemTrayIcon.DoubleClick:
            self.showNormal()

    @Slot()
    def showProgramsPage(self):
        self.showNormal()
        self.tabWidget.setCurrentWidget(self.programsListPage)

    @Slot()
    def showLogsPage(self):
        self.showNormal()
        self.tabWidget.setCurrentWidget(self.logsPage)
    
    @Slot()
    def showDocumentation(self):
        self.showNormal()
        self.tabWidget.setCurrentWidget(self.documentation)

    @Slot()
    def quit(self):
        self.fromQuit = True
        qApp.quit()

    def createTrayIcon(self):
        self.showProgramsAction = QAction("Programs", self)
        self.showProgramsAction.triggered.connect(self.showProgramsPage)
        self.showNewProgramAction = QAction("New Program", self)
        self.showNewProgramAction.triggered.connect(self.newProgram)
        self.showSetProgramAction = QAction("Logs", self)
        self.showSetProgramAction.triggered.connect(self.showLogsPage)
        self.showDocumentationAction = QAction("Documentation", self)
        self.showDocumentationAction.triggered.connect(self.showDocumentation)
        self.quitAction = QAction("Quit", self)
        self.quitAction.triggered.connect(self.quit)

        self.trayIconMenu = QMenu(self)
        self.trayIconMenu.addAction(self.showProgramsAction)
        self.trayIconMenu.addAction(self.showSetProgramAction)
        self.trayIconMenu.addAction(self.showNewProgramAction)
        self.trayIconMenu.addAction(self.showDocumentationAction)
        self.trayIconMenu.addSeparator()
        self.trayIconMenu.addAction(self.quitAction)
        self.trayIcon = QSystemTrayIcon(self)

        self.trayIcon.setContextMenu(self.trayIconMenu)
        self.trayIcon.activated.connect(self.iconActivated)
        self.trayIcon.setIcon(QIcon(":/images/yammi-banana-icon.png"))
        self.trayIcon.show()
示例#7
0
class GUI(QMainWindow, Ui_MainWindow, QtStyleTools):
    ICON: QIcon
    TITLE: str = "Contour ShuttleXpress"
    WHEEL_MAP: Dict[int, QObject]
    BUTTON_MAP: List[QObject]
    LOG_COLORS = {
        logging.DEBUG: 'lightgray',
        logging.INFO: 'white',
        logging.WARNING: 'orange',
        logging.ERROR: 'red',
        logging.CRITICAL: 'purple',
    }

    def __init__(self) -> None:
        super().__init__()

        # self.load_ui()  # Broken
        # Use pyside-uic form.ui > gui.py to generate the UI instead
        self.setupUi(self)

        # Hide ASAP to avoid window flash
        self.about_widget.setHidden(True)
        self.plugins_widget.setHidden(True)
        self.config_widget.setHidden(True)
        self.log_widget.setHidden(True)

        h = LogHandler(self.append_log)
        fs = '%(levelname)-8s %(message)s'
        formatter = logging.Formatter(fs)
        h.setFormatter(formatter)
        logging.getLogger().addHandler(h)

        self.ICON = QIcon('images/icon.png')

        self.WHEEL_MAP = {
            -7: self.wheel_neg7,
            -6: self.wheel_neg6,
            -5: self.wheel_neg5,
            -4: self.wheel_neg4,
            -3: self.wheel_neg3,
            -2: self.wheel_neg2,
            -1: self.wheel_neg1,
            0: self.wheel_cent0,
            1: self.wheel_pos1,
            2: self.wheel_pos2,
            3: self.wheel_pos3,
            4: self.wheel_pos4,
            5: self.wheel_pos5,
            6: self.wheel_pos6,
            7: self.wheel_pos7,
        }
        self.BUTTON_MAP = [None, self.button_1, self.button_2, self.button_3, self.button_4, self.button_5]

        self.setWindowIcon(self.ICON)
        self.setWindowTitle(self.TITLE)
        #self.set_ms_windows_icon()
        extra = {
            # Button colors
            'danger': '#dc3545',
            'warning': '#ffc107',
            'success': '#17a2b8',

            # Font
            'font_family': 'Roboto',
        }
        self.apply_stylesheet(self, theme='dark_red.xml', extra=extra)

        # self.setWindowFlags(self.windowFlags() | Qt.Dialog | Qt.MSWindowsFixedSizeDialogHint)
        # self.statusbar.setSizeGripEnabled(False)

        self.update_status_bar("Connecting...")

        self.show()

        if QSystemTrayIcon.isSystemTrayAvailable():
            self.systray = QSystemTrayIcon()
            self.systray.setIcon(self.ICON)
            systray_menu = QMenu(title=self.TITLE, parent=self)
            quit_action = QAction("&Quit", self)
            systray_menu.addAction(quit_action)
            quit_action.triggered.connect(self.close)
            self.systray.setContextMenu(systray_menu)
            self.systray.setVisible(True)
            self.systray.activated.connect(self.handle_systray_activation)

        shuttle_signals.data.connect(self.handle_events)
        self.shuttle_worker = ShuttleWorker()
        self.shuttle_worker.start()
        self.shuttle_worker.finished.connect(self.shuttle_worker.quit)

        self.about_text.setMarkdown(f"""
Contour ShuttleXpress
=====================

A multiplatform userland driver, configuration editor, event manager & generator for Contour ShuttleXpress.

Version: `{__version__}`

Source: `{__repo__}`

Running on Python v{python_version()}

Legal notice
------------

### License

Copyright 2021-2022 Raphaël Doursenaud

This software is released under the terms of the GNU General Public License, version 3.0 or later (GPL-3.0-or-later).

### Dependencies & License Acknowledgment

**Python**

Used under the terms of the PSF License Agreement.

**libusb hidapi**

Copyright Alan Ott, Signal 11 Software.  
Used under the terms of the GNU General Public License, version 3.0 (GPL-3.0).

**Trezor cython-hidapi**  

Copyright Pavol Rusnak, SatoshiLabs.  
Used under the terms of the GNU General Public License, version 3.0 (GPL-3.0).

**Qt PySide6**

Used under the terms of the GNU Lesser General Public License v3.0 (LGPL-3.0).

**UN-GCPDS Qt-Material**

Used under the BSD-2-Clause License.

**Material Design Icons**

Used under the Pictogrammers Free License.

### Trademarks

Contour, ShuttleXpress and ShuttlePro are trademarks of Contour Innovations LLC in the United States of America.

These are not registered or active trademarks in the European Union and France where I reside.
""")
        self.about_button.clicked.connect(self.toggle_about_vis)
        self.plug_button.clicked.connect(self.toggle_plugins_vis)
        self.conf_button.clicked.connect(self.toggle_config_vis)
        self.log_button.clicked.connect(self.toggle_log_vis)
        self.log_clear_button.clicked.connect(self.clear_log)

    # def load_ui(self):
    #    loader = QUiLoader()
    #    path = os.path.join(os.path.dirname(__file__), "mainwindow.ui")
    #    ui_file = QFile(path)
    #    ui_file.open(QFile.ReadOnly)
    #    print(ui_file.readAll())
    #    loader.load(ui_file, self)
    #    ui_file.close()

    def handle_systray_activation(self, reason: QSystemTrayIcon.ActivationReason) -> None:
        if reason is QSystemTrayIcon.ActivationReason.Trigger:
            self.toggle_main_window_visibility()

    def toggle_main_window_visibility(self) -> None:
        self.hide() if self.isVisible() else self.show()

    def update_status_bar(self, message: str) -> None:
        self.statusbar.showMessage(message)

    def toggle_about_vis(self) -> None:
        self.about_widget.setVisible(self.about_widget.isHidden())

    def toggle_config_vis(self) -> None:
        self.config_widget.setVisible(self.config_widget.isHidden())

    def toggle_plugins_vis(self) -> None:
        self.plugins_widget.setVisible(self.plugins_widget.isHidden())

    def toggle_log_vis(self) -> None:
        self.log_widget.setVisible(self.log_widget.isHidden())

    @Slot(str, logging.LogRecord)
    def append_log(self, message, record):
        color = self.LOG_COLORS.get(record.levelno, 'black')
        s = f'<pre><font color="{color}">{message}</font></pre>'
        self.log_text.appendHtml(s)

    def clear_log(self) -> None:
        self.log_text.clear()

    def handle_events(self, event: Event) -> None:
        self.update_status_bar(event.desc)
        if isinstance(event, ConnectionEvent):
            self.usb_status.setChecked(True)
        elif isinstance(event, DisconnectionEvent):
            self.usb_status.setChecked(False)
        #       self.shuttle_worker.stop()
        elif isinstance(event, RotaryEvent):
            self.handle_rotary_event(event)
        elif isinstance(event, ButtonEvent):
            self.handle_button(event.element)

    def handle_rotary_event(self, rotary_event: RotaryEvent) -> None:
        if type(rotary_event.element) is Wheel:
            self.handle_wheel(rotary_event.element, rotary_event.direction, rotary_event.value)
        elif type(rotary_event.element) is Dial:
            self.handle_dial(rotary_event.element, rotary_event.direction, rotary_event.value)

    def handle_wheel(self, wheel: Wheel, direction: bool, change: int) -> None:
        self.WHEEL_MAP[wheel.pos].setChecked(True)

    def handle_dial(self, dial: Dial, direction: bool, change: int) -> None:
        self.dial.setValue(self.dial.value() + change)

    def handle_button(self, button: Button) -> None:
        self.BUTTON_MAP[button.num].setChecked(button.push)

    def closeEvent(self, event: PySide6.QtGui.QCloseEvent) -> None:
        self.shuttle_worker.stop()

    @staticmethod
    def set_ms_windows_icon() -> None:
        """
        Force Microsoft Windows to properly display the application icon in the task bar

        Workaround from: https://stackoverflow.com/a/27872625
        """
        try:
            import ctypes
            myappid = u'eu.ematech.contour.shuttlexpress'  # arbitrary string
            ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
        except AttributeError as e:
            logging.warning(f"{e}")
            pass

    @staticmethod
    def set_mac_os_title() -> None:
        """
        Force Mac OS X to properly display the app name in the title bar using PyObjC

        Workaround from: https://stackoverflow.com/a/54755290
        """
        try:
            from Foundation import NSBundle
            bundle = NSBundle.mainBundle()
            if bundle:
                app_name = GUI.TITLE
                app_info = bundle.localizedInfoDictionary() or bundle.infoDictionary()
                if app_info:
                    app_info['CFBundleName'] = app_name
        except ImportError as e:
            logging.warning(f"{e}")
            pass