Exemplo n.º 1
0
class MetricsWindowTab(QWidget):

    def __init__(self, parent=None):
        super().__init__(parent)
        self.name = self.tr("Metrics Window")

        self.inputTextLabel = QLabel(self.tr("Default text:"), self)
        self.inputTextList = QListWidget(self)
        self.inputTextList.setDragDropMode(QAbstractItemView.InternalMove)
        self.addItemButton = QPushButton(self)
        self.addItemButton.setIcon(icons.i_plus())
        self.addItemButton.clicked.connect(self.addItem)
        self.removeItemButton = QPushButton(self)
        self.removeItemButton.setIcon(icons.i_minus())
        self.removeItemButton.clicked.connect(self.removeItem)

        buttonsLayout = QHBoxLayout()
        buttonsLayout.addWidget(self.addItemButton)
        buttonsLayout.addWidget(self.removeItemButton)
        spacer = QWidget()
        spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
        buttonsLayout.addWidget(spacer)

        layout = QVBoxLayout(self)
        layout.addWidget(self.inputTextLabel)
        layout.addWidget(self.inputTextList)
        layout.addLayout(buttonsLayout)
        self.setLayout(layout)

        self.readSettings()

    def addItem(self):
        item = QListWidgetItem(self.inputTextList)
        item.setFlags(item.flags() | Qt.ItemIsEditable)
        self.inputTextList.setCurrentItem(item)
        self.inputTextList.editItem(item)
        self.removeItemButton.setEnabled(True)

    def removeItem(self):
        i = self.inputTextList.currentRow()
        self.inputTextList.takeItem(i)
        if not self.inputTextList.count():
            self.removeItemButton.setEnabled(False)

    def readSettings(self):
        self.inputTextList.clear()
        entries = settings.metricsWindowComboBoxItems()
        for entry in entries:
            item = QListWidgetItem(entry, self.inputTextList)
            item.setFlags(item.flags() | Qt.ItemIsEditable)
        if not len(entries):
            self.removeItemButton.setEnabled(False)

    def writeSettings(self):
        entries = []
        for i in range(self.inputTextList.count()):
            item = self.inputTextList.item(i)
            entries.append(item.text())
        settings.setMetricsWindowComboBoxItems(entries)
Exemplo n.º 2
0
class MetricsWindowTab(QWidget):

    def __init__(self, parent=None):
        super().__init__(parent)
        self.name = self.tr("Metrics Window")

        self.inputTextLabel = QLabel(self.tr("Default text:"), self)
        self.inputTextList = QListWidget(self)
        self.inputTextList.setDragDropMode(QAbstractItemView.InternalMove)
        self.addItemButton = QPushButton("+", self)
        self.addItemButton.clicked.connect(self.addItem)
        self.removeItemButton = QPushButton("−", self)
        self.removeItemButton.clicked.connect(self.removeItem)

        layout = QGridLayout(self)
        l = 0
        layout.addWidget(self.inputTextLabel, l, 0, 1, 3)
        l += 1
        layout.addWidget(self.inputTextList, l, 0, 1, 3)
        l += 1
        layout.addWidget(self.addItemButton, l, 0)
        layout.addWidget(self.removeItemButton, l, 1)
        self.setLayout(layout)

        self.readSettings()

    def addItem(self):
        item = QListWidgetItem(self.inputTextList)
        item.setFlags(item.flags() | Qt.ItemIsEditable)
        self.inputTextList.setCurrentItem(item)
        self.inputTextList.editItem(item)
        self.removeItemButton.setEnabled(True)

    def removeItem(self):
        i = self.inputTextList.currentRow()
        self.inputTextList.takeItem(i)
        if not self.inputTextList.count():
            self.removeItemButton.setEnabled(False)

    def readSettings(self):
        self.inputTextList.clear()
        entries = settings.metricsWindowComboBoxItems()
        for entry in entries:
            item = QListWidgetItem(entry, self.inputTextList)
            item.setFlags(item.flags() | Qt.ItemIsEditable)
        if not len(entries):
            self.removeItemButton.setEnabled(False)

    def writeSettings(self):
        entries = []
        for i in range(self.inputTextList.count()):
            item = self.inputTextList.item(i)
            entries.append(item.text())
        settings.setMetricsWindowComboBoxItems(entries)
