""" Common functions """ from PyQt6 import QtWidgets import string import random import sys import subprocess import logging from copy import copy from collections import OrderedDict log = logging.getLogger("AVP.Toolkit.Common") class blockSignals: """ Context manager to temporarily block list of QtWidgets from updating, and guarantee restoring the previous state afterwards. """ def __init__(self, widgets): if type(widgets) is dict: self.widgets = concatDictVals(widgets) else: self.widgets = widgets if hasattr(widgets, "__iter__") else [widgets] def __enter__(self): log.verbose( "Blocking signals for %s", ", ".join([str(w.__class__.__name__) for w in self.widgets]), ) self.oldStates = [w.signalsBlocked() for w in self.widgets] for w in self.widgets: w.blockSignals(True) def __exit__(self, *args): log.verbose("Resetting blockSignals to %s", str(bool(sum(self.oldStates)))) for w, state in zip(self.widgets, self.oldStates): w.blockSignals(state) def concatDictVals(d): """Concatenates all values in given dict into one list.""" key, value = d.popitem() d[key] = value final = copy(value) if type(final) is not list: final = [final] final.extend([val for val in d.values()]) else: value.extend([item for val in d.values() for item in val]) return final def badName(name): """Returns whether a name contains non-alphanumeric chars""" return any([letter in string.punctuation for letter in name]) def alphabetizeDict(dictionary): """Alphabetizes a dict into OrderedDict""" return OrderedDict(sorted(dictionary.items(), key=lambda t: t[0])) def presetToString(dictionary): """Returns string repr of a preset""" return repr(alphabetizeDict(dictionary)) def presetFromString(string): """Turns a string repr of OrderedDict into a regular dict""" return dict(eval(string)) def appendUppercase(lst): for form, i in zip(lst, range(len(lst))): lst.append(form.upper()) return lst def pipeWrapper(func): """A decorator to insert proper kwargs into Popen objects.""" def pipeWrapper(commandList, **kwargs): if sys.platform == "win32": # Stop CMD window from appearing on Windows startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW kwargs["startupinfo"] = startupinfo if "bufsize" not in kwargs: kwargs["bufsize"] = 10**8 if "stdin" not in kwargs: kwargs["stdin"] = subprocess.DEVNULL return func(commandList, **kwargs) return pipeWrapper @pipeWrapper def checkOutput(commandList, **kwargs): return subprocess.check_output(commandList, **kwargs) def disableWhenEncoding(func): def decorator(self, *args, **kwargs): if self.encoding: return else: return func(self, *args, **kwargs) return decorator def disableWhenOpeningProject(func): def decorator(self, *args, **kwargs): if self.core.openingProject: return else: return func(self, *args, **kwargs) return decorator def rgbFromString(string): """Turns an RGB string like "255, 255, 255" into a tuple""" try: tup = tuple([int(i) for i in string.split(",")]) if len(tup) != 3: raise ValueError for i in tup: if i > 255 or i < 0: raise ValueError return tup except Exception as e: log.warning( "Could not parse '%s' as a color (encountered %s).", string, type(e).__name__, ) return (255, 255, 255) def formatTraceback(tb=None): import traceback if tb is None: import sys tb = sys.exc_info()[2] return "Traceback:\n%s" % "\n".join(traceback.format_tb(tb)) def connectWidget(widget, func): unsupportedWidgets = ["QtWidgets.QFontComboBox"] if type(widget) == QtWidgets.QLineEdit: widget.textChanged.connect(func) elif type(widget) == QtWidgets.QSpinBox or type(widget) == QtWidgets.QDoubleSpinBox: widget.valueChanged.connect(func) elif type(widget) == QtWidgets.QCheckBox: widget.stateChanged.connect(func) elif type(widget) == QtWidgets.QComboBox: widget.currentIndexChanged.connect(func) elif type(widget) in unsupportedWidgets: log.info( "Could not connect %s using connectWidget()", str(widget.__class__.__name__) ) else: log.warning("Failed to connect %s ", str(widget.__class__.__name__)) return False return True def setWidgetValue(widget, val): """Generic setValue method for use with any typical QtWidget""" log.verbose("Setting %s to %s" % (str(widget.__class__.__name__), val)) if type(widget) == QtWidgets.QLineEdit: widget.setText(val) elif type(widget) == QtWidgets.QSpinBox or type(widget) == QtWidgets.QDoubleSpinBox: widget.setValue(val) elif type(widget) == QtWidgets.QCheckBox: widget.setChecked(val) elif type(widget) == QtWidgets.QComboBox: widget.setCurrentIndex(val) else: log.warning("Failed to set %s ", str(widget.__class__.__name__)) return False return True def getWidgetValue(widget): if type(widget) == QtWidgets.QLineEdit: return widget.text() elif type(widget) == QtWidgets.QSpinBox or type(widget) == QtWidgets.QDoubleSpinBox: return widget.value() elif type(widget) == QtWidgets.QCheckBox: return widget.isChecked() elif type(widget) == QtWidgets.QComboBox: return widget.currentIndex() def randomColor(): return (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))