from qtpy import QT_VERSION from qtpy import QtCore from qtpy import QtGui from qtpy import QtWidgets QT5 = QT_VERSION[0] == '5' # NOQA import labelme.utils # TODO(unknown): # - Calculate optimal position so as not to go out of screen area. class LabelQLineEdit(QtWidgets.QLineEdit): def setListWidget(self, list_widget): self.list_widget = list_widget def keyPressEvent(self, e): if e.key() in [QtCore.Qt.Key_Up, QtCore.Qt.Key_Down]: self.list_widget.keyPressEvent(e) else: super(LabelQLineEdit, self).keyPressEvent(e) class LabelDialog(QtWidgets.QDialog): def __init__(self, text="Enter object label", parent=None, labels=None, sort_labels=True, show_text_field=True): super(LabelDialog, self).__init__(parent) self.edit = LabelQLineEdit() self.edit.setPlaceholderText(text) self.edit.setValidator(labelme.utils.labelValidator()) self.edit.editingFinished.connect(self.postProcess) layout = QtWidgets.QVBoxLayout() if show_text_field: layout.addWidget(self.edit) # buttons self.buttonBox = bb = QtWidgets.QDialogButtonBox( QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel, QtCore.Qt.Horizontal, self, ) bb.button(bb.Ok).setIcon(labelme.utils.newIcon('done')) bb.button(bb.Cancel).setIcon(labelme.utils.newIcon('undo')) bb.accepted.connect(self.validate) bb.rejected.connect(self.reject) layout.addWidget(bb) # label_list self.labelList = QtWidgets.QListWidget() self._sort_labels = sort_labels if labels: self.labelList.addItems(labels) if self._sort_labels: self.labelList.sortItems() else: self.labelList.setDragDropMode( QtGui.QAbstractItemView.InternalMove) self.labelList.currentItemChanged.connect(self.labelSelected) self.edit.setListWidget(self.labelList) layout.addWidget(self.labelList) self.setLayout(layout) # completion completer = QtWidgets.QCompleter() completer.setCompletionMode(QtWidgets.QCompleter.InlineCompletion) completer.setModel(self.labelList.model()) self.edit.setCompleter(completer) def addLabelHistory(self, label): if self.labelList.findItems(label, QtCore.Qt.MatchExactly): return self.labelList.addItem(label) if self._sort_labels: self.labelList.sortItems() def labelSelected(self, item): self.edit.setText(item.text()) def validate(self): text = self.edit.text() if hasattr(text, 'strip'): text = text.strip() else: text = text.trimmed() if text: self.accept() def postProcess(self): text = self.edit.text() if hasattr(text, 'strip'): text = text.strip() else: text = text.trimmed() self.edit.setText(text) def popUp(self, text=None, move=True): # if text is None, the previous label in self.edit is kept if text is None: text = self.edit.text() self.edit.setText(text) self.edit.setSelection(0, len(text)) items = self.labelList.findItems(text, QtCore.Qt.MatchFixedString) if items: assert len(items) == 1 self.labelList.setCurrentItem(items[0]) row = self.labelList.row(items[0]) self.edit.completer().setCurrentRow(row) self.edit.setFocus(QtCore.Qt.PopupFocusReason) if move: self.move(QtGui.QCursor.pos()) return self.edit.text() if self.exec_() else None