Exemplo n.º 3
0
class GlyphSetTab(QWidget):

    def __init__(self, parent=None):
        super().__init__(parent)
        self.name = self.tr("Glyph sets")

        self.defaultGlyphSetBox = QCheckBox(
            self.tr("Default glyph set:"), self)
        self.defaultGlyphSetDrop = QComboBox(self)
        self.defaultGlyphSetBox.toggled.connect(self.toggleGlyphSetDrop)

        self.glyphSetList = QListWidget(self)
        self.glyphSetList.setSortingEnabled(True)
        self.glyphSetContents = QPlainTextEdit(self)
        self.glyphSetList.currentItemChanged.connect(
            self.updateGlyphSetContents)
        self.glyphSetList.itemChanged.connect(self.renameGlyphSet)
        self._cachedName = None
        splitter = QSplitter(self)
        splitter.addWidget(self.glyphSetList)
        splitter.addWidget(self.glyphSetContents)
        self.addGlyphSetButton = QPushButton(self)
        self.addGlyphSetButton.setIcon(icons.i_plus())
        self.addGlyphSetButton.clicked.connect(lambda: self.addGlyphSet())
        self.removeGlyphSetButton = QPushButton(self)
        self.removeGlyphSetButton.setIcon(icons.i_minus())
        self.removeGlyphSetButton.clicked.connect(self.removeGlyphSet)
        self.importButton = QPushButton(self.tr("Import"), self)
        importMenu = QMenu(self)
        importMenu.addAction(
            self.tr("Import from Current Font"), self.importFromCurrentFont)
        self.importButton.setMenu(importMenu)
        self.glyphListBox = QCheckBox(self.tr("Glyph list path:"), self)
        self.glyphListEdit = QLineEdit(self)
        self.glyphListEdit.setReadOnly(True)
        self.glyphListButton = QPushButton(self.tr("Browse…"), self)
        self.glyphListButton.clicked.connect(self.getGlyphList)
        self.glyphListBox.toggled.connect(self.glyphListEdit.setEnabled)
        self.glyphListBox.toggled.connect(self.glyphListButton.setEnabled)

        buttonsLayout = QHBoxLayout()
        buttonsLayout.addWidget(self.addGlyphSetButton)
        buttonsLayout.addWidget(self.removeGlyphSetButton)
        spacer = QWidget()
        spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
        buttonsLayout.addWidget(spacer)
        buttonsLayout.addWidget(self.importButton)

        firstLayout = QGridLayout()
        l = 0
        firstLayout.addWidget(self.defaultGlyphSetBox, l, 0, 1, 2)
        firstLayout.addWidget(self.defaultGlyphSetDrop, l, 3, 1, 3)
        l += 1
        firstLayout.addWidget(splitter, l, 0, 1, 6)
        l += 1
        firstLayout.addLayout(buttonsLayout, l, 0, 1, 3)
        secondLayout = QHBoxLayout()
        secondLayout.addWidget(self.glyphListBox)
        secondLayout.addWidget(self.glyphListEdit)
        secondLayout.addWidget(self.glyphListButton)
        mainLayout = QVBoxLayout(self)
        mainLayout.addLayout(firstLayout)
        mainLayout.addLayout(secondLayout)
        self.setLayout(mainLayout)

        self.readSettings()

    def addGlyphSet(self, glyphNames=[], glyphSetName=None):
        if glyphSetName is None:
            glyphSetName = self.tr("New glyph set")
        if glyphSetName in self.glyphSets:
            index = 1
            while "%s %d" % (glyphSetName, index) in self.glyphSets:
                index += 1
            glyphSetName = "%s %d" % (glyphSetName, index)
        self.glyphSets[glyphSetName] = glyphNames
        item = QListWidgetItem(glyphSetName, self.glyphSetList)
        item.setFlags(item.flags() | Qt.ItemIsEditable)
        self.glyphSetList.setCurrentItem(item)
        self.glyphSetList.editItem(item)
        self.removeGlyphSetButton.setEnabled(True)

    def removeGlyphSet(self):
        i = self.glyphSetList.currentRow()
        text = self.glyphSetList.takeItem(i).text()
        del self.glyphSets[text]
        if self.glyphSetList.count() < 2:
            self.removeGlyphSetButton.setEnabled(False)

    def renameGlyphSet(self):
        newKey = self.glyphSetList.currentItem()
        if newKey is None:
            return
        newKey = newKey.text()
        self.glyphSets[newKey] = self.glyphSets[self._cachedName]
        del self.glyphSets[self._cachedName]

    def importFromCurrentFont(self):
        font = QApplication.instance().currentFont()
        name = "%s %s" % (font.info.familyName, font.info.styleName)
        self.addGlyphSet(font.glyphOrder, name)

    def toggleGlyphSetDrop(self):
        sender = self.sender()
        self.defaultGlyphSetDrop.setEnabled(sender.isChecked())

    def updateGlyphSetContents(self, current, previous):
        # store content of the textEdit in the glyphSet dict
        if previous is not None:
            glyphNames = self.glyphSetContents.toPlainText().split()
            self.glyphSets[previous.text()] = glyphNames
        # now update the text edit to current glyphSet
        glyphSetName = current.text()
        text = " ".join(self.glyphSets[glyphSetName])
        self.glyphSetContents.setPlainText(text)
        # cache current name for renames
        self._cachedName = glyphSetName

    def getGlyphList(self):
        fileFormats = (
            self.tr("Text file {}").format("(*.txt)"),
            self.tr("All files {}").format("(*.*)"),
        )
        path, _ = QFileDialog.getOpenFileName(
            self, self.tr("Open File"), '', ";;".join(fileFormats)
        )
        if path:
            self.glyphListEdit.setText(path)

    def readSettings(self):
        defaultGlyphSet = settings.defaultGlyphSet()
        self.defaultGlyphSetBox.setChecked(len(defaultGlyphSet))

        self.glyphSets = settings.readGlyphSets()
        self.defaultGlyphSetDrop.clear()
        self.defaultGlyphSetDrop.addItems(self.glyphSets.keys())

        self.glyphSetList.clear()
        glyphSetNames = self.glyphSets.keys()
        # Normally we should be enforcing this rather decently in the interface
        # already
        if glyphSetNames:
            for glyphSetName in glyphSetNames:
                item = QListWidgetItem(glyphSetName, self.glyphSetList)
                item.setFlags(item.flags() | Qt.ItemIsEditable)
            self.glyphSetList.setCurrentRow(0)
        self.removeGlyphSetButton.setEnabled(len(self.glyphSets) > 1)

        glyphListPath = settings.glyphListPath()
        self.glyphListBox.setChecked(bool(glyphListPath))
        self.glyphListEdit.setEnabled(bool(glyphListPath))
        self.glyphListEdit.setText(glyphListPath)
        self.glyphListButton.setEnabled(bool(glyphListPath))

    def writeSettings(self):
        # store content of the textEdit in the glyphSet dict
        glyphNames = self.glyphSetContents.toPlainText().split()
        currentGlyphSet = self.glyphSetList.currentItem().text()
        self.glyphSets[currentGlyphSet] = glyphNames

        settings.writeGlyphSets(self.glyphSets)
        if not self.defaultGlyphSetBox.isChecked():
            settings.setDefaultGlyphSet(None)
        else:
            defaultGlyphSet = self.defaultGlyphSetDrop.currentText()
            settings.setDefaultGlyphSet(defaultGlyphSet)
        if not self.glyphListBox.isChecked():
            settings.setGlyphListPath(None)
        else:
            glyphListPath = self.glyphListEdit.text()
            if glyphListPath:
                settings.setGlyphListPath(glyphListPath)
                QApplication.instance().loadGlyphList()
