# -*- coding: utf-8 -*- # pylint: disable=invalid-name,no-name-in-module # ----------------------------------------------------------------------------- # Copyright (c) 2016-2017 Anaconda, Inc. # # May be copied and distributed freely only as part of an Anaconda or # Miniconda installation. # ----------------------------------------------------------------------------- """Helper widgets.""" from __future__ import absolute_import, division, print_function, with_statement from qtpy.QtCore import QSize, Qt, Signal from qtpy.QtGui import QIcon from qtpy.QtWidgets import QHBoxLayout, QLineEdit, QPushButton, QSizePolicy, QToolButton from anaconda_navigator.utils.qthelpers import update_pointer class ButtonSearch(QPushButton): """Button used for CSS styling.""" sig_entered = Signal() sig_left = Signal() def mousePressEvent(self, event): """Override Qt method.""" super().mousePressEvent(event) update_pointer() self.setProperty('focused', False) def enterEvent(self, event): """Override Qt method.""" if self.isEnabled(): update_pointer(Qt.ArrowCursor) self.setProperty('focused', True) self.sig_entered.emit() else: self.setProperty('focused', False) super().enterEvent(event) def leaveEvent(self, event): """Override Qt method.""" if self.isEnabled(): update_pointer() self.setProperty('focused', False) self.sig_left.emit() else: self.setProperty('focused', False) super().leaveEvent(event) def setProperty(self, name, value): """Override Qt method.""" super().setProperty(name, value) self.style().unpolish(self) self.style().polish(self) self.update() class ButtonShow(ButtonSearch): # pylint: disable=missing-class-docstring def mousePressEvent(self, event): """Override Qt method.""" def mouseReleaseEvent(self, event): """Override Qt method.""" def mouseDoubleClickEvent(self, event): """Override Qt method.""" class PasswordEdit(QLineEdit): """Password edit with show password button.""" def __init__(self, *args, **kwargs): """Lineedit search widget with clear button.""" super().__init__(*args, **kwargs) self._empty = True self._show_icons = True self.button_icon = ButtonShow() # Setup self.button_icon.setDefault(False) self.button_icon.setFocusPolicy(Qt.NoFocus) self.button_icon.setCheckable(False) self.setAttribute(Qt.WA_MacShowFocusRect, False) self.setEchoMode(QLineEdit.Password) # Layouts layout = QHBoxLayout() layout.addWidget(self.button_icon, 0, Qt.AlignRight) layout.setSpacing(0) layout.addSpacing(2) layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) # Signals self.button_icon.sig_entered.connect(self._show_password) self.button_icon.sig_left.connect(self._hide_password) self.textEdited.connect(self.update_box) self.update_box(None) self.set_icon_size(16, 16) self.setTabOrder(self, self.button_icon) def _show_password(self): """""" self.setEchoMode(QLineEdit.Normal) def _hide_password(self): """""" self.setEchoMode(QLineEdit.Password) def set_icon_size(self, width, height): """Set clear button icon size.""" self.button_icon.setMaximumSize(QSize(width, height)) self.setStyleSheet(f'PasswordEdit {{padding-right: {int(width * 1.5)}px;}}') # The 1.5 is to avoid overlapping def set_icon_visibility(self, value): """Set clear button visibility.""" self._show_icons = value self.update_box() def update_box(self, text=None): """Update icon visibility and status.""" if text and self._show_icons: self.button_icon.setIcon(QIcon()) else: if self._show_icons: self.button_icon.setIcon(QIcon()) self._empty = not bool(text) self.button_icon.setDisabled(self._empty) def update_style_sheet(self): """Update custom CSS style sheet.""" class LineEditSearch(QLineEdit): """Lineedit search widget with clear button.""" def __init__(self, *args, **kwargs): """Lineedit search widget with clear button.""" super().__init__(*args, **kwargs) self._empty = True self._show_icons = False self.button_icon = ButtonSearch() # Setup self.button_icon.setDefault(True) self.button_icon.setFocusPolicy(Qt.NoFocus) self.setAttribute(Qt.WA_MacShowFocusRect, False) # Layouts layout = QHBoxLayout() layout.addWidget(self.button_icon, 0, Qt.AlignRight) layout.setSpacing(0) layout.addSpacing(2) layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) # Signals self.textEdited.connect(self.update_box) self.button_icon.clicked.connect(self.clear_text) self.update_box(None) self.set_icon_size(16, 16) self.setTabOrder(self, self.button_icon) def set_icon_size(self, width, height): """Set clear button icon size.""" self.button_icon.setMaximumSize(QSize(width, height)) self.setStyleSheet(f'LineEditSearch {{padding-right: {width}px;}}') def set_icon_visibility(self, value): """Set clear button visibility.""" self._show_icons = value self.update_box() def update_box(self, text=None): """Update icon visibility and status.""" if text and self._show_icons: self.button_icon.setIcon(QIcon()) else: if self._show_icons: self.button_icon.setIcon(QIcon()) self._empty = not bool(text) self.button_icon.setDisabled(self._empty) def clear_text(self): """Clear all text in the line edit.""" self.setText('') self.setFocus() self.update_box() def update_style_sheet(self): """Update custom CSS style sheet.""" def keyPressEvent(self, event): """Override Qt method.""" key = event.key() if key in [Qt.Key_Escape]: self.clear_text() else: super().keyPressEvent(event) class ButtonToggleCollapse(QToolButton): # pylint: disable=too-few-public-methods """Button to collapse the environment list.""" def __init__(self, *args, **kwargs): """Button to collapse the environment list.""" super().__init__(*args, **kwargs) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.setFocusPolicy(Qt.NoFocus) self.setCheckable(True) self.clicked.connect(self._update_icon) def setProperty(self, name, value): """Override Qt method.""" QToolButton.setProperty(self, name, value) self.style().unpolish(self) self.style().polish(self) self.update() def _update_icon(self): self.setProperty('checked', self.isChecked()) # --- Local testing # ----------------------------------------------------------------------------- def local_test(): # pragma: no cover """Run loca tests.""" from anaconda_navigator.utils.qthelpers import qapplication # pylint: disable=import-outside-toplevel app = qapplication() widget = PasswordEdit() widget.update_style_sheet() widget.show() app.exec_() if __name__ == '__main__': # pragma: no cover local_test()