예제 #1
0
class MainWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        self.setWindowTitle("Piano Manager")
        self.setFixedSize(800, 480)
        # self.showFullScreen()

        # Create Page Objects Here
        LogInPage = LogIn()
        SignUpPage = SignUp()
        InUsePage = InUse()

        # Connect pages to switch each others
        LogInPage.ui.ButtonRegister.clicked.connect(partial(
            self.switchPage, 1))
        LogInPage.ui.DButtonYes.clicked.connect(partial(self.switchPage, 2))
        SignUpPage.ui.buttonHome.clicked.connect(partial(self.switchPage, 0))
        InUsePage.ui.ButtonQuit.clicked.connect(partial(self.switchPage, 0))

        # Insert pages into QStackedWidget
        self.centralWidgets = QStackedWidget()
        self.centralWidgets.addWidget(LogInPage)  # index: 0
        self.centralWidgets.addWidget(SignUpPage)  # index: 1
        self.centralWidgets.addWidget(InUsePage)  # index: 2

        self.setCentralWidget(self.centralWidgets)

    def getCurWidget(self):
        return self.centralWidgets.currentWidget()

    def switchPage(self, idx):
        self.getCurWidget().clearPage()
        self.centralWidgets.setCurrentIndex(idx)
        self.getCurWidget().setPage()
class DatatypeSelector(QGroupBox):
    def __init__(self,
                 title: str,
                 datatype_to_widget,
                 parent: "QWidget" = None):
        super().__init__(title, parent)

        # Maps a datatype with its respective widget. The widget is optional
        self._datatype_to_widget = datatype_to_widget

        self._datatype_combobox = QComboBox()

        self._stacked_widgets = QStackedWidget()

        for (i, (name, datatype_factory)) in enumerate(
                DataTypeContainer.providers.items()):
            datatype_instance = datatype_factory()
            self._datatype_combobox.addItem(name, datatype_instance)

            if datatype_factory in self._datatype_to_widget:
                self._stacked_widgets.insertWidget(
                    i, self._datatype_to_widget[datatype_factory](
                        datatype_instance))

        self._main_layout = QVBoxLayout()
        self._main_layout.addWidget(self._datatype_combobox)
        self._main_layout.addWidget(self._stacked_widgets)

        self.setLayout(self._main_layout)

        self._datatype_combobox.currentIndexChanged[int].connect(
            self._change_active_widget)

    @property
    def selected_datatype(self):
        return self._datatype_combobox.currentData()

    def change_current_datatype(self, new_datatype_dict: dict):
        index = self._datatype_combobox.findText(new_datatype_dict["class"])

        if index != -1:
            self._datatype_combobox.setCurrentIndex(index)
            self._datatype_combobox.currentData().from_dict(new_datatype_dict)
            self._stacked_widgets.currentWidget().reload()

    def _change_active_widget(self, index):
        self._stacked_widgets.setCurrentIndex(index)

        # Hide the `stacked_widgets` when the current datatype doesn't needs to display
        # a widget
        if self._stacked_widgets.currentIndex() != index:
            self._stacked_widgets.setVisible(False)
        else:
            self._stacked_widgets.setVisible(True)

    def to_dict(self):
        return self.selected_datatype.to_dict()
예제 #3
0
class stackedExample(QWidget):
    def __init__(self):
        super(stackedExample, self).__init__()

        self.leftList = QListWidget()
        self.leftList.insertItem(0, 'Contact')
        self.leftList.insertItem(1, 'Personal')
        self.leftList.insertItem(2, 'Educational')

        self.stack_1 = QWidget()
        self.stack_2 = QWidget()
        self.stack_3 = QWidget()

        self.stack_1_UI()
        self.stack_2_UI()
        self.stack_3_UI()

        self.stack = QStackedWidget()
        self.stack.addWidget(self.stack_1)
        self.stack.addWidget(self.stack_2)
        self.stack.addWidget(self.stack_3)

        hbox = QHBoxLayout()
        hbox.addWidget(self.leftList)
        hbox.addWidget(self.stack)

        self.setLayout(hbox)
        self.leftList.currentRowChanged.connect(self.display)
        self.setGeometry(300, 50, 10, 10)
        self.setWindowTitle("Stack Widget Demo")
        self.show()

    def stack_1_UI(self):
        layout = QFormLayout()
        layout.addRow("Name", QLineEdit())
        layout.addRow("Address", QLineEdit())
        #self.setTabText(0,"Contact Details")
        self.stack_1.setLayout(layout)

    def stack_2_UI(self):
        layout = QFormLayout()
        sex = QHBoxLayout()
        sex.addWidget(QRadioButton("Male"))
        sex.addWidget(QRadioButton("Female"))
        layout.addRow(QLabel("Sex"), sex)
        layout.addRow("Date of Birth", QLineEdit())
        self.stack_2.setLayout(layout)

    def stack_3_UI(self):
        layout = QHBoxLayout()
        layout.addWidget(QLabel("subjects"))
        layout.addWidget(QCheckBox("Physics"))
        layout.addWidget(QCheckBox("Maths"))
        self.stack_3.setLayout(layout)

    def display(self, i):
        self.stack.setCurrentIndex(i)
class ControlWidget(QWidget):

    def __init__(self, status_bar):
        super().__init__()
        self.statusBar = status_bar
        self.initUI()

    def initUI(self):
        """
        Init app

        """
        self._stacked_widget = QStackedWidget()
        signal_controller = SignalSender()
        signal_controller.signal_newWindowIndx2MainWindow.connect(self.set_widget_by_index)
        signal_controller.signal_goto_settings.connect(self.set_widget_settings)

        self.grid = QGridLayout()
        self.grid.addWidget(self._stacked_widget)

        # Create log in widget
        self._log_in_widget = LogInWidget(self.statusBar, signal_controller)
        self._log_in_widget.set_index(self._stacked_widget.addWidget(self._log_in_widget))

        # Create file receiver
        self._file_receiver = FileReceiverWidget(self, signal_controller)
        self._file_receiver.set_index(self._stacked_widget.addWidget(self._file_receiver))

        # Create file sender
        self._file_sender = FileSenderWidget(self, signal_controller)
        self._file_sender.set_index(self._stacked_widget.addWidget(self._file_sender))

        # Create settings
        self._config_widget= ConfigWidget(self)
        self._config_widget.set_index(self._stacked_widget.addWidget(self._config_widget))

        self.setLayout(self.grid)
        self._stacked_widget.setCurrentIndex(self._log_in_widget.get_index())
        self.setWindowTitle("Main menu")

    def set_widget_settings(self):
        self.set_widget_by_index(self._config_widget.get_index())

    def set_widget_by_index(self, index: int):
        self._stacked_widget.setCurrentIndex(index)

    def get_status_bar(self):
        return self.statusBar
예제 #5
0
class MainWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        self.setWindowTitle("음취헌 Piano Manager")
        self.setFixedSize(800, 480)

        page_in_use = InUse()
        page_log_in = LogIn()
        page_sign_up = SignUp()

        self.widget = QStackedWidget()
        self.widget.addWidget(page_log_in)  # index 0
        self.widget.addWidget(page_in_use)  # index 1
        self.widget.addWidget(page_sign_up)  # index 2
        self.setCentralWidget(self.widget)

        page_in_use.ui.button_quit.clicked.connect(partial(
            self.switch_page, 0))

        page_log_in.ui.button_register.clicked.connect(
            partial(self.switch_page, 2))
        page_log_in.ui.dialog_true.button_yes.clicked.connect(
            partial(self.switch_page, 1))

        page_sign_up.widget(4).ui.dialog_true.button_ok.clicked.connect(
            partial(self.switch_page, 0))
        for i in range(5):
            page_sign_up.widget(i).ui.button_home.clicked.connect(
                partial(self.switch_page, 0))

    def switch_page(self, idx):
        if idx == 1:
            self.widget.widget(1).set_page(self.widget.widget(0).get_contact())
            self.widget.currentWidget().clear_page()
            self.widget.setCurrentIndex(idx)
        else:
            self.widget.currentWidget().clear_page()
            self.widget.setCurrentIndex(idx)
            self.widget.currentWidget().set_page()
예제 #6
0
class PageAllegroOptions(QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self)
        self.parent = parent
        self.parent.addWidget(self)
        self.auto_login, self.auto_pwd, self.auto_email, self.auto_time = data.get_autofill()
        self.gridLayout = QGridLayout(self)
        self.gridLayout.setContentsMargins(0, 0, 0, 0)
        self.gridLayout.setSpacing(0)
        self.gridLayout.setColumnStretch(0, 3)
        self.gridLayout.setColumnStretch(1, 7)

        self.pushButton_auto = QPushButton(self)
        self.pushButton_auto.setText("Autofill")
        self.pushButton_auto.setStyleSheet(styles.btn_allegro_ops_auto)
        self.pushButton_auto.setCheckable(True)
        self.pushButton_auto.setChecked(True)
        self.pushButton_auto.clicked.connect(lambda: self.on_auto())
        self.gridLayout.addWidget(self.pushButton_auto, 0, 0, 1, 1)

        self.pushButton_help = QPushButton(self)
        self.pushButton_help.setText("Help")
        self.pushButton_help.setStyleSheet(styles.btn_allegro_ops_auto)
        self.pushButton_help.setCheckable(True)
        self.pushButton_help.setChecked(False)
        self.pushButton_help.clicked.connect(lambda: self.on_help())
        self.gridLayout.addWidget(self.pushButton_help, 1, 0, 1, 1)

        self.spacer_btn_d = QSpacerItem(40, 20, QSizePolicy.Expanding)
        self.gridLayout.addItem(self.spacer_btn_d, 2, 0, 1, 1)

        self.stackedWidget = QStackedWidget(self)
        self.stackedWidget.setStyleSheet("""QStackedWidget{background-color: #fff;}""")
        self.gridLayout.addWidget(self.stackedWidget, 0, 1, 3, 1)

        self.widget_auto = QWidget(self.stackedWidget)
        self.widget_auto.setStyleSheet("""QWidget{background-color: #fff;}""")
        self.stackedWidget.addWidget(self.widget_auto)

        self.widget_help = QWidget(self.stackedWidget)
        self.widget_help.setStyleSheet("""QWidget{background-color: #fff;}""")
        self.stackedWidget.addWidget(self.widget_help)

        self.gridLayout_help = QVBoxLayout(self.widget_help)
        self.gridLayout_help.setContentsMargins(50, 50, 50, 50)
        self.gridLayout_help.setSpacing(50)

        self.label_help = QLabel(self.widget_help)
        self.label_help.setStyleSheet(styles.label_lineEdit)
        self.label_help.setWordWrap(True)
        self.label_help.setText(styles.help_text)
        self.gridLayout_help.addWidget(self.label_help)

        self.spacer_help = QSpacerItem(40, 20, QSizePolicy.Expanding)
        self.gridLayout_help.addItem(self.spacer_help)

        self.gridLayout_auto = QGridLayout(self.widget_auto)
        self.gridLayout_auto.setContentsMargins(0, 0, 0, 0)
        self.gridLayout_auto.setSpacing(20)
        self.gridLayout_auto.setColumnStretch(0, 1)
        self.gridLayout_auto.setColumnStretch(1, 1)
        self.gridLayout_auto.setColumnStretch(2, 1)
        self.gridLayout_auto.setColumnStretch(3, 1)
        self.gridLayout_auto.setRowStretch(0, 3)
        self.gridLayout_auto.setRowStretch(1, 1)
        self.gridLayout_auto.setRowStretch(2, 1)
        self.gridLayout_auto.setRowStretch(3, 1)
        self.gridLayout_auto.setRowStretch(4, 1)
        self.gridLayout_auto.setRowStretch(5, 1)
        self.gridLayout_auto.setRowStretch(6, 3)

        self.lineEdit_login = QLineEdit(self.widget_auto)
        self.lineEdit_login.setMinimumSize(QSize(0, 60))
        self.lineEdit_login.setSizeIncrement(QSize(40, 40))
        self.lineEdit_login.setStyleSheet(styles.lineEdit_opt)
        self.gridLayout_auto.addWidget(self.lineEdit_login, 1, 2, 1, 1)
        self.lineEdit_login.setPlaceholderText("login or email of your account")
        self.lineEdit_login.setText(self.auto_login)

        self.lineEdit_password = QLineEdit(self.widget_auto)
        self.lineEdit_password.setMinimumSize(QSize(20, 60))
        self.lineEdit_password.setStyleSheet(styles.lineEdit_opt)
        self.lineEdit_password.setEchoMode(QLineEdit.Password)
        self.lineEdit_password.setReadOnly(False)
        self.gridLayout_auto.addWidget(self.lineEdit_password, 2, 2, 1, 1)
        self.lineEdit_password.setPlaceholderText("password of your account")
        self.lineEdit_password.setText(self.auto_pwd)

        self.lineEdit_email = QLineEdit(self.widget_auto)
        self.lineEdit_email.setMinimumSize(QSize(0, 60))
        self.lineEdit_email.setStyleSheet(styles.lineEdit_opt)
        self.lineEdit_email.setFrame(True)
        self.lineEdit_email.setEchoMode(QLineEdit.Normal)
        self.gridLayout_auto.addWidget(self.lineEdit_email, 3, 2, 1, 1)
        self.lineEdit_email.setPlaceholderText("email to which the notification will be sent")
        self.lineEdit_email.setText(self.auto_email)

        self.lineEdit_time = QLineEdit(self.widget_auto)
        self.lineEdit_time.setMinimumSize(QSize(0, 60))
        self.lineEdit_time.setStyleSheet(styles.lineEdit)
        self.gridLayout_auto.addWidget(self.lineEdit_time, 4, 2, 1, 1)
        self.lineEdit_time.setPlaceholderText("interval between refreshes")
        self.lineEdit_time.setText(str(self.auto_time))

        self.label_login = QLabel("Allegro login", self)
        self.label_login.setStyleSheet(styles.label_lineEdit)
        self.gridLayout_auto.addWidget(self.label_login, 1, 1, 1, 1)

        self.label_password = QLabel("Allegro password", self)
        self.label_password.setStyleSheet(styles.label_lineEdit)
        self.gridLayout_auto.addWidget(self.label_password, 2, 1, 1, 1)

        self.label_email = QLabel("Email to notificate", self)
        self.label_email.setStyleSheet(styles.label_lineEdit)
        self.gridLayout_auto.addWidget(self.label_email, 3, 1, 1, 1)

        self.label_time = QLabel("Refresh time[s]", self)
        self.label_time.setStyleSheet(styles.label_lineEdit)
        self.gridLayout_auto.addWidget(self.label_time, 4, 1, 1, 1)

        self.pushButton_set = QPushButton("Set", self.widget_auto)
        self.pushButton_set.clicked.connect(lambda: self.on_set())
        self.pushButton_set.setMinimumSize(QSize(0, 40))
        self.pushButton_set.setStyleSheet(styles.btn_dark)
        self.gridLayout_auto.addWidget(self.pushButton_set, 5, 2, 1, 1)

        self.spacer_auto_l = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
        self.gridLayout_auto.addItem(self.spacer_auto_l, 1, 1, 1, 1)

        self.spacer_auto_r = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
        self.gridLayout_auto.addItem(self.spacer_auto_r, 1, 3, 1, 1)

        self.spacer_auto_t = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
        self.gridLayout_auto.addItem(self.spacer_auto_t, 0, 0, 1, 1)

        self.spacer_auto_b = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
        self.gridLayout_auto.addItem(self.spacer_auto_b, 6, 0, 1, 1)

    def on_set(self):
        data.add_autofill(self.lineEdit_login.text(), self.lineEdit_password.text(), self.lineEdit_email.text(), int(self.lineEdit_time.text()))
        auto_login, auto_pwd, auto_email, auto_time = data.get_autofill()
        self.parent.pageAllegroAdd.lineEdit_login.setText(auto_login)
        self.parent.pageAllegroAdd.lineEdit_password.setText(auto_pwd)
        self.parent.pageAllegroAdd.lineEdit_email.setText(auto_email)
        self.parent.pageAllegroAdd.lineEdit_time.setText(str(auto_time))

    def on_auto(self):
        self.pushButton_auto.setChecked(True)
        self.pushButton_help.setChecked(False)
        self.stackedWidget.setCurrentIndex(0)

    def on_help(self):
        self.pushButton_auto.setChecked(False)
        self.pushButton_help.setChecked(True)
        self.stackedWidget.setCurrentIndex(1)
예제 #7
0
파일: settings.py 프로젝트: cernyd/newnigma
class _ViewSwitcherWidget(QWidget):
    """Object that handles displaying of Enigma model wikis and images"""
    def __init__(self, master, regen_plug):
        """
        :param master: Qt parent object
        :param regen_plug: {callable} Regenerates settings view to new contents
        """
        super().__init__(master)

        layout = QHBoxLayout()
        self.setLayout(layout)

        # LIST OF AVAILABLE MODELS =============================================

        self.model_list = QListWidget()
        self.model_list.setMaximumWidth(150)
        self.model_list.setMinimumWidth(150)
        self.model_list.setSizePolicy(QSizePolicy.Expanding,
                                      QSizePolicy.Expanding)
        self.model_list.currentRowChanged.connect(self.select_model)

        self.regen_plug = regen_plug

        # STACKED MODEL VIEWS ==================================================

        self.stacked_wikis = QStackedWidget()
        for i, model in enumerate(VIEW_DATA):
            self.model_list.insertItem(i, model)
            description = VIEW_DATA[model]["description"]
            self.stacked_wikis.addWidget(
                _EnigmaViewWidget(self, model, description))
        self.total_models = len(VIEW_DATA)

        layout.addWidget(self.model_list)
        layout.addWidget(self.stacked_wikis)

        # Sets initially viewed
        self.currently_selected = None

    def select_model(self, i):
        """Called when the "Use this model" button is pressed
        :param i: {str} Newly selected model index
        """
        logging.info('Changing settings view to model "%s"' %
                     list(VIEW_DATA.keys())[i])
        model = list(VIEW_DATA.keys())[i]
        self.regen_plug(model)
        self.stacked_wikis.setCurrentIndex(i)

        self.model_list.blockSignals(True)
        self.model_list.setCurrentRow(i)
        self.model_list.blockSignals(False)

        self.currently_selected = model

    def highlight(self, i):
        """Highlights an option with Blue color, indicating that
        it is currently selected in EnigmaAPI
        :param i: {int} Index from list options
        """
        for index in range(self.total_models):
            item = self.model_list.item(index)
            item.setForeground(Qt.black)
            item.setToolTip(None)

        selected = self.model_list.item(i)
        selected.setBackground(Qt.gray)  # .setForeground(Qt.blue)
        selected.setToolTip("Currently used Enigma model")
예제 #8
0
 def setCurrentIndex(self, index):
     self.fader_widget = FaderWidget(self.currentWidget(),
                                     self.widget(index))
     QStackedWidget.setCurrentIndex(self, index)
예제 #9
0
class appConfigScreen(QWidget):
    keybind_signal = Signal("QObject")
    update_signal = Signal("QObject")

    def __init__(self, appName, parms={}):
        super().__init__()
        self.dbg = False
        self.level = 'user'
        exePath = sys.argv[0]
        if os.path.islink(sys.argv[0]):
            exePath = os.path.realpath(sys.argv[0])
        baseDir = os.path.abspath(os.path.dirname(exePath))
        os.chdir(baseDir)
        self.rsrc = "%s/rsrc" % baseDir
        self.parms = parms
        self.modules = []
        self.appName = appName
        self.textDomain = self.appName.lower().replace(" ", "_")
        gettext.textdomain('{}'.format(self.textDomain))
        _ = gettext.gettext
        self.wikiPage = appName
        self.background = "%s/background.png" % self.rsrc
        self.banner = "%s/%s" % (self.rsrc, "banner.png")
        self.last_index = 0
        self.stacks = {0: {'name': _("Options"), 'icon': 'icon'}}
        self.appConfig = appConfig()
        self.config = {}

    #def init

    def _debug(self, msg):
        if self.dbg:
            print("%s" % msg)

    #def _debug

    def setWiki(self, url):
        self.wikiPage = url

    #def setWiki

    def setTextDomain(self, textDomain):
        self.textDomain = textDomain

    #def setTextDomain

    def setRsrcPath(self, rsrc):
        if os.path.isdir(rsrc):
            self.rsrc = rsrc
        else:
            self._debug("%s doesn't exists")
        self._debug("Resources dir: %s" % self.rsrc)

    #def setRsrcPath

    def setIcon(self, icon):
        self._debug("Icon: %s" % icon)
        icn = icon
        if not os.path.isfile(icon):
            sw_ko = False
            self._debug("%s not found" % icon)
            if QtGui.QIcon.fromTheme(icon):
                icn = QtGui.QIcon.fromTheme(icon)
                if icn.name() == "":
                    self._debug("%s not present at theme" % icon)
                    sw_ko = True
                else:
                    self._debug("%s found at theme" % icon)
                    self._debug("Name: %s found at theme" % icn.name())
            elif os.path.isfile("%s/%s" % (self.rsrc, icon)):
                icon = "%s/%s" % (self.rsrc, icon)
                self._debug("%s found at rsrc folder" % icon)
                icn = QtGui.QIcon(icon)
            else:
                icn = QtGui.QIcon.fromTheme("application-menu")
                self._debug("Icon not found at %s" % self.rsrc)
            if sw_ko:
                icn = QtGui.QIcon.fromTheme("application-menu")
                self._debug("Icon %s not found at theme" % icon)
        self.setWindowIcon(icn)

    #def setIcon

    def setBanner(self, banner):
        if not os.path.isfile(banner):
            if os.path.isfile("%s/%s" % (self.rsrc, banner)):
                banner = "%s/%s" % (self.rsrc, banner)
            else:
                banner = ""
                self._debug("Banner not found at %s" % self.rsrc)
        self.banner = banner

    #def setBanner

    def setBackgroundImage(self, background):
        if not os.path.isfile(background):
            if os.path.isfile("%s/%s" % (self.rsrc, background)):
                background = "%s/%s" % (self.rsrc, background)
            else:
                background = ""
                self._debug("Background not found at %s" % self.rsrc)
        self.background = background

    #def setBanner

    def setConfig(self, confDirs, confFile):
        self.appConfig.set_baseDirs(confDirs)
        self.appConfig.set_configFile(confFile)

    #def setConfig(self,confDirs,confFile):

    def _searchWiki(self):
        url = ""
        baseUrl = "https://wiki.edu.gva.es/lliurex/tiki-index.php?page="
        if self.wikiPage.startswith("http"):
            url = self.wikiPage
        else:
            url = "%s%s" % (baseUrl, self.wikiPage)
        #try:
        #	req=Request(url)
        #	content=urlopen(req).read()
        #except:
        #	self._debug("Wiki not found at %s"%url)
        #	url=""
        return (url)

    #def _searchWiki

    def _get_default_config(self):
        data = {}
        data = self.appConfig.getConfig('system')
        self.level = data['system'].get('config', 'user')
        if self.level != 'system':
            data = self.appConfig.getConfig(self.level)
            level = data[self.level].get('config', 'n4d')
            if level != self.level:
                self.level = level
                data = self.appConfig.getConfig(level)
                data[self.level]['config'] = self.level

        self._debug("Read level from config: %s" % self.level)
        return (data)

    #def _get_default_config(self,level):

    def getConfig(self, level=None, exclude=[]):
        data = self._get_default_config()
        if not level:
            level = self.level
        if level != 'system':
            data = {}
            data = self.appConfig.getConfig(level, exclude)
        self.config = data.copy()
        self._debug("Read level from config: %s" % level)
        return (data)

    #def getConfig(self,level):

    def Show(self):
        if self.config == {}:
            self.getConfig()
        self.setStyleSheet(self._define_css())
        if os.path.isdir("stacks"):
            for mod in os.listdir("stacks"):
                if mod.endswith(".py"):
                    mod_name = mod.split(".")[0]
                    mod_import = "from stacks.%s import *" % mod_name
                    try:
                        exec(mod_import)
                        self.modules.append(mod_name)
                        self._debug("Load stack %s" % mod_name)
                    except Exception as e:
                        #						self._debug("Unable to load %s: %s"%(mod_name,e))
                        print("Unable to load %s: %s" % (mod_name, e))
        idx = 1
        for mod_name in self.modules:
            try:
                mod = eval("%s(self)" % mod_name)
            except Exception as e:
                #				self._debug("Import failed for %s: %s"%(mod_name,e))
                print("Import failed for %s: %s" % (mod_name, e))
                continue
            if type(mod.index) == type(0):
                if mod.index > 0:
                    idx = mod.index
            try:
                if mod.enabled == False:
                    continue
            except:
                pass
            while idx in self.stacks.keys():
                idx += 1
                self._debug("New idx for %s: %s" % (mod_name, idx))
            if 'parm' in mod.__dict__.keys():
                try:
                    if mod.parm:
                        self._debug("Setting parms for %s" % mod_name)
                        self._debug("self.parms['%s']" % mod.parm)
                        mod.apply_parms(eval("self.parms['%s']" % mod.parm))
                except Exception as e:
                    self._debug("Failed to pass parm %s to %s: %s" %
                                (mod.parm, mod_name, e))
            try:
                mod.setTextDomain(self.textDomain)
            except Exception as e:
                print("Can't set textdomain for %s: %s" % (mod_name, e))
            try:
                mod.setAppConfig(self.appConfig)
            except Exception as e:
                print("Can't set appConfig for %s: %s" % (mod_name, e))
            try:
                if mod.visible == False:
                    visible = False
                else:
                    visible = True
            except:
                visible = True
            self.stacks[idx] = {
                'name': mod.description,
                'icon': mod.icon,
                'tooltip': mod.tooltip,
                'module': mod,
                'visible': visible
            }
            try:
                mod.message.connect(self._show_message)
            except:
                pass
        self._render_gui()
        return (False)

    def _render_gui(self):
        self.getConfig()
        box = QGridLayout()
        img_banner = QLabel()
        if os.path.isfile(self.banner):
            img = QtGui.QPixmap(self.banner)
            img_banner.setPixmap(img)
        img_banner.setAlignment(Qt.AlignCenter)
        img_banner.setObjectName("banner")
        box.addWidget(img_banner, 0, 0, 1, 2)
        self.lst_options = QListWidget()
        self.stk_widget = QStackedWidget()
        idx = 0
        if len(self.stacks) > 2:
            l_panel = self._left_panel()
            box.addWidget(l_panel, 1, 0, 1, 1, Qt.Alignment(1) | Qt.AlignTop)
        #	self.stk_widget.setCurrentIndex(0)
        else:
            idx = 1
        #	self.stk_widget.setCurrentIndex(1)
        r_panel = self._right_panel()
        self.stk_widget.setCurrentIndex(idx)
        #self.gotoStack(idx,"")
        box.addWidget(r_panel, 1, 1, 1, 1)
        self.setLayout(box)
        self.show()

    #def _render_gui

    def _left_panel(self):
        panel = QWidget()
        box = QVBoxLayout()
        btn_menu = QPushButton()
        icn = QtGui.QIcon.fromTheme("application-menu")
        btn_menu.setIcon(icn)
        btn_menu.setIconSize(QSize(BTN_MENU_SIZE, BTN_MENU_SIZE))
        btn_menu.setMaximumWidth(BTN_MENU_SIZE)
        btn_menu.setMaximumHeight(BTN_MENU_SIZE)
        btn_menu.setToolTip(_("Options"))
        btn_menu.setObjectName("menuButton")
        #		box.addWidget(btn_menu,Qt.Alignment(1))
        indexes = []
        for index, option in self.stacks.items():
            idx = index
            lst_widget = QListWidgetItem()
            lst_widget.setText(option['name'])
            mod = option.get('module', None)
            if mod:
                try:
                    idx = mod.index
                except:
                    pass
            if idx > 0:
                icn = QtGui.QIcon.fromTheme(option['icon'])
                lst_widget.setIcon(icn)
                if 'tooltip' in option.keys():
                    lst_widget.setToolTip(option['tooltip'])
                while idx in indexes:
                    idx += 1
                indexes.append(index)
            self.stacks[idx]['widget'] = lst_widget
        orderedStacks = {}
        orderedStacks[0] = self.stacks[0]
        #self.lst_options.addItem(orderedStacks[0]['widget'])
        cont = 0
        indexes.sort()
        for index in indexes:
            if index:
                orderedStacks[cont] = self.stacks[index].copy()
                if self.stacks[index].get('visible', True) == True:
                    self.lst_options.addItem(orderedStacks[cont]['widget'])
                cont += 1

        self.stacks = orderedStacks.copy()
        box.addWidget(self.lst_options)
        self.lst_options.currentRowChanged.connect(self._show_stack)
        self.lst_options.setCurrentIndex(QModelIndex())
        self.last_index = None
        panel.setLayout(box)
        self.resize(self.size().width() + box.sizeHint().width(),
                    self.size().height() + box.sizeHint().height() / 2)
        self.lst_options.setFixedSize(
            self.lst_options.sizeHintForColumn(0) + 2 *
            (self.lst_options.frameWidth() + 15), self.height()
        )  #self.lst_options.sizeHintForRow(0) * self.lst_options.count() + 2 * (self.lst_options.frameWidth()+15))

        return (panel)

    #def _left_panel

    def _right_panel(self):
        panel = QWidget()
        box = QVBoxLayout()
        idx = 0
        text = [
            _("Welcome to the configuration of ") + self.appName,
            _("From here you can:<br>")
        ]
        orderIdx = list(self.stacks.keys())
        for idx in orderIdx:
            data = self.stacks[idx]
            stack = data.get('module', None)
            if stack:
                stack.setLevel(self.level)
                stack.setConfig(self.config)
                stack._load_screen()

                if self.stacks[idx].get('visible', True) == True:
                    text.append(
                        "&nbsp;*&nbsp;<a href=\"appconf://%s\"><span style=\"font-weight:bold;text-decoration:none\">%s</span></a>"
                        % (idx + 1, stack.menu_description))
                try:
                    self.stk_widget.insertWidget(idx, stack)
                except:
                    self.stk_widget.insertWidget(idx, stack.init_stack())
        stack = QWidget()
        stack.setObjectName("panel")
        s_box = QVBoxLayout()
        lbl_txt = QLabel()
        lbl_txt.setTextFormat(Qt.RichText)
        lbl_txt.setText("<br>".join(text))
        lbl_txt.linkActivated.connect(self._linkStack)
        lbl_txt.setObjectName("desc")
        lbl_txt.setAlignment(Qt.AlignTop)
        lbl_txt.setTextInteractionFlags(Qt.TextBrowserInteraction)
        s_box.addWidget(lbl_txt, 1)
        #Get wiki page
        url = self._searchWiki()
        if url:
            desc = _("Wiki help")
            lbl_wiki = QLabel(
                "<a href=\"%s\"><span style=\"text-align: right;\">%s</span></a>"
                % (url, desc))
            lbl_wiki.setOpenExternalLinks(True)
            s_box.addWidget(lbl_wiki, 0, Qt.AlignRight)
        stack.setLayout(s_box)
        self.stk_widget.insertWidget(0, stack)
        #self.stacks[0]['module']=stack

        box.addWidget(self.stk_widget)
        panel.setLayout(box)
        return (panel)

    #def _right_panel

    def _linkStack(self, *args):
        stack = args[0].split('/')[-1]
        self.gotoStack(int(stack), '')

    def gotoStack(self, idx, parms):
        self._show_stack(idx=idx, parms=parms)

    def _show_stack(self, item=None, idx=None, parms=None):
        if (self.last_index == abs(self.lst_options.currentRow())
                and (idx == self.last_index
                     or isinstance(item, int))):  # or self.last_index==None)):
            return

        if isinstance(
                self.stacks.get(self.last_index, {}).get('module', None),
                appConfigStack) == True:
            if self.stacks[self.last_index]['module'].getChanges():
                if self._save_changes(self.stacks[self.last_index]
                                      ['module']) == QMessageBox.Cancel:
                    self.lst_options.setCurrentRow(self.last_index)
                    return
                else:
                    self.stacks[self.last_index]['module'].setChanged(False)
            self.stacks[self.last_index]['module'].initScreen()
            if self.stacks[self.last_index]['module'].refresh:
                self._debug("Refresh config")
                self.getConfig()
        else:
            self._debug(self.stacks.get(self.last_index, {}).get('module'))
            self.last_index = 0
        if isinstance(idx, int) == False:
            idx = self.lst_options.currentRow() + 1
        self.last_index = idx - 1
        try:
            self.stacks[idx]['module'].setConfig(self.config)
        except:
            pass
        self.stk_widget.setCurrentIndex(idx)
        #		self.statusBar.hide()
        if parms:
            self.stacks[idx]['module'].setParms(parms)

    #def _show_stack

    def closeEvent(self, event):
        try:
            if self.stacks[self.last_index]['module'].getChanges():
                if self._save_changes(self.stacks[self.last_index]
                                      ['module']) == QMessageBox.Cancel:
                    event.ignore()
        except:
            pass

    def _show_message(self, msg, status=None):
        return