Exemplo n.º 4
0
class GlyphSetTab(QWidget):

    def __init__(self, parent=None):
        super().__init__(parent)
        self.name = self.tr("Glyph sets")

        self.defaultGlyphSetBox = QCheckBox(
            self.tr("Default glyph set:"), self)
        self.defaultGlyphSetDrop = QComboBox(self)
        self.defaultGlyphSetBox.toggled.connect(self.toggleGlyphSetDrop)

        self.glyphSetList = QListWidget(self)
        self.glyphSetList.setSortingEnabled(True)
        self.glyphSetContents = QPlainTextEdit(self)
        self.glyphSetList.currentItemChanged.connect(
            self.updateGlyphSetContents)
        self.glyphSetList.itemChanged.connect(self.renameGlyphSet)
        self._cachedName = None
        splitter = QSplitter(self)
        splitter.addWidget(self.glyphSetList)
        splitter.addWidget(self.glyphSetContents)
        self.addGlyphSetButton = QPushButton("+", self)
        self.addGlyphSetButton.clicked.connect(lambda: self.addGlyphSet())
        self.removeGlyphSetButton = QPushButton("−", self)
        self.removeGlyphSetButton.clicked.connect(self.removeGlyphSet)
        self.importButton = QPushButton(self.tr("Import"), self)
        importMenu = QMenu(self)
        importMenu.addAction(
            self.tr("Import from current font"), self.importFromCurrentFont)
        self.importButton.setMenu(importMenu)
        self.glyphListBox = QCheckBox(self.tr("Glyph list path:"), self)
        self.glyphListEdit = QLineEdit(self)
        self.glyphListEdit.setReadOnly(True)
        self.glyphListButton = QPushButton(self.tr("Browse…"), self)
        self.glyphListButton.clicked.connect(self.getGlyphList)
        # TODO: find correct solution for this and maybe make a widget w
        # setSizesToText()
        # http://stackoverflow.com/a/19502467/2037879
        textWidth = self.glyphListButton.fontMetrics().boundingRect(
            self.glyphListButton.text()).width() + 16
        self.glyphListButton.setMaximumWidth(textWidth)
        self.glyphListBox.toggled.connect(self.glyphListEdit.setEnabled)
        self.glyphListBox.toggled.connect(self.glyphListButton.setEnabled)

        firstLayout = QGridLayout()
        l = 0
        firstLayout.addWidget(self.defaultGlyphSetBox, l, 0, 1, 2)
        firstLayout.addWidget(self.defaultGlyphSetDrop, l, 3, 1, 3)
        l += 1
        firstLayout.addWidget(splitter, l, 0, 1, 6)
        l += 1
        firstLayout.addWidget(self.addGlyphSetButton, l, 0)
        firstLayout.addWidget(self.removeGlyphSetButton, l, 1)
        firstLayout.addWidget(self.importButton, l, 2)
        secondLayout = QHBoxLayout()
        secondLayout.addWidget(self.glyphListBox, 0)
        secondLayout.addWidget(self.glyphListEdit, 1)
        secondLayout.addWidget(self.glyphListButton, 2)
        mainLayout = QVBoxLayout(self)
        mainLayout.addLayout(firstLayout)
        mainLayout.addLayout(secondLayout)
        self.setLayout(mainLayout)

        self.readSettings()

    def addGlyphSet(self, glyphNames=[], glyphSetName=None):
        if glyphSetName is None:
            glyphSetName = self.tr("New glyph set")
        if glyphSetName in self.glyphSets:
            index = 1
            while "%s %d" % (glyphSetName, index) in self.glyphSets:
                index += 1
            glyphSetName = "%s %d" % (glyphSetName, index)
        self.glyphSets[glyphSetName] = glyphNames
        item = QListWidgetItem(glyphSetName, self.glyphSetList)
        item.setFlags(item.flags() | Qt.ItemIsEditable)
        self.glyphSetList.setCurrentItem(item)
        self.glyphSetList.editItem(item)
        self.removeGlyphSetButton.setEnabled(True)

    def removeGlyphSet(self):
        i = self.glyphSetList.currentRow()
        text = self.glyphSetList.takeItem(i).text()
        del self.glyphSets[text]
        if self.glyphSetList.count() < 2:
            self.removeGlyphSetButton.setEnabled(False)

    def renameGlyphSet(self):
        newKey = self.glyphSetList.currentItem()
        if newKey is None:
            return
        newKey = newKey.text()
        self.glyphSets[newKey] = self.glyphSets[self._cachedName]
        del self.glyphSets[self._cachedName]

    def importFromCurrentFont(self):
        font = QApplication.instance().currentFont()
        name = "%s %s" % (font.info.familyName, font.info.styleName)
        self.addGlyphSet(font.glyphOrder, name)

    def toggleGlyphSetDrop(self):
        sender = self.sender()
        self.defaultGlyphSetDrop.setEnabled(sender.isChecked())

    def updateGlyphSetContents(self, current, previous):
        # store content of the textEdit in the glyphSet dict
        if previous is not None:
            glyphNames = self.glyphSetContents.toPlainText().split()
            self.glyphSets[previous.text()] = glyphNames
        # now update the text edit to current glyphSet
        glyphSetName = current.text()
        text = " ".join(self.glyphSets[glyphSetName])
        self.glyphSetContents.setPlainText(text)
        # cache current name for renames
        self._cachedName = glyphSetName

    def getGlyphList(self):
        fileFormats = (
            self.tr("Text file {}").format("(*.txt)"),
            self.tr("All files {}").format("(*.*)"),
        )
        path, _ = QFileDialog.getOpenFileName(
            self, self.tr("Open File"), '', ";;".join(fileFormats)
        )
        if path:
            self.glyphListEdit.setText(path)

    def readSettings(self):
        defaultGlyphSet = settings.defaultGlyphSet()
        self.defaultGlyphSetBox.setChecked(len(defaultGlyphSet))

        self.glyphSets = settings.readGlyphSets()
        self.defaultGlyphSetDrop.clear()
        self.defaultGlyphSetDrop.addItems(self.glyphSets.keys())

        self.glyphSetList.clear()
        glyphSetNames = self.glyphSets.keys()
        # Normally we should be enforcing this rather decently in the interface
        # already
        if glyphSetNames:
            for glyphSetName in glyphSetNames:
                item = QListWidgetItem(glyphSetName, self.glyphSetList)
                item.setFlags(item.flags() | Qt.ItemIsEditable)
            self.glyphSetList.setCurrentRow(0)
        self.removeGlyphSetButton.setEnabled(len(self.glyphSets) > 1)

        glyphListPath = settings.glyphListPath()
        self.glyphListBox.setChecked(bool(glyphListPath))
        self.glyphListEdit.setEnabled(bool(glyphListPath))
        self.glyphListEdit.setText(glyphListPath)
        self.glyphListButton.setEnabled(bool(glyphListPath))

    def writeSettings(self):
        # store content of the textEdit in the glyphSet dict
        glyphNames = self.glyphSetContents.toPlainText().split()
        currentGlyphSet = self.glyphSetList.currentItem().text()
        self.glyphSets[currentGlyphSet] = glyphNames

        settings.writeGlyphSets(self.glyphSets)
        if not self.defaultGlyphSetBox.isChecked():
            settings.setDefaultGlyphSet(None)
        else:
            defaultGlyphSet = self.defaultGlyphSetDrop.currentText()
            settings.setDefaultGlyphSet(defaultGlyphSet)
        if not self.glyphListBox.isChecked():
            settings.setGlyphListPath(None)
        else:
            glyphListPath = self.glyphListEdit.text()
            if glyphListPath:
                settings.setGlyphListPath(glyphListPath)
                QApplication.instance().loadGlyphList()
