aboutsummaryrefslogtreecommitdiff
path: root/src/avp/toolkit/common.py
blob: a6195ed120721a8627256a32ea966a7ae15ddcfb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
"""
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))