#		self.statusBar.setText(msg)
#		if status:
#			self.statusBar.show(status)
#		else:
#		self.statusBar.show(status)
#def _show_message

    def _save_changes(self, module):
        dia = QMessageBox(
            QMessageBox.Question, _("Apply changes"),
            _("There're changes not saved at current screen.\nDiscard them and continue?"
              ), QMessageBox.Discard | QMessageBox.Cancel, self)
        return (dia.exec_())

    def _define_css(self):
        css = """
		QPushButton{
			padding: 6px;
			margin:6px;
			font: 14px Roboto;
		}
		QPushButton#menu:active{
			background:none;
		}
		QStatusBar{
			background:red;
			color:white;
			font: 14px Roboto bold;
		}
		QLabel{
			padding:6px;
			margin:6px;
		}
	
		#dlgLabel{
			font:12px Roboto;
			margin:0px;
			border:0px;
			padding:3px;
		}
		
		QLineEdit{
			border:0px;
			border-bottom:1px solid grey;
			padding:1px;
			font:14px Roboto;
			margin-right:6px;
		}
		#panel{
			background-image:url("%s");
			background-size:stretch;
			background-repeat:no-repeat;
			background-position:center;
		}
		#desc{
			background-color:rgba(255,255,255,0.7);
			color:black;
		}
		#banner{
			padding:1px;
			margin:1px;
			border:0px;
		}
		""" % self.background
        return (css)
예제 #10
0
class UpdatePrompt(QDialog):
    def __init__(self):
        super().__init__()
        self.makeView()
        return

    def makeView(self):
        layout = QVBoxLayout()
        btnLayout = QHBoxLayout()
        self.centStack = QStackedWidget()
        self.updateButton = QPushButton('Update')
        self.cancelButton = QPushButton('Cancel')
        notifyLabel = QLabel('There are upgrades scheduled')
        self.inputBox = QLineEdit()
        self.outputBox = QTextBrowser()
        #refreshIcon = QIcon.fromTheme('process-working')
        self.refreshIcon = QMovie('assets/spin3.gif')
        refreshAnimation = QLabel()

        layout.addWidget(notifyLabel)
        layout.addWidget(self.centStack)
        layout.addWidget(self.inputBox)
        layout.addLayout(btnLayout)
        btnLayout.addWidget(self.cancelButton)
        btnLayout.addWidget(self.updateButton)

        self.centStack.addWidget(refreshAnimation)
        self.centStack.addWidget(self.outputBox)
        refreshAnimation.setMovie(self.refreshIcon)
        refreshAnimation.setAlignment(Qt.AlignCenter)
        self.refreshIcon.start()

        self.inputBox.setEchoMode(QLineEdit.Password)
        self.inputBox.setFocus()
        self.inputBox.returnPressed.connect(self.pkgUpdates)
        self.updateButton.clicked.connect(self.pkgUpdates)
        self.cancelButton.clicked.connect(self.cancelUpdates)
        self.updateButton.setDefault(True)

        self.centStack.setCurrentIndex(1)
        notifyLabel.setAlignment(Qt.AlignTop)
        self.outputBox.setReadOnly(True)
        #self.outputBox.setAlignment(Qt.AlignTop)
        self.setWindowTitle('Package Upgrades')
        self.setLayout(layout)
        self.resize(450, 250)
        return

    async def asetup(self, password):
        async with trio.open_nursery() as nursery:
            finishedState = trio.Event()
            nursery.start_soon(self.upProc, password, 'update', finishedState)
            #nursery.start_soon(self.KEAlive, finishedState)
        return

    async def upProc(self, password, cmd, finishedState):
        proc = await trio.open_process(['sudo', '-S', 'apt-get', cmd, '-y'],
                                       stdin=subprocess.PIPE,
                                       stdout=subprocess.PIPE,
                                       stderr=subprocess.STDOUT)
        await proc.stdin.send_all((password + '\n').encode())

        while (proc.poll() == None):
            QCoreApplication.processEvents()
            await trio.sleep(0.1)

        result = ''
        result = await self.pullOutput(proc)
        self.appendToOutput(result)
        proc.terminate()

        if (cmd == 'update'):
            await self.upProc(password, 'upgrade', finishedState)
            finishedState.set()
        return

    async def pullOutput(self, proc):
        x = await proc.stdout.receive_some()
        x = x.decode()
        result = ''
        while (x != ''):
            QCoreApplication.processEvents()
            result = result + x
            x = await proc.stdout.receive_some()
            x = x.decode()
        return result

    async def KEAlive(self, finishedState):
        while finishedState.is_set():
            QCoreApplication.processEvents()
            trio.sleep(0.1)
        return

        return

    def appendToOutput(self, add):
        currentText = self.outputBox.toPlainText()
        self.outputBox.setText(currentText + 'Running updates\n' + add + '\n')
        print(add)
        return

    def pkgUpdates(self):
        self.centStack.setCurrentIndex(0)
        self.refreshIcon.start()
        QCoreApplication.processEvents()

        password = self.inputBox.text()

        if (password == ''):
            self.passError('The password field cannot be empty')
            return

        self.inputBox.clear()
        self.inputBox.setDisabled(True)
        self.updateButton.setDisabled(True)
        trio.run(self.asetup, password)
        self.centStack.setCurrentIndex(1)
        self.refreshIcon.stop()
        self.updateButton.setDisabled(False)
        self.inputBox.setDisabled(False)
        return

    def passError(self, s):
        passError = QDialog(self)
        msg = QLabel(s)
        layout = QVBoxLayout()
        layout.addWidget(msg)
        passError.setLayout(layout)

        okBtn = QPushButton('OK')
        okBtn.clicked.connect(passError.reject)
        layout.addWidget(okBtn)

        passError.exec_()
        return

    def cancelUpdates(self):
        #Needs way of closing subprocess during async run
        self.reject()
        return
예제 #11
0
class UIStackedWidget(object):
    '''
    By default:

             QWidget or QDockWidget
    +----------------------------------------------------------+
    |        QVBoxLayout                                       |
    |   +---------------------------------------------------+  |
    |   |                                                   |  |
    |   |    +-------------------------------------------+  |  |
    |   |    |   QList                                   |  |  |
    |   |    |                                           |  |  |
    |   |    |                                           |  |  |
    |   |    +-------------------------------------------+  |  |
    |   |    +-------------------------------------------+  |  |
    |   |    |   QStackedWidget                          |  |  |
    |   |    |                                           |  |  |
    |   |    |                                           |  |  |
    |   |    +-------------------------------------------+  |  |
    |   |                                                   |  |
    |   +---------------------------------------------------+  |
    |                                                          |
    +----------------------------------------------------------+

    or if layout = horizontal:

             QWidget or QDockWidget
    +----------------------------------------------------------+
    |        QHBoxLayout                                       |
    |   +---------------------------------------------------+  |
    |   |                                                   |  |
    |   |    +--------------+   +------------------------+  |  |
    |   |    |   QList      |   |  QStackedWidget        |  |  |
    |   |    |              |   |                        |  |  |
    |   |    |              |   |                        |  |  |
    |   |    +--------------+   +------------------------+  |  |
    |   |                                                   |  |
    |   +---------------------------------------------------+  |
    |                                                          |
    +----------------------------------------------------------+


    '''
    def createStack(self, layout='vertical'):
        self.stack_list = QListWidget()
        self.list_margin_size = 11

        self.Stack = QStackedWidget(self)
        self.layout_type = layout

        if self.layout_type == 'horizontal':
            box = QHBoxLayout(self)
            self.list_margin_size = 18
            self.stack_list.setStyleSheet(
                "margin-top: {size}px".format(size=self.list_margin_size))
        else:
            box = QVBoxLayout(self)
            self.stack_list.setStyleSheet(
                "margin-left : {size}px; margin-right : {size2}px".format(
                    size=self.list_margin_size,
                    size2=self.list_margin_size + 1))

        box.addWidget(self.stack_list)
        box.addWidget(self.Stack)
        box.setAlignment(self.stack_list, Qt.AlignTop)

        self.setLayout(box)
        self.stack_list.currentRowChanged.connect(self.display)

        self.tabs = {}

        self.num_tabs = 0
        self.widgets = {}

    def display(self, i):
        self.Stack.setCurrentIndex(i)

    def currentIndex(self):
        return self.Stack.currentIndex()

    def addTab(self, title, widget='form'):
        self.stack_list.addItem(title)

        if widget == 'form':
            widget = UIFormFactory.getQWidget(self)

        self.Stack.addWidget(widget)
        self.tabs[title] = widget
        self.num_tabs += 1
        height_multiplier = self.num_tabs + 1
        if self.layout_type != 'vertical':
            height_multiplier += 1
            self.stack_list.setMaximumWidth(
                self.stack_list.sizeHintForColumn(0) * 1.2 +
                self.list_margin_size * 2)
            self.stack_list.setMaximumHeight(
                self.stack_list.sizeHintForRow(0) * height_multiplier +
                self.list_margin_size * 2)
        self.stack_list.setMaximumHeight(
            self.stack_list.sizeHintForRow(0) * height_multiplier)

    def addTabs(self, titles):
        for title in titles:
            self.addTab(title=title)
예제 #12
0
class Window(QMainWindow, WindowMenu, Plots):
    def __init__(self, parent=None):
        super(Window, self).__init__(parent)
        self.setWindowTitle("Leak Detection Evaluation Form")
        self.main_style_qss = "Eclippy.qss"
        self._main_widget = QWidget(self)
        self._main_layout = QVBoxLayout(self._main_widget)
        self._form_widget = QWidget(self)
        self._form_layout = QVBoxLayout(self._form_widget)
        self._database_widget = QWidget(self)
        self._database_layout = QVBoxLayout(self._database_widget)
        self._database_table_label = QLabel()
        self._database_table_label.setObjectName("dbtablelabel")
        self._database_table_label.setStyleSheet(
            'QLabel[objectName^="dbtablelabel"] {font-size: 12pt; font-weight: bold;}'
        )
        self._database_table_export_button = QPushButton("Export Table (CSV)")
        self._database_table_export_button.clicked.connect(
            self.exportDatabaseTable)
        database_table_export_row = QWidget()
        database_table_export_lay = QHBoxLayout(database_table_export_row)
        database_table_export_lay.setContentsMargins(0, 0, 0, 0)
        database_table_export_lay.addWidget(HorizontalFiller())
        database_table_export_lay.addWidget(self._database_table_export_button)

        self._database_layout.addWidget(self._database_table_label)
        self._database_table = DataTable(use_max_height=False)
        self._database_layout.addWidget(self._database_table)
        self._database_layout.addWidget(database_table_export_row)
        self._main_tabs = QTabWidget(self)
        self._main_layout.addWidget(self._main_tabs)
        self._main_tabs.addTab(self._form_widget, "Form")
        self._main_tabs.addTab(self._database_widget, "Database")

        snwa_logo = QPixmap("snwa_logo.png")
        self._logo = QLabel(self)
        self._logo.setPixmap(snwa_logo)
        search_row = QWidget(self)
        search_lay = QHBoxLayout(search_row)
        search_lay.addWidget(self._logo)

        self._search_toolbar = QToolBar(self)
        self._new_rec_button = QPushButton("Create New Record")
        self._new_rec_button.clicked.connect(self.createNewRecord)
        self._new_rec_button.setIcon(QIcon(QPixmap("plus.png")))

        self._search_toolbar.addWidget(self._new_rec_button)

        # Database
        DB_LOC = "LeakDetectionDatabase.db"
        self._database = SQLiteLib(DB_LOC)

        self.setTabs()
        Plots.__init__(self)

        self._data_table_label = QLabel("Client Table")
        self._data_table = DataTable(1, 1, self)

        search_bars = self.setSearchBars()
        search_bars.setContentsMargins(0, 0, 0, 0)
        search_lay.setContentsMargins(0, 0, 0, 0)
        search_lay.addWidget(search_bars)
        search_lay.addWidget(HorizontalFiller(self))
        self.readDataFromDatabase()

        self._ap_phase_widget = Client.AP_PHASE_ID.value
        self._address_widget = Client.ADDRESS.value
        self._main_tabs.currentChanged.connect(self.mainTabChange)
        self._ap_phase_widget.returnPressed.connect(
            self.checkApPhaseIDsInDatabase)

        # Layout -----------------------------------

        # Docks
        self._form_menu_dock = QDockWidget("Form Selections", self)
        self._form_menu_dock.setAllowedAreas(Qt.LeftDockWidgetArea
                                             | Qt.RightDockWidgetArea)
        self._form_menu_dock.setFeatures(self._form_menu_dock.features()
                                         & ~QDockWidget.DockWidgetClosable)
        self._form_menu_dock.setWidget(self._form_menu)
        self.addDockWidget(Qt.LeftDockWidgetArea, self._form_menu_dock)

        self._plot_menu_dock = QDockWidget(
            "Plotted Data (Double Click to Activate Chart)", self)
        self._plot_menu_dock.setAllowedAreas(Qt.LeftDockWidgetArea
                                             | Qt.RightDockWidgetArea)
        self._plot_menu_dock.setWidget(self._plot_menu)
        self.addDockWidget(Qt.RightDockWidgetArea, self._plot_menu_dock)

        WindowMenu.__init__(self)

        # Tabs
        form_area = QWidget(self)
        form_lay = QVBoxLayout(form_area)
        form_lay.addWidget(search_row)
        form_lay.addWidget(self._search_toolbar)
        form_lay.addWidget(BreakLine(self))
        form_lay.addWidget(self._tab_label)
        form_lay.addWidget(self._tabs)
        form_lay.addWidget(self._data_table_label)
        form_lay.addWidget(self._data_table)
        form_lay.setContentsMargins(0, 0, 0, 0)

        self._form_layout.addWidget(form_area)
        self.updateDataTable()

        self.setCentralWidget(self._main_widget)

    def closeEvent(self, event):
        for plot_name in self._plots:
            if self._plots[plot_name].isVisible():
                self._plots[plot_name].close()
        if self._search_window != None and self._search_window.isVisible():
            self._search_window.close()

    def setSearchBars(self):
        self._database.openDatabase()

        self._search_apPhase_combo = ExtendedComboBox(self)
        self._search_address_combo = ExtendedComboBox(self)
        search_data = getAddresses(
            self._database.getValuesFrom2Fields(Tables.CLIENT.name,
                                                Client.ADDRESS.name,
                                                Client.AP_PHASE_ID.name))
        self._search_ap_phase_ids = [value[1] for value in search_data]
        search_addresses = [value[0] for value in search_data]
        self._search_apPhase_combo.addItems(self._search_ap_phase_ids)
        self._search_address_combo.addItems(search_addresses)
        self._search_apPhase_combo.currentIndexChanged.connect(
            self.apPhaseComboChange)
        self._search_apPhase_combo.currentTextChanged.connect(
            self.newSearchApCombo)
        self._search_address_combo.currentIndexChanged.connect(
            self.addressComboChange)
        self._search_address_combo.currentTextChanged.connect(
            self.newSearchAdrCombo)
        self._new = False
        self._ap_phase_change = False
        self._address_change = False

        self._database.closeDatabase()

        bot_menu = QWidget(self)
        bot_menu_layout = QFormLayout(bot_menu)
        bot_menu.setStyleSheet("QLabel { font-weight: bold; }")
        bot_menu_layout.addRow("Search ApPhase ID:",
                               self._search_apPhase_combo)
        bot_menu_layout.addRow("Search Address:", self._search_address_combo)
        return bot_menu

    def setTabs(self):
        #self._tabs = QTabWidget(self)
        self._tab_label = QLabel("Client", self)
        self._tab_label.setObjectName("tablabel")
        self._tab_label.setStyleSheet(
            'QLabel[objectName^="tablabel"] {font-size: 12pt; font-weight: bold;}'
        )
        self._tabs = QStackedWidget(self)
        table_names = []
        for table in Tables:
            table_name = table.value.getTabName()
            table_names.append(table_name)
            table.value.setTab(self, self._database)
            table.value.setFormParent(self)

            #self._tabs.addTab(table.value, table_name)
            self._tabs.addWidget(table.value)
        self._form_menu = FormMenu(item_names=table_names, parent=self)
        self._form_menu.currentRowChanged.connect(self.selectMenuItemChange)

    def selectMenuItemChange(self, index):
        self._tabs.setCurrentIndex(index)
        text = self._form_menu.currentItem().text()
        self._tab_label.setText(text)
        self._data_table_label.setText(text + " Table")
        self.updateDataTable()
        self.updateDatabaseTable()

    def updateDataTable(self):
        self._data_table.setRowCount(0)
        self._data_table.setRowCount(1)
        data = self._tabs.currentWidget()

        fields = data.getFields()
        values = data.getValues()
        col_count = len(values)
        self._data_table.setColumnCount(col_count)
        for col, (field, value) in enumerate(zip(fields, values)):
            header = QTableWidgetItem(field)
            item = QTableWidgetItem(str(value))
            self._data_table.setHorizontalHeaderItem(col, header)
            self._data_table.setItem(0, col, item)

        #self._data_table.resizeColumnsToContents()
        self._data_table.verticalHeader().setStretchLastSection(True)

    def readDataFromDatabase(self):
        for table in Tables:
            table.value.readDataIntoForm(
                self._search_apPhase_combo.currentText())

    def setApPhaseChangeCheck(self, change):
        self._ap_phase_change = change
        for table in Tables:
            table.value._ap_phase_change = change

    def setAddressChangeCheck(self, change):
        self._address_change = change
        for table in Tables:
            table.value._address_change = change

    def setNewForTables(self, new_val):
        self._new = new_val
        for table in Tables:
            table.value._new = new_val

    def apPhaseComboChange(self):
        if not self._address_change:
            self.setApPhaseChangeCheck(True)
            self.clearForm()
            self.readDataFromDatabase()
            self._search_address_combo.setCurrentIndex(
                self._search_apPhase_combo.currentIndex())
            self.updateDataTable()
            self.setNewForTables(False)
            self.setApPhaseChangeCheck(False)

    def addressComboChange(self):
        if not self._ap_phase_change:
            self.setAddressChangeCheck(True)
            self.clearForm()
            self._search_apPhase_combo.setCurrentIndex(
                self._search_address_combo.currentIndex())
            self.readDataFromDatabase()
            self.updateDataTable()
            self.setNewForTables(False)
            self.setAddressChangeCheck(False)

    def newSearchApCombo(self):
        if not self._address_change and self._search_apPhase_combo.currentText(
        ) == "":
            self._ap_phase_change = True
            Tables.CLIENT.value._ap_phase_change = True
            self._search_address_combo.setCurrentText("")
            self._ap_phase_widget.setPlaceholderText("Enter new ApPhase ID...")
            self._address_widget.setPlaceholderText("Enter new Address...")
            Tables.CLIENT.value.clearValues()
            self.setNewForTables(True)
            Tables.CLIENT.value._ap_phase_change = False
            self._ap_phase_change = False

    def newSearchAdrCombo(self):
        if not self._ap_phase_change and self._search_address_combo.currentText(
        ) == "":
            self._address_change = True
            self._search_apPhase_combo.setCurrentText("")
            self._ap_phase_widget.setPlaceholderText("Enter new ApPhase ID...")
            self._address_widget.setPlaceholderText("Enter new Address...")
            self.setNewForTables(True)
            Tables.CLIENT.value.clearValues()
            self._address_change = False

    def updateSearchCombos(self):
        ap_phase_id = self._ap_phase_widget.text()
        search_data = getAddresses(
            self._database.getValuesFrom2Fields(Tables.CLIENT.name,
                                                Client.ADDRESS.name,
                                                Client.AP_PHASE_ID.name))
        search_ap_phase_ids = [value[1] for value in search_data]
        search_addresses = [value[0] for value in search_data]
        self._search_apPhase_combo.clear()
        self._search_address_combo.clear()
        self._search_apPhase_combo.addItems(search_ap_phase_ids)
        self._search_address_combo.addItems(search_addresses)
        index = self._search_apPhase_combo.findText(ap_phase_id)
        self._search_apPhase_combo.setCurrentIndex(index)

    def updateDatabaseTable(self):
        if self._main_tabs.currentIndex() == 1:
            table_name = self._tabs.currentWidget().getTableName()
            tab_name = self._tabs.currentWidget().getTabName()
            self._database_table_label.setText("Table: {tn} ({tbn})".format(
                tn=table_name, tbn=tab_name))
            self._database.openDatabase()
            data = self._database.readTable(table_name)
            self._database.closeDatabase()
            headers = getFieldNames(table_name)
            data_count = len(data)
            self._database_table.setRowCount(0)
            self._database_table.setColumnCount(len(headers))
            self._database_table.setRowCount(data_count)

            for col, header_text in enumerate(headers):
                header = QTableWidgetItem(header_text)
                self._database_table.setHorizontalHeaderItem(col, header)

            for row, data_row in enumerate(data):
                data_row = list(data_row)
                data_row.pop(0)
                for col, data_value in enumerate(data_row):
                    item = QTableWidgetItem(str(data_value))
                    self._database_table.setItem(row, col, item)

    def exportDatabaseTable(self):
        file_name = self.exportCSVDialog()
        temp_row = []
        headers = []
        for col in range(self._database_table.columnCount()):
            headers.append(
                self._database_table.horizontalHeaderItem(col).text())

        if file_name:
            with open(file_name, 'w', newline='') as n_f:
                writer = csv.writer(n_f)
                writer.writerow(headers)

                for row in range(self._database_table.rowCount()):
                    for col in range(self._database_table.columnCount()):
                        temp_row.append(
                            self._database_table.item(row, col).text())

                    writer.writerow(temp_row)
                    temp_row.clear()

    def exportCSVDialog(self):
        file_dialog = QFileDialog()
        file_name, ext = file_dialog.getSaveFileName(self, 'Export CSV File',
                                                     "", "CSV (*.csv)")
        return file_name

    def mainTabChange(self, index):
        if index == 1:
            self.updateDatabaseTable()

    def start(self):
        with open(self.main_style_qss, 'r') as main_qss:
            main_style = main_qss.read()
            app.setStyleSheet(main_style)
        self.showMaximized()
        sys.exit(app.exec_())