Exemplo n.º 5
0
class ListEntry(BaseParamWidget):
    def __init__(self, layout_dir: str, title: str,
                 initial_value: List[List[str]], new_id_func: Callable):
        super().__init__(layout_dir)
        self.choices = []
        self.text_list = []
        lab_title = QLabel(text=title)
        layout = QHBoxLayout()
        self.central_layout.addWidget(lab_title)
        self.on_check_callback = None
        self.list_widget = QListWidget()
        self.set_value(initial_value)
        layout_tools = QVBoxLayout()
        self.button_add_item = QPushButton('+')
        self.button_delete_item = QPushButton('-')
        self.button_delete_item.clicked.connect(self.delete_row)
        self.button_add_item.clicked.connect(self.add_row)
        self.button_add_item.setMaximumWidth(20)
        self.button_delete_item.setMaximumWidth(20)
        layout_tools.addWidget(self.button_add_item)
        layout_tools.addWidget(self.button_delete_item)
        layout.addLayout(layout_tools)
        layout.addWidget(self.list_widget)
        self.central_layout.addLayout(layout)
        self.data = initial_value
        self.new_id_func = new_id_func

    def new_id(self):
        if callable(self.new_id_func):
            return self.new_id_func()
        else:
            return None

    def add_row(self):
        self.data[0].append(self.new_id())
        self.data[1].append('Unnamed')
        self.set_value(self.data)

    def delete_row(self):
        # item = self.list_widget.currentItem()
        index = self.list_widget.currentIndex().row()
        self.data[0].pop(index)
        self.data[1].pop(index)
        self.set_value(self.data)

    def on_listwidget_double_cicked(self):
        print('edit')
        item = self.list_widget.currentItem()
        self.list_widget.editItem(item)

    def get_value(self):
        text = []
        for i in range(self.list_widget.count()):
            text.append(self.list_widget.item(i).text())
        self.data[1] = text
        return self.data

    def set_value(self, data: List[List[str]]):
        self.list_widget.clear()
        self.list_widget.addItems(data[1])
        self.data = data
        for index in range(self.list_widget.count()):
            item = self.list_widget.item(index)
            item.setFlags(item.flags() | Qt.ItemIsEditable)
