import os
import sys
from qtpy.QtCore import QObject, Signal, QEvent, QBuffer, QIODevice, Qt
from qtpy import QtWidgets, QtCore, QtGui
from pathlib import Path
from pymodaq_utils.config import Config
from pymodaq_utils.logger import set_logger, get_module_name
from pyqtgraph import mkQApp as mkQApppg
config = Config()
logger = set_logger(get_module_name(__file__))
[docs]
def first_available_integer(liste):
i = 0
while i in liste:
i += 1
return i
here = Path(__file__).parent
custom_folder = here.parent.joinpath('QtDesigner_Ressources/custom/')
QtCore.QDir.addSearchPath('custom', str(custom_folder))
[docs]
def set_dark_palette(app):
from qtpy.QtGui import QPalette, QColor
app.setStyle("Fusion")
palette = QPalette()
palette.setColor(QPalette.ColorRole.Window, QColor(53,53,53))
palette.setColor(QPalette.ColorRole.WindowText, Qt.GlobalColor.white)
palette.setColor(QPalette.ColorRole.Base, QColor(42,42,42))
palette.setColor(QPalette.ColorRole.ToolTipBase, Qt.GlobalColor.white)
palette.setColor(QPalette.ColorRole.ToolTipText, Qt.GlobalColor.white)
palette.setColor(QPalette.ColorRole.Dark, QColor(35,35,35))
palette.setColor(QPalette.ColorRole.Shadow, QColor(20,20,20))
palette.setColor(QPalette.ColorRole.AlternateBase, QColor(53, 53, 53))
palette.setColor(QPalette.ColorRole.ToolTipBase, Qt.GlobalColor.black)
palette.setColor(QPalette.ColorRole.ToolTipText, Qt.GlobalColor.white)
palette.setColor(QPalette.ColorRole.Text, Qt.GlobalColor.white)
palette.setColor(QPalette.ColorRole.Button, QColor(53, 53, 53))
palette.setColor(QPalette.ColorRole.ButtonText, Qt.GlobalColor.white)
palette.setColor(QPalette.ColorRole.BrightText, Qt.GlobalColor.red)
palette.setColor(QPalette.ColorRole.Link, QColor(42, 130, 218))
palette.setColor(QPalette.ColorRole.Highlight, QColor(42, 130, 218))
palette.setColor(QPalette.ColorRole.HighlightedText, QColor(250,250,250))
palette.setColor(QPalette.Disabled, QPalette.ColorRole.ButtonText, Qt.GlobalColor.darkGray)
palette.setColor(QPalette.Disabled, QPalette.ColorRole.WindowText, Qt.GlobalColor.darkGray)
palette.setColor(QPalette.Disabled, QPalette.ColorRole.Text, Qt.GlobalColor.darkGray)
palette.setColor(QPalette.Disabled, QPalette.ColorRole.Light, QColor(53, 53, 53))
app.setPalette(palette)
# Checkbox are not visible in dark style but it is not possible to
# modify QCheckBox style without messing up the check mark (it disappears)
# so images are needed to avoid the problem.
app.setStyleSheet("""
QCheckBox::indicator {
width: 1em;
height: 1em;
}
QCheckBox::indicator:unchecked {
image: url('custom:checkbox/unchecked.png');
}
QCheckBox::indicator:unchecked:disabled {
image: url('custom:checkbox/unchecked_disabled.png');
}
QCheckBox::indicator:unchecked:focus {
image: url('custom:checkbox/unchecked_focus.png');
}
QCheckBox::indicator:unchecked:pressed {
image: url('custom:checkbox/unchecked_pressed.png');
}
QCheckBox::indicator:checked {
image: url('custom:checkbox/checked.png');
}
QCheckBox::indicator:checked:disabled {
image: url('custom:checkbox/checked_disabled.png');
}
QCheckBox::indicator:checked:focus {
image: url('custom:checkbox/checked_focus.png');
}
QCheckBox::indicator:checked:pressed {
image: url('custom:checkbox/checked_pressed.png');
}
QCheckBox::indicator:indeterminate {
image: url('custom:checkbox/indeterminate.png');
}
QCheckBox::indicator:indeterminate:disabled {
image: url('custom:checkbox/indeterminate_disabled.png');
}
QCheckBox::indicator:indeterminate:focus {
image: url('custom:checkbox/indeterminate_focus.png');
}
QCheckBox::indicator:indeterminate:pressed {
image: url('custom:checkbox/indeterminate_pressed.png');
}
QToolBarExtension {
background: #555555;
qproperty-icon: url('custom:arrow/right.png');
}
QToolTip {
color: white;
background-color: #555555;
border: 1px solid white;
}
""")
[docs]
def clickable(widget):
class Filter(QObject):
clicked = Signal()
def eventFilter(self, obj, event):
if obj == widget:
if event.type() == QEvent.MouseButtonRelease:
if obj.rect().contains(event.pos()):
self.clicked.emit()
# The developer can opt for .emit(obj) to get the object within the slot.
return True
return False
filter = Filter(widget)
widget.installEventFilter(filter)
return filter.clicked
[docs]
def h5tree_to_QTree(base_node, base_tree_elt=None, pixmap_items=[]):
"""
| Convert a loaded h5 file to a QTreeWidgetItem element structure containing two columns.
| The first is the name of the h5 current node, the second is the path of the node in the h5 structure.
|
| Recursive function discreasing on base_node.
================== ======================================== ===============================
**Parameters** **Type** **Description**
*h5file* instance class File from tables module loaded h5 file
*base_node* pytables h5 node parent node
*base_tree_elt* QTreeWidgetItem parent QTreeWidgetItem element
================== ======================================== ===============================
Returns
-------
QTreeWidgetItem
h5 structure copy converted into QtreeWidgetItem structure.
See Also
--------
h5tree_to_QTree
"""
if base_tree_elt is None:
base_tree_elt = QtWidgets.QTreeWidgetItem([base_node.name, "", base_node.path])
for node_name, node in base_node.children().items():
child = QtWidgets.QTreeWidgetItem([node_name, "", node.path])
klass = node.attrs['CLASS']
tooltip = []
if 'origin' in node.attrs.attrs_name:
tooltip.append(node.attrs['origin'])
elif klass == 'GROUP':
for c in node.children().values():
if 'origin' in c.attrs.attrs_name:
tooltip.append(c.attrs['origin'])
break
if hasattr(node, 'title') and node.title:
tooltip.append(node.title)
child.setToolTip(0, '/'.join(tooltip))
if 'pixmap' in node.attrs.attrs_name:
pixmap_items.append(dict(node=node, item=child))
if klass == 'GROUP':
h5tree_to_QTree(node, child, pixmap_items)
base_tree_elt.addChild(child)
return base_tree_elt, pixmap_items
[docs]
def set_enable_recursive(children, enable=False):
"""Apply the enable state on all children widgets, do it recursively
Parameters
----------
children: (list) elements children ofa pyqt5 element
enable: (bool) set enabled state (True) of all children widgets
"""
for child in children:
if not children:
return
elif isinstance(child, QtWidgets.QSpinBox) or isinstance(child, QtWidgets.QComboBox) or \
isinstance(child, QtWidgets.QPushButton) or isinstance(child, QtWidgets.QListWidget):
child.setEnabled(enable)
else:
set_enable_recursive(child.children(), enable)
[docs]
def pngbinary2Qlabel(databinary, scale_height: int = None):
buff = QBuffer()
buff.open(QIODevice.WriteOnly)
buff.write(databinary)
dat = buff.data()
pixmap = QtGui.QPixmap()
pixmap.loadFromData(dat, 'PNG')
if scale_height is not None and isinstance(scale_height, int):
pixmap = pixmap.scaledToHeight(scale_height)
label = QtWidgets.QLabel()
label.setPixmap(pixmap)
return label
[docs]
def start_qapplication() -> QtWidgets.QApplication:
app = QtWidgets.QApplication(sys.argv)
if config('style', 'darkstyle'):
set_dark_palette(app)
return app
[docs]
def mkQApp(name: str):
app = mkQApppg(name)
if config('style', 'darkstyle'):
set_dark_palette(app)
return app
[docs]
def exec():
app = mkQApp('a name')
return app.exec() if hasattr(app, 'exec') else app.exec_()