예제 #13
0
class MainWindow(QMainWindow):  # Main window
    def __init__(self):
        super().__init__()
        self.setWindowTitle = 'DD烤肉机'
        self.resize(1870, 820)
        self.mainWidget = QWidget()
        self.mainLayout = QGridLayout()  # Grid layout
        self.mainLayout.setSpacing(10)
        self.mainWidget.setLayout(self.mainLayout)
        self.duration = 60000
        self.bitrate = 2000
        self.fps = 60

        self.initProcess = InitProcess()
        self.previewSubtitle = PreviewSubtitle()
        self.dnldWindow = YoutubeDnld()
        self.exportWindow = exportSubtitle()
        self.videoDecoder = VideoDecoder()
        self.exportWindow.exportArgs.connect(self.exportSubtitle)
        self.stack = QStackedWidget()
        self.stack.setFixedWidth(1300)
        self.mainLayout.addWidget(self.stack, 0, 0, 10, 8)
        buttonWidget = QWidget()
        buttonLayout = QHBoxLayout()
        buttonWidget.setLayout(buttonLayout)
        self.playButton = QPushButton('从本地打开')
        self.playButton.clicked.connect(self.open)
        self.playButton.setFixedWidth(400)
        self.playButton.setFixedHeight(75)
        self.dnldButton = QPushButton('Youtube下载器')
        self.dnldButton.clicked.connect(self.popDnld)
        self.dnldButton.setFixedWidth(400)
        self.dnldButton.setFixedHeight(75)
        buttonLayout.addWidget(self.playButton)
        buttonLayout.addWidget(self.dnldButton)
        self.stack.addWidget(buttonWidget)

        self.videoPath = ''
        self.videoWidth = 1920
        self.videoHeight = 1080
        self.globalInterval = 200
        self.setPlayer()
        self.setSubtitle()
        self.setToolBar()
        self.setCentralWidget(self.mainWidget)
        self.playStatus = False
        self.volumeStatus = True
        self.volumeValue = 100
        self.subSelectedTxt = ''
        self.subReplayTime = 1
        self.clipBoard = []
        self.grabKeyboard()
        self.show()

    def setPlayer(self):
        self.playerWidget = QGraphicsVideoItem()
        self.scene = QGraphicsScene()
        self.view = QGraphicsView(self.scene)
        self.view.resize(1280, 730)
        self.scene.addItem(self.playerWidget)
        self.stack.addWidget(self.view)
        self.player = QMediaPlayer(self, QMediaPlayer.VideoSurface)
        self.player.setVideoOutput(self.playerWidget)
        self.view.installEventFilter(self)
        self.view.show()
        self.srtTextItemDict = {0: QGraphicsTextItem(), 1: QGraphicsTextItem(), 2: QGraphicsTextItem(), 3: QGraphicsTextItem(), 4: QGraphicsTextItem()}
        for _, srtTextItem in self.srtTextItemDict.items():
            self.scene.addItem(srtTextItem)

    def setSubtitle(self):
        self.subtitleDict = {x: {-1: [100, '']} for x in range(5)}
        self.subTimer = QTimer()
        self.subTimer.setInterval(100)
        self.subtitle = QTableWidget()
        self.subtitle.setAutoScroll(False)
        self.subtitle.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.mainLayout.addWidget(self.subtitle, 0, 8, 10, 12)
        self.subtitle.setColumnCount(5)
        self.subtitle.selectRow(0)
        self.subtitle.setHorizontalHeaderLabels(['%s' % (i + 1) for i in range(5)])
        self.subtitle.setVerticalHeaderLabels([cnt2Time2(i, self.globalInterval) for i in range(self.subtitle.rowCount())])
        for index in range(5):
            self.subtitle.setColumnWidth(index, 130)
        self.subtitle.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel)
        self.subtitle.setEditTriggers(QAbstractItemView.DoubleClicked)
        self.subtitle.horizontalHeader().sectionClicked.connect(self.addSubtitle)
        self.subtitle.doubleClicked.connect(self.releaseKeyboard)
        self.subtitle.cellChanged.connect(self.subEdit)
        self.subtitle.verticalHeader().sectionClicked.connect(self.subHeaderClick)
        self.subtitle.setContextMenuPolicy(Qt.CustomContextMenu)
        self.subtitle.customContextMenuRequested.connect(self.popTableMenu)
        self.initSubtitle()

    def initSubtitle(self):
        self.initProcess.show()
        self.subtitle.cellChanged.disconnect(self.subEdit)
        for x in range(self.subtitle.columnCount()):
            for y in range(self.subtitle.rowCount()):
                self.subtitle.setSpan(y, x, 1, 1)
        self.subtitle.setRowCount(self.duration // self.globalInterval + 1)
        for x in range(self.subtitle.columnCount()):
            for y in range(self.subtitle.rowCount()):
                self.subtitle.setItem(y, x, QTableWidgetItem(''))
                self.subtitle.item(y, x).setBackground(QBrush(QColor('#232629')))
        self.subtitle.setVerticalHeaderLabels([cnt2Time2(i, self.globalInterval) for i in range(self.subtitle.rowCount())])
        self.subtitle.cellChanged.connect(self.subEdit)
        self.initProcess.hide()

    def addSubtitle(self, index):
        subtitlePath = QFileDialog.getOpenFileName(self, "请选择字幕", None, "字幕文件 (*.srt *.vtt *.ass *.ssa)")[0]
        if subtitlePath:
            self.initProcess.show()
            self.subtitle.cellChanged.disconnect(self.subEdit)
            if subtitlePath.endswith('.ass') or subtitlePath.endswith('.ssa'):
                p = subprocess.Popen(['utils/ffmpeg.exe', '-y', '-i', subtitlePath, 'temp_sub.srt'])
                p.wait()
                subtitlePath = 'temp_sub.srt'
            subData = {}
            with open(subtitlePath, 'r', encoding='utf-8') as f:
                f = f.readlines()
            subText = ''
            YoutubeAutoSub = False
            for l in f:
                if '<c>' in l:
                    YoutubeAutoSub = True
                    break
            for cnt, l in enumerate(f):
                if '<c>' in l:
                    lineData = l.split('c>')
                    if len(lineData) > 3:
                        subText, start, _ = lineData[0].split('<')
                        start = calSubTime(start[:-1]) // self.globalInterval * self.globalInterval
                        if start not in self.subtitleDict[index]:
                            end = calSubTime(lineData[-3][1:-2]) // self.globalInterval * self.globalInterval
                            for i in range(len(lineData) // 2):
                                subText += lineData[i * 2 + 1][:-2]
                            subData[start] = [end - start, subText]
                    else:
                        subText, start, _ = lineData[0].split('<')
                        start = calSubTime(start[:-1]) // self.globalInterval * self.globalInterval
                        if start not in self.subtitleDict[index]:
                            subText += lineData[1][:-2]
                            subData[start] = [self.globalInterval, subText]
                elif '-->' in l and f[cnt + 2].strip() and '<c>' not in f[cnt + 2]:
                    subText = f[cnt + 2][:-1]
                    start = calSubTime(l[:12]) // self.globalInterval * self.globalInterval
                    if start not in self.subtitleDict[index]:
                        end = calSubTime(l[17:29]) // self.globalInterval * self.globalInterval
                        subData[start] = [end - start, subText]
                if '-->' in l and f[cnt + 1].strip() and not YoutubeAutoSub:
                    start = calSubTime(l[:12]) // self.globalInterval * self.globalInterval
                    if start not in self.subtitleDict[index]:
                        end = calSubTime(l[17:29]) // self.globalInterval * self.globalInterval
                        delta = end - start
                        if delta > 10:
                            if '<b>' in f[cnt + 1]:
                                subData[start] = [delta, f[cnt + 1].split('<b>')[1].split('<')[0]]
                            else:
                                subData[start] = [delta, f[cnt + 1][:-1]]
            self.subtitleDict[index].update(subData)
            maxRow = 0
            for _, v in self.subtitleDict.items():
                startMax = max(v.keys())
                rowCount = (startMax + v[startMax][0]) // self.globalInterval
                if rowCount > maxRow:
                    maxRow = rowCount
            if maxRow < self.duration // self.globalInterval + 1:
                maxRow = self.duration // self.globalInterval
            else:
                self.duration = maxRow * self.globalInterval
            self.subtitle.setRowCount(maxRow)
            self.subtitle.setVerticalHeaderLabels([cnt2Time2(i, self.globalInterval) for i in range(self.subtitle.rowCount())])
            for start, rowData in subData.items():
                startRow = start // self.globalInterval
                endRow = startRow + rowData[0] // self.globalInterval
                for row in range(startRow, endRow):
                    self.subtitle.setItem(row, index, QTableWidgetItem(rowData[1]))
                    self.subtitle.item(row, index).setBackground(QBrush(QColor('#35545d')))
                self.subtitle.setSpan(startRow, index, endRow - startRow, 1)
            self.refreshComboBox()
            self.subtitle.cellChanged.connect(self.subEdit)
            self.initProcess.hide()

    def subTimeOut(self):
        fontColor = self.previewSubtitle.fontColor
        fontSize = (self.previewSubtitle.fontSize + 5) / 2.5
        fontBold = self.previewSubtitle.bold
        fontItalic = self.previewSubtitle.italic
        fontShadowOffset = self.previewSubtitle.shadowOffset
        for _, srtTextItem in self.srtTextItemDict.items():
            srtTextItem.setDefaultTextColor(fontColor)
            font = QFont()
            font.setFamily("微软雅黑")
            font.setPointSize(fontSize)
            font.setBold(fontBold)
            font.setItalic(fontItalic)
            srtTextItem.setFont(font)
            srtTextShadow = QGraphicsDropShadowEffect()
            srtTextShadow.setOffset(fontShadowOffset)
            srtTextItem.setGraphicsEffect(srtTextShadow)
        try:
            selected = self.subtitle.selectionModel().selection().indexes()
            for x, i in enumerate(selected):
                if self.subtitle.item(i.row(), x):
                    txt = self.subtitle.item(i.row(), x).text()
                    if txt:
                        self.srtTextItemDict[x].setPlainText('#%s:' % (x + 1) + txt)
                        txtSize = self.srtTextItemDict[x].boundingRect().size()
                        posY = self.playerWidget.size().height() - txtSize.height() * (x + 1)
                        posX = (self.playerWidget.size().width() - txtSize.width()) / 2
                        self.srtTextItemDict[x].setPos(posX, posY)
                    else:
                        self.srtTextItemDict[x].setPlainText('')
                else:
                    self.srtTextItemDict[x].setPlainText('')
        except:
            pass

    def subHeaderClick(self, index):
        if self.player.duration():
            position = index * self.globalInterval
            self.player.setPosition(position)
            self.videoSlider.setValue(position * 1000 // self.player.duration())
            self.setTimeLabel()

    def subEdit(self, row, index):
        repeat = self.subtitle.rowSpan(row, index)
        self.setSubtitleDict(row, index, repeat, self.subtitle.item(row, index).text())
        self.subtitle.cellChanged.disconnect(self.subEdit)
        for cnt in range(repeat):
            if self.subtitle.item(row + cnt, index).text():
                self.subtitle.item(row, index).setBackground(QBrush(QColor('#35545d')))
            else:
                self.subtitle.item(row, index).setBackground(QBrush(QColor('#232629')))
        self.subtitle.cellChanged.connect(self.subEdit)

    def setSubtitleDict(self, row, index, num, text):
        self.subtitleDict[index][row * self.globalInterval] = [num * self.globalInterval, text]

    def popTableMenu(self, pos):
        self.subtitle.cellChanged.disconnect(self.subEdit)
        pos = QPoint(pos.x() + 55, pos.y() + 30)
        menu = QMenu()
        copy = menu.addAction('复制')
        paste = menu.addAction('粘贴')
        setSpan = menu.addAction('合并')
        clrSpan = menu.addAction('拆分')
        addSub = menu.addAction('导入字幕')
        cutSub = menu.addAction('裁剪字幕')
        action = menu.exec_(self.subtitle.mapToGlobal(pos))
        selected = self.subtitle.selectionModel().selection().indexes()
        yList = [selected[0].row(), selected[-1].row()]
        xSet = set()
        for i in range(len(selected)):
            xSet.add(selected[i].column())
        if action == copy:
            for x in xSet:
                self.clipBoard = []
                for y in range(yList[0], yList[1] + 1):
                    if self.subtitle.item(y, x):
                        self.clipBoard.append(self.subtitle.item(y, x).text())
                    else:
                        self.clipBoard.append('')
                break
        elif action == paste:
            self.subtitle.cellChanged.connect(self.subEdit)
            for x in xSet:
                for cnt, text in enumerate(self.clipBoard):
                    self.subtitle.setItem(yList[0] + cnt, x, QTableWidgetItem(text))
                    self.subtitleDict[x][(yList[0] + cnt) * self.globalInterval] = [self.globalInterval, text]
            self.subtitle.cellChanged.disconnect(self.subEdit)
        elif action == setSpan:
            for x in xSet:
                if not self.subtitle.item(yList[0], x):
                    firstItem = ''
                else:
                    firstItem = self.subtitle.item(yList[0], x).text()
                for y in range(yList[0], yList[1] + 1):
                    self.subtitle.setSpan(y, x, 1, 1)
                    self.subtitle.setItem(y, x, QTableWidgetItem(firstItem))
                    self.subtitle.item(y, x).setBackground(QBrush(QColor('#35545d')))
                    if y * self.globalInterval in self.subtitleDict[x]:
                        del self.subtitleDict[x][y * self.globalInterval]
            for x in xSet:
                self.subtitle.setSpan(yList[0], x, yList[1] - yList[0] + 1, 1)
            self.setSubtitleDict(yList[0], x, yList[1] - yList[0] + 1, firstItem)
        elif action == clrSpan:
            for x in xSet:
                if not self.subtitle.item(yList[0], x):
                    firstItem = ''
                else:
                    firstItem = self.subtitle.item(yList[0], x).text()
                for cnt, y in enumerate(range(yList[0], yList[1] + 1)):
                    self.subtitle.setSpan(y, x, 1, 1)
                    if not cnt:
                        self.subtitle.setItem(yList[0], x, QTableWidgetItem(firstItem))
                        if firstItem:
                            self.subtitle.item(y, x).setBackground(QBrush(QColor('#35545d')))
                        else:
                            self.subtitle.item(y, x).setBackground(QBrush(QColor('#232629')))
                    else:
                        self.subtitle.setItem(y, x, QTableWidgetItem(''))
                        self.subtitle.item(y, x).setBackground(QBrush(QColor('#232629')))
                    self.setSubtitleDict(yList[0], x, yList[1] - yList[0] + 1, firstItem)
                break
        elif action == addSub:
            self.subtitle.cellChanged.connect(self.subEdit)
            for x in xSet:
                self.addSubtitle(x)
            self.subtitle.cellChanged.disconnect(self.subEdit)
        elif action == cutSub:
            for x in xSet:
                start = yList[0] * self.globalInterval
                end = yList[1] * self.globalInterval
                self.exportSubWindow(start, end, x + 1)
        self.subtitle.cellChanged.connect(self.subEdit)

    def setToolBar(self):
        '''
        menu bar, file menu, play menu, tool bar.
        '''
        toolBar = QToolBar()
        self.setContextMenuPolicy(Qt.NoContextMenu)
        self.addToolBar(toolBar)
        fileMenu = self.menuBar().addMenu('&文件')
        openAction = QAction(QIcon.fromTheme('document-open'), '&打开...', self, shortcut=QKeySequence.Open, triggered=self.open)
        fileMenu.addAction(openAction)
        downloadAction = QAction(QIcon.fromTheme('document-open'), '&Youtube下载器', self, triggered=self.popDnld)
        fileMenu.addAction(downloadAction)
        exitAction = QAction(QIcon.fromTheme('application-exit'), '&退出', self, shortcut='Ctrl+Q', triggered=self.close)
        fileMenu.addAction(exitAction)

        playMenu = self.menuBar().addMenu('&功能')
        self.playIcon = self.style().standardIcon(QStyle.SP_MediaPlay)
        self.pauseIcon = self.style().standardIcon(QStyle.SP_MediaPause)
        self.playAction = toolBar.addAction(self.playIcon, '播放')
        self.playAction.triggered.connect(self.mediaPlay)
        self.volumeIcon = self.style().standardIcon(QStyle.SP_MediaVolume)
        self.volumeMuteIcon = self.style().standardIcon(QStyle.SP_MediaVolumeMuted)
        self.volumeAction = toolBar.addAction(self.volumeIcon, '静音')
        self.volumeAction.triggered.connect(self.volumeMute)
        previewAction = QAction(QIcon.fromTheme('document-open'), '&设置预览字幕', self, triggered=self.popPreview)
        playMenu.addAction(previewAction)

        decodeMenu = self.menuBar().addMenu('&输出')
        decodeAction = QAction(QIcon.fromTheme('document-open'), '&输出字幕及视频', self, triggered=self.decode)
        decodeMenu.addAction(decodeAction)

        self.volSlider = Slider()
        self.volSlider.setOrientation(Qt.Horizontal)
        self.volSlider.setMinimum(0)
        self.volSlider.setMaximum(100)
        self.volSlider.setFixedWidth(120)
        self.volSlider.setValue(self.player.volume())
        self.volSlider.setToolTip(str(self.volSlider.value()))
        self.volSlider.pointClicked.connect(self.setVolume)
        toolBar.addWidget(self.volSlider)

        self.videoPositionEdit = LineEdit('00:00')
        self.videoPositionEdit.setAlignment(Qt.AlignRight)
        self.videoPositionEdit.setFixedWidth(75)
        self.videoPositionEdit.setFont(QFont('Timers', 14))
        self.videoPositionEdit.clicked.connect(self.mediaPauseOnly)
        self.videoPositionEdit.editingFinished.connect(self.mediaPlayOnly)
        self.videoPositionLabel = QLabel(' / 00:00  ')
        self.videoPositionLabel.setFont(QFont('Timers', 14))
        toolBar.addWidget(QLabel('    '))
        toolBar.addWidget(self.videoPositionEdit)
        toolBar.addWidget(self.videoPositionLabel)

        self.timer = QTimer()
        self.timer.setInterval(100)
        self.videoSlider = Slider()
        self.videoSlider.setEnabled(False)
        self.videoSlider.setOrientation(Qt.Horizontal)
        self.videoSlider.setMinimum(0)
        self.videoSlider.setMaximum(1000)
        self.videoSlider.setFixedWidth(1000)
        self.videoSlider.sliderMoved.connect(self.timeStop)
        self.videoSlider.sliderReleased.connect(self.timeStart)
        self.videoSlider.pointClicked.connect(self.videoSliderClick)
        toolBar.addWidget(self.videoSlider)

        toolBar.addWidget(QLabel('   '))
        self.globalIntervalComBox = QComboBox()
        self.globalIntervalComBox.addItems(['间隔 100ms', '间隔 200ms', '间隔 500ms', '间隔 1s'])
        self.globalIntervalComBox.setCurrentIndex(1)
        self.globalIntervalComBox.currentIndexChanged.connect(self.setGlobalInterval)
        toolBar.addWidget(self.globalIntervalComBox)
        toolBar.addWidget(QLabel('  '))
        self.subEditComBox = QComboBox()
        self.refreshComboBox()
        toolBar.addWidget(self.subEditComBox)
        toolBar.addWidget(QLabel('  '))
        moveForward = QPushButton('- 1')
        moveForward.setFixedWidth(50)
        toolBar.addWidget(moveForward)
        toolBar.addWidget(QLabel('  '))
        moveAfterward = QPushButton('+ 1')
        moveAfterward.setFixedWidth(50)
        toolBar.addWidget(moveAfterward)
        toolBar.addWidget(QLabel('  '))
        clearSub = QPushButton('清空')
        clearSub.setFixedWidth(50)
        toolBar.addWidget(clearSub)
        toolBar.addWidget(QLabel('  '))
        outputSub = QPushButton('裁剪')
        outputSub.setFixedWidth(50)
        toolBar.addWidget(outputSub)
        moveForward.clicked.connect(self.moveForward)
        moveAfterward.clicked.connect(self.moveAfterward)
        clearSub.clicked.connect(self.clearSub)
        outputSub.clicked.connect(self.exportSubWindow)

    def setGlobalInterval(self, index):
        if not self.playStatus:
            self.mediaPlay()
        self.globalInterval = {0: 100, 1: 200, 2: 500, 3: 1000}[index]
        self.initSubtitle()
        self.initProcess.show()
        self.subtitle.cellChanged.disconnect(self.subEdit)
        for index, subData in self.subtitleDict.items():
            for start, rowData in subData.items():
                startRow = start // self.globalInterval
                deltaRow = rowData[0] // self.globalInterval
                if deltaRow:
                    endRow = startRow + deltaRow
                    for row in range(startRow, endRow):
                        self.subtitle.setItem(row, index, QTableWidgetItem(rowData[1]))
                        if row >= 0:
                            self.subtitle.item(row, index).setBackground(QBrush(QColor('#35545d')))
                    self.subtitle.setSpan(startRow, index, endRow - startRow, 1)
        self.subtitle.cellChanged.connect(self.subEdit)
        self.initProcess.hide()

    def moveForward(self):
        self.initProcess.show()
        self.subtitle.cellChanged.disconnect(self.subEdit)
        index = self.subEditComBox.currentIndex()
        for y in range(self.subtitle.rowCount()):
            self.subtitle.setSpan(y, index, 1, 1)
            self.subtitle.setItem(y, index, QTableWidgetItem(''))
            self.subtitle.item(y, index).setBackground(QBrush(QColor('#232629')))
        tmpDict = self.subtitleDict[index]
        self.subtitleDict[index] = {}
        for start, rowData in tmpDict.items():
            self.subtitleDict[index][start - self.globalInterval] = rowData
        for start, rowData in self.subtitleDict[index].items():
            startRow = start // self.globalInterval
            endRow = startRow + rowData[0] // self.globalInterval
            for row in range(startRow, endRow):
                self.subtitle.setItem(row, index, QTableWidgetItem(rowData[1]))
                self.subtitle.item(row, index).setBackground(QBrush(QColor('#35545d')))
            self.subtitle.setSpan(startRow, index, endRow - startRow, 1)
        self.subtitle.cellChanged.connect(self.subEdit)
        self.initProcess.hide()

    def moveAfterward(self):
        self.initProcess.show()
        self.subtitle.cellChanged.disconnect(self.subEdit)
        index = self.subEditComBox.currentIndex()
        for y in range(self.subtitle.rowCount()):
            self.subtitle.setSpan(y, index, 1, 1)
            self.subtitle.setItem(y, index, QTableWidgetItem(''))
            self.subtitle.item(y, index).setBackground(QBrush(QColor('#232629')))
        tmpDict = self.subtitleDict[index]
        self.subtitleDict[index] = {}
        for start, rowData in tmpDict.items():
            self.subtitleDict[index][start + self.globalInterval] = rowData
        for start, rowData in self.subtitleDict[index].items():
            startRow = start // self.globalInterval
            endRow = startRow + rowData[0] // self.globalInterval
            for row in range(startRow, endRow):
                self.subtitle.setItem(row, index, QTableWidgetItem(rowData[1]))
                self.subtitle.item(row, index).setBackground(QBrush(QColor('#35545d')))
            self.subtitle.setSpan(startRow, index, endRow - startRow, 1)
        self.subtitle.cellChanged.connect(self.subEdit)
        self.initProcess.hide()

    def clearSub(self):
        index = self.subEditComBox.currentIndex()
        reply = QMessageBox.information(self, '清空字幕', '清空第 %s 列字幕条?' % (index + 1), QMessageBox.Yes | QMessageBox.No)
        if reply == QMessageBox.Yes:
            self.initProcess.show()
            self.subtitle.cellChanged.disconnect(self.subEdit)
            self.subtitleDict[index] = {0: [self.globalInterval, '']}
            for i in range(self.subtitle.rowCount()):
                self.subtitle.setSpan(i, index, 1, 1)
                self.subtitle.setItem(i, index, QTableWidgetItem(''))
                self.subtitle.item(i, index).setBackground(QBrush(QColor('#232629')))
                self.subtitle.setHorizontalHeaderItem(index, QTableWidgetItem('%s' % (index + 1)))
            self.subtitle.cellChanged.connect(self.subEdit)
            self.initProcess.hide()

    def exportSubWindow(self, start=0, end=0, index=None):
        self.releaseKeyboard()
        self.exportWindow.hide()
        self.exportWindow.show()
        start = '00:00.0' if not start else self.splitTime(start)
        end = self.splitTime(self.duration) if not end else self.splitTime(end)
        if not index:
            index = self.subEditComBox.currentIndex() + 1
        self.exportWindow.setDefault(start, end, index)

    def exportSubtitle(self, exportArgs):
        start = calSubTime2(exportArgs[0])
        end = calSubTime2(exportArgs[1])
        subStart = calSubTime2(exportArgs[2])
        index = exportArgs[3] - 1
        subData = self.subtitleDict[index]
        rowList = sorted(subData.keys())
        exportRange = []
        for t in rowList:
            if t >= start and t <= end:
                exportRange.append(t)
        subNumber = 1
        with open(exportArgs[-1], 'w', encoding='utf-8') as exportFile:
            for t in exportRange:
                text = subData[t][1]
                if text:
                    start = ms2Time(t + subStart)
                    end = ms2Time(t + subStart + subData[t][0])
                    exportFile.write('%s\n%s --> %s\n%s\n\n' % (subNumber, start, end, text))
                    subNumber += 1
        QMessageBox.information(self, '导出字幕', '导出完成', QMessageBox.Yes)
        self.exportWindow.hide()

    def refreshComboBox(self):
        self.subEditComBox.clear()
        for i in range(self.subtitle.columnCount()):
            self.subEditComBox.addItem('字幕 ' + str(i + 1))

    def open(self):
        self.videoPath = QFileDialog.getOpenFileName(self, "请选择视频文件", None, "MP4格式 (*.mp4);;所有文件(*.*)")[0]
        if self.videoPath:
            cmd = ['utils/ffmpeg.exe', '-i', self.videoPath]
            p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
            p.wait()
            for l in p.stdout.readlines():
                l = l.decode('utf8')
                if 'Duration' in l:
                    self.duration = calSubTime(l.split(' ')[3][:-1])
                if 'Stream' in l and 'DAR' in l:
                    self.videoWidth, self.videoHeight = map(int, l.split(' [')[0].split(' ')[-1].split('x'))
                    args = l.split(',')
                    for cnt, arg in enumerate(args):
                        if 'kb' in arg:
                            self.bitrate = int(arg.split('kb')[0])
                            self.fps = int(args[cnt + 1].split('fps')[0])
                            break
                    break
            self.initProcess.show()
            self.subtitle.cellChanged.disconnect(self.subEdit)
            self.subtitle.setRowCount(self.duration // self.globalInterval + 1)
            self.subtitle.setVerticalHeaderLabels([cnt2Time2(i, self.globalInterval) for i in range(self.subtitle.rowCount())])
            self.subtitle.cellChanged.connect(self.subEdit)
            self.initProcess.hide()
            url = QUrl.fromLocalFile(self.videoPath)
            self.stack.setCurrentIndex(1)
            self.playerWidget.setSize(QSizeF(1280, 720))
            self.player.setMedia(url)
            self.playStatus = True
            self.videoSlider.setEnabled(True)
            self.mediaPlay()
            self.timer.start()
            self.timer.timeout.connect(self.timeOut)
            self.subTimer.start()
            self.subTimer.timeout.connect(self.subTimeOut)

    def popDnld(self):
        self.releaseKeyboard()
        self.dnldWindow.hide()
        self.dnldWindow.show()

    def popPreview(self):
        self.releaseKeyboard()
        self.previewSubtitle.hide()
        self.previewSubtitle.show()

    def decode(self):
        self.releaseKeyboard()
        self.videoDecoder.setDefault(self.videoPath, self.videoWidth, self.videoHeight, self.duration, self.bitrate, self.fps, self.subtitleDict)
        self.videoDecoder.hide()
        self.videoDecoder.show()

    def mediaPlay(self):
        if self.playStatus:
            self.player.play()
            self.grabKeyboard()
            self.timeStart()
            self.playStatus = False
            self.playAction.setIcon(self.pauseIcon)
            self.playAction.setText('暂停')
        else:
            self.player.pause()
            self.timeStop()
            self.playStatus = True
            self.playAction.setIcon(self.playIcon)
            self.playAction.setText('播放')

    def mediaPlayOnly(self):
        self.grabKeyboard()
        try:
            timeText = self.videoPositionEdit.text().split(':')
            m, s = timeText[:2]
            if not m:
                m = '00'
            if not s:
                s = '00'
            if len(m) > 3:
                m = m[:3]
            if len(s) > 2:
                s = s[:2]
            if m.isdigit():
                m = int(m)
            if s.isdigit():
                s = int(s)
            if s > 60:
                s = 60
            total_m = self.player.duration() // 60000
            if m > total_m:
                m = total_m
            self.player.setPosition(m * 60000 + s * 1000)
            self.videoSlider.setValue(self.player.position() * 1000 / self.player.duration())
        except:
            pass
        self.videoPositionEdit.setReadOnly(True)
        self.timeStart()

    def mediaPauseOnly(self):
        self.releaseKeyboard()
        self.videoPositionEdit.setReadOnly(False)
        self.player.pause()
        self.timeStop()
        self.playStatus = True
        self.playAction.setIcon(self.playIcon)
        self.playAction.setText('播放')

    def splitTime(self, playTime):
        playTime = playTime // 1000
        m = str(playTime // 60)
        s = playTime % 60
        s = ('0%s' % s)[-2:]
        if len(m) > 2:
            t = '%3s:%2s' % (m, s)
        else:
            t = '%2s:%2s' % (m, s)
        return t

    def timeOut(self):
        row = self.player.position() // self.globalInterval
        self.subtitle.selectRow(row)
        self.subtitle.verticalScrollBar().setValue(row - 10)
        if self.dnldWindow.isHidden() or self.exportWindow.isHidden() or self.videoDecoder.isHidden():
            self.grabKeyboard()
        try:
            self.videoSlider.setValue(self.player.position() * 1000 / self.player.duration())
            self.setTimeLabel()
        except:
            pass

    def timeStop(self):
        self.timer.stop()

    def timeStart(self):
        self.timer.start()

    def videoSliderClick(self, p):
        self.videoSlider.setValue(p.x())
        self.player.setPosition(p.x() * self.player.duration() // 1000)
        self.setTimeLabel()

    def setVolume(self, p):
        self.volumeValue = p.x()
        if self.volumeValue > 100:
            self.volumeValue = 100
        if self.volumeValue < 0:
            self.volumeValue = 0
        self.volSlider.setValue(self.volumeValue)
        self.player.setVolume(self.volumeValue)
        self.volSlider.setToolTip(str(self.volSlider.value()))
        if self.volumeValue:
            self.volumeStatus = True
            self.volumeAction.setIcon(self.volumeIcon)
        else:
            self.volumeStatus = False
            self.volumeAction.setIcon(self.volumeMuteIcon)

    def volumeMute(self):
        if self.volumeStatus:
            self.volumeStatus = False
            self.old_volumeValue = self.player.volume()
            self.player.setVolume(0)
            self.volSlider.setValue(0)
            self.volumeAction.setIcon(self.volumeMuteIcon)
        else:
            self.volumeStatus = True
            self.player.setVolume(self.old_volumeValue)
            self.volSlider.setValue(self.old_volumeValue)
            self.volumeAction.setIcon(self.volumeIcon)

    def setTimeLabel(self):
        now = self.player.position()
        total = self.player.duration()
        now = self.splitTime(now)
        total = self.splitTime(total)
        self.videoPositionEdit.setText(now)
        self.videoPositionLabel.setText(' / %s  ' % total)

    def eventFilter(self, obj, event):
        if obj == self.view:
            if event.type() == QEvent.MouseButtonPress:
                self.mediaPlay()
        return QMainWindow.eventFilter(self, obj, event)

    def keyPressEvent(self, QKeyEvent):
        key = QKeyEvent.key()
        if key == Qt.Key_Left:
            if self.videoSlider.isEnabled():
                self.player.setPosition(self.player.position() - 5000)
                self.videoSlider.setValue(self.player.position() * 1000 / self.player.duration())
                self.setTimeLabel()
        elif key == Qt.Key_Right:
            if self.videoSlider.isEnabled():
                self.player.setPosition(self.player.position() + 5000)
                self.videoSlider.setValue(self.player.position() * 1000 / self.player.duration())
                self.setTimeLabel()
        elif key == Qt.Key_Up:
            self.volumeValue += 10
            if self.volumeValue > 100:
                self.volumeValue = 100
            self.volSlider.setValue(self.volumeValue)
            self.player.setVolume(self.volumeValue)
        elif key == Qt.Key_Down:
            self.volumeValue -= 10
            if self.volumeValue < 0:
                self.volumeValue = 0
            self.volSlider.setValue(self.volumeValue)
            self.player.setVolume(self.volumeValue)
        elif key == Qt.Key_Space:
            self.mediaPlay()
예제 #14
0
# ---------------------------
# StackedWidgetに登録されたwidgetをインデックスで指定して表示する
# ---------------------------
import sys
from PySide2.QtWidgets import QApplication, QTextEdit, QStackedWidget

app = QApplication(sys.argv)

qw_text_edit_1 = QTextEdit()
qw_text_edit_1.append('1')

qw_text_edit_2 = QTextEdit()
qw_text_edit_2.append('2')

qw_stack = QStackedWidget()
idx_qw_text_edit_1 = qw_stack.addWidget(qw_text_edit_1)
idx_qw_text_edit_2 = qw_stack.addWidget(qw_text_edit_2)
print(idx_qw_text_edit_1, idx_qw_text_edit_2)

# 表示するwidgetをインデックスで指定する
qw_stack.setCurrentIndex(idx_qw_text_edit_2)
print(qw_stack.currentIndex())

qw_stack.show()

sys.exit(app.exec_())
예제 #15
0
class ChannelArithmeticDialog(ieb.ImarisExtensionBase):
    """
    Channel Arithmetic and Beyond
    =============================
    `View on GitHub <https://github.com/niaid/imaris_extensions>`_

    This program enables one to specify arithmetic expressions which are used to
    create new channels. The basic arithmetic operations are supported: +,-,*,/,**.
    More advanced operations that run short `SimpleITK <https://simpleitk.org/>`_
    code snippets are also supported.

    Channels are referenced using square brackets and the channel index, starting
    at **zero**. To apply an expression to all channels, use the channel index 'i'.

    When creating a single new channel, the arithmetic expression consists of literal
    channel numbers, one can select a name and color for the new channel. When
    creating multiple new channels, the arithmetic expression is applied to all channels,
    the postfix '_modified' is appended to the original channel names and the original
    color is copied over. Note that for all channels created by the program the
    channel description will include the arithmetic expression used to create that
    channel. This transparently supports your efforts to conduct reproducible
    research.

    Because an Imaris image has a specific pixel type (8, 16, 32 bit unsigned integer
    and 32 bit floating point) all computations are performed using a 32 bit floating
    point representation and then clamped to the range of the image's pixel type.

    The program allows you to use the same expression on multiple files. In this
    case literal channel values are limited by the number of shared channels. Thus,
    if working with two files one with three channels and one with four channels,
    the valid literal channel values are limited to 0, 1, 2. We cannot use 3 as it does not
    exist in all files. On the other hand, if our autofluorescence channel is one
    of these channels, e.g. channel 0, we can subtract it from all channels in
    both files, `[i]-[0]`.

    Basic Examples
    --------------

    Multiply channels zero and three:

    .. code-block:: Python

      [0]*[3]

    Multiply channels zero and three and subtract the result from channel four:

    .. code-block:: Python

      [4] - ([0]*[3])

    Duplicate all channels:

    .. code-block:: Python

      [i]

    Subtract channel zero from all channels:

    .. code-block:: Python

      [i]-[0]


    Advanced Examples
    -----------------

    Threshold channel one using a value of 100, resulting image is binary
    values in {0,1}:

    .. code-block:: Python

      [1]>100

    Threshold a specific channel to create a binary result using the Otsu
    filter:

    .. code-block:: Python

      sitk.OtsuThreshold([1], 0, 1)

    Threshold a specific channel retaining the values above the threshold:

    .. code-block:: Python

      sitk.Cast([1]>100, sitk.sitkFloat32)*[1]

    Threshold a specific channel, get all connected components, then
    sort the components according to size, discarding those smaller than a minimum
    size and create a binary mask corresponding to the largest component, which is
    the first label(second largest component label is 2 etc.)

    .. code-block:: Python

      sitk.RelabelComponent(sitk.ConnectedComponent([1]>100), minimumObjectSize = 50)==1

    Create a binary mask representing the colocalization of two channels,
    intensity values below 20 are considred noise:

    .. code-block:: Python

      ([1]>20)*([2]>20)

    Create a binary mask representing the colocalization of two channels.
    We are interested in all pixels in channel 2 that have a value above 20
    and that are less than 1.0um away from pixels in channel 1 that have a value
    above 100 (**note**: this operation yields different results when run using
    a slice-by-slice approach vs. a volumetric approach):

    .. code-block:: Python

        (sitk.Cast([2]>20, sitk.sitkFloat32) *
         sitk.Abs(sitk.SignedMaurerDistanceMap([1]>100, insideIsPositive=False, squaredDistance=False, useImageSpacing=True)))<=1.0

    Create a binary mask using thresholding and then perform morphological
    closing (dilation followed by erosion) with distance maps, useful
    for filling holes:

    .. code-block:: Python

      sitk.SignedMaurerDistanceMap(sitk.SignedMaurerDistanceMap([1]>100, insideIsPositive=False, squaredDistance=False, useImageSpacing=True) < 1.0, insideIsPositive=False, squaredDistance=False, useImageSpacing=True)<-1.0

    Create a binary mask using thresholding and then perform morphological
    opening (erosion followed by dilation) with distance maps, useful
    for removing small islands:

    .. code-block:: Python

      sitk.SignedMaurerDistanceMap(sitk.SignedMaurerDistanceMap([1]>100, insideIsPositive=False, squaredDistance=False, useImageSpacing=True) < -0.2, insideIsPositive=False, squaredDistance=False, useImageSpacing=True)<0.2
    """  # noqa

    def __init__(self):
        super(ChannelArithmeticDialog, self).__init__()
        # Channel indexes in the arithmetic calculator are denoted using a
        # regular expression: one or more digits in square brackets (e.g. [1234]).
        # First digit is zero and nothing afterwards or first digit is in [1-9] and
        # there are possibly more digits afterwards.
        # Starting index is zero.
        self.channel_pattern = re.compile(r"\[(0|[1-9]\d*)\]")

        # Use QT's global threadpool, documentation says: "This global thread pool
        # automatically maintains an optimal number of threads based on the
        # number of cores in the CPU."
        self.threadpool = QThreadPool.globalInstance()

        # Configure the help dialog.
        self.help_dialog = HelpDialog(w=700, h=500)
        self.help_dialog.setWindowTitle("Channel Arithmetic Help")
        self.help_dialog.set_rst_text(
            inspect.getdoc(self), pygments_css_file_name="pygments_dark.css")

        self.__create_gui()
        self.setWindowTitle("Channel Arithmetic")
        self.processing_error = False

        self.show()

    def __create_gui(self):
        menu_bar = self.menuBar()
        # Force menubar to be displayed in the application on OSX/Linux, otherwise it
        # is displayed in the system menubar
        menu_bar.setNativeMenuBar(False)
        self.help_button = QPushButton("Help")
        self.help_button.clicked.connect(self.help_dialog.show)
        menu_bar.setCornerWidget(self.help_button, Qt.TopLeftCorner)

        central_widget = QWidget(self)
        gui_layout = QVBoxLayout()
        central_widget.setLayout(gui_layout)
        self.setCentralWidget(central_widget)

        select_files_widget = self.__create_select_files_widget()
        arithmetic_widget = self.__create_arithmetic_widget()

        self.stack = QStackedWidget(self)
        self.stack.addWidget(select_files_widget)
        self.stack.addWidget(arithmetic_widget)
        gui_layout.addWidget(self.stack)

        self.status_bar = self.statusBar()

    def closeEvent(self, event):
        """
        Override the closeEvent method so that clicking the 'x' button also
        closes all of the dialogs.
        """
        self.help_dialog.close()
        event.accept()

    def __create_arithmetic_widget(self):
        wid = QWidget(self)
        arithmetic_layout = QVBoxLayout()
        wid.setLayout(arithmetic_layout)

        self.valid_indexes_label = QLabel("")
        arithmetic_layout.addWidget(self.valid_indexes_label)

        layout = QHBoxLayout()
        layout.setAlignment(Qt.AlignLeft)
        layout.addWidget(QLabel("Enter new channel arithmetic expression:"))
        arithmetic_layout.addLayout(layout)

        self.arithmetic_expression_text_edit = QTextEdit()
        arithmetic_layout.addWidget(self.arithmetic_expression_text_edit)

        self.slice_by_slice_checkbox = QCheckBox(
            "Slice by slice (smaller memory footprint).")
        arithmetic_layout.addWidget(self.slice_by_slice_checkbox)

        layout = QHBoxLayout()
        layout.addWidget(QLabel("New channel name:"))
        self.new_channel_name_line_edit = QLineEdit()
        layout.addWidget(self.new_channel_name_line_edit)
        arithmetic_layout.addLayout(layout)

        layout = QHBoxLayout()
        layout.addWidget(QLabel("New channel color:"))
        self.new_channel_color_button = QPushButton()
        self.new_channel_color_button.clicked.connect(
            self.__select_color_callback)
        layout.addWidget(self.new_channel_color_button)
        arithmetic_layout.addLayout(layout)

        self.apply_button = QPushButton("Apply")
        self.apply_button.clicked.connect(self.__channel_arithmetic_wrapper)
        arithmetic_layout.addWidget(self.apply_button)

        progress_wid = QWidget()
        self.progress_grid_layout = QGridLayout()
        progress_wid.setLayout(self.progress_grid_layout)
        scroll_area = QScrollArea()
        scroll_area.setWidget(progress_wid)
        scroll_area.setWidgetResizable(True)
        arithmetic_layout.addWidget(scroll_area)

        layout = QHBoxLayout()
        layout.setAlignment(Qt.AlignLeft)
        self.processing_prev_button = QPushButton("Prev")
        self.processing_prev_button.clicked.connect(
            lambda: self.stack.setCurrentIndex(0))
        layout.addWidget(self.processing_prev_button)
        arithmetic_layout.addLayout(layout)

        return wid

    def __configure_and_show_arithmetic_widget(self):
        file_names = self.input_files_edit.toPlainText().split("\n")
        num_channels = []
        problematic_images = []
        for file_name in file_names:
            try:
                meta_data = sio.read_metadata(file_name)
                num_channels.append(len(meta_data["channels_information"]))
            except Exception:
                problematic_images.append(file_name)
        if problematic_images:
            self._error_function(
                "Problem encountered reading the following file(s):\n" +
                "\n".join(problematic_images))
            return
        self.max_channel_index = min(num_channels) - 1
        self.valid_indexes_label.setText(
            f"Valid channel indexes: 0...{self.max_channel_index}, i")
        self.arithmetic_expression_text_edit.clear()
        self.slice_by_slice_checkbox.setChecked(False)
        self.new_channel_name_line_edit.clear()

        # Remove all widgets from layout, done in reverse order because
        # removing from the begining shifts the rest of the items
        for i in reversed(range(self.progress_grid_layout.count())):
            self.progress_grid_layout.itemAt(i).widget().setParent(None)

        for i, file_name in enumerate(file_names):
            self.progress_grid_layout.addWidget(
                QLabel(os.path.basename(file_name)), i, 0)
            progress_bar = QProgressBar()
            progress_bar.setMaximum(100)
            self.progress_grid_layout.addWidget(progress_bar, i, 1)

        self.stack.setCurrentIndex(1)

    def __create_select_files_widget(self):
        wid = QWidget()
        input_layout = QVBoxLayout()
        wid.setLayout(input_layout)

        layout = QHBoxLayout()
        layout.addWidget(QLabel("File names:"))
        layout.setAlignment(Qt.AlignLeft)
        button = QPushButton("Browse")
        button.setToolTip("Select input files for arithmetic operation.")
        button.clicked.connect(self.__browse_select_input_callback)
        layout.addWidget(button)
        input_layout.addLayout(layout)

        self.input_files_edit = QTextEdit()
        self.input_files_edit.setReadOnly(True)
        input_layout.addWidget(self.input_files_edit)

        layout = QHBoxLayout()
        layout.setAlignment(Qt.AlignRight)
        self.input_files_next_button = QPushButton("Next")
        self.input_files_next_button.setEnabled(False)
        self.input_files_next_button.clicked.connect(
            self.__configure_and_show_arithmetic_widget)
        layout.addWidget(self.input_files_next_button)
        input_layout.addLayout(layout)

        return wid

    def __browse_select_input_callback(self):
        file_names, _ = QFileDialog.getOpenFileNames(
            self,
            "QFileDialog.getOpenFileNames()",
            "",
            "Imaris Images (*.ims);;All Files (*)",
        )
        if file_names:
            self.input_files_edit.setText("\n".join(file_names))
            self.input_files_next_button.setEnabled(True)

    def __select_color_callback(self):
        color = QColorDialog.getColor()
        if color.isValid():
            self.new_channel_color_button.setStyleSheet(
                f"background-color :rgb({color.red()},{color.green()},{color.blue()})"
            )

    def __channel_arithmetic_wrapper(self):
        # Get the arithmetic expression after removing all whitespace
        arithmetic_expression = "".join(
            self.arithmetic_expression_text_edit.toPlainText().split())
        color = self.new_channel_color_button.palette().button().color()

        if arithmetic_expression:
            # Get the explicit channel indexes that appear in the expression and
            # check that they are in the valid range.
            channel_indexes = re.findall(self.channel_pattern,
                                         arithmetic_expression)
            invalid_channels = [
                ci for ci in channel_indexes
                if int(ci) not in range(self.max_channel_index + 1)
            ]
            if invalid_channels:
                self._error_function(
                    "The following channels specified in the arithmetic expression"
                    +
                    f" are outside the valid range [0,{self.max_channel_index}]: "
                    + ", ".join(invalid_channels))
                return

            # Disable the UI interaction during computation
            self.arithmetic_expression_text_edit.setReadOnly(True)
            self.slice_by_slice_checkbox.setEnabled(False)
            self.new_channel_name_line_edit.setReadOnly(True)
            self.new_channel_color_button.setEnabled(False)
            self.apply_button.setEnabled(False)
            self.processing_prev_button.setEnabled(False)

            QApplication.setOverrideCursor(Qt.WaitCursor)
            file_names = self.input_files_edit.toPlainText().split("\n")
            self.num_threads_left = len(file_names)
            for i, input_file_name in enumerate(file_names):
                # Configure and perform computation in another thread.
                arithmetic_calculator = ArithmeticCalculator(
                    self.channel_pattern)
                arithmetic_calculator.signals.finished.connect(
                    self.__arithmetic_finished)
                arithmetic_calculator.signals.processing_error.connect(
                    self._processing_error_function)
                arithmetic_calculator.signals.progress_signal.connect(
                    self.progress_grid_layout.itemAtPosition(
                        i, 1).widget().setValue)
                arithmetic_calculator.signals.update_state_signal.connect(
                    self.status_bar.showMessage)
                arithmetic_calculator.input_file_name = input_file_name
                arithmetic_calculator.arithmetic_expression = arithmetic_expression
                arithmetic_calculator.new_channel_color = [
                    color.red() / 255.0,
                    color.green() / 255.0,
                    color.blue() / 255.0,
                ]
                arithmetic_calculator.new_channel_alpha = color.alpha() / 255.0
                arithmetic_calculator.new_channel_name = (
                    self.new_channel_name_line_edit.text().strip())
                arithmetic_calculator.slice_by_slice = (
                    self.slice_by_slice_checkbox.isChecked())
                self.threadpool.start(arithmetic_calculator)
        else:
            self._error_function(
                "No action taken: arithmetic expression not set.")

    def __arithmetic_finished(self):
        self.num_threads_left = self.num_threads_left - 1
        if self.num_threads_left == 0:
            QApplication.restoreOverrideCursor()
            self.status_bar.clearMessage()
            for i in range(self.progress_grid_layout.rowCount()):
                self.progress_grid_layout.itemAtPosition(
                    i, 1).widget().setValue(0)
            # Enable the UI interaction after computation
            self.arithmetic_expression_text_edit.setReadOnly(False)
            self.slice_by_slice_checkbox.setEnabled(True)
            self.new_channel_name_line_edit.setReadOnly(False)
            self.new_channel_color_button.setEnabled(True)
            self.apply_button.setEnabled(True)
            self.processing_prev_button.setEnabled(True)

            # Inform the user that the calculations completed. If processing errors
            # occured then the desired operation may not have happened, but the
            # calculation was completed.
            QMessageBox().information(self, "Message",
                                      "Calculation completed.")
            self.processing_error = False
예제 #16
0
class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.json_path = ''
        self.currDB = ''
        self.dc = dataController()
        self.createWidgetStack()
        self.createActions()
        self.createMenus()
        self.createToolBars()
        self.createStatusBar()
        self.resize(1000, 800)
        self.setWindowTitle("Logger")
        self.setCentralWidget(self.widget_stack)


    def createWidgetStack(self):
        self.widget_stack = QStackedWidget()
        self.centralWidget = MainWidget(self.dc)
        self.plotWidget =  plotMainWidget(self.dc)
        self.widget_stack.addWidget(self.centralWidget)
        self.widget_stack.addWidget(self.plotWidget)
        self.widget_stack.setCurrentIndex(0)

    def open(self):
        fileName =  QFileDialog.getOpenFileName(self)[0]
        if self.json_path == '':
            QMessageBox.warning(self, "Application", "load json file first\n")
            return
        
        if fileName != '':
            print(fileName)
            self.dc.initBinFile(fileName, self.json_path)
            self.centralWidget.initDomainCombo()
            self.createNewPlotView()  
            self.widget_stack.setCurrentIndex(0)

    def openJson(self):
        fileName =  QFileDialog.getOpenFileName(self)[0]
        if fileName:
            self.json_path = fileName
        self.widget_stack.setCurrentIndex(0)

    def openDB(self):
        fileName=  QFileDialog.getOpenFileName(self)[0]
        if fileName:
            self.dc.initDB(fileName)
            self.centralWidget.initDomainCombo()
            if fileName != self.currDB:
                self.createNewPlotView()            
                self.currDB = fileName 
        self.widget_stack.setCurrentIndex(0)    
    
    def createNewPlotView(self):
        self.widget_stack.removeWidget(self.plotWidget)
        self.plotWidget =  plotMainWidget(self.dc)
        self.widget_stack.addWidget(self.plotWidget)
    
    def saveToFile(self):
        path, filtr =  QFileDialog.getSaveFileName(self)
        if path:
            self.centralWidget.CW_exportToFile(path)
    
    def openChart(self):
        if not self.dc:
            QMessageBox.warning(self, "Application", "load json file first\n")
            return
        self.widget_stack.setCurrentIndex(1)
    
    def goBack(self):
       self.widget_stack.setCurrentIndex(0)


    def createActions(self):
        open_bin_file = os.path.join(icon_path,'bin.png')

        self.openAct = QAction( QIcon(open_bin_file),
                "&Open...", self, shortcut= QKeySequence.Open,
                statusTip="Open an existing file", triggered=self.open)

        open_json_file = os.path.join(icon_path,'json.png')

        self.openJSONAct =  QAction( QIcon(open_json_file),
                            "Open...", self, shortcut= QKeySequence.Open,
                            statusTip="Open JSON file", triggered=self.openJson)
        open_db= os.path.join(icon_path,'db.png')
        self.openDBact = QAction( QIcon(open_db),
                            "Open...", self, shortcut= QKeySequence.Open,
                            statusTip="Open DB", triggered=self.openDB)
        disk_icon_path= os.path.join(icon_path,'save.png')
        self.saveToFileAct = QAction( QIcon(disk_icon_path),
                            "Save to file...", self, shortcut= QKeySequence.Open,
                            statusTip="save to file", triggered=self.saveToFile)
        chart_icon_path= os.path.join(icon_path,'chart.png')
        self.openChartAct = QAction( QIcon(chart_icon_path),
                            "Open chart windows", self, shortcut= QKeySequence.Open,
                            statusTip="open chart windows", triggered=self.openChart)
        back_icon_path= os.path.join(icon_path,'back.png')
        self.goBackAct = QAction( QIcon(back_icon_path),
                            "Go Back", self, shortcut= QKeySequence.Open,
                            statusTip="Go back", triggered=self.goBack)
   
    def createMenus(self):
        self.fileMenu = self.menuBar().addMenu("&File")
        self.fileMenu.addAction(self.openAct)
        self.fileMenu.addAction(self.openJSONAct)
        self.fileMenu.addAction(self.openDBact)
        self.fileMenu.addAction(self.saveToFileAct)
        self.fileMenu.addSeparator()
        self.fileMenu.addAction(self.openChartAct)
        self.fileMenu.addAction(self.goBackAct)
     

    def createToolBars(self):
        self.fileToolBar = self.addToolBar("File")
        self.fileToolBar.addAction(self.openAct)
        self.fileToolBar.addAction(self.openJSONAct)
        self.fileToolBar.addAction(self.openDBact)
        self.fileToolBar.addAction(self.saveToFileAct)
        self.fileToolBar.addAction(self.openChartAct)
        self.fileToolBar.addAction(self.goBackAct)

    def createStatusBar(self):
        self.statusBar().showMessage("Ready")
예제 #17
0
class ControlFrame(QFrame):
    def __init__(self, dataset, display_panel, threads):
        super().__init__()
        if isinstance(display_panel, DisplayFrame):
            self.display_panel = display_panel
        else:
            raise TypeError("'display_panel' must be the instance of "
                            "'DisplayFrame'")
        self.dataset = dataset
        self.threads = threads

        self.__layout = QVBoxLayout()
        self.setLayout(self.__layout)
        self.__layout.setContentsMargins(0, 0, 0, 0)

        self.__set_running_options_ui()
        self.__set_fuzzy_set_operation_types_ui()
        self.__set_fuzzy_variables_ui()
        self.__set_fuzzy_rules_ui()
        self.__set_console_ui()

    def __set_running_options_ui(self):
        group_box = QGroupBox("Running Options")
        inner_layout = QHBoxLayout()
        group_box.setLayout(inner_layout)

        self.data_selector = QComboBox()
        self.data_selector.addItems(list(self.dataset.keys()))
        self.data_selector.setStatusTip("Select the road map case.")
        self.data_selector.currentIndexChanged.connect(self.__change_map)

        self.fps = QSpinBox()
        self.fps.setMinimum(1)
        self.fps.setMaximum(60)
        self.fps.setValue(20)
        self.fps.setStatusTip(
            "The re-drawing rate for car simulator. High fps "
            "may cause the plot shows discontinuously.")

        self.start_btn = QPushButton("Run")
        self.start_btn.setStatusTip("Run the car.")
        self.start_btn.clicked.connect(self.__run)

        self.stop_btn = QPushButton("Stop")
        self.stop_btn.setStatusTip("Force the simulation stop running.")
        self.stop_btn.setDisabled(True)

        self.save_btn = QPushButton()
        self.save_btn.setIcon(QIcon(':/icons/save_icon.png'))
        self.save_btn.setStatusTip("Save every details for the last time "
                                   "running.")
        self.save_btn.clicked.connect(self.__save_results)
        self.save_btn.setDisabled(True)

        self.__change_map()
        inner_layout.addWidget(self.data_selector, 1)
        inner_layout.addWidget(QLabel("FPS:"))
        inner_layout.addWidget(self.fps)
        inner_layout.addWidget(self.start_btn)
        inner_layout.addWidget(self.stop_btn)
        inner_layout.addWidget(self.save_btn)

        self.__layout.addWidget(group_box)

    def __set_fuzzy_set_operation_types_ui(self):
        group_box = QGroupBox("Fuzzy Sets Operation Types")
        inner_layout = QFormLayout()
        group_box.setLayout(inner_layout)

        self.implication_selections = RadioButtonSet([
            ("imp_dr", QRadioButton("Dienes-Rescher")),
            ("imp_l", QRadioButton("Lukasieweicz")),
            ("imp_z", QRadioButton("Zadel")), ("imp_g", QRadioButton("Godel")),
            ("imp_m", QRadioButton("Mamdani")),
            ("imp_p", QRadioButton("Product"))
        ])
        self.combination_vars_selections = RadioButtonSet([
            ("tn_min", QRadioButton("Minimum")),
            ("tn_ap", QRadioButton("Algebraic Product")),
            ("tn_bp", QRadioButton("Bounded Product")),
            ("tn_dp", QRadioButton("Drastic Product"))
        ])
        self.combination_rules_selections = RadioButtonSet([
            ("tc_max", QRadioButton("Maximum")),
            ("tc_as", QRadioButton("Algebraic Sum")),
            ("tc_bs", QRadioButton("Bounded Sum")),
            ("tc_ds", QRadioButton("Drastic Sum"))
        ])
        self.defuzzifier_selections = RadioButtonSet([
            ("gravity_center", QRadioButton("Center of Gravity")),
            ("maxima_mean", QRadioButton("Mean of Maxima")),
            ("modified_maxima_mean", QRadioButton("Modified Mean of Maxima"))
        ])

        self.implication_selections.set_selected('imp_m')
        self.combination_vars_selections.set_selected('tn_min')
        self.combination_rules_selections.set_selected('tc_max')
        self.defuzzifier_selections.set_selected('gravity_center')

        self.implication_selections.setStatusTip("Choose the method for fuzzy "
                                                 "implication.")
        self.combination_vars_selections.setStatusTip(
            "Choose the method of "
            "combination of multiple "
            "fuzzy variables.")
        self.combination_rules_selections.setStatusTip("Choose the method of "
                                                       "combination of "
                                                       "multiple fuzzy rules.")
        self.defuzzifier_selections.setStatusTip("Choose the method for the "
                                                 "defuzifier.")

        inner_layout.addRow(QLabel("Implication:"),
                            self.implication_selections)
        inner_layout.addRow(QLabel("Combination of Variables:"),
                            self.combination_vars_selections)
        inner_layout.addRow(QLabel("Combination of Rules:"),
                            self.combination_rules_selections)
        inner_layout.addRow(QLabel("Defuzzifier:"),
                            self.defuzzifier_selections)

        self.__layout.addWidget(group_box)

    def __set_fuzzy_variables_ui(self):
        group_box = QGroupBox("Fuzzy Variables Settings")
        group_box.setStatusTip("Set the membership functions for each fuzzy "
                               "variable.")
        inner_layout = QVBoxLayout()
        self.fuzzyvar_setting_stack = QStackedWidget()
        self.fuzzyvar_ui_selection = RadioButtonSet([
            ("front", QRadioButton("Front Distance Radar")),
            ("lrdiff", QRadioButton("(Left-Right) Distance Radar")),
            ("consequence", QRadioButton("Consequence"))
        ])
        self.fuzzyvar_setting_dist_front = FuzzierVarSetting()
        self.fuzzyvar_setting_dist_front.small.mean.setValue(5)
        self.fuzzyvar_setting_dist_front.medium.mean.setValue(12)
        self.fuzzyvar_setting_dist_front.large.mean.setValue(20)

        self.fuzzyvar_setting_dist_lrdiff = FuzzierVarSetting()
        self.fuzzyvar_setting_dist_lrdiff.small.mean.setValue(-10)
        self.fuzzyvar_setting_dist_lrdiff.medium.mean.setValue(0)
        self.fuzzyvar_setting_dist_lrdiff.large.mean.setValue(10)

        self.fuzzyvar_setting_consequence = FuzzierVarSetting()
        self.fuzzyvar_setting_consequence.small.mean.setValue(-12)
        self.fuzzyvar_setting_consequence.small.sd.setValue(20)
        self.fuzzyvar_setting_consequence.medium.mean.setValue(0)
        self.fuzzyvar_setting_consequence.medium.sd.setValue(20)
        self.fuzzyvar_setting_consequence.large.mean.setValue(12)
        self.fuzzyvar_setting_consequence.large.sd.setValue(20)

        inner_layout.addWidget(self.fuzzyvar_ui_selection)
        inner_layout.addWidget(self.fuzzyvar_setting_stack)
        group_box.setLayout(inner_layout)

        self.fuzzyvar_setting_stack.addWidget(self.fuzzyvar_setting_dist_front)
        self.fuzzyvar_setting_stack.addWidget(
            self.fuzzyvar_setting_dist_lrdiff)
        self.fuzzyvar_setting_stack.addWidget(
            self.fuzzyvar_setting_consequence)

        self.fuzzyvar_ui_selection.sig_rbtn_changed.connect(
            self.__change_fuzzyvar_setting_ui_stack)

        self.__layout.addWidget(group_box)

    def __set_fuzzy_rules_ui(self):
        antecedents = ('small', 'medium', 'large')

        group_box = QGroupBox("Fuzzy Rules Setting")
        inner_layout = QVBoxLayout()
        group_box.setStatusTip("Set the rules for the fuzzy system.")

        self.rules_setting = FuzzyRulesSetting(
            [p for p in itertools.product(antecedents, repeat=2)])
        self.rules_setting.set_consequence_fuzzysets(
            ('large', 'small', 'small', 'large', 'small', 'small', 'large',
             'small', 'small'))

        inner_layout.addWidget(self.rules_setting)
        group_box.setLayout(inner_layout)
        self.__layout.addWidget(group_box)

    def __set_console_ui(self):
        self.__console = QTextEdit()
        self.__console.setReadOnly(True)
        self.__console.setStatusTip("Show the logs of status changing.")
        self.__layout.addWidget(self.__console)

    @Slot(str)
    def __change_fuzzyvar_setting_ui_stack(self, name):
        if name == 'front':
            self.fuzzyvar_setting_stack.setCurrentIndex(0)
        elif name == 'lrdiff':
            self.fuzzyvar_setting_stack.setCurrentIndex(1)
        else:
            self.fuzzyvar_setting_stack.setCurrentIndex(2)

    @Slot()
    def __change_map(self):
        self.__current_data = self.dataset[self.data_selector.currentText()]
        self.__car = Car(self.__current_data['start_pos'],
                         self.__current_data['start_angle'], 3,
                         self.__current_data['route_edge'])
        self.display_panel.change_map(self.__current_data)

    @Slot(str)
    def __print_console(self, text):
        self.__console.append(text)

    @Slot(list)
    def __get_results(self, results):
        """Get the results of last running and draw the path of it."""
        self.results = results
        self.display_panel.show_path([d['x'] for d in results],
                                     [d['y'] for d in results])

    @Slot()
    def __save_results(self):
        save_dir = QFileDialog.getExistingDirectory(self,
                                                    'Select Saving Directory')
        file4d_filepath = os.path.join(save_dir, 'train4D.txt')
        file6d_filepath = os.path.join(save_dir, 'train6D.txt')
        with open(file4d_filepath, 'w') as file4d:
            for result in self.results:
                file4d.write('{:.7f} {:.7f} {:.7f} {:.7f}\n'.format(
                    result['front_dist'], result['right_dist'],
                    result['left_dist'], result['wheel_angle']))
        with open(file6d_filepath, 'w') as file6d:
            for result in self.results:
                file6d.write(
                    '{:.7f} {:.7f} {:.7f} {:.7f} {:.7f} {:.7f}\n'.format(
                        result['x'], result['y'], result['front_dist'],
                        result['right_dist'], result['left_dist'],
                        result['wheel_angle']))
        self.__print_console('Note: Detailed results have been saved in both'
                             ' "%s" and "%s".' %
                             (file4d_filepath, file6d_filepath))

    @Slot()
    def __init_widgets(self):
        self.start_btn.setDisabled(True)
        self.stop_btn.setEnabled(True)
        self.save_btn.setDisabled(True)
        self.fps.setDisabled(True)
        self.data_selector.setDisabled(True)
        self.implication_selections.setDisabled(True)
        self.combination_vars_selections.setDisabled(True)
        self.combination_rules_selections.setDisabled(True)
        self.defuzzifier_selections.setDisabled(True)
        self.fuzzyvar_setting_dist_front.setDisabled(True)
        self.fuzzyvar_setting_dist_lrdiff.setDisabled(True)
        self.fuzzyvar_setting_consequence.setDisabled(True)
        self.rules_setting.setDisabled(True)

    @Slot()
    def __reset_widgets(self):
        self.start_btn.setEnabled(True)
        self.stop_btn.setDisabled(True)
        self.save_btn.setEnabled(True)
        self.fps.setEnabled(True)
        self.data_selector.setEnabled(True)
        self.implication_selections.setEnabled(True)
        self.combination_vars_selections.setEnabled(True)
        self.combination_rules_selections.setEnabled(True)
        self.defuzzifier_selections.setEnabled(True)
        self.fuzzyvar_setting_dist_front.setEnabled(True)
        self.fuzzyvar_setting_dist_lrdiff.setEnabled(True)
        self.fuzzyvar_setting_consequence.setEnabled(True)
        self.rules_setting.setEnabled(True)

    @Slot()
    def __run(self):
        # reset the map
        self.__change_map()
        # create a QThread
        self.thread = RunCar(self.__car, self.__create_fuzzy_system(),
                             (self.__current_data['end_area_lt'],
                              self.__current_data['end_area_rb']),
                             self.fps.value())
        # Record the new created threads for the closeEvent in gui_base.py
        # By doing this, user can destroy the QMainWindow elegantly when there
        # are threads still running.
        self.threads.append(self.thread)
        self.stop_btn.clicked.connect(self.thread.stop)
        self.thread.started.connect(self.__init_widgets)
        self.thread.finished.connect(self.__reset_widgets)
        self.thread.sig_console.connect(self.__print_console)
        self.thread.sig_car.connect(self.display_panel.move_car)
        self.thread.sig_car_collided.connect(
            self.display_panel.show_car_collided)
        self.thread.sig_dists.connect(self.display_panel.show_dists)
        self.thread.sig_results.connect(self.__get_results)
        self.thread.start()

    def __create_fuzzy_system(self):
        """Create a fuzzy system with the parameter given in control panel."""
        dist_front = FuzzyVariable()
        dist_front.add_membershipf(
            'small',
            get_gaussianf(
                *self.fuzzyvar_setting_dist_front.small.get_values()))
        dist_front.add_membershipf(
            'medium',
            get_gaussianf(
                *self.fuzzyvar_setting_dist_front.medium.get_values()))
        dist_front.add_membershipf(
            'large',
            get_gaussianf(
                *self.fuzzyvar_setting_dist_front.large.get_values()))

        dist_lrdiff = FuzzyVariable()
        dist_lrdiff.add_membershipf(
            'small',
            get_gaussianf(
                *self.fuzzyvar_setting_dist_lrdiff.small.get_values()))
        dist_lrdiff.add_membershipf(
            'medium',
            get_gaussianf(
                *self.fuzzyvar_setting_dist_lrdiff.medium.get_values()))
        dist_lrdiff.add_membershipf(
            'large',
            get_gaussianf(
                *self.fuzzyvar_setting_dist_lrdiff.large.get_values()))

        consequence = FuzzyVariable()
        consequence.add_membershipf(
            'small',
            get_gaussianf(
                *self.fuzzyvar_setting_consequence.small.get_values()))
        consequence.add_membershipf(
            'medium',
            get_gaussianf(
                *self.fuzzyvar_setting_consequence.medium.get_values()))
        consequence.add_membershipf(
            'large',
            get_gaussianf(
                *self.fuzzyvar_setting_consequence.large.get_values()))

        fuzzy_system = FuzzySystem(consequence, dist_front, dist_lrdiff)
        fuzzy_system.set_operation_types(
            self.implication_selections.get_selected_name(),
            self.combination_vars_selections.get_selected_name(),
            self.combination_rules_selections.get_selected_name(),
            self.defuzzifier_selections.get_selected_name())

        for antecendent_names, consequence_name in self.rules_setting.rules.items(
        ):
            fuzzy_system.add_rule(consequence_name, antecendent_names)

        return fuzzy_system
예제 #18
0
class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        if not MainWindow.objectName():
            MainWindow.setObjectName(u"MainWindow")
        MainWindow.resize(800, 550)
        MainWindow.setMinimumSize(QSize(800, 550))
        self.centralwidget = QWidget(MainWindow)
        self.centralwidget.setObjectName(u"centralwidget")
        self.centralwidget.setStyleSheet(u"background:rgb(91,90,90);")
        self.verticalLayout = QVBoxLayout(self.centralwidget)
        self.verticalLayout.setSpacing(0)
        self.verticalLayout.setObjectName(u"verticalLayout")
        self.verticalLayout.setContentsMargins(0, 0, 0, 0)
        self.frame_top = QFrame(self.centralwidget)
        self.frame_top.setObjectName(u"frame_top")
        self.frame_top.setMaximumSize(QSize(16777215, 55))
        self.frame_top.setFrameShape(QFrame.NoFrame)
        self.frame_top.setFrameShadow(QFrame.Plain)
        self.horizontalLayout = QHBoxLayout(self.frame_top)
        self.horizontalLayout.setSpacing(0)
        self.horizontalLayout.setObjectName(u"horizontalLayout")
        self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
        self.frame_toodle = QFrame(self.frame_top)
        self.frame_toodle.setObjectName(u"frame_toodle")
        self.frame_toodle.setMinimumSize(QSize(80, 55))
        self.frame_toodle.setMaximumSize(QSize(80, 55))
        self.frame_toodle.setStyleSheet(u"background:rgb(0,143,150);")
        self.frame_toodle.setFrameShape(QFrame.NoFrame)
        self.frame_toodle.setFrameShadow(QFrame.Plain)
        self.horizontalLayout_3 = QHBoxLayout(self.frame_toodle)
        self.horizontalLayout_3.setSpacing(0)
        self.horizontalLayout_3.setObjectName(u"horizontalLayout_3")
        self.horizontalLayout_3.setContentsMargins(0, 0, 0, 0)
        self.toodle = QPushButton(self.frame_toodle)
        self.toodle.setObjectName(u"toodle")
        self.toodle.setMinimumSize(QSize(80, 55))
        self.toodle.setMaximumSize(QSize(80, 55))
        self.toodle.setStyleSheet(u"QPushButton {\n"
                                  "	border: none;\n"
                                  "	background-color: rgba(0,0,0,0);\n"
                                  "}\n"
                                  "QPushButton:hover {\n"
                                  "	background-color: rgb(0,178,178);\n"
                                  "}\n"
                                  "QPushButton:pressed {	\n"
                                  "	background-color: rgba(0,0,0,0);\n"
                                  "}")
        icon = QIcon()
        icon.addFile(u"icons/1x/logo.png", QSize(), QIcon.Normal, QIcon.Off)
        self.toodle.setIcon(icon)
        self.toodle.setIconSize(QSize(22, 12))
        self.toodle.setFlat(True)

        self.horizontalLayout_3.addWidget(self.toodle)

        self.horizontalLayout.addWidget(self.frame_toodle)

        self.frame_top_east = QFrame(self.frame_top)
        self.frame_top_east.setObjectName(u"frame_top_east")
        self.frame_top_east.setMaximumSize(QSize(16777215, 55))
        self.frame_top_east.setStyleSheet(u"background:rgb(51,51,51);")
        self.frame_top_east.setFrameShape(QFrame.NoFrame)
        self.frame_top_east.setFrameShadow(QFrame.Plain)
        self.horizontalLayout_4 = QHBoxLayout(self.frame_top_east)
        self.horizontalLayout_4.setSpacing(0)
        self.horizontalLayout_4.setObjectName(u"horizontalLayout_4")
        self.horizontalLayout_4.setContentsMargins(0, 0, 0, 0)
        self.frame_appname = QFrame(self.frame_top_east)
        self.frame_appname.setObjectName(u"frame_appname")
        self.frame_appname.setFrameShape(QFrame.NoFrame)
        self.frame_appname.setFrameShadow(QFrame.Plain)
        self.horizontalLayout_10 = QHBoxLayout(self.frame_appname)
        self.horizontalLayout_10.setSpacing(7)
        self.horizontalLayout_10.setObjectName(u"horizontalLayout_10")
        self.horizontalLayout_10.setContentsMargins(0, 0, 0, 0)
        self.lab_appname = QLabel(self.frame_appname)
        self.lab_appname.setObjectName(u"lab_appname")
        font = QFont()
        font.setFamily(u"Segoe UI Light")
        font.setPointSize(24)
        self.lab_appname.setFont(font)
        self.lab_appname.setStyleSheet(u"color:rgb(255,255,255);")

        self.horizontalLayout_10.addWidget(self.lab_appname)

        self.horizontalLayout_4.addWidget(self.frame_appname)

        self.frame_min = QFrame(self.frame_top_east)
        self.frame_min.setObjectName(u"frame_min")
        self.frame_min.setMinimumSize(QSize(55, 55))
        self.frame_min.setMaximumSize(QSize(55, 55))
        self.frame_min.setFrameShape(QFrame.NoFrame)
        self.frame_min.setFrameShadow(QFrame.Plain)
        self.horizontalLayout_7 = QHBoxLayout(self.frame_min)
        self.horizontalLayout_7.setSpacing(0)
        self.horizontalLayout_7.setObjectName(u"horizontalLayout_7")
        self.horizontalLayout_7.setContentsMargins(0, 0, 0, 0)
        self.bn_min = QPushButton(self.frame_min)
        self.bn_min.setObjectName(u"bn_min")
        self.bn_min.setMaximumSize(QSize(55, 55))
        self.bn_min.setStyleSheet(u"QPushButton {\n"
                                  "	border: none;\n"
                                  "	background-color: rgba(0,0,0,0);\n"
                                  "}\n"
                                  "QPushButton:hover {\n"
                                  "	background-color: rgb(0,143,150);\n"
                                  "}\n"
                                  "QPushButton:pressed {	\n"
                                  "	background-color: rgba(0,0,0,0);\n"
                                  "}")
        icon1 = QIcon()
        icon1.addFile(u"icons/1x/hideAsset 53.png", QSize(), QIcon.Normal, QIcon.Off)
        self.bn_min.setIcon(icon1)
        self.bn_min.setIconSize(QSize(22, 22))
        self.bn_min.setFlat(True)

        self.horizontalLayout_7.addWidget(self.bn_min)

        self.horizontalLayout_4.addWidget(self.frame_min)

        self.frame_max = QFrame(self.frame_top_east)
        self.frame_max.setObjectName(u"frame_max")
        self.frame_max.setMinimumSize(QSize(55, 55))
        self.frame_max.setMaximumSize(QSize(55, 55))
        self.frame_max.setFrameShape(QFrame.NoFrame)
        self.frame_max.setFrameShadow(QFrame.Plain)
        self.horizontalLayout_6 = QHBoxLayout(self.frame_max)
        self.horizontalLayout_6.setSpacing(0)
        self.horizontalLayout_6.setObjectName(u"horizontalLayout_6")
        self.horizontalLayout_6.setContentsMargins(0, 0, 0, 0)
        self.bn_max = QPushButton(self.frame_max)
        self.bn_max.setObjectName(u"bn_max")
        self.bn_max.setMaximumSize(QSize(55, 55))
        self.bn_max.setStyleSheet(u"QPushButton {\n"
                                  "	border: none;\n"
                                  "	background-color: rgba(0,0,0,0);\n"
                                  "}\n"
                                  "QPushButton:hover {\n"
                                  "	background-color: rgb(0,143,150);\n"
                                  "}\n"
                                  "QPushButton:pressed {	\n"
                                  "	background-color: rgba(0,0,0,0);\n"
                                  "}")
        icon2 = QIcon()
        icon2.addFile(u"icons/1x/max.png", QSize(), QIcon.Normal, QIcon.Off)
        self.bn_max.setIcon(icon2)
        self.bn_max.setIconSize(QSize(22, 22))
        self.bn_max.setFlat(True)

        self.horizontalLayout_6.addWidget(self.bn_max)

        self.horizontalLayout_4.addWidget(self.frame_max)

        self.frame_close = QFrame(self.frame_top_east)
        self.frame_close.setObjectName(u"frame_close")
        self.frame_close.setMinimumSize(QSize(55, 55))
        self.frame_close.setMaximumSize(QSize(55, 55))
        self.frame_close.setFrameShape(QFrame.NoFrame)
        self.frame_close.setFrameShadow(QFrame.Plain)
        self.horizontalLayout_5 = QHBoxLayout(self.frame_close)
        self.horizontalLayout_5.setSpacing(0)
        self.horizontalLayout_5.setObjectName(u"horizontalLayout_5")
        self.horizontalLayout_5.setContentsMargins(0, 0, 0, 0)
        self.bn_close = QPushButton(self.frame_close)
        self.bn_close.setObjectName(u"bn_close")
        self.bn_close.setMaximumSize(QSize(55, 55))
        self.bn_close.setStyleSheet(u"QPushButton {\n"
                                    "	border: none;\n"
                                    "	background-color: rgba(0,0,0,0);\n"
                                    "}\n"
                                    "QPushButton:hover {\n"
                                    "	background-color: rgb(0,143,150);\n"
                                    "}\n"
                                    "QPushButton:pressed {	\n"
                                    "	background-color: rgba(0,0,0,0);\n"
                                    "}")
        icon3 = QIcon()
        icon3.addFile(u"icons/1x/closeAsset 43.png", QSize(), QIcon.Normal, QIcon.Off)
        self.bn_close.setIcon(icon3)
        self.bn_close.setIconSize(QSize(22, 22))
        self.bn_close.setFlat(True)

        self.horizontalLayout_5.addWidget(self.bn_close)

        self.horizontalLayout_4.addWidget(self.frame_close)

        self.horizontalLayout.addWidget(self.frame_top_east)

        self.verticalLayout.addWidget(self.frame_top)

        self.frame_bottom = QFrame(self.centralwidget)
        self.frame_bottom.setObjectName(u"frame_bottom")
        self.frame_bottom.setFrameShape(QFrame.NoFrame)
        self.frame_bottom.setFrameShadow(QFrame.Plain)
        self.horizontalLayout_2 = QHBoxLayout(self.frame_bottom)
        self.horizontalLayout_2.setSpacing(0)
        self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
        self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)
        self.frame_bottom_west = QFrame(self.frame_bottom)
        self.frame_bottom_west.setObjectName(u"frame_bottom_west")
        self.frame_bottom_west.setMinimumSize(QSize(80, 0))
        self.frame_bottom_west.setMaximumSize(QSize(80, 16777215))
        self.frame_bottom_west.setStyleSheet(u"background:rgb(51,51,51);")
        self.frame_bottom_west.setFrameShape(QFrame.NoFrame)
        self.frame_bottom_west.setFrameShadow(QFrame.Plain)
        self.verticalLayout_3 = QVBoxLayout(self.frame_bottom_west)
        self.verticalLayout_3.setSpacing(0)
        self.verticalLayout_3.setObjectName(u"verticalLayout_3")
        self.verticalLayout_3.setContentsMargins(0, 0, 0, 0)
        self.frame_home = QFrame(self.frame_bottom_west)
        self.frame_home.setObjectName(u"frame_home")
        self.frame_home.setMinimumSize(QSize(80, 55))
        self.frame_home.setMaximumSize(QSize(160, 55))
        self.frame_home.setFrameShape(QFrame.NoFrame)
        self.frame_home.setFrameShadow(QFrame.Plain)
        self.horizontalLayout_15 = QHBoxLayout(self.frame_home)
        self.horizontalLayout_15.setSpacing(0)
        self.horizontalLayout_15.setObjectName(u"horizontalLayout_15")
        self.horizontalLayout_15.setContentsMargins(0, 0, 0, 0)
        self.bn_home = QPushButton(self.frame_home)
        self.bn_home.setObjectName(u"bn_home")
        self.bn_home.setMinimumSize(QSize(80, 55))
        self.bn_home.setMaximumSize(QSize(160, 55))
        self.bn_home.setStyleSheet(u"QPushButton {\n"
                                   "	border: none;\n"
                                   "	background-color: rgba(0,0,0,0);\n"
                                   "}\n"
                                   "QPushButton:hover {\n"
                                   "	background-color: rgb(91,90,90);\n"
                                   "}\n"
                                   "QPushButton:pressed {	\n"
                                   "	background-color: rgba(0,0,0,0);\n"
                                   "}")
        icon4 = QIcon()
        icon4.addFile(u"icons/1x/homeAsset 46.png", QSize(), QIcon.Normal, QIcon.Off)
        self.bn_home.setIcon(icon4)
        self.bn_home.setIconSize(QSize(22, 22))
        self.bn_home.setFlat(True)

        self.horizontalLayout_15.addWidget(self.bn_home)

        self.verticalLayout_3.addWidget(self.frame_home)

        self.frame_8 = QFrame(self.frame_bottom_west)
        self.frame_8.setObjectName(u"frame_8")
        self.frame_8.setFrameShape(QFrame.NoFrame)
        self.frame_8.setFrameShadow(QFrame.Plain)
        self.verticalLayout_4 = QVBoxLayout(self.frame_8)
        self.verticalLayout_4.setSpacing(0)
        self.verticalLayout_4.setObjectName(u"verticalLayout_4")
        self.verticalLayout_4.setContentsMargins(0, 0, 0, 0)

        self.verticalLayout_3.addWidget(self.frame_8)

        self.horizontalLayout_2.addWidget(self.frame_bottom_west)

        self.frame_bottom_east = QFrame(self.frame_bottom)
        self.frame_bottom_east.setObjectName(u"frame_bottom_east")
        self.frame_bottom_east.setFrameShape(QFrame.NoFrame)
        self.frame_bottom_east.setFrameShadow(QFrame.Plain)
        self.verticalLayout_2 = QVBoxLayout(self.frame_bottom_east)
        self.verticalLayout_2.setSpacing(0)
        self.verticalLayout_2.setObjectName(u"verticalLayout_2")
        self.verticalLayout_2.setContentsMargins(0, 0, 0, 0)
        self.frame = QFrame(self.frame_bottom_east)
        self.frame.setObjectName(u"frame")
        self.frame.setFrameShape(QFrame.NoFrame)
        self.frame.setFrameShadow(QFrame.Plain)
        self.horizontalLayout_14 = QHBoxLayout(self.frame)
        self.horizontalLayout_14.setSpacing(0)
        self.horizontalLayout_14.setObjectName(u"horizontalLayout_14")
        self.horizontalLayout_14.setContentsMargins(0, 0, 0, 0)
        self.stackedWidget = QStackedWidget(self.frame)
        self.stackedWidget.setObjectName(u"stackedWidget")
        self.stackedWidget.setMinimumSize(QSize(0, 55))
        self.stackedWidget.setStyleSheet(u"")
        self.page_home = QWidget()
        self.page_home.setObjectName(u"page_home")
        self.page_home.setStyleSheet(u"background:rgb(91,90,90);")
        self.horizontalLayout_19 = QHBoxLayout(self.page_home)
        self.horizontalLayout_19.setSpacing(0)
        self.horizontalLayout_19.setObjectName(u"horizontalLayout_19")
        self.horizontalLayout_19.setContentsMargins(0, 5, 0, 5)
        self.frame_home_main = QFrame(self.page_home)
        self.frame_home_main.setObjectName(u"frame_home_main")
        self.frame_home_main.setFrameShape(QFrame.NoFrame)
        self.frame_home_main.setFrameShadow(QFrame.Plain)
        self.verticalLayout_5 = QVBoxLayout(self.frame_home_main)
        self.verticalLayout_5.setSpacing(5)
        self.verticalLayout_5.setObjectName(u"verticalLayout_5")
        self.verticalLayout_5.setContentsMargins(5, 5, 5, 5)
        font1 = QFont()
        font1.setFamily(u"Segoe UI Semilight")
        font1.setPointSize(10)
        self.lab_home_main_disc = QLabel(self.frame_home_main)
        self.lab_home_main_disc.setObjectName(u"lab_home_main_disc")
        font2 = QFont()
        font2.setFamily(u"Segoe UI")
        font2.setPointSize(10)
        self.lab_home_main_disc.setFont(font2)
        self.lab_home_main_disc.setStyleSheet(u"color:rgb(255,255,255);")
        self.lab_home_main_disc.setAlignment(Qt.AlignLeading | Qt.AlignLeft | Qt.AlignTop)
        self.lab_home_main_disc.setWordWrap(True)
        self.lab_home_main_disc.setMargin(5)

        self.verticalLayout_5.addWidget(self.lab_home_main_disc)

        self.horizontalLayout_19.addWidget(self.frame_home_main)

        self.vert_divide = QFrame(self.page_home)
        self.vert_divide.setObjectName(u"vert_divide")
        self.vert_divide.setFrameShape(QFrame.VLine)
        self.vert_divide.setFrameShadow(QFrame.Sunken)

        self.horizontalLayout_19.addWidget(self.vert_divide)

        self.frame_home_stat = QFrame(self.page_home)
        self.frame_home_stat.setObjectName(u"frame_home_stat")
        self.frame_home_stat.setMinimumSize(QSize(220, 0))
        self.frame_home_stat.setMaximumSize(QSize(220, 16777215))
        self.frame_home_stat.setFrameShape(QFrame.NoFrame)
        self.frame_home_stat.setFrameShadow(QFrame.Plain)
        self.verticalLayout_6 = QVBoxLayout(self.frame_home_stat)
        self.verticalLayout_6.setSpacing(5)
        self.verticalLayout_6.setObjectName(u"verticalLayout_6")
        self.verticalLayout_6.setContentsMargins(5, 5, 5, 5)

        self.bn_home_image = QPushButton(self.frame_home_stat)
        self.bn_home_image.setObjectName(u"bn_home_image")
        self.bn_home_image.setEnabled(True)
        self.bn_home_image.setMinimumSize(QSize(205, 25))
        self.bn_home_image.setMaximumSize(QSize(205, 25))
        self.bn_home_image.setFont(font1)
        self.bn_home_image.setStyleSheet(u"QPushButton {\n"
                                         "	border: 2px solid rgb(51,51,51);\n"
                                         "	border-radius: 5px;	\n"
                                         "	color:rgb(255,255,255);\n"
                                         "	background-color: rgb(51,51,51);\n"
                                         "}\n"
                                         "QPushButton:hover {\n"
                                         "	border: 2px solid rgb(0,143,150);\n"
                                         "	background-color: rgb(0,143,150);\n"
                                         "}\n"
                                         "QPushButton:pressed {	\n"
                                         "	border: 2px solid rgb(0,143,150);\n"
                                         "	background-color: rgb(51,51,51);\n"
                                         "}\n"
                                         "\n"
                                         "QPushButton:disabled {	\n"
                                         "	border-radius: 5px;	\n"
                                         "	border: 2px solid rgb(112,112,112);\n"
                                         "	background-color: rgb(112,112,112);\n"
                                         "}")

        self.verticalLayout_6.addWidget(self.bn_home_image)

        self.bn_home_rec = QPushButton(self.frame_home_stat)
        self.bn_home_rec.setObjectName(u"bn_home_rec")
        self.bn_home_rec.setEnabled(True)
        self.bn_home_rec.setMinimumSize(QSize(205, 25))
        self.bn_home_rec.setMaximumSize(QSize(205, 25))
        self.bn_home_rec.setFont(font1)
        self.bn_home_rec.setStyleSheet(u"QPushButton {\n"
                                       "	border: 2px solid rgb(51,51,51);\n"
                                       "	border-radius: 5px;	\n"
                                       "	color:rgb(255,255,255);\n"
                                       "	background-color: rgb(51,51,51);\n"
                                       "}\n"
                                       "QPushButton:hover {\n"
                                       "	border: 2px solid rgb(0,143,150);\n"
                                       "	background-color: rgb(0,143,150);\n"
                                       "}\n"
                                       "QPushButton:pressed {	\n"
                                       "	border: 2px solid rgb(0,143,150);\n"
                                       "	background-color: rgb(51,51,51);\n"
                                       "}\n"
                                       "\n"
                                       "QPushButton:disabled {	\n"
                                       "	border-radius: 5px;	\n"
                                       "	border: 2px solid rgb(112,112,112);\n"
                                       "	background-color: rgb(112,112,112);\n"
                                       "}")

        self.verticalLayout_6.addWidget(self.bn_home_rec)

        self.horizontalLayout_19.addWidget(self.frame_home_stat)

        self.stackedWidget.addWidget(self.page_home)
        self.page_about_home = QWidget()
        self.page_about_home.setObjectName(u"page_about_home")
        self.page_about_home.setStyleSheet(u"background:rgb(91,90,90);")
        self.verticalLayout_13 = QVBoxLayout(self.page_about_home)
        self.verticalLayout_13.setSpacing(5)
        self.verticalLayout_13.setObjectName(u"verticalLayout_13")
        self.verticalLayout_13.setContentsMargins(5, 5, 5, 5)
        self.lab_about_home = QLabel(self.page_about_home)
        self.lab_about_home.setObjectName(u"lab_about_home")
        self.lab_about_home.setMinimumSize(QSize(0, 55))
        self.lab_about_home.setMaximumSize(QSize(16777215, 55))
        font3 = QFont()
        font3.setFamily(u"Segoe UI")
        font3.setPointSize(24)
        self.lab_about_home.setFont(font3)
        self.lab_about_home.setStyleSheet(u"color:rgb(255,255,255);")

        self.verticalLayout_13.addWidget(self.lab_about_home)

        self.frame_about_home = QFrame(self.page_about_home)
        self.frame_about_home.setObjectName(u"frame_about_home")
        self.frame_about_home.setFrameShape(QFrame.StyledPanel)
        self.frame_about_home.setFrameShadow(QFrame.Raised)
        self.horizontalLayout_28 = QHBoxLayout(self.frame_about_home)
        self.horizontalLayout_28.setSpacing(0)
        self.horizontalLayout_28.setObjectName(u"horizontalLayout_28")
        self.horizontalLayout_28.setContentsMargins(5, 5, 0, 5)
        self.text_about_home = QTextEdit(self.frame_about_home)
        self.text_about_home.setObjectName(u"text_about_home")
        self.text_about_home.setEnabled(True)
        self.text_about_home.setFont(font2)
        self.text_about_home.setStyleSheet(u"color:rgb(255,255,255);")
        self.text_about_home.setFrameShape(QFrame.NoFrame)
        self.text_about_home.setFrameShadow(QFrame.Plain)
        self.text_about_home.setReadOnly(True)
        self.text_about_home.setTextInteractionFlags(Qt.TextBrowserInteraction)

        self.horizontalLayout_28.addWidget(self.text_about_home)

        self.vsb_about_home = QScrollBar(self.frame_about_home)
        self.vsb_about_home.setObjectName(u"vsb_about_home")
        self.vsb_about_home.setStyleSheet(u"QScrollBar:vertical {\n"
                                          "	background:rgb(51,51,51);\n"
                                          "    width:20px;\n"
                                          "    margin: 0px 0px 0px 0px;\n"
                                          "}\n"
                                          "QScrollBar::handle:vertical {\n"
                                          "    background:rgb(0,143,170);\n"
                                          "}\n"
                                          "QScrollBar::add-page:vertical {\n"
                                          " 	background:rgb(51,51,51);\n"
                                          "}\n"
                                          "QScrollBar::sub-page:vertical {\n"
                                          " 	background:rgb(51,51,51);\n"
                                          "}")
        self.vsb_about_home.setOrientation(Qt.Vertical)

        self.horizontalLayout_28.addWidget(self.vsb_about_home)
        self.verticalLayout_13.addWidget(self.frame_about_home)
        self.stackedWidget.addWidget(self.page_about_home)

        self.horizontalLayout_14.addWidget(self.stackedWidget)
        self.verticalLayout_2.addWidget(self.frame)

        self.frame_low = QFrame(self.frame_bottom_east)
        self.frame_low.setObjectName(u"frame_low")
        self.frame_low.setMinimumSize(QSize(0, 20))
        self.frame_low.setMaximumSize(QSize(16777215, 20))
        self.frame_low.setStyleSheet(u"")
        self.frame_low.setFrameShape(QFrame.NoFrame)
        self.frame_low.setFrameShadow(QFrame.Plain)
        self.horizontalLayout_11 = QHBoxLayout(self.frame_low)
        self.horizontalLayout_11.setSpacing(0)
        self.horizontalLayout_11.setObjectName(u"horizontalLayout_11")
        self.horizontalLayout_11.setContentsMargins(0, 0, 0, 0)
        self.frame_tab = QFrame(self.frame_low)
        self.frame_tab.setObjectName(u"frame_tab")
        font10 = QFont()
        font10.setFamily(u"Segoe UI")
        self.frame_tab.setFont(font10)
        self.frame_tab.setStyleSheet(u"background:rgb(51,51,51);")
        self.frame_tab.setFrameShape(QFrame.NoFrame)
        self.frame_tab.setFrameShadow(QFrame.Plain)
        self.horizontalLayout_12 = QHBoxLayout(self.frame_tab)
        self.horizontalLayout_12.setSpacing(0)
        self.horizontalLayout_12.setObjectName(u"horizontalLayout_12")
        self.horizontalLayout_12.setContentsMargins(0, 0, 0, 0)
        self.lab_tab = QLabel(self.frame_tab)
        self.lab_tab.setObjectName(u"lab_tab")
        font11 = QFont()
        font11.setFamily(u"Segoe UI Light")
        font11.setPointSize(10)
        self.lab_tab.setFont(font11)
        self.lab_tab.setStyleSheet(u"color:rgb(255,255,255);")
        self.horizontalLayout_12.addWidget(self.lab_tab)
        self.horizontalLayout_11.addWidget(self.frame_tab)

        self.frame_drag = QFrame(self.frame_low)
        self.frame_drag.setObjectName(u"frame_drag")
        self.frame_drag.setMinimumSize(QSize(20, 20))
        self.frame_drag.setMaximumSize(QSize(20, 20))
        self.frame_drag.setStyleSheet(u"background:rgb(51,51,51);")
        self.frame_drag.setFrameShape(QFrame.NoFrame)
        self.frame_drag.setFrameShadow(QFrame.Plain)
        self.horizontalLayout_13 = QHBoxLayout(self.frame_drag)
        self.horizontalLayout_13.setSpacing(0)
        self.horizontalLayout_13.setObjectName(u"horizontalLayout_13")
        self.horizontalLayout_13.setContentsMargins(0, 0, 0, 0)

        self.horizontalLayout_11.addWidget(self.frame_drag)
        self.verticalLayout_2.addWidget(self.frame_low)

        self.horizontalLayout_2.addWidget(self.frame_bottom_east)
        self.verticalLayout.addWidget(self.frame_bottom)

        MainWindow.setCentralWidget(self.centralwidget)
        self.retranslateUi(MainWindow)
        self.stackedWidget.setCurrentIndex(7)

        QMetaObject.connectSlotsByName(MainWindow)

    # setupUi

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"MainWindow", None))
        self.toodle.setText("")
        self.lab_appname.setText(
            QCoreApplication.translate("MainWindow", u"<html><head/><body><p><br/></p></body></html>", None))
        self.bn_min.setToolTip(QCoreApplication.translate("MainWindow", u"Minimize", None))
        self.bn_min.setText("")
        self.bn_max.setToolTip(QCoreApplication.translate("MainWindow", u"Maximize", None))
        self.bn_max.setText("")
        self.bn_close.setToolTip(QCoreApplication.translate("MainWindow", u"Close", None))
        self.bn_close.setText("")
        self.bn_home.setToolTip(QCoreApplication.translate("MainWindow", u"Home", None))
        self.bn_home.setText("")
        self.lab_about_home.setText(QCoreApplication.translate("MainWindow", u"How to use", None))
        self.bn_home_image.setText(QCoreApplication.translate("MainWindow", u"Upload Image", None))
        self.bn_home_rec.setText(QCoreApplication.translate("MainWindow", u"Recognition", None))
        self.lab_tab.setText(
            QCoreApplication.translate("MainWindow", u"<html><head/><body><p><br/></p></body></html>", None))
        self.frame_drag.setToolTip(QCoreApplication.translate("MainWindow", u"Drag", None))
예제 #19
0
    def __init__(self, parent=None):
        super().__init__(parent)

        self.setMinimumSize(800, 600)
        self.setWindowTitle(self.tr("Preferences"))

        self._preferences = Preferences()

        #
        # Content

        self._generalPage = PreferencesGeneralPage()
        self._generalPage.setZeroMargins()
        self._generalPage.preferencesChanged.connect(
            self._onPreferencesChanged)

        self._documentsPage = PreferencesDocumentsPage()
        self._documentsPage.setZeroMargins()
        self._documentsPage.preferencesChanged.connect(
            self._onPreferencesChanged)

        self._documentPresetsPage = PreferencesDocumentPresetsPage()
        self._documentPresetsPage.setZeroMargins()
        self._documentPresetsPage.preferencesChanged.connect(
            self._onPreferencesChanged)

        stackedBox = QStackedWidget()
        stackedBox.addWidget(self._generalPage)
        stackedBox.addWidget(self._documentsPage)
        stackedBox.addWidget(self._documentPresetsPage)
        stackedBox.setCurrentIndex(0)

        listBox = QListWidget()
        listBox.addItem(self._generalPage.title())
        listBox.addItem(self._documentsPage.title())
        listBox.addItem(self._documentPresetsPage.title())
        listBox.setCurrentRow(stackedBox.currentIndex())
        listBox.currentRowChanged.connect(stackedBox.setCurrentIndex)

        preferencesBox = QHBoxLayout()
        preferencesBox.addWidget(listBox, 1)
        preferencesBox.addWidget(stackedBox, 3)

        # Button box
        buttonBox = QDialogButtonBox(QDialogButtonBox.RestoreDefaults
                                     | QDialogButtonBox.Ok
                                     | QDialogButtonBox.Apply
                                     | QDialogButtonBox.Cancel)
        self._buttonApply = buttonBox.button(QDialogButtonBox.Apply)
        buttonBox.button(QDialogButtonBox.RestoreDefaults).clicked.connect(
            self._onButtonDefaultsClicked)
        buttonBox.accepted.connect(self._onButtonOkClicked)
        buttonBox.button(QDialogButtonBox.Apply).clicked.connect(
            self._onButtonApplyClicked)
        buttonBox.rejected.connect(self.close)

        # Main layout
        layout = QVBoxLayout(self)
        layout.addLayout(preferencesBox)
        layout.addWidget(buttonBox)

        self._updatePreferences()
        self._buttonApply.setEnabled(False)
예제 #20
0
class ColorPanel(QWidget):
    """
    颜色面板柱状条
    作者:feiyangqingyun(QQ:517216493) 2017-11-21
    译者:sunchuquin(QQ:1715216365) 2021-07-04
    """
    def __init__(self, parent: QWidget = None):
        super(ColorPanel, self).__init__(parent)
        self.resize(650, 450)

        g_layout = QVBoxLayout()

        self.stackedWidget = QStackedWidget()
        self.pageFader = QWidget()
        layout = QVBoxLayout()
        self.colorPanelFader = ColorPanelFader()
        layout.addWidget(self.colorPanelFader)
        layout.setContentsMargins(0, 0, 0, 0)
        self.pageFader.setLayout(layout)
        self.pageHSB = QWidget()
        layout = QHBoxLayout()
        self.colorPanelHSB = ColorPanelHSB()
        self.colorPanelBar = ColorPanelBar()
        self.colorPanelBar.setMinimumWidth(60)
        self.colorPanelBar.setMaximumWidth(60)
        layout.addWidget(self.colorPanelHSB)
        layout.addWidget(self.colorPanelBar)
        layout.setContentsMargins(0, 0, 0, 0)
        self.pageHSB.setLayout(layout)
        self.pageBtn = QWidget()
        layout = QVBoxLayout()
        self.colorPanelBtn = ColorPanelBtn()
        layout.addWidget(self.colorPanelBtn)
        layout.setContentsMargins(0, 0, 0, 0)
        self.pageBtn.setLayout(layout)
        self.stackedWidget.addWidget(self.pageFader)
        self.stackedWidget.addWidget(self.pageHSB)
        self.stackedWidget.addWidget(self.pageBtn)
        g_layout.addWidget(self.stackedWidget)

        self.widgetColor = QWidget()
        self.btnHue = ColorButton()
        self.btnSat = ColorButton()
        self.btnBright = ColorButton()
        self.btnCyan = ColorButton()
        self.btnMagenta = ColorButton()
        self.btnYellow = ColorButton()
        self.btnRed = ColorButton()
        self.btnGreen = ColorButton()
        self.btnBlue = ColorButton()
        self.widgetColor.setMinimumHeight(45)
        self.widgetColor.setMaximumHeight(45)
        layout = QHBoxLayout()
        layout.addWidget(self.btnHue)
        layout.addWidget(self.btnSat)
        layout.addWidget(self.btnBright)
        layout.addWidget(self.btnCyan)
        layout.addWidget(self.btnMagenta)
        layout.addWidget(self.btnYellow)
        layout.addWidget(self.btnRed)
        layout.addWidget(self.btnGreen)
        layout.addWidget(self.btnBlue)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(1)
        self.widgetColor.setLayout(layout)
        g_layout.addWidget(self.widgetColor)

        self.widgetPanel = QWidget()
        layout = QHBoxLayout()
        self.btnPanelFader = ColorButton()
        self.btnPanelHSB = ColorButton()
        self.btnPanelBtn = ColorButton()
        self.labColor = QLabel()
        self.labColor.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
        layout.addWidget(self.btnPanelFader)
        layout.addWidget(self.btnPanelHSB)
        layout.addWidget(self.btnPanelBtn)
        layout.addWidget(self.labColor)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(1)
        self.widgetPanel.setLayout(layout)
        g_layout.addWidget(self.widgetPanel)
        self.setLayout(g_layout)

        self.initForm()

    def initForm(self) -> None:
        self.btnHue.borderColor = QColor(Qt.darkGray)
        self.btnSat.borderColor = QColor(Qt.darkGray)
        self.btnBright.borderColor = QColor(Qt.darkGray)
        self.btnHue.normalColor = QColor(Qt.darkGray).light(20)
        self.btnSat.normalColor = QColor(Qt.darkGray).light(20)
        self.btnBright.normalColor = QColor(Qt.darkGray).light(20)

        self.btnCyan.borderColor = QColor(Qt.cyan)
        self.btnMagenta.borderColor = QColor(Qt.magenta)
        self.btnYellow.borderColor = QColor(Qt.yellow)
        self.btnCyan.normalColor = QColor(Qt.cyan).light(50)
        self.btnMagenta.normalColor = QColor(Qt.magenta).light(50)
        self.btnYellow.normalColor = QColor(Qt.yellow).light(50)

        self.btnRed.borderColor = QColor(Qt.red)
        self.btnGreen.borderColor = QColor(Qt.green)
        self.btnBlue.borderColor = QColor(Qt.blue)
        self.btnRed.normalColor = QColor(Qt.red).light(50)
        self.btnGreen.normalColor = QColor(Qt.green).light(50)
        self.btnBlue.normalColor = QColor(Qt.blue).light(50)

        self.btnPanelFader.text = "颜色滑块面板"
        self.btnPanelHSB.text = "颜色选取面板"
        self.btnPanelBtn.text = "颜色按钮面板"

        self.btnPanelFader.normalColor = QColor("#16A085")
        self.btnPanelHSB.normalColor = QColor("#C0392B")
        self.btnPanelBtn.normalColor = QColor("#27AE60")

        font: QFont = QFont()
        font.setPixelSize(15)
        font.setBold(True)
        self.btnPanelFader.textFont = font
        self.btnPanelHSB.textFont = font
        self.btnPanelBtn.textFont = font

        self.colorPanelFader.colorChanged.connect(self.colorChangedFader)
        self.colorPanelHSB.colorChanged.connect(self.colorChangedHSB)
        self.colorPanelBar.colorChanged.connect(self.colorChangedBar)
        self.colorPanelBtn.colorChanged.connect(self.colorChangedBtn)

        self.widgetColor.setEnabled(False)
        self.stackedWidget.setCurrentIndex(0)
        self.colorPanelBar.staticMode = False
        self.colorChangedBar(QColor(Qt.red), 0, 100)

        self.btnPanelFader.clicked.connect(self.buttonClicked)
        self.btnPanelHSB.clicked.connect(self.buttonClicked)
        self.btnPanelBtn.clicked.connect(self.buttonClicked)

    def colorChangedFader(self, color: QColor, hue: float, sat: float,
                          bright: float) -> None:
        self.btnHue.text = "Hue\n%0.1f" % round(hue, 1)
        self.btnSat.text = "Sat\n%0.1f" % round(sat, 1)
        self.btnBright.text = "Bright\n%0.1f" % round(bright, 1)

        self.setColor(color)

    def colorChangedHSB(self, color: QColor, hue: float, sat: float) -> None:
        self.colorPanelBar.topColor = color
        self.colorPanelBar.borderColor = color

        self.btnHue.text = "Hue\n%0.1f" % round(hue, 1)
        self.btnSat.text = "Sat\n%0.1f" % round(sat, 1)
        self.btnBright.text = "Bright\n%0.1f" % round(
            self.colorPanelBar.percent, 1)

        c: QColor = QColor.fromHsvF(hue / 360, sat / 100,
                                    self.colorPanelBar.percent / 100)
        self.setColor(c)

    def colorChangedBar(self, color: QColor, value: float,
                        percent: float) -> None:
        if self.colorPanelHSB.isVisible():
            self.colorPanelHSB.percent = percent

        hue: float = color.hue()
        hue = 360 if hue < 0 else hue
        sat: float = color.saturationF() * 100

        if not self.colorPanelBar.isVisible():
            self.btnHue.text = "Hue\n%0.1f" % round(hue, 1)
            self.btnSat.text = "Sat\n%0.1f" % round(sat, 1)

        self.btnBright.text = "Bright\n%0.1f" % round(percent, 1)

        self.setColor(color)

    def colorChangedBtn(self, color: QColor) -> None:
        self.colorChangedBar(color, 0, 100)

    def setColor(self, color: QColor) -> None:
        # 根据背景色自动计算合适的前景色
        gray: float = (0.299 * color.red() + 0.587 * color.green() +
                       0.114 * color.blue()) / 255
        textColor: QColor = QColor(Qt.black) if gray > 0.5 else QColor(
            Qt.white)
        self.labColor.setText(color.name().upper())
        self.labColor.setStyleSheet(
            "QLabel{font:25px;color:%s;background:%s;}" %
            (textColor.name(), color.name()))

        percentRed: float = color.redF() * 100
        percentGreen: float = color.greenF() * 100
        percentBlue: float = color.blueF() * 100

        self.btnCyan.text = "Cyan\n%0.1f%%" % round(100 - percentRed, 1)
        self.btnMagenta.text = "Magenta\n%0.1f%%" % round(
            100 - percentGreen, 1)
        self.btnYellow.text = "Yellow\n%0.1f%%" % round(100 - percentBlue, 1)

        self.btnRed.text = "Red\n%0.1f%%" % round(percentRed, 1)
        self.btnGreen.text = "Green\n%0.1f%%" % round(percentGreen, 1)
        self.btnBlue.text = "Blue\n%0.1f%%" % round(percentBlue, 1)

    def buttonClicked(self) -> None:
        btn: ColorButton = self.sender()
        if btn == self.btnPanelFader:
            self.stackedWidget.setCurrentIndex(0)
        elif btn == self.btnPanelHSB:
            self.stackedWidget.setCurrentIndex(1)
        elif btn == self.btnPanelBtn:
            self.stackedWidget.setCurrentIndex(2)
예제 #21
0
class MainWindowUi(QMainWindow):
    """sets up ui properties of MainWindowUi class"""
    def __init__(self) -> None:
        """inits MainWindow class

        configuring parameters of MainWindow class and inherits from QtWidget.QMainWindow
        loads .ui file sets up file and directory path vars, inits click events(menuebar, coboboxes, btns) and
        shows gui the first time

        Returns:
            None"""
        super(MainWindowUi, self).__init__()
        self.setWindowTitle("It_Hilfe")
        self.resize(820, 450)
        self.setWindowIcon(QIcon("./data/favicon2.png"))
        self.setMinimumSize(700, 250)

        self.file_path = None
        self.dir = None
        self.last_open_file_path = None
        self.last_open_file_dir = None
        self.initial_theme = None
        self.registered_devices = {}
        self.user_config_file = "./data/user_config.json"

        # setup stackedwidget
        self.stacked_widget = QStackedWidget()
        self.setCentralWidget(self.stacked_widget)
        self.setup_menubar()
        self.setup_p_view()
        self.setup_p_register()
        self.setup_p_create()
        self.setup_p_preferences()
        self.setup_signals()

        self.font = QFont()
        self.font.setPointSize(9)

        self.validate(self.set_user_preferences,
                      file_path=self.user_config_file,
                      schema=validate_json.ItHilfeUserPreferencesSchema,
                      forbidden=[""])

        # setup statusbar
        self.statusbar = self.statusBar()

        self.stacked_widget.setCurrentWidget(self.p_view)

    def setup_menubar(self) -> None:
        """inits menubar

        Returns:
            None"""
        self.menu_Bar = self.menuBar()

        menu_file = self.menu_Bar.addMenu("file")
        self.action_open = QAction("open")
        self.action_save = QAction("save")
        self.action_new = QAction("new")
        self.action_print = QAction("print")
        self.action_preferences = QAction("preferences")
        self.action_hide_menu_bar = QAction("hide menubar")
        self.action_print.setShortcut(QKeySequence("Ctrl+p"))
        self.action_open.setShortcut(QKeySequence("Ctrl+o"))
        self.action_save.setShortcut(QKeySequence("Ctrl+s"))
        self.action_hide_menu_bar.setShortcut(QKeySequence("Ctrl+h"))
        self.action_hide_menu_bar.setIcon(QIcon("./data/show_hide.ico"))
        self.action_print.setIcon(QIcon("./data/print2.ico"))
        self.action_open.setIcon(QIcon("./data/open.ico"))
        self.action_save.setIcon(QIcon("./data/save.ico"))
        self.action_new.setIcon(QIcon("./data/newfile.ico"))
        self.action_preferences.setIcon(QIcon("./data/preferences.ico"))

        menu_file.addAction(self.action_open)
        menu_file.addAction(self.action_save)
        menu_file.addAction(self.action_new)
        menu_file.addAction(self.action_print)
        menu_file.addAction(self.action_preferences)

        menu_edit = self.menu_Bar.addMenu("edit")
        self.action_register = QAction("register")
        self.action_register.setShortcut(QKeySequence("Ctrl+n"))
        self.action_register.setIcon(QIcon("./data/register.ico"))

        menu_edit.addAction(self.action_register)

        menu_view = self.menu_Bar.addMenu("view")
        menu_view.addAction(self.action_hide_menu_bar)

    def setup_p_view(self) -> None:
        """inits stacked widget page widget

        Returns:
            None"""
        self.p_view = QtWidgets.QWidget()
        self.stacked_widget.addWidget(self.p_view)

        self.model = QStandardItemModel(self.p_view)
        self.model.setHorizontalHeaderLabels(labels)

        self.filters = []
        source_model = self.model
        for filter_num in range(7):
            filter = QSortFilterProxyModel()
            filter.setSourceModel(source_model)
            filter.setFilterKeyColumn(filter_num)
            source_model = filter
            self.filters.append(filter)

        delegate = ComboDelegate()
        self.table = QtWidgets.QTableView(self.p_view)
        self.table.setModel(self.filters[-1])
        self.table.setItemDelegateForColumn(2, delegate)
        self.table.horizontalHeader().setStretchLastSection(True)
        self.table.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

        self.header = FilterHeader(self.table)
        self.header.set_filter_boxes()
        self.header.setMaximumHeight(50)
        self.table.setHorizontalHeader(self.header)

        self.bt_burger = QPushButton(self.p_view)
        self.bt_burger.setIcon(QIcon("./data/menu2.svg"))
        self.bt_burger.setIconSize(QSize(30, 30))
        self.bt_burger.setToolTip('slide out description')
        l_burger = QLabel("menu", self.p_view)

        self.bt_register_new = QPushButton(self.p_view)
        self.bt_register_new.setIcon(QIcon("./data/add.ico"))
        self.bt_register_new.setIconSize(QSize(30, 30))
        self.bt_register_new.setToolTip("register new")
        l_register_new = QLabel("register new", self.p_view)

        self.bt_delete_column = QPushButton(self.p_view)
        self.bt_delete_column.setIcon(QIcon("./data/remove.ico"))
        self.bt_delete_column.setIconSize(QSize(30, 30))
        self.bt_delete_column.setToolTip(
            "delete columns with min 1 cell selected")
        l_delete = QLabel("delete column", self.p_view)

        self.bt_hide_show_filter = QPushButton(self.p_view)
        self.bt_hide_show_filter.setIcon(QIcon("./data/show_hide.ico"))
        self.bt_hide_show_filter.setIconSize(QSize(30, 30))
        self.bt_hide_show_filter.setToolTip("hide/show filter input")
        l_hide_show = QLabel("hide/show", self.p_view)

        self.left_btn_frame = QFrame(self.p_view)
        self.left_btn_frame.setMaximumWidth(40)
        self.left_btn_frame.setContentsMargins(0, 0, 0, 0)

        self.left_menu_frame = QFrame(self.p_view)
        self.left_menu_frame.setMaximumWidth(0)
        self.left_menu_frame.setContentsMargins(0, 0, 0, 0)

        p_view_layout2 = QtWidgets.QVBoxLayout(self.left_btn_frame)
        p_view_layout2.addWidget(self.bt_burger)
        p_view_layout2.addWidget(self.bt_register_new)
        p_view_layout2.addWidget(self.bt_delete_column)
        p_view_layout2.addWidget(self.bt_hide_show_filter)
        p_view_layout2.setAlignment(Qt.AlignTop)
        p_view_layout2.setContentsMargins(0, 0, 0, 0)

        self.p_view_layout3 = QtWidgets.QVBoxLayout(self.left_menu_frame)
        self.p_view_layout3.addWidget(l_burger)
        self.p_view_layout3.addWidget(l_register_new)
        self.p_view_layout3.addWidget(l_delete)
        self.p_view_layout3.addWidget(l_hide_show)
        self.p_view_layout3.setAlignment(Qt.AlignTop | Qt.AlignCenter)
        self.p_view_layout3.setContentsMargins(0, 0, 0, 0)
        self.p_view_layout3.setSpacing(25)

        p_view_layout = QHBoxLayout(self.p_view)
        p_view_layout.setContentsMargins(0, 0, 0, 0)
        p_view_layout.addWidget(self.left_btn_frame)
        p_view_layout.addWidget(self.left_menu_frame)
        p_view_layout.addWidget(self.table)
        self.p_view.setLayout(p_view_layout)

        self.p_view.addAction(self.action_open)
        self.p_view.addAction(self.action_save)
        self.p_view.addAction(self.action_new)
        self.p_view.addAction(self.action_print)
        self.p_view.addAction(self.action_register)
        self.p_view.addAction(self.action_hide_menu_bar)

    def setup_p_register(self) -> None:
        """inits stacked widget page widgets

        Returns:
            None"""

        self.p_register = QtWidgets.QWidget()
        self.stacked_widget.addWidget(self.p_register)

        l_user = QtWidgets.QLabel("Username", self.p_register)
        self.in_username = QtWidgets.QLineEdit(self.p_register)
        l_devicename = QtWidgets.QLabel("Devicename", self.p_register)
        self.in_devicename = QtWidgets.QLineEdit(self.p_register)
        l_devicetype = QtWidgets.QLabel("DeviceType", self.p_register)
        self.in_combobox_devicetype = QtWidgets.QComboBox(self.p_register)
        l_os = QtWidgets.QLabel("OS", self.p_register)
        self.in_combobox_os = QtWidgets.QComboBox(self.p_register)
        l_comment = QtWidgets.QLabel("Comment", self.p_register)
        self.in_comment = QtWidgets.QTextEdit(self.p_register)
        self.bt_enter_register = QPushButton("register", self.p_register)
        self.bt_cancel_register = QPushButton("cancel", self.p_register)

        p_register_layout = QtWidgets.QVBoxLayout(self.p_register)
        p_register_layout.addWidget(l_user)
        p_register_layout.addWidget(self.in_username)
        p_register_layout.addWidget(l_devicename)
        p_register_layout.addWidget(self.in_devicename)
        p_register_layout.addWidget(l_devicetype)
        p_register_layout.addWidget(self.in_combobox_devicetype)
        p_register_layout.addWidget(l_os)
        p_register_layout.addWidget(self.in_combobox_os)
        p_register_layout.addWidget(l_comment)
        p_register_layout.addWidget(self.in_comment)
        p_register_layout.addWidget(self.bt_enter_register)
        p_register_layout.addWidget(self.bt_cancel_register)

    def setup_p_create(self) -> None:
        """inits stacked widget page widget

        Returns:
            None"""

        self.p_create = QtWidgets.QWidget()
        self.stacked_widget.addWidget(self.p_create)

        l_new_filepath = QtWidgets.QLabel("new filepath", self.p_create)
        self.bt_mod_new_path = QPushButton("mod filepath", self.p_create)
        self.in_new_filepath = QtWidgets.QLineEdit(self.p_create)
        l_new_filename = QtWidgets.QLabel("new filename", self.p_create)
        self.in_new_filename = QtWidgets.QLineEdit(self.p_create)
        self.bt_create = QPushButton("create", self.p_create)
        self.bt_cancel_create = QPushButton("cancel", self.p_create)

        p_create_layout = QtWidgets.QVBoxLayout(self.p_create)
        p_create_layout.addWidget(l_new_filepath)
        p_create_layout.addWidget(self.in_new_filepath)
        p_create_layout.addWidget(l_new_filename)
        p_create_layout.addWidget(self.in_new_filename)
        p_create_layout.addStretch(100)
        p_create_layout.addWidget(self.bt_mod_new_path)
        p_create_layout.addWidget(self.bt_create)
        p_create_layout.addWidget(self.bt_cancel_create)

    def setup_p_preferences(self) -> None:
        """inits setup_p_preferences stacked widget page widget

            Returns:
                None"""

        self.p_preferences = QWidget()
        self.p_preferences.resize(500, 250)
        self.p_preferences.setWindowTitle("preferences")
        self.list_Widget = QListWidget(self.p_preferences)
        self.list_Widget.addItems(["appearance", "about"])
        self.list_Widget.setMaximumWidth(100)

        self.stacked_widget_preferences = QStackedWidget(self.p_preferences)

        # setup appearance
        self.apperence_widget = QWidget()
        self.stacked_widget_preferences.addWidget(self.apperence_widget)
        self.in_combo_themes = QComboBox(self.apperence_widget)
        self.in_combo_themes.addItems(["dark_theme", "light_theme"])

        self.in_combo_theme_initial = QComboBox(self.apperence_widget)
        self.in_combo_theme_initial.addItems(["dark_theme", "light_theme"])

        self.text_size_slider = QSlider(QtCore.Qt.Orientation.Horizontal,
                                        self.apperence_widget)
        self.text_size_slider.setTickPosition(QSlider.TickPosition.TicksAbove)
        self.text_size_slider.setMaximum(15)
        self.text_size_slider.setMinimum(8)

        stacked_widget_preferences_layout = QGridLayout(self.apperence_widget)
        stacked_widget_preferences_layout.setAlignment(QtCore.Qt.AlignTop)
        stacked_widget_preferences_layout.addWidget(QLabel("theme"), 0, 0)
        stacked_widget_preferences_layout.addWidget(self.in_combo_themes, 0, 1)
        stacked_widget_preferences_layout.addWidget(QLabel("initial theme"), 1,
                                                    0)
        stacked_widget_preferences_layout.addWidget(
            self.in_combo_theme_initial, 1, 1)
        stacked_widget_preferences_layout.addWidget(QLabel("Fontsize"), 2, 0)
        stacked_widget_preferences_layout.addWidget(self.text_size_slider, 2,
                                                    1)

        self.about_widget = QWidget()
        self.stacked_widget_preferences.addWidget(self.about_widget)

        about_text_edit = QTextEdit(self.about_widget)
        about_text_edit.setText(
            "developed by Maurice Jarck\nwith kind support from Shuai Lou\n07.2020-04.2021"
        )
        about_text_edit.setEnabled(False)
        stacked_widget_about_layout = QGridLayout(self.about_widget)
        stacked_widget_about_layout.addWidget(about_text_edit)

        p_apperance_layout = QHBoxLayout(self.p_preferences)
        p_apperance_layout.addWidget(self.list_Widget)
        p_apperance_layout.addWidget(self.stacked_widget_preferences)

    def setup_signals(self) -> None:
        """connects signals

        Returns:
            None"""

        # header
        for filter, editor in zip(self.filters, self.header.editors):
            editor.textChanged.connect(filter.setFilterRegExp)

        # line edit
        self.in_new_filename.returnPressed.connect(lambda: self.validate(
            self.new,
            line_edit_list=[self.in_new_filepath, self.in_new_filename],
            data=False))

        # comboboxes
        self.in_combobox_devicetype.addItems(
            ["choose here"] + [x.__name__ for x in valid_devices])
        self.in_combobox_devicetype.currentIndexChanged.connect(
            lambda: self.update_combobox(
                self.in_combobox_os, valid_devices[
                    self.in_combobox_devicetype.currentIndex() - 1].expected_OS
            ))
        self.in_combo_themes.currentIndexChanged.connect(
            lambda: self.change_theme(self.in_combo_themes.currentText()))
        self.in_combo_theme_initial.currentTextChanged.connect(lambda: setattr(
            self, "initial_theme", self.in_combo_theme_initial.currentText()))
        # btns
        self.bt_delete_column.clicked.connect(self.delete)
        # self.bt_hide_show_filter.clicked.connect(lambda: self.toggle_hide_show_ani(37, 47, "height", self.header, b"maximumHeight"))
        self.bt_hide_show_filter.clicked.connect(self.header.hide_show)
        # self.bt_hide_show_filter.clicked.connect(lambda: self.toggle_hide_show_ani(30, 44, "height", self.header, b"maximumHeight"))
        self.bt_register_new.clicked.connect(
            lambda: self.stacked_widget.setCurrentWidget(self.p_register))
        self.bt_enter_register.clicked.connect(lambda: self.validate(
            self.register,
            line_edit_list=[self.in_username, self.in_devicename],
            combo_box_list=[self.in_combobox_devicetype, self.in_combobox_os],
            forbidden=list(self.registered_devices.keys()),
            checkfname=True))
        self.bt_create.clicked.connect(lambda: self.validate(
            self.new,
            line_edit_list=[self.in_new_filepath, self.in_new_filename],
            data=False))
        self.bt_mod_new_path.clicked.connect(lambda: self.new(True))
        self.bt_burger.clicked.connect(lambda: self.toggle_hide_show_ani(
            0,
            66,
            "width",
            self.left_menu_frame,
            b"maximumWidth",
        ))
        # menu bar
        self.action_register.triggered.connect(
            lambda: self.stacked_widget.setCurrentWidget(self.p_register))
        self.action_open.triggered.connect(self.get_open_file_path)
        self.action_save.triggered.connect(self.save)
        self.action_new.triggered.connect(lambda: self.new(True))
        self.action_print.triggered.connect(
            lambda: self.validate(self.print, data=False, checkfname=True))
        self.action_hide_menu_bar.triggered.connect(
            lambda: self.toggle_hide_show(self.menu_Bar))
        self.action_preferences.triggered.connect(self.p_preferences.show)
        # cancel
        self.bt_cancel_register.clicked.connect(lambda: self.cancel([
            self.in_username, self.in_devicename, self.in_combobox_os, self.
            in_comment
        ]))

        # list widget
        self.list_Widget.currentRowChanged.connect(
            lambda: self.stacked_widget_preferences.setCurrentIndex(
                self.list_Widget.currentIndex().row()))

        # slider
        self.text_size_slider.sliderMoved.connect(
            lambda: self.change_font_size(self.text_size_slider.value()))
        # self.text_size_slider.sliderMoved.connect(lambda: print(self.text_size_slider.value()))

    def change_theme(self, theme) -> None:
        """changes theme according to combobox selection

        Returns:
            None"""

        with open(f"./data/{theme}.css", "r") as file:
            stylesheed = " ".join(file.readlines())
            self.setStyleSheet(stylesheed)
            self.p_preferences.setStyleSheet(stylesheed)

        if self.in_combo_themes.currentText() == "dark_theme":

            self.left_btn_frame.setStyleSheet(
                u"background: #455364; border: 0px solid;")
            self.p_view_layout3.setSpacing(30)

        else:
            self.left_btn_frame.setStyleSheet(
                u"background: #ADADAD; border: 0px solid;")
            self.p_view_layout3.setSpacing(25)

        return self.in_combo_themes.currentText()

    def toggle_hide_show_ani(self, collapsed_val: int, expanded_val: int,
                             actual: str, to_animate, property: bytes):
        """interpolates over a defined range of vales and sets it to a given property of a given widget"""
        if getattr(to_animate, actual)() == expanded_val:
            destination = collapsed_val
        else:
            destination = expanded_val
        print(getattr(to_animate, actual)(), destination)
        self.ani = QPropertyAnimation(to_animate, property)
        self.ani.setDuration(300)
        self.ani.setStartValue(getattr(to_animate, actual)())
        self.ani.setEndValue(destination)
        self.ani.setEasingCurve(QEasingCurve.Linear)
        self.ani.start()

    def toggle_hide_show(self, widget: QWidget) -> None:
        """toggles visibiliy of a given widget
        Arg:
            widget: widget which is aimed to be hidden or shown
        Returs:
            None"""

        if widget.isVisible():
            widget.hide()
        else:
            widget.show()

    def reopen_last_file(self) -> None:
        """asks for reopening of the last opened file"""
        if self.last_open_file_path != "" or self.last_open_file_path is not None:
            reopen_dialog = QMessageBox.question(
                self.p_view, "reopen last file?",
                "Do you want to reopen the last edited file?",
                QMessageBox.Yes | QMessageBox.No)
            if reopen_dialog == QMessageBox.Yes:
                self.file_path = self.last_open_file_path
                self.load()

    def change_font_size(self, size: int) -> None:
        """changes all font sizes"""
        self.font.setPointSize(size)
        self.menu_Bar.setFont(self.font)
        self.header.setFont(self.font)
        self.table.setFont(self.font)
        self.p_preferences.setFont(self.font)

    def set_user_preferences(self) -> None:
        """Reads user_config file and sets its propertys"""
        with open(self.user_config_file, "r") as config_file:
            data = dict(json.load(config_file))

            self.last_open_file_path = data["last_open_file_path"]
            self.initial_theme = data['initial_theme']
            self.change_font_size(data['font_size'])
            self.text_size_slider.setValue(data['font_size'])
            self.in_combo_theme_initial.setCurrentText(self.initial_theme)
            self.in_combo_themes.setCurrentText(self.initial_theme)

            with open(f"./data/{self.initial_theme}.css") as file:
                style_sheed = " ".join(file.readlines())
                self.setStyleSheet(style_sheed)
                self.p_preferences.setStyleSheet(style_sheed)

            self.bt_burger.setStyleSheet(
                "border: 0px solid; background: transparent;")
            self.bt_register_new.setStyleSheet(
                "border: 0px solid; background: transparent;")
            self.bt_delete_column.setStyleSheet(
                "border: 0px solid; background: transparent;")
            self.bt_hide_show_filter.setStyleSheet(
                "border: 0px solid; background: transparent;")
            self.left_menu_frame.setStyleSheet(u" border: 0px solid;")

            if self.initial_theme == "dark_theme":
                self.left_btn_frame.setStyleSheet(
                    u"background: #455364; border: 0px solid;")

            else:
                self.left_btn_frame.setStyleSheet(
                    u"background: #ADADAD; border: 0px solid;")

    def cancel(self, widgets: list) -> None:
        """click event for all cancel buttons

        shows fist page in stacked widget and clears all widgets in widgets

        Args:
               widgets: defines list containing widgets to clear, only widgets with method .clear() are possible

        Returns:
            None"""
        for widget in widgets:
            widget.clear()
        self.stacked_widget.setCurrentWidget(self.p_view)

    def update_combobox(self, box, data: list) -> None:
        """ clears combo box

        updates combobox so that old content not needed any more isnt displayed and adds 'choose here' dummy
        to ensure an index change will be made (updating next box depends on index change)
        Args:
            box: instance of pyqt5.QtWidgets.qComboBox
            data: data supposed to be inserted into combobox
        Returns:
            None"""

        box.clear()
        box.addItems(["choose here"] + data)

    def validate(self,
                 command,
                 file_path: str = None,
                 schema=None,
                 line_edit_list: list = None,
                 combo_box_list: list = None,
                 data=None,
                 forbidden: list = None,
                 checkfname: bool = None) -> None:
        """validates user input

        Args:
            command: function to be called after vailidation process if finished
            line_edit_list: contents pyqt5.QtWidgets.QlineEdit instances to be checked if empty or current text in forbidden or not in allowed
            combo_box_list: contents pyqt5.QtWidgets.qComboBox instances to be checked if nothing selected
            data: data to be passed into command function if needed
            forbidden: houses keys which are not allowed to be entered
            checkfname: check weather an file path exists or not

        Returns:
            None"""

        fails = 0
        if line_edit_list is not None:
            for x in line_edit_list:
                if x.text() == "":
                    x.setText("fill all fields")
                    fails += 1
                if forbidden is not None and x.text() in forbidden:
                    x.setText("in forbidden!!")
                    fails += 1
        if combo_box_list is not None:
            for combobox in combo_box_list:
                if combobox.currentText() == "":
                    self.statusbar.showMessage("all comboboxes must be filled")
                    fails += 1
        if checkfname is True and self.file_path is None:
            self.statusbar.showMessage(
                "no file path specified, visit Ctrl+o or menuebar/edit/open to fix"
            )
            fails += 1

        if file_path is not None:
            if forbidden is not None and file_path in forbidden:
                fails += 1
                self.statusbar.showMessage("select a file to continue")
            else:
                try:
                    validate_json.validate(file_path, schema)
                except ValidationError as e:
                    self.msg_box = QtWidgets.QMessageBox.critical(
                        self, "validation failed",
                        f"Invalid Json file, problem in: {e.messages}")
                    fails += 1
        if fails == 0:
            if data is None:
                command()
            else:
                command(data)
        else:
            message = f"problem\ncommand: {command.__name__}\nfails: {fails}"
            print(message)
            return message

    def register(self) -> None:
        """registers a new device and saves

        Returns:
            None"""
        logic.register(devname=self.in_devicename.text(),
                       devtype=[
                           device for device in valid_devices
                           if device.__name__ ==
                           self.in_combobox_devicetype.currentText()
                       ].pop(),
                       username=self.in_username.text(),
                       os=self.in_combobox_os.currentText(),
                       comment=self.in_comment.toPlainText(),
                       datetime=str(datetime.datetime.now()),
                       registered_devices=self.registered_devices)

        new_values = [
            self.in_devicename.text(),
            self.in_username.text(),
            self.in_combobox_os.currentText(),
            [
                device.__name__ for device in valid_devices if device.__name__
                == self.in_combobox_devicetype.currentText()
            ].pop(),
            self.in_comment.toPlainText(),
            str(datetime.datetime.now())
        ]
        row = [QStandardItem(str(item)) for item in new_values]
        self.model.appendRow(row)

        self.stacked_widget.setCurrentWidget(self.p_view)
        self.in_devicename.clear()
        self.in_username.clear()
        self.in_combobox_os.clear()
        self.in_comment.clear()
        self.save()

    def delete(self) -> None:
        """deletes all rows associated with min 1 slected cell
        Returns:
            None"""
        rows = sorted(set(index.row()
                          for index in self.table.selectedIndexes()),
                      reverse=True)
        qb = QMessageBox()
        answ = qb.question(self, 'delete rows',
                           f"Are you sure to delete {rows} rows?",
                           qb.Yes | qb.No)

        if answ == qb.Yes:
            for row in rows:
                self.registered_devices.pop(
                    str(self.model.index(row, 0).data()))
                self.model.removeRow(row)
            qb.information(self, 'notification', f"deleted {rows} row")
        else:
            qb.information(self, 'notification', "Nothing Changed")
        self.save()

    def get_open_file_path(self) -> None:
        """gets file-path and set it to self.file_path, extra step for json validation

        Returns:
            None"""

        self.file_path = \
            QFileDialog.getOpenFileName(self, "open file", f"{self.last_open_file_dir or 'c://'}",
                                        "json files (*json)")[0]
        self.validate(command=self.load,
                      file_path=self.file_path,
                      schema=validate_json.ItHilfeDataSchema,
                      forbidden=[""])

    def load(self) -> None:
        """opens json file and loads its content into registered devices

        Returns:
            None"""

        self.model.clear()
        self.registered_devices.clear()
        with open(self.file_path, "r") as file:
            data = dict(json.load(file))
            devices = data["devices"].values()
            self.last_open_file_dir = data["last_open_file_dir"]
            for value in devices:
                row = []
                for i, item in enumerate(value):
                    cell = QStandardItem(str(item))
                    row.append(cell)
                    if i == 0 or i == 3 or i == 5:
                        cell.setEditable(False)
                self.model.appendRow(row)

                new = [x for x in valid_devices
                       if x.__name__ == value[3]].pop(0)(value[0], value[1],
                                                         value[4], value[5])
                new.OS = value[2]
                self.registered_devices[value[0]] = new

        self.model.setHorizontalHeaderLabels(labels)
        self.statusbar.showMessage("")

        # auto complete
        for a in range(len(self.header.editors)):
            completer = QCompleter([
                self.model.data(self.model.index(x, a))
                for x in range(self.model.rowCount())
            ])
            completer.setCompletionMode(QCompleter.InlineCompletion)
            self.header.editors[a].setCompleter(completer)

    def save(self) -> None:
        """saves content fo self.registered_devices into specified json file

        Returns:
            None"""
        if not self.file_path:
            self.statusbar.showMessage(
                "no file path set all changes get lost if closed")
        else:
            with open(
                    self.file_path,
                    'w',
            ) as file:
                devices = {
                    k: [
                        v.name, v.user, v.OS, v.__class__.__name__, v.comment,
                        v.datetime
                    ]
                    for (k, v) in enumerate(self.registered_devices.values())
                }
                last_open_file_dir = "/".join(self.file_path.split("/")[:-1])
                resulting_dict = {
                    "devices": devices,
                    "last_open_file_dir": last_open_file_dir
                }
                json.dump(resulting_dict, file)
                self.statusbar.showMessage("saved file")

        with open(self.user_config_file, "w") as user_preferences_file:
            json.dump(
                {
                    "last_open_file_path": self.last_open_file_path,
                    "initial_theme": self.initial_theme,
                    "font_size": self.text_size_slider.value()
                }, user_preferences_file)

    def new(self, stage: bool, test: bool = False) -> None:
        """creates new csv file to save into

        stage is True: set filepath
        stage is False: set new name, save
        Args:
            stage: determines a which stage to execute this function

        Returns:
            None"""

        if stage is True:
            if not test:
                self.dir = QFileDialog.getExistingDirectory(
                    self, "select a folder", "c://")
            self.stacked_widget.setCurrentWidget(self.p_create)
            self.in_new_filepath.setText(self.dir)
            self.registered_devices.clear()

        else:
            self.file_path = self.dir + f"/{self.in_new_filename.text()}.json"
            self.save()
            self.stacked_widget.setCurrentWidget(self.p_view)

    def print(self, test: bool) -> None:
        """setup and preview pViewTable for paper printing

        Returns:
            None"""

        with open(self.file_path) as f:
            self.data = json.dumps(dict(json.load(f)),
                                   sort_keys=True,
                                   indent=6,
                                   separators=(".", "="))
        self.document = QtWidgets.QTextEdit()
        self.document.setText(self.data)

        if not test:
            printer = QPrinter()
            previewDialog = QPrintPreviewDialog(printer, self)
            previewDialog.paintRequested.connect(
                lambda: self.document.print_(printer))
            previewDialog.exec_()
예제 #22
0
class Task_ledger(QWidget):
    def __init__(self, system, parent=None):
        super(Task_ledger, self).__init__(parent)
        self.stackedWidgetPage1 = QWidget()
        self.stackedWidgetPage2 = QWidget()
        self.stackedWidgetPage3 = QWidget()
        self.stackedWidgetPage4 = QWidget()
        self.dialog = dialog_logout.Logout_Dialog()

        self.system = system

    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.setFixedSize(1000, 600)
        Form.setWindowTitle("Task Ledger")

        self.stackedWidget = QStackedWidget(Form)
        self.stackedWidget.setGeometry(QRect(0, 0, 1000, 600))
        self.stackedWidget.setObjectName("stackedWidget")

        # Landing Page
        self.stackedWidgetPage1.setObjectName("stackedWidgetPage1")
        self.landing = landing.LandingPageUI(self.stackedWidgetPage1)
        self.landing.setGeometry(0, 0, 1000, 60)
        self.landing.setupUi(self.stackedWidgetPage1)
        self.stackedWidget.addWidget(self.stackedWidgetPage1)
        self.landing.pushButton.clicked.connect(self.goto_login)

        # Login Page
        self.stackedWidgetPage2.setObjectName("stackedWidgetPage2")
        self.login = login.LoginUI(self.stackedWidgetPage2)
        self.login.setupUi(self.stackedWidgetPage2)
        self.login.setGeometry(0, 0, 1000, 60)
        self.login.reg_label.clicked.connect(self.goto_reg)
        self.login.back.clicked.connect(self.goto_landing)
        self.stackedWidget.addWidget(self.stackedWidgetPage2)

        # register Page
        self.stackedWidgetPage3.setObjectName("stackedWidgetPage3")
        self.reg = reg.RegisterUI(self.stackedWidgetPage3)
        self.reg.setupUi(self.stackedWidgetPage3)
        self.reg.setGeometry(0, 0, 1000, 600)
        self.reg.back.clicked.connect(self.goto_login)
        self.stackedWidget.addWidget(self.stackedWidgetPage3)

        # main
        self.stackedWidgetPage4.setObjectName("stackedWidgetPage4")
        self.main = main.MainUI(self.stackedWidgetPage4)
        # Pass system object to the child Widget
        self.main.bind_system(self.system)
        self.main.setupUi(self.stackedWidgetPage4)
        self.main.setGeometry(0, 0, 1000, 600)
        self.main.navbar.log_out.clicked.connect(self.logout)
        self.stackedWidget.addWidget(self.stackedWidgetPage4)

        self.stackedWidget.setCurrentIndex(0)

    def logout(self):
        self.dialog.setupUi(self.dialog)
        self.dialog.okay.clicked.connect(self.goto_landing)
        self.dialog.okay.clicked.connect(self.dialog.close)
        self.dialog.no.clicked.connect(self.dialog.close)
        self.dialog.show()

    def goto_landing(self):
        self.stackedWidget.setCurrentIndex(0)

    def goto_login(self):
        self.stackedWidget.setCurrentIndex(1)

    def goto_reg(self):
        self.stackedWidget.setCurrentIndex(2)

    def goto_main(self):
        self.stackedWidget.setCurrentIndex(3)
예제 #23
0
class TTVSetsImporterWidget(QWidget):
    ttv_updated = Signal(TTVSets)

    def __init__(
        self,
        format_to_widget,
        parent: "QWidget" = None,
    ):
        super().__init__(parent)

        # Components
        self._ttv = None

        # Maps a  with its respective Widget
        self._format_to_widget = format_to_widget

        self._stacked_widgets = QStackedWidget()

        self._name_textbox = QLineEdit("Unnamed")

        self._formatter_selector = QComboBox()
        for (dataset_io_name,
             widget_factory) in self._format_to_widget.items():
            self._formatter_selector.addItem(
                dataset_io_name, getattr(DatasetIORegistry, dataset_io_name))
            self._stacked_widgets.addWidget(
                self._format_to_widget[dataset_io_name]())

        def horizontal_line():
            line = QFrame()
            line.setFrameShape(QFrame.HLine)
            line.setFrameShadow(QFrame.Sunken)
            line.setFixedHeight(2)
            line.setContentsMargins(0, 30, 0, 0)
            return line

        self._x_datatype_selector = DatatypeSelectorFactory(
            title="X (Input) Datatype")
        self._y_datatype_selector = DatatypeSelectorFactory(
            title="Y (Output) Datatype")

        datatypes_layout = QHBoxLayout()
        datatypes_layout.addWidget(self._x_datatype_selector)
        datatypes_layout.addWidget(self._y_datatype_selector)

        self._info_layout = QFormLayout()
        self._info_layout.addRow("Name", self._name_textbox)
        self._info_layout.addRow("Format", self._formatter_selector)

        self._main_layout = QVBoxLayout()
        self._main_layout.addLayout(self._info_layout)
        self._main_layout.addWidget(horizontal_line())
        self._main_layout.addWidget(self._stacked_widgets)
        self._main_layout.addWidget(horizontal_line())
        self._main_layout.addLayout(datatypes_layout)

        self._load_ttv_from_file_button = QPushButton("Load from file...")
        self._load_ttv_from_file_button.clicked.connect(
            self._load_ttv_from_file)

        self._update_ttv_button = QPushButton("Load TTV")
        self._update_ttv_button.clicked.connect(self._update_ttv)

        self._button_box = QDialogButtonBox()
        self._button_box.addButton(self._load_ttv_from_file_button,
                                   QDialogButtonBox.ResetRole)
        self._button_box.addButton(self._update_ttv_button,
                                   QDialogButtonBox.ApplyRole)

        self._main_layout.addWidget(self._button_box)

        self.setLayout(self._main_layout)

        self._formatter_selector.currentIndexChanged[int].connect(
            lambda i: self._stacked_widgets.setCurrentIndex(i))

    def get_ttv(self) -> "TTVSets":
        return self._ttv

    def _update_ttv(self):
        self._ttv = self._stacked_widgets.currentWidget().load_ttv(
            self._name_textbox.text(),
            self._x_datatype_selector.selected_datatype,
            self._y_datatype_selector.selected_datatype,
        )

        self.ttv_updated.emit(self._ttv)

    def _load_ttv_from_file(self):
        print("Loading from file...")

        description_file_path = QFileDialog.getOpenFileName(
            self, "Open TTV .json file")[0]

        if description_file_path:
            LOGGER.debug("Loading %s...", description_file_path)

            ttv_dir = os.path.dirname(description_file_path)
            ttv_description = TTVSetsIO.load_ttv_description(
                description_file_path)

            # Update name
            self._name_textbox.setText(ttv_description["name"])

            # Pick the new formatter
            formatter_idx = self._formatter_selector.findText(
                ttv_description["format"])

            if formatter_idx != -1:
                self._formatter_selector.setCurrentIndex(formatter_idx)
                self._selected_index_changed(formatter_idx)

            # TODO: Cover case when "train" is null
            self._x_datatype_selector.change_current_datatype(
                ttv_description["train"]["x_type"])
            self._y_datatype_selector.change_current_datatype(
                ttv_description["train"]["y_type"])

            self._stacked_widgets.currentWidget().update_widgets(
                ttv_dir, ttv_description)

            self._update_ttv()

        else:
            LOGGER.debug("Loading cancelled")

    def _selected_index_changed(self, index: int):
        self._stacked_widgets.setCurrentIndex(index)

    def sizeHint(self) -> "QSize":
        """Optimal size of the widget."""
        return QSize(450, 150)

    def __reduce__(self):
        return (
            TTVSetsImporterWidget,
            (self._ttv_sets_dialog, None),
        )
예제 #24
0
class ExifViewer(QMainWindow):
    WINDOW_SIZE = {'width': 900, 'height': 600}

    def __init__(self, parent=None):
        super().__init__(parent)
        self.qw_tree = None
        self.qw_stack = None
        self.tree_type_to_stack_idx = None
        self.exif_reader = None

        self.setWindowTitle("exif viewer")
        self.resize(self.WINDOW_SIZE['width'], self.WINDOW_SIZE['height'])

    def make_viewer(self, exif_reader):
        self.exif_reader = exif_reader
        ifds = self.exif_reader.get_exif()

        self.qw_tree = QTreeWidget(self)
        qt_util_init_tree(self.qw_tree, header_list=['ifd_name'])

        self.qw_stack = QStackedWidget(self)
        self.tree_type_to_stack_idx = {}
        for tree_item_type, (ifd_name, ifd) in enumerate(ifds.items()):
            # -----------------------
            # treeにifd nameを書き込んでroot_treeに登録する.
            # -----------------------
            qw_tree_item = QTreeWidgetItem(['{} ifd'.format(ifd_name), ''],
                                           type=tree_item_type)
            self.qw_tree.addTopLevelItem(qw_tree_item)

            # -----------------------
            # text_editにexif情報を書き込んでstacked_widgetに登録する.
            # -----------------------
            qw_text_edit = QTextEdit(self)
            qt_util_init_text_edit(qw_text_edit)
            qt_util_append_text_edit(qw_text_edit, None, head=True)
            for _, tag in ifd.items():
                qt_util_append_text_edit(qw_text_edit,
                                         tag,
                                         head=False,
                                         display_max_len=50)
            qt_util_reset_text_edit_cursor(qw_text_edit)

            idx = self.qw_stack.addWidget(qw_text_edit)
            self.tree_type_to_stack_idx[tree_item_type] = idx
        else:
            self.qw_tree.itemClicked.connect(self._tree_item_clicked)

        # -----------------------
        # widgetをlayoutに登録する.
        # -----------------------
        widgets = [self.qw_tree, self.qw_stack]
        self._make_layout(widgets)
        self._make_toolbar()

        self.show()  # widgetを表示する.

    def _make_toolbar(self):
        # action_to_text = QAction(QIcon(os.path.join('icon', 'text.png')), 'save', self)
        save_icon = QApplication.style().standardIcon(
            QStyle.SP_DialogSaveButton)
        save_action = QAction(icon=save_icon, text='save', parent=self)
        save_action.triggered.connect(self._save_text)

        exit_icon = QApplication.style().standardIcon(
            QStyle.SP_DialogCloseButton)
        exit_action = QAction(icon=exit_icon, text='exit', parent=self)
        exit_action.triggered.connect(self._quit)

        # ツールバー作成
        self.toolbar = self.addToolBar('tool bar')
        self.toolbar.setIconSize(QSize(35, 35))
        self.toolbar.setFixedHeight(35)
        self.toolbar.addAction(save_action)
        self.toolbar.addAction(exit_action)

    def _make_layout(self, widgets):
        qw_splitter = QSplitter(self)
        for widget in widgets:
            qw_splitter.addWidget(widget)
        qw_splitter.setSizes(
            [self.WINDOW_SIZE['width'] * 0.1, self.WINDOW_SIZE['width'] * 0.9])

        # layout = QHBoxLayout()
        # layout.addWidget(qw_splitter)
        # qw = QWidget()
        # qw.setLayout(layout)
        # self.setCentralWidget(qw)

        # self.setWindowFlags(Qt.WindowStaysOnTopHint) # 常に手前に表示する.

        # MainWindowのCentral領域にWidgetを設定
        self.setCentralWidget(qw_splitter)

    @Slot()
    def _tree_item_clicked(self, item, column):
        self.qw_stack.setCurrentIndex(self.tree_type_to_stack_idx[item.type()])
        current_text_edit = self.qw_stack.currentWidget()
        qt_util_reset_text_edit_cursor(current_text_edit)

    @Slot()
    def _save_text(self):
        filename = QFileDialog.getSaveFileName(self, '名前を付けて保存')
        out_path = filename[0]
        if out_path:
            self.exif_reader.save_log(out_path)

    @Slot()
    def _quit(self):
        qApp.quit()
예제 #25
0
class Application(QMainWindow):

    # Booleans indicating which window is opened
    __isTesting = False
    __isTraining = False
    __isCreation = False
    __isPreProcessingText = False
    __isPreProcessingImage = False
    __isChoice = False

    @Slot()
    def goToTraining(self):
        if self.__isCreation:
            self.__isCreation = False
            self.__isTraining = True
            self.__trainingWindow = TrainingWindow(
                self.__creationWindow.dataset, self.__choiceWindow.classes,
                (self.__creationWindow.modelList,
                 self.__creationWindow.networkName.text()), True)
            self.__trainingWindow.goBackButton.clicked.connect(
                self.backtoCreation)
            self.__windows.addWidget(self.__trainingWindow)
            self.__windows.setCurrentIndex(3)

        elif self.__isChoice:
            if not self.__choiceWindow.datasetLoaded:
                ret = QMessageBox.warning(self, "Dataset",
                                          "Veuillez charger un dataset",
                                          QMessageBox.Ok)
                return
            if not self.__choiceWindow.networkLoaded:
                ret = QMessageBox.warning(
                    self, "Reseau de neurones",
                    "Veuillez charger un reseau de neurones ou en creer un nouveau",
                    QMessageBox.Ok)
                return
            self.__isTraining = True
            self.__isChoice = False
            self.__trainingWindow = TrainingWindow(
                self.__choiceWindow.dataset, self.__choiceWindow.classes,
                (self.__choiceWindow.network, self.__choiceWindow.networkName),
                False)
            self.__trainingWindow.goBackButton.clicked.connect(
                self.backToChoice)
            self.__windows.addWidget(self.__trainingWindow)
            self.__windows.setCurrentIndex(2)

    @Slot()
    def goToTesting(self):
        self.__isTesting = True
        self.__testingWindow = TestingWindow()
        self.__windows.addWidget(self.__testingWindow)
        self.__windows.setCurrentIndex(1)
        self.__testingWindow.buttons[3].clicked.connect(self.backToMenu)

    @Slot()
    def goToCreation(self):
        if not self.__choiceWindow.datasetLoaded:
            ret = QMessageBox.warning(self, "Dataset",
                                      "Veuillez d'abord charger un dataset",
                                      QMessageBox.Ok)
            return
        self.__isChoice = False
        if self.__choiceWindow.networkLoaded:
            ret = QMessageBox.warning(self, "Reseau de neurones",
                                      "Un reseau de neurones est deja charge",
                                      QMessageBox.Ok)
            return
        self.__isCreation = True
        self.__creationWindow = CreationWindow(self.__choiceWindow.dataset)
        self.__windows.addWidget(self.__creationWindow)
        self.__windows.setCurrentIndex(2)
        self.__creationWindow.goBackButton.clicked.connect(self.backToChoice)
        self.__creationWindow.done.connect(self.goToTraining)

    @Slot()
    def goToChoice(self):
        self.__isChoice = True
        self.__choiceWindow = ChoiceWindow()
        self.__windows.addWidget(self.__choiceWindow)
        self.__windows.setCurrentIndex(1)
        self.__choiceWindow.buttons[2].clicked.connect(self.goToCreation)
        self.__choiceWindow.buttons[3].clicked.connect(self.goToTraining)
        self.__choiceWindow.buttons[4].clicked.connect(self.backToMenu)

    @Slot()
    def backtoCreation(self):
        self.__isCreation = True
        self.__isTraining = False
        self.__windows.setCurrentIndex(2)
        self.__windows.removeWidget(self.__trainingWindow)
        self.__trainingWindow.deleteLater()

    @Slot()
    def goToPreprocessingText(self):
        self.__isPreProcessingText = True
        self.__preProcessingTextWindow = PreprocessingTextWindow()
        self.__preProcessingTextWindow.pushButton_return.clicked.connect(
            self.backToMenu)
        self.__windows.addWidget(self.__preProcessingTextWindow)
        self.__windows.setCurrentIndex(1)

    @Slot()
    def goToPreprocessingImage(self):
        self.__isPreProcessingImage = True
        self.__preProcessingImageWindow = PreprocessingImageWindow()
        self.__preProcessingImageWindow.pushButton_return.clicked.connect(
            self.backToMenu)
        self.__windows.addWidget(self.__preProcessingImageWindow)
        self.__windows.setCurrentIndex(1)

    @Slot()
    def backToMenu(self):
        self.__windows.setCurrentIndex(0)
        if self.__isTesting:
            self.__isTesting = False
            self.__windows.removeWidget(self.__testingWindow)
            self.__testingWindow.deleteLater()
        elif self.__isPreProcessingText:
            self.__isPreProcessingText = False
            self.__windows.removeWidget(self.__preProcessingTextWindow)
            self.__preProcessingTextWindow.deleteLater()
        elif self.__isPreProcessingImage:
            self.__isPreProcessingImage = False
            self.__windows.removeWidget(self.__preProcessingImageWindow)
            self.__preProcessingImageWindow.deleteLater()
        elif self.__isChoice:
            self.__isChoice = False
            self.__windows.removeWidget(self.__choiceWindow)
            self.__choiceWindow.deleteLater()
            self.__choiceWindow = None

    @Slot()
    def backToChoice(self):
        self.__isChoice = True
        self.__windows.setCurrentIndex(1)
        if self.__isCreation:
            self.__isCreation = False
            self.__windows.removeWidget(self.__creationWindow)
            self.__creationWindow.deleteLater()
        elif self.__isTraining:
            self.__isTraining = False
            self.__windows.removeWidget(self.__trainingWindow)
            self.__trainingWindow.deleteLater()

    def __init__(self, *args, **kwargs):
        super(Application, self).__init__(*args, **kwargs)

        # Initializing menu window
        self.__menuWindow = MenuWindow()
        self.__windows = QStackedWidget(self)
        self.__windows.addWidget(self.__menuWindow)
        self.__windows.setCurrentIndex(0)
        self.setCentralWidget(self.__windows)

        # Connecting buttons
        self.__menuWindow.buttons[0].clicked.connect(
            self.goToPreprocessingImage)
        self.__menuWindow.buttons[1].clicked.connect(
            self.goToPreprocessingText)
        self.__menuWindow.buttons[2].clicked.connect(self.goToChoice)
        self.__menuWindow.buttons[3].clicked.connect(self.goToTesting)
        self.__menuWindow.buttons[4].clicked.connect(QApplication.quit)
예제 #26
0
class MainWidget(QWidget):
    def __init__(self, parent: QWidget, model: Model) -> None:
        super().__init__(parent)

        logger.add(self.log)

        self.mainlayout = QVBoxLayout()
        self.setLayout(self.mainlayout)

        self.splitter = QSplitter(Qt.Vertical)

        self.stack = QStackedWidget()
        self.splitter.addWidget(self.stack)

        # mod list widget

        self.modlistwidget = QWidget()
        self.modlistlayout = QVBoxLayout()
        self.modlistlayout.setContentsMargins(0, 0, 0, 0)
        self.modlistwidget.setLayout(self.modlistlayout)
        self.stack.addWidget(self.modlistwidget)

        # search bar

        self.searchbar = QLineEdit()
        self.searchbar.setPlaceholderText('Search...')
        self.modlistlayout.addWidget(self.searchbar)

        # mod list

        self.modlist = ModList(self, model)
        self.modlistlayout.addWidget(self.modlist)

        self.searchbar.textChanged.connect(lambda e: self.modlist.setFilter(e))

        # welcome message

        welcomelayout = QVBoxLayout()
        welcomelayout.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
        welcomewidget = QWidget()
        welcomewidget.setLayout(welcomelayout)
        welcomewidget.dragEnterEvent = self.modlist.dragEnterEvent  # type: ignore
        welcomewidget.dragMoveEvent = self.modlist.dragMoveEvent  # type: ignore
        welcomewidget.dragLeaveEvent = self.modlist.dragLeaveEvent  # type: ignore
        welcomewidget.dropEvent = self.modlist.dropEvent  # type: ignore
        welcomewidget.setAcceptDrops(True)

        icon = QIcon(str(getRuntimePath('resources/icons/open-folder.ico')))
        iconpixmap = icon.pixmap(32, 32)
        icon = QLabel()
        icon.setPixmap(iconpixmap)
        icon.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
        icon.setContentsMargins(4, 4, 4, 4)
        welcomelayout.addWidget(icon)

        welcome = QLabel('''<p><font>
            No mod installed yet.
            Drag a mod into this area to get started!
            </font></p>''')
        welcome.setAttribute(Qt.WA_TransparentForMouseEvents)
        welcome.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
        welcomelayout.addWidget(welcome)

        self.stack.addWidget(welcomewidget)

        # output log

        self.output = QTextEdit(self)
        self.output.setTextInteractionFlags(Qt.NoTextInteraction)
        self.output.setReadOnly(True)
        self.output.setContextMenuPolicy(Qt.NoContextMenu)
        self.output.setPlaceholderText('Program output...')
        self.splitter.addWidget(self.output)

        # TODO: enhancement: add a launch game icon
        # TODO: enhancement: show indicator if scripts have to be merged

        self.splitter.setStretchFactor(0, 1)
        self.splitter.setStretchFactor(1, 0)
        self.mainlayout.addWidget(self.splitter)

        if len(model):
            self.stack.setCurrentIndex(0)
            self.splitter.setSizes([self.splitter.size().height(), 50])
        else:
            self.stack.setCurrentIndex(1)
            self.splitter.setSizes([self.splitter.size().height(), 0])
        model.updateCallbacks.append(self.modelUpdateEvent)

    def keyPressEvent(self, event: QKeyEvent) -> None:
        if event.key() == Qt.Key_Escape:
            self.modlist.setFocus()
            self.searchbar.setText('')
        elif event.matches(QKeySequence.Find):
            self.searchbar.setFocus()
        elif event.matches(QKeySequence.Paste):
            self.pasteEvent()
        super().keyPressEvent(event)

    def pasteEvent(self) -> None:
        clipboard = QApplication.clipboard().text().splitlines()
        if len(clipboard) == 1 and isValidNexusModsUrl(clipboard[0]):
            self.parentWidget().showDownloadModDialog()
        else:
            urls = [
                url for url in QApplication.clipboard().text().splitlines()
                if len(str(url.strip()))
            ]
            if all(
                    isValidModDownloadUrl(url) or isValidFileUrl(url)
                    for url in urls):
                asyncio.create_task(self.modlist.checkInstallFromURLs(urls))

    def modelUpdateEvent(self, model: Model) -> None:
        if len(model) > 0:
            if self.stack.currentIndex() != 0:
                self.stack.setCurrentIndex(0)
                self.repaint()
        else:
            if self.stack.currentIndex() != 1:
                self.stack.setCurrentIndex(1)
                self.repaint()

    def unhideOutput(self) -> None:
        if self.splitter.sizes()[1] < 10:
            self.splitter.setSizes([self.splitter.size().height(), 50])

    def unhideModList(self) -> None:
        if self.splitter.sizes()[0] < 10:
            self.splitter.setSizes([50, self.splitter.size().height()])

    def log(self, message: Any) -> None:
        # format log messages to user readable output
        settings = QSettings()

        record = message.record
        message = record['message']
        extra = record['extra']
        level = record['level'].name.lower()

        name = str(extra['name']
                   ) if 'name' in extra and extra['name'] is not None else ''
        path = str(extra['path']
                   ) if 'path' in extra and extra['path'] is not None else ''
        dots = bool(
            extra['dots']
        ) if 'dots' in extra and extra['dots'] is not None else False
        newline = bool(
            extra['newline']
        ) if 'newline' in extra and extra['newline'] is not None else False
        output = bool(
            extra['output']
        ) if 'output' in extra and extra['output'] is not None else bool(
            message)
        modlist = bool(
            extra['modlist']
        ) if 'modlist' in extra and extra['modlist'] is not None else False

        if level in ['debug'
                     ] and settings.value('debugOutput', 'False') != 'True':
            if newline:
                self.output.append(f'')
            return

        n = '<br>' if newline else ''
        d = '...' if dots else ''
        if len(name) and len(path):
            path = f' ({path})'

        if output:
            message = html.escape(message, quote=True)

            if level in ['success', 'error', 'warning']:
                message = f'<strong>{message}</strong>'
            if level in ['success']:
                message = f'<font color="#04c45e">{message}</font>'
            if level in ['error', 'critical']:
                message = f'<font color="#ee3b3b">{message}</font>'
            if level in ['warning']:
                message = f'<font color="#ff6500">{message}</font>'
            if level in ['debug', 'trace']:
                message = f'<font color="#aaa">{message}</font>'
                path = f'<font color="#aaa">{path}</font>' if path else ''
                d = f'<font color="#aaa">{d}</font>' if d else ''

            time = record['time'].astimezone(
                tz=None).strftime('%Y-%m-%d %H:%M:%S')
            message = f'<font color="#aaa">{time}</font> {message}'
            self.output.append(
                f'{n}{message.strip()}{" " if name or path else ""}{name}{path}{d}'
            )
        else:
            self.output.append(f'')

        self.output.verticalScrollBar().setValue(
            self.output.verticalScrollBar().maximum())
        self.output.repaint()

        if modlist:
            self.unhideModList()
        if settings.value('unhideOutput', 'True') == 'True' and output:
            self.unhideOutput()
예제 #27
0
class ORIRMain(QFramelessWindow):
    def __init__(self):
        super(ORIRMain, self).__init__()
        self._m_navigation_bar = QSlideNavigationBar()
        self._m_stacked_widget = QStackedWidget()
        self._m_stacked_widget.setMouseTracking(True)
        self._layout = QHBoxLayout()

        self._init_navigation_bar()
        self._layout.addWidget(self._m_navigation_bar)
        self._layout.addWidget(self._m_stacked_widget)
        self._layout.setStretchFactor(self._m_navigation_bar, 1)
        self._layout.setStretchFactor(self._m_stacked_widget, 40)
        self.set_layout(None, self._layout)

        self._debug_page = ORIR_Debug()
        self._m_stacked_widget.addWidget(self._debug_page)
        self._loganalysis_page = ORIR_LogAnalysis()
        self._m_stacked_widget.addWidget(self._loganalysis_page)
        self._collectiondata_page = ORIR_CollectionData()
        self._m_stacked_widget.addWidget(self._collectiondata_page)

        self._m_tool_page = ORIR_Tool()
        self._m_stacked_widget.addWidget(self._m_tool_page)

        self._help_page = ORIR_Help()
        self._m_stacked_widget.addWidget(self._help_page)

        self._m_navigation_bar.itemClicked.connect(self._on_change_page)
        # self.set_window_icon('../resources/icons/battery.ico')
        self.setWindowFlags(Qt.FramelessWindowHint or Qt.WindowSystemMenuHint
                            or Qt.WindowMinMaxButtonsHint)

    def _on_update_status_bar(self, str):
        """
        更新状态栏
        :param str:要更新的信息
        :return:
        """
        self.set_status_text(str)

    def _on_change_page(self, index: int, item_name: str):
        """
        切换页面的槽函数
        :param index:
        :param item_name:
        :return:
        """
        self._m_stacked_widget.setCurrentIndex(index)

    def _init_navigation_bar(self):
        """
        初始化导航栏
        :return: None
        """
        self._m_navigation_bar.set_orientation(Qt.Vertical)
        self._m_navigation_bar.set_fixed(True)
        self._m_navigation_bar.add_item('前期调试')
        self._m_navigation_bar.add_item('日志分析')
        self._m_navigation_bar.add_item('采点工具')
        self._m_navigation_bar.add_item('辅助工具')
        self._m_navigation_bar.add_item('帮助')
        self._m_navigation_bar.set_item_line_style(
            QSlideNavigationBar.ItemLineStyle.ItemLeft)
        self._m_navigation_bar.set_item_line_color(QColor('red'))
        self._m_navigation_bar.setMaximumWidth(20)

    def closeEvent(self, event):
        # message为窗口标题
        # Are you sure to quit?窗口显示内容
        # QtGui.QMessageBox.Yes | QtGui.QMessageBox.No窗口按钮部件
        # QtGui.QMessageBox.No默认焦点停留在NO上
        reply = QMessageBox.question(self, 'Message', "确定退出?",
                                     QMessageBox.Yes | QMessageBox.No,
                                     QMessageBox.No)
        # 判断返回结果处理相应事项
        if reply == QMessageBox.Yes:
            self._debug_page.close_all()
            self._m_tool_page.close_all()
            event.accept()
        else:
            event.ignore()