# -*- coding: utf-8 -*-
"""
GUI Base Widget Classes
=======================
Provides a collection of custom :class:`~PyQt5.QtWidgets.QWidget` base classes
that allow for certain widgets to be standardized.
"""
# %% IMPORTS
# Built-in imports
from sys import platform
# Package imports
from qtpy import QtCore as QC, QtWidgets as QW
# All declaration
__all__ = ['QW_QAction', 'QW_QComboBox', 'QW_QDoubleSpinBox',
'QW_QEditableComboBox', 'QW_QLabel', 'QW_QMenu', 'QW_QSpinBox',
'QW_QToolBar']
# %% CLASS DEFINITIONS
# Make subclass of QW.QAction that automatically sets details based on status
[docs]class QW_QAction(QW.QAction):
"""
Defines the :class:`~QW_QAction` class.
This class provides default settings and extra options for the
:class:`~PyQt5.QtWidgets.QAction` class.
"""
# Override constructor
[docs] def __init__(self, parent, text, *, shortcut=None, tooltip=None,
statustip=None, icon=None, triggered=None, role=None):
"""
Initializes the :class:`~QW_QAction` class.
Parameters
----------
parent : :obj:`~PyQt5.QtWidgets.QWidget` object or None
The parent widget for this dialog or *None* for no parent.
text : str
The label that this action must have.
Optional
--------
shortcut : :obj:`~PyQt5.QtGui.QKeySequence` or None. Default: None
The key sequence that must be set as the shortcut for this action.
If *None*, no shortcut will be set.
tooltip : str or None. Default: None
The text that must be set as the tooltip for this action.
If *None*, the tooltip is set to `text`.
If `shortcut` is not *None*, the tooltip will also include the
shortcut.
statustip : str or None. Default: None
The text that must be set as the statustip for this action.
If *None*, the statustip is set to `tooltip`.
icon : :obj:`~PyQt5.QtGui.QIcon` object or None. Default: None
The icon that must be set as the icon for this action.
If *None*, no icon will be set.
triggered : function or None. Default: None
The Qt slot function that must be called whenever this action is
triggered.
If *None*, no slot will connected to this action's signal.
role : :obj:`~PyQt5.QtWidgets.QAction.MenuRole` object or None. \
Default: None
The menu role that must be set as the role of this action.
If *None*, it is set to :obj:`~PyQt5.QtWidgets.NoRole`.
"""
# Call super constructor
if icon is None:
super().__init__(text, parent)
else:
super().__init__(icon, text, parent)
# Set all the details
self.setDetails(shortcut=shortcut,
tooltip=tooltip,
statustip=statustip)
# Set the signal trigger
if triggered is not None:
self.triggered.connect(triggered)
# Set the action menu role
self.setMenuRole(self.NoRole if role is None else role)
# Make new method that automatically sets Shortcut, ToolTip and StatusTip
[docs] def setDetails(self, *, shortcut=None, tooltip=None, statustip=None):
"""
Uses the provided `shortcut`; `tooltip`; and `statustip` to set the
details of this action.
Parameters
----------
shortcut : :obj:`~PyQt5.QtGui.QKeySequence` or None. Default: None
The key sequence that must be set as the shortcut for this action.
If *None*, no shortcut will be set.
tooltip : str or None. Default: None
The text that must be set as the tooltip for this action.
If *None*, the tooltip is set to `text`.
If `shortcut` is not *None*, the tooltip will also include the
shortcut.
statustip : str or None. Default: None
The text that must be set as the statustip for this action.
If *None*, the statustip is set to `tooltip`.
"""
# If shortcut is not None, set it
if shortcut is not None:
super().setShortcut(shortcut)
shortcut = self.shortcut().toString()
# If tooltip is None, its base is set to the action's name
if tooltip is None:
base_tooltip = self.text().replace('&', '')
tooltip = base_tooltip
# Else, provided tooltip is used as the base
else:
base_tooltip = tooltip
# If shortcut is not None, add it to the tooltip
if shortcut is not None:
tooltip = "%s (%s)" % (base_tooltip, shortcut)
# Set tooltip
super().setToolTip(tooltip)
# If statustip is None, it is set to base_tooltip
if statustip is None:
statustip = base_tooltip
# Set statustip
super().setStatusTip(statustip)
# Override setShortcut to raise an error when used
def setShortcut(self, *args, **kwargs):
raise AttributeError("Using this method is not allowed! Use "
"'setDetails()' instead!")
# Override setToolTip to raise an error when used
def setToolTip(self, *args, **kwargs):
raise AttributeError("Using this method is not allowed! Use "
"'setDetails()' instead!")
# Override setStatusTip to raise an error when used
def setStatusTip(self, *args, **kwargs):
raise AttributeError("Using this method is not allowed! Use "
"'setDetails()' instead!")
# Create custom combobox class with more signals
[docs]class QW_QComboBox(QW.QComboBox):
"""
Defines the :class:`~QW_QComboBox` class.
This class provides default settings and extra options for the
:class:`~PyQt5.QtWidgets.QComboBox` class.
"""
popup_shown = QC.Signal([int], [str])
popup_hidden = QC.Signal([int], [str])
# Override the showPopup to emit a signal whenever it is triggered
def showPopup(self, *args, **kwargs):
self.popup_shown[int].emit(self.currentIndex())
self.popup_shown[str].emit(self.currentText())
return(super().showPopup(*args, **kwargs))
# Override the hidePopup to emit a signal whenever it is triggered.
def hidePopup(self, *args, **kwargs):
self.popup_hidden[int].emit(self.currentIndex())
self.popup_hidden[str].emit(self.currentText())
return(super().hidePopup(*args, **kwargs))
# Create custom QComboBox class that is editable
[docs]class QW_QEditableComboBox(QW_QComboBox):
"""
Defines the :class:`~QW_QEditableComboBox` class.
This class makes the :class:`~QW_QComboBox` class editable.
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setEditable(True)
self.setInsertPolicy(self.NoInsert)
self.completer().setCompletionMode(QW.QCompleter.PopupCompletion)
self.completer().setFilterMode(QC.Qt.MatchContains)
# Create custom QAbstractSpinBox that automatically sets some properties
class QW_QAbstractSpinBox(QW.QAbstractSpinBox):
"""
Defines the :class:`~QW_QAbstractSpinBox` class.
This class provides default settings and extra options for the
:class:`~PyQt5.QtWidgets.QAbstractSpinBox` class.
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setStepType(self.AdaptiveDecimalStepType)
self.setAccelerated(True)
self.setGroupSeparatorShown(True)
self.setStyleSheet(
"""
QAbstractSpinBox {{
margin: {0}px 0px {0}px 0px;
max-height: 24px;}}
""".format("-1" if platform.startswith('linux') else '0'))
# Create custom QDoubleSpinBox
class QW_QDoubleSpinBox(QW.QDoubleSpinBox, QW_QAbstractSpinBox):
pass
# Create custom QSpinBox
class QW_QSpinBox(QW.QSpinBox, QW_QAbstractSpinBox):
pass
# Create custom label class with more signals
[docs]class QW_QLabel(QW.QLabel):
"""
Defines the :class:`~QW_QLabel` class.
This class provides default settings and extra options for the
:class:`~PyQt5.QtWidgets.QLabel` class.
"""
mousePressed = QC.Signal()
# Override the mousePressEvent to emit a signal whenever it is triggered
def mousePressEvent(self, event):
self.mousePressed.emit()
event.accept()
# Create custom QMenu class that swaps the order of inputs
# Create custom QToolbar class that swaps the order of inputs