Exemplo n.º 6
0
class Example(QWidget):
    def __init__(self):
        super().__init__()

        self.filenames = json_files()

        if type(self.filenames) is list:
            self.curr_file = self.filenames[0]
        else:
            self.curr_file = self.filenames

        self.initUI()

    def initUI(self):

        self.num = -1  # index for search bar query
        self.show_save = False  # bool for showing unsaved changes dialog
        self.temp_file = ".temp.csv"
        self.refresh_file = False  # failsafe 1 for itemChanged trigger

        self.list_1 = QListWidget()

        lister(file=self.curr_file, target=self.list_1, index=0, mode=0)
        self.list_1.clicked.connect(self.clear_selection)
        self.list_1.installEventFilter(self)

        self.list_items = self.list_1.count(
        )  # failsafe 2 for itemChanged trigger
        self.list_1.itemChanged.connect(self.edit_next_item)
        self.list_1.verticalScrollBar().valueChanged.connect(self.sync_scroll)

        self.list_2 = QListWidget()
        lister(file=self.curr_file, target=self.list_2, index=1, mode=0)
        self.list_2.clicked.connect(self.clear_selection)

        self.list_3 = QListWidget()
        lister(file=self.curr_file, target=self.list_3, index=2, mode=0)
        self.list_3.clicked.connect(self.clear_selection)

        self.all_lists = [self.list_1, self.list_2, self.list_3]

        self.menubar = QMenuBar()
        self.menubar.setNativeMenuBar(False)

        exit_event = QAction('Exit', self)
        exit_event.setShortcut('Ctrl+W')
        exit_event.triggered.connect(app.quit)

        showAct = QAction('Show extras', self, checkable=True)
        showAct.setChecked(False)
        showAct.setShortcut('Ctrl+E')
        showAct.triggered.connect(self.hide_notes)

        addAct = QAction('Fields', self)
        addAct.setShortcut('Ctrl+N')
        addAct.triggered.connect(self.add_item)

        fileOpen = QAction('Open file', self)
        fileOpen.triggered.connect(self.fileDialog)
        fileOpen.setShortcut('Ctrl+O')

        fileSave = QAction('Save file', self)
        fileSave.triggered.connect(self.save)
        fileSave.triggered.connect(self.refresh_recents)
        fileSave.setShortcut('Ctrl+S')

        self.fileRecents = QMenu('Recent file', self)
        self.refresh_recents()

        self.toggle_theme = QAction('Toggle theme', self, checkable=True)
        self.toggle_theme.setChecked(json_theme())
        self.toggle_theme.triggered.connect(self.theme)
        self.toggle_theme.setShortcut('Ctrl+T')

        self.col_sort_index = QMenu('Sorting column index', self)
        self.col_sort_index.addAction(QAction(str(0), self))
        self.col_sort_index.addAction(QAction(str(1), self))
        self.col_sort_index.addAction(QAction(str(2), self))
        self.col_sort_index.triggered.connect(self.sort_col_choice)

        self.col_search_index = QMenu('Searching column index', self)
        self.col_search_index.addAction(QAction(str(0), self))
        self.col_search_index.addAction(QAction(str(1), self))
        self.col_search_index.addAction(QAction(str(2), self))
        self.col_search_index.triggered.connect(self.search_col_choice)

        self.sort = QAction('Sort entries', self, checkable=True)
        self.curr_col = 0
        self.search_col = 0
        self.sort.triggered.connect(self.refresh_list)
        self.sort.setShortcut('Ctrl+R')

        self.addFields = self.menubar.addMenu('Add')
        self.addFields.addAction(addAct)

        self.optionMenu = self.menubar.addMenu('Options')
        self.optionMenu.addAction(exit_event)
        self.optionMenu.addAction(showAct)
        self.optionMenu.addAction(self.toggle_theme)
        self.optionMenu.addMenu(self.col_sort_index)
        self.optionMenu.addMenu(self.col_search_index)
        self.optionMenu.addAction(self.sort)

        self.fileMenu = self.menubar.addMenu('File')
        self.fileMenu.addAction(fileOpen)
        self.fileMenu.addAction(fileSave)
        self.fileMenu.addMenu(self.fileRecents)

        self.search_bar = QLineEdit()
        self.search_bar.setPlaceholderText('Search vocab')
        self.search_bar.setClearButtonEnabled(True)
        self.search_bar.setMaxLength(10)
        self.search_bar.returnPressed.connect(self.search_item)

        self.status_bar = QStatusBar()
        status(self.status_bar, self.list_1)

        grid = QGridLayout()
        grid.setSpacing(10)
        grid.addWidget(self.menubar, 0, 0)
        grid.addWidget(self.list_1, 1, 0)
        grid.addWidget(self.list_2, 1, 1)
        grid.addWidget(self.list_3, 1, 2)
        grid.addWidget(self.search_bar, 0, 1)
        grid.addWidget(self.status_bar)

        self.theme()
        self.setLayout(grid)
        self.setGeometry(*json_window_size())
        self.setWindowTitle(f'{split_name(self.curr_file)}')
        self.show()

        self.list_1.scrollToBottom()
        self.list_2.verticalScrollBar().setHidden(True)
        self.list_3.verticalScrollBar().setHidden(True)
        self.list_3.setHidden(True)

    def sync_scroll(self):

        scroll_location = self.list_1.verticalScrollBar().value()

        self.list_2.verticalScrollBar().setValue(scroll_location)
        self.list_3.verticalScrollBar().setValue(scroll_location)

    def edit_next_item(self, event):
        """When an item is added and edited on the first col, starts editing its counterpart on the next col"""

        if self.list_items == self.list_1.count(
        ) - 2 or self.list_items != self.list_1.count(
        ) and self.refresh_file == False:

            item = self.list_2.item(self.list_2.count() - 1)
            self.list_2.editItem(item)

            self.list_items = self.list_1.count()

    def closeEvent(self, event):
        """Triggered upon program exit, shows a dialog for unsaved changes using a bool"""

        if self.show_save == True:

            reply = QMessageBox.question(
                self, 'Message',
                "You may have unsaved changes, are you sure you want to quit?",
                QMessageBox.Yes | QMessageBox.No, QMessageBox.No)

            if reply == QMessageBox.Yes:
                try:
                    remove(self.temp_file)
                except:
                    pass

                event.accept()
            else:
                event.ignore()

        else:
            pass

    def sort_col_choice(self, action):
        self.curr_col = int(action.text())

    def search_col_choice(self, action):
        self.search_col = int(action.text())

    def refresh_list(self):
        """Refreshes the contents of the lists, when sorting is used"""

        self.save(
            mode=1
        )  # saves a temp copy, with changes, but irreversable sorting introduced

        clear_lists(self.all_lists)

        if self.sort.isChecked() == True:
            mode = 2
        else:
            mode = 0

        try:
            lister(file=self.temp_file,
                   target=self.list_1,
                   index=0,
                   mode=mode,
                   column=self.curr_col)
            lister(file=self.temp_file,
                   target=self.list_2,
                   index=1,
                   mode=mode,
                   column=self.curr_col)
            lister(file=self.temp_file,
                   target=self.list_3,
                   index=2,
                   mode=mode,
                   column=self.curr_col)

        except:
            lister(file=self.curr_file,
                   target=self.list_1,
                   index=0,
                   mode=mode,
                   column=self.curr_col)
            lister(file=self.curr_file,
                   target=self.list_2,
                   index=1,
                   mode=mode,
                   column=self.curr_col)
            lister(file=self.curr_file,
                   target=self.list_3,
                   index=2,
                   mode=mode,
                   column=self.curr_col)

    def refresh_recents(self):

        try:

            file_1 = QAction(self.curr_file, self)
            self.fileRecents.addAction(file_1)
            file_1.triggered.connect(self.clickedFileAct)

            if type(self.filenames) is list:

                if self.filenames[1] != None:
                    file_2 = QAction(self.filenames[1], self)
                    self.fileRecents.addAction(file_2)
                    file_2.triggered.connect(self.clickedFileAct)

                if self.filenames[2] != None:
                    file_3 = QAction(self.filenames[2], self)
                    self.fileRecents.addAction(file_3)
                    file_3.triggered.connect(self.clickedFileAct)

        except:
            pass

    def clickedFileAct(self):

        self.refresh_file = True

        file = self.sender().text()
        self.curr_file = file
        self.setWindowTitle(f'{split_name(self.curr_file)}')

        clear_lists(self.all_lists)

        lister(file=self.curr_file, target=self.list_1, index=0)
        lister(file=self.curr_file, target=self.list_2, index=1)
        lister(file=self.curr_file, target=self.list_3, index=2)

        status(self.status_bar, self.list_1)
        self.theme()

        self.list_1.scrollToBottom()
        self.list_3.setHidden(True)

        self.refresh_file = False

    def eventFilter(self, source, event):
        """Item (row) deletion"""

        if (event.type() == QEvent.ContextMenu and source is self.list_1):
            menu = QMenu()
            menu.addAction("Delete row")
            if menu.exec_(event.globalPos()):
                item = source.itemAt(event.pos())
                try:
                    model = self.list_1.indexFromItem(item)
                    row = model.row()

                    self.show_save = True

                    self.list_1.takeItem(row)
                    self.list_2.takeItem(row)
                    self.list_3.takeItem(row)

                    status(self.status_bar, self.list_1,
                           f'Deleted row number: {row+1}.')
                    self.clearSelection()

                except:
                    pass

            return True
        return super(Example, self).eventFilter(source, event)

    def hide_notes(self):
        """Toggles showing the note column and stretches the window for clearer reading of it"""

        self.list_3.setHidden(not self.list_3.isHidden())

    def theme(self):
        """Sets the theme for the window and its widgets"""

        palette = QPalette()

        # dark theme
        if self.toggle_theme.isChecked() == True:

            palette.setColor(QPalette.Window, QColor(0, 0, 0))
            dark = "background-color: rgb(0, 0, 0); color: rgb(255, 255, 255);"

            self.menubar.setStyleSheet(dark)
            self.addFields.setStyleSheet(dark)
            self.optionMenu.setStyleSheet(dark)
            self.fileMenu.setStyleSheet(dark)
            self.search_bar.setStyleSheet(
                "background-color: rgb(0, 0, 0); color: rgb(255, 255, 255)"
            )  # border: 0px; for transparency
            self.status_bar.setStyleSheet(dark)

            style_items(self.all_lists, dark_theme=True)

        # light theme
        elif self.toggle_theme.isChecked() == False:

            palette.setColor(QPalette.Window, QColor(255, 255, 255))
            light = "background-color: rgb(255, 255, 255); color: rgb(0, 0, 0)"

            self.menubar.setStyleSheet(light)
            self.addFields.setStyleSheet(light)
            self.optionMenu.setStyleSheet(light)
            self.fileMenu.setStyleSheet(light)
            self.search_bar.setStyleSheet(light)
            self.status_bar.setStyleSheet(light)

            style_items(self.all_lists, dark_theme=False)

        self.setPalette(palette)

        self.theme_bool = self.toggle_theme.isChecked(
        )  # used in the save func

    def search_item(self):
        """Takes input from the search bar and matches with an item, 
		gets index and scrolls to it, more reusults being qued with the num class var
		"""

        query = self.search_bar.text()
        search = self.all_lists[self.search_col].findItems(
            query, Qt.MatchContains)
        status(self.status_bar, self.list_1, f'Found {len(search)} results.')
        self.clear_selection()

        # testing search in all column

        # search_list =[]
        # for x in range(3):
        # 	search_list.append(self.all_lists[x].findItems(query, Qt.MatchContains))

        # parent_list = []
        # for x in range(3):
        # 	for y in range(len(search_list[x])):
        # 		parent_list.append(self.all_lists[x]) # replace with x

        # import itertools
        # merged = list(itertools.chain.from_iterable(search_list))

        # search_dict = dict(zip(parent_list, merged))
        # print(search_dict)
        # print()
        # print(len(merged))
        # print(len(parent_list))

        self.num += 1
        for i in search:

            try:
                model_index = self.all_lists[self.search_col].indexFromItem(
                    search[self.num])

            except:
                self.num = 0
                model_index = self.all_lists[self.search_col].indexFromItem(
                    search[self.num])

            item_index = model_index.row()

            self.all_lists[self.search_col].item(item_index).setSelected(True)
            self.list_1.scrollToItem(self.list_1.item(item_index),
                                     QAbstractItemView.PositionAtCenter)

    def add_item(self):

        self.show_save = True

        for x in range(3):
            if x == 0:
                lister(file=self.curr_file,
                       target=self.list_1,
                       index=x,
                       mode=1)

            elif x == 1:
                lister(file=self.curr_file,
                       target=self.list_2,
                       index=x,
                       mode=1)

            elif x == 2:
                lister(file=self.curr_file,
                       target=self.list_3,
                       index=x,
                       mode=1)

        item = self.list_1.item(self.list_1.count() - 1)
        self.list_1.editItem(item)
        status(self.status_bar, self.list_1)

        self.list_1.scrollToBottom()
        self.list_2.scrollToBottom()
        self.list_3.scrollToBottom()

    def clear_selection(self):
        """Clears all item slections for aesthetical purposes, but only single clicks"""

        self.list_1.clearSelection()
        self.list_2.clearSelection()
        self.list_3.clearSelection()

    def fileDialog(self):

        fname = QFileDialog()
        path = fname.getOpenFileName(self,
                                     'Open file',
                                     getcwd(),
                                     filter='csv (*.csv);;')
        if path[0] == '':  # failsafe for canceling the dialog
            return self.curr_file

        self.curr_file = path[0]
        self.setWindowTitle(f'{split_name(self.curr_file)}')

        clear_lists(self.all_lists)

        lister(file=self.curr_file, target=self.list_1, index=0)
        lister(file=self.curr_file, target=self.list_2, index=1)
        lister(file=self.curr_file, target=self.list_3, index=2)

        status(self.status_bar, self.list_1)
        self.theme()

    def save(self, mode=0):

        self.show_save = False

        list1_items = items_text(self.list_1)
        list2_items = items_text(self.list_2)
        list3_items = items_text(self.list_3)

        total_dicts = []
        for (a, b, c) in zip(list1_items, list2_items,
                             list3_items):  # each letter is a column
            dictionary = {'word_1': a, 'word_2': b, 'notes': c}
            total_dicts.append(dictionary)

        if mode == 0:

            writer(file=self.curr_file, data=total_dicts)
            status(self.status_bar, self.list_1, ('Saved current changes.'))

            try:
                json_template(theme=self.theme_bool,
                              files=[self.curr_file, None, None],
                              window_size=self.geometry().getRect()
                              )  # current size values of the window

            except:
                json_template(
                )  # bug cannot be avoided, even though used setChecked at the beggining

        elif mode == 1:

            self.show_save = True
            writer(file=self.temp_file, data=total_dicts)

        # avoids stacking and refreshes recent file actions
        actions = self.fileRecents.actions()
        for action in actions:
            self.fileRecents.removeAction(action)
Exemplo n.º 7
0
class GridControl(QGroupBox):
    """
    Widget for controlling grids in Main Window.
    """
    """Signals"""
    sig_place_grid = pyqtSignal()
    sig_crop_region = pyqtSignal(list, float, str)
    sig_generate_rotated_image = pyqtSignal(float)

    def __init__(self, parent, title, num_rows, num_cols):
        super().__init__(parent=parent, title=title)

        # self.gc_box = QGroupBox(parent=self, title='Grid control')
        self.layout = QGridLayout()
        self.label_checkbox = QCheckBox('Toggle labels', parent=self)
        self.col_label = QLabel('Columns:', parent=self)
        self.row_label = QLabel('Rows: ', parent=self)
        self.col_spinbox = QSpinBox(parent=self,
                                    value=num_cols,
                                    maximum=26,
                                    minimum=1)
        self.row_spinbox = QSpinBox(parent=self,
                                    value=num_rows,
                                    maximum=40,
                                    minimum=1)
        self.btn_like_grid = QPushButton('I like this grid!', parent=self)
        self.grid_list = QListWidget(parent=self)
        self.btn_crop_grid = QPushButton('Crop', parent=self)
        self.btn_del_grid = QPushButton('Delete', parent=self)

        self.parent = self.parentWidget()

        self.configure_gui()
        self.configure_signals()

    def configure_gui(self):
        """
            Configure grid control
        """
        """Layout"""
        self.layout.addWidget(self.row_label, 0, 0)
        self.layout.addWidget(self.col_label, 0, 1)
        self.layout.addWidget(self.col_spinbox, 1, 1)
        self.layout.addWidget(self.row_spinbox, 1, 0)
        self.layout.addWidget(self.label_checkbox, 2, 0, 1, 2)
        self.layout.addWidget(self.btn_like_grid, 3, 0, 1, 2)
        self.layout.addWidget(self.grid_list, 4, 0, 1, 2)
        self.layout.addWidget(self.btn_crop_grid, 5, 0)
        self.layout.addWidget(self.btn_del_grid, 5, 1)
        self.setLayout(self.layout)
        self.setGeometry(0, 0, 150, 400)
        self.move(520, 90)
        """Checkbox"""
        self.label_checkbox.resize(self.label_checkbox.sizeHint())
        self.label_checkbox.setCheckState(Qt.Unchecked)
        self.label_checkbox.stateChanged.connect(self.label_checkbox_checked)
        self.label_checkbox_checked()  # update grid to default settings
        """Row/column spinboxes"""
        self.row_spinbox.valueChanged.connect(self.parent.set_num_rows)
        self.col_spinbox.valueChanged.connect(self.parent.set_num_cols)
        """I like this grid! button"""
        self.btn_like_grid.resize(self.btn_like_grid.sizeHint())
        self.btn_like_grid.setEnabled(False)
        self.btn_like_grid.clicked.connect(self.like_grid_button_clicked)
        """Grid list"""
        self.grid_list.setSelectionMode(QAbstractItemView.SingleSelection)
        self.grid_list.itemSelectionChanged.connect(self.change_selected_grid)
        self.grid_list.itemDoubleClicked.connect(self.change_grid_name)
        """Crop and del button"""
        self.btn_crop_grid.setEnabled(False)
        self.btn_crop_grid.clicked.connect(self.crop_grid_button_clicked)
        self.btn_del_grid.setEnabled(False)
        self.btn_del_grid.clicked.connect(self.del_grid_button_clicked)

    def configure_signals(self):
        self.sig_place_grid.connect(self.parent.place_grid)
        self.sig_generate_rotated_image.connect(self.parent.rotate_image)

    @pyqtSlot()
    def change_selected_grid(self):
        """
        Call when selected grid in `GridList` changes.
        `Crop` and `Del` are enabled, and selected grid
        changes def_color.

        Returns
        -------

        """
        grid_list = []
        for i in range(self.grid_list.count()):
            grid_list.append(self.grid_list.item(i))

        grid_list_selected = self.grid_list.selectedItems()

        for grid_item in grid_list:
            grid_item.grid.set_color_and_thickness(color=Qt.blue)

        for grid_item in grid_list_selected:
            grid_item.grid.set_color_and_thickness(color=Qt.red, thickness=3.)

        if len(grid_list_selected) > 0:
            self.btn_crop_grid.setEnabled(True)
            self.btn_del_grid.setEnabled(True)
        else:
            self.btn_crop_grid.setEnabled(False)
            self.btn_del_grid.setEnabled(False)

    @pyqtSlot()
    def change_grid_name(self):
        item = self.grid_list.selectedItems()[0]
        self.grid_list.editItem(item)

    @pyqtSlot()
    def crop_grid_button_clicked(self):
        """
        Crop images using the selected grid in `GridList`.
        For each grid square, emit signal `sig_crop_region`,
        passing `QRectF` scaled coordinates of region to crop.

        Returns
        -------

        """
        """Collect grid information"""
        grid_item = self.grid_list.selectedItems()[0]
        image_coordinates = grid_item.grid.image_coordinates
        num_rows = grid_item.grid.num_rows
        num_cols = grid_item.grid.num_cols
        angle = grid_item.grid.phi
        alphabet = string.ascii_uppercase
        """Create directory and crop images"""
        directory = grid_item.text()
        if not os.path.exists(directory):
            os.makedirs(directory)
            """generate counter-rotated_image for cropping"""
            self.sig_generate_rotated_image.emit(-angle)
            """Crop images"""
            for ix, image_coordinate in enumerate(image_coordinates):
                """Get bg_image coordinate"""
                tl_x, tl_y = image_coordinate[0, 0]
                tl = QPointF(tl_x, tl_y)  # top left
                bl_x, bl_y = image_coordinate[0, 1]
                bl = QPointF(bl_x, bl_y)  # top right
                tr_x, tr_y = image_coordinate[1, 0]
                tr = QPointF(tr_x, tr_y)  # bottom left
                br_x, br_y = image_coordinate[1, 1]
                br = QPointF(br_x, br_y)  # bottom right
                """Find polygon to be cropped"""
                coords = [tl, bl, br, tr]
                # pol = QPolygonF(coords)
                """Determine file name"""
                col = (ix // num_rows)
                row = (ix % num_rows) + 1
                file_name = str(alphabet[col]) + str(row)
                full_path = os.path.join(directory, file_name)
                self.sig_crop_region.emit(coords, angle, full_path)
        else:
            print('Can\'t crop bg_image: folder already exist')

    @pyqtSlot()
    def del_grid_button_clicked(self):
        """
        Delete grid from `GridList`.
        Returns
        -------

        """
        """Find selected GridListItemWidget """
        grid_item = self.grid_list.selectedItems()[0]
        """Remove from GridList"""
        item_ix = self.grid_list.row(grid_item)
        self.grid_list.takeItem(item_ix)
        """Remove from scene"""
        grid_item.grid.clear_grid()

    @pyqtSlot()
    def like_grid_button_clicked(self):
        """
        Add grid to `grid_list` and emit `sig_place_grid`.

        Returns
        -------

        """

        self.btn_like_grid.setEnabled(False)
        """Add grid to placed grid widget"""
        item = GridListWidgetItem(parent=self.grid_list)
        item.set_grid(self.parent.view.current_grid)
        # TODO ItemIsEditable does not work
        # item.setFlags(Qt.ItemIsEditable)
        # item.setFlags(Qt.ItemIsSelectable)

        self.sig_place_grid.emit()

    @pyqtSlot()
    def label_checkbox_checked(self):
        """
        Enable/disable labels "A1,..,etc." in current grid.
        :return:
        """
        check_state = self.label_checkbox.checkState()
        grid = self.parent.view.current_grid

        if check_state == Qt.Checked:
            grid.label_enabled = True
        elif check_state == Qt.Unchecked:
            grid.label_enabled = False
        """Redraw grid"""
        try:
            tl, br = grid.tl_br_qpointf
        except ValueError:
            pass
        else:
            tl_x = tl.x()
            tl_y = tl.y()
            br_x = br.x()
            br_y = br.y()
            angle = grid.phi
            grid.draw_grid(tl_x, tl_y, br_x, br_y, angle)