class SearchFindWidget(QWidget, object): textChanged = Signal(str) editingFinished = Signal(str) returnPressed = Signal() def __init__(self, search_line=None, parent=None): super(SearchFindWidget, self).__init__(parent=parent) self.setObjectName('SearchFindWidget') self.text = '' self._placeholder_text = '' main_layout = layouts.HorizontalLayout(spacing=2, margins=(2, 2, 2, 2)) self.setLayout(main_layout) self._search_line = search_line or QLineEdit(self) self._search_menu = QMenu() self._search_menu.addAction('Test') icon_size = self.style().pixelMetric(QStyle.PM_SmallIconSize) delete_icon = resources.icon('delete') search_icon = QIcon(resources.icon('search')) self._clear_btn = buttons.IconButton(delete_icon, icon_padding=2, parent=self) self._clear_btn.setIconSize(QSize(icon_size, icon_size)) self._clear_btn.setFixedSize(QSize(icon_size, icon_size)) self._clear_btn.hide() self._search_btn = buttons.IconButton(search_icon, icon_padding=2, parent=self) self._search_btn.setIconSize(QSize(icon_size, icon_size)) self._search_btn.setFixedSize(QSize(icon_size, icon_size)) # self._search_btn.setStyleSheet('border: none;') # self._search_btn.setPopupMode(QToolButton.InstantPopup) self._search_btn.setEnabled(True) self._search_line.setStyleSheet(""" QLineEdit { padding-left: %spx; padding-right: %spx; border-radius:10px; border:2px; border-color:red; } """ % (self._search_button_padded_width(), self._clear_button_padded_width())) self._search_line.setMinimumSize( max( self._search_line.minimumSizeHint().width(), self._clear_button_padded_width() + self._search_button_padded_width()), max( self._search_line.minimumSizeHint().height(), max(self._clear_button_padded_width(), self._search_button_padded_width()))) main_layout.addWidget(self._search_line) self._search_line.setFocus() self._search_line.textChanged.connect(self.textChanged) self._search_line.textChanged.connect(self.set_text) # self._search_line.editingFinished.connect(self.editingFinished) # self._search_line.returnPressed.connect(self.returnPressed) self._clear_btn.clicked.connect(self.clear) self._search_btn.clicked.connect(self._popup_menu) @property def search_line(self): return self._search_line def changeEvent(self, event): if event.type() == QEvent.EnabledChange: enabled = self.isEnabled() self._search_btn.setEnabled(enabled and self._search_menu) self._search_line.setEnabled(enabled) self._clear_btn.setEnabled(enabled) super(SearchFindWidget, self).changeEvent(event) def resizeEvent(self, event): if not (self._clear_btn and self._search_line): return super(SearchFindWidget, self).resizeEvent(event) x = self.width() - self._clear_button_padded_width() * 0.85 y = (self.height() - self._clear_btn.height()) * 0.5 self._clear_btn.move(x - 3, y) self._search_btn.move(self._search_line_frame_width() * 2, (self.height() - self._search_btn.height()) * 0.5) def keyPressEvent(self, event): if event.key() == Qt.Key_Escape: self.clear() super(SearchFindWidget, self).keyPressEvent(event) def get_text(self): if not self._search_line: return '' return self._search_line.text() def set_text(self, text): if not (self._clear_btn and self._search_line): return self._clear_btn.setVisible(not (len(text) == 0)) if text != self.get_text(): self._search_line.setText(text) def get_placeholder_text(self): if not self._search_line: return '' return self._search_line.text() def set_placeholder_text(self, text): if not self._search_line: return self._search_line.setPlaceholderText(text) def get_menu(self): search_icon = resources.icon('search') self._search_btn.setIcon(search_icon) self._search_btn.setEnabled(self.isEnabled() and self._menu) def set_focus(self, reason=Qt.OtherFocusReason): if self._search_line: self._search_line.setFocus(reason) else: self.setFocus(Qt.OtherFocusReason) def clear(self): if not self._search_line: return self._search_line.clear() self.set_focus() def select_all(self): if not self._search_line: return self._search_line.selectAll() def _search_line_frame_width(self): return self._search_line.style().pixelMetric( QStyle.PM_DefaultFrameWidth) def _clear_button_padded_width(self): return self._clear_btn.width() + self._search_line_frame_width() * 2 def _clear_button_padded_height(self): return self._clear_btn.height() + self._search_line_frame_width() * 2 def _search_button_padded_width(self): return self._search_btn.width() + self._search_line_frame_width() * 2 def _search_button_padded_height(self): return self._search_btn.height() + self._search_line_frame_width() * 2 def _popup_menu(self): if self._search_menu: screen_rect = QApplication.desktop().availableGeometry( self._search_btn) size_hint = self._search_menu.sizeHint() rect = self._search_btn.rect() top_diff = rect.top() - size_hint.height() x = rect.right() - size_hint.width( ) if self._search_btn.isRightToLeft() else rect.left() y = rect.bottom( ) if self._search_btn.mapToGlobal(QPoint(0, rect.bottom())).y( ) + size_hint.height() <= screen_rect.height() else top_diff point = self._search_btn.mapToGlobal(QPoint(x, y)) point.setX( max(screen_rect.left(), min(point.x(), screen_rect.right() - size_hint.width()))) point.setY(point.y() + 1) print('pop up on {}'.format(point)) self._search_menu.popup(point)
class propertiesDialog(QDialog, Ui_propertiesDialog): """ Properties dialog class """ def __init__(self, properties, headers=None, mode='adri'): """ mode a: allow add mode d: allow delete mode r: allow reorder mode i: force name to be valid identifier """ super().__init__() self.setupUi(self) self.properties = OrderedDict(properties) self.mode = mode # set to cursor position # will place window in current screen, even when cursor at some 'odd location' rect = self.geometry() rect.moveTo(QCursor.pos()) self.setGeometry( rect ) # will place window in current screen, even when at some 'odd location' self.propertiesTableView.setStyle(customStyle()) model = customModel(parent=self.propertiesTableView) self.propertiesTableView.setModel(model) self.row = -1 if 'd' in self.mode: self.propertiesTableView.customContextMenuRequested.connect( self.showContextMenu) if 'a' in self.mode: self.addProperty.clicked.connect(self.addRow) else: self.addProperty.hide() if 'r' in mode: self.propertiesTableView.setDragDropMode( QAbstractItemView.InternalMove) # push buttons signals self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) model.populate(self.properties, headers) def showContextMenu(self, pos): self.row = self.propertiesTableView.indexAt(pos).row() self.menu = QMenu(self) deleteRowAction = QAction('Delete', self) deleteRowAction.triggered.connect(self.deleteRow) self.menu.addAction(deleteRowAction) # add other required actions self.menu.popup(QCursor.pos()) def deleteRow(self): model = self.propertiesTableView.model() model.removeRows(self.row, 1) def addRow(self): model = self.propertiesTableView.model() data = [QStandardItem('') for i in range(model.columnCount())] for d in data: d.setDropEnabled(False) model.appendRow(data) def accept(self): print('OK') model = self.propertiesTableView.model() new_properties = OrderedDict() for row in range(model.rowCount()): values = [] name = model.data(model.index(row, 0)) for col in range(1, model.columnCount()): ix = model.index(row, col) widget = self.propertiesTableView.indexWidget(ix) if widget: value = widget.value else: value = model.data(model.index(row, col)) # string type if name in self.properties: # restore original type value = type(self.properties[name][col - 1])(value) values.append(value) name = str(name).strip() if 'i' in self.mode: if name.isidentifier(): # valid name new_properties[name] = values elif name: new_properties[name] = values self.properties = new_properties super().accept()