source: orange/Orange/OrangeCanvas/gui/utils.py @ 11508:5f54d6c68d9e

Revision 11508:5f54d6c68d9e, 8.4 KB checked in by Ales Erjavec <ales.erjavec@…>, 11 months ago (diff)

Moved gradient functions into gui.utils.

Line 
1"""
2Helper utilities
3
4"""
5
6import sys
7import traceback
8
9from contextlib import contextmanager
10
11from PyQt4.QtGui import (
12    QWidget, QMessageBox, QGradient, QLinearGradient, QRadialGradient, QBrush,
13    QPainter, QStyleOption, QStyle
14)
15
16from PyQt4.QtCore import QPointF
17
18import sip
19
20QWIDGETSIZE_MAX = ((1 << 24) - 1)
21
22
23@contextmanager
24def updates_disabled(widget):
25    """Disable QWidget updates (using QWidget.setUpdatesEnabled)
26    """
27    old_state = widget.updatesEnabled()
28    widget.setUpdatesEnabled(False)
29    try:
30        yield
31    finally:
32        widget.setUpdatesEnabled(old_state)
33
34
35@contextmanager
36def signals_disabled(qobject):
37    """Disables signals on an instance of QObject.
38    """
39    old_state = qobject.signalsBlocked()
40    qobject.blockSignals(True)
41    try:
42        yield
43    finally:
44        qobject.blockSignals(old_state)
45
46
47@contextmanager
48def disabled(qobject):
49    """Disables a disablable QObject instance.
50    """
51    if not (hasattr(qobject, "setEnabled") and hasattr(qobject, "isEnabled")):
52        raise TypeError("%r does not have 'enabled' property" % qobject)
53
54    old_state = qobject.isEnabled()
55    qobject.setEnabled(False)
56    try:
57        yield
58    finally:
59        qobject.setEnabled(old_state)
60
61
62def StyledWidget_paintEvent(self, event):
63    """A default styled QWidget subclass  paintEvent function.
64    """
65    opt = QStyleOption()
66    opt.init(self)
67    painter = QPainter(self)
68    self.style().drawPrimitive(QStyle.PE_Widget, opt, painter, self)
69
70
71class StyledWidget(QWidget):
72    """
73    """
74    paintEvent = StyledWidget_paintEvent
75
76
77def is_transparency_supported():
78    """Is window transparency supported by the current windowing system.
79
80    """
81    if sys.platform == "win32":
82        return is_dwm_compositing_enabled()
83    elif sys.platform == "cygwin":
84        return False
85    elif sys.platform == "darwin":
86        if has_x11():
87            return is_x11_compositing_enabled()
88        else:
89            # Quartz compositor
90            return True
91    elif sys.platform.startswith("linux"):
92        # TODO: wayland??
93        return is_x11_compositing_enabled()
94    elif sys.platform.startswith("freebsd"):
95        return is_x11_compositing_enabled()
96    elif has_x11():
97        return is_x11_compositing_enabled()
98    else:
99        return False
100
101
102def has_x11():
103    """
104    Is Qt build against X11 server.
105    """
106    try:
107        from PyQt4.QtGui import QX11Info
108        return True
109    except ImportError:
110        return False
111
112
113def is_x11_compositing_enabled():
114    """Is X11 compositing manager running.
115    """
116    try:
117        from PyQt4.QtGui import QX11Info
118    except ImportError:
119        return False
120
121    return QX11Info.isCompositingManagerRunning()
122
123
124def is_dwm_compositing_enabled():
125    """Is Desktop Window Manager compositing (Aero) enabled.
126    """
127    import ctypes
128
129    enabled = ctypes.c_bool()
130    try:
131        DwmIsCompositionEnabled = ctypes.windll.dwmapi.DwmIsCompositionEnabled
132    except (AttributeError, WindowsError):
133        # dwmapi or DwmIsCompositionEnabled is not present
134        return False
135
136    rval = DwmIsCompositionEnabled(ctypes.byref(enabled))
137
138    return rval == 0 and enabled.value
139
140
141def gradient_darker(grad, factor):
142    """Return a copy of the QGradient darkened by factor.
143
144    .. note:: Only QLinearGradeint and QRadialGradient are supported.
145
146    """
147    if type(grad) is QGradient:
148        if grad.type() == QGradient.LinearGradient:
149            grad = sip.cast(grad, QLinearGradient)
150        elif grad.type() == QGradient.RadialGradient:
151            grad = sip.cast(grad, QRadialGradient)
152
153    if isinstance(grad, QLinearGradient):
154        new_grad = QLinearGradient(grad.start(), grad.finalStop())
155    elif isinstance(grad, QRadialGradient):
156        new_grad = QRadialGradient(grad.center(), grad.radius(),
157                                   grad.focalPoint())
158    else:
159        raise TypeError
160
161    new_grad.setCoordinateMode(grad.coordinateMode())
162
163    for pos, color in grad.stops():
164        new_grad.setColorAt(pos, color.darker(factor))
165
166    return new_grad
167
168
169def brush_darker(brush, factor):
170    """Return a copy of the brush darkened by factor.
171    """
172    grad = brush.gradient()
173    if grad:
174        return QBrush(gradient_darker(grad, factor))
175    else:
176        brush = QBrush(brush)
177        brush.setColor(brush.color().darker(factor))
178        return brush
179
180
181def create_gradient(base_color, stop=QPointF(0, 0),
182                    finalStop=QPointF(0, 1)):
183    """
184    Create a default linear gradient using `base_color` .
185
186    """
187    grad = QLinearGradient(stop, finalStop)
188    grad.setStops([(0.0, base_color),
189                   (0.5, base_color),
190                   (0.8, base_color.darker(105)),
191                   (1.0, base_color.darker(110)),
192                   ])
193    grad.setCoordinateMode(QLinearGradient.ObjectBoundingMode)
194    return grad
195
196
197def create_css_gradient(base_color, stop=QPointF(0, 0),
198                        finalStop=QPointF(0, 1)):
199    """
200    Create a Qt css linear gradient fragment based on the `base_color`.
201    """
202    gradient = create_gradient(base_color, stop, finalStop)
203    return css_gradient(gradient)
204
205
206def css_gradient(gradient):
207    """
208    Given an instance of a `QLinearGradient` return an equivalent qt css
209    gradient fragment.
210
211    """
212    stop, finalStop = gradient.start(), gradient.finalStop()
213    x1, y1, x2, y2 = stop.x(), stop.y(), finalStop.x(), finalStop.y()
214    stops = gradient.stops()
215    stops = "\n".join("    stop: {0:f} {1}".format(stop, color.name())
216                      for stop, color in stops)
217    return ("qlineargradient(\n"
218            "    x1: {x1}, y1: {y1}, x2: {x1}, y2: {y2},\n"
219            "{stops})").format(x1=x1, y1=y1, x2=x2, y2=y2, stops=stops)
220
221
222def message_critical(text, title=None, informative_text=None, details=None,
223                     buttons=None, default_button=None, exc_info=False,
224                     parent=None):
225    """Show a critical message.
226    """
227    if not text:
228        text = "An unexpected error occurred."
229
230    if title is None:
231        title = "Error"
232
233    return message(QMessageBox.Critical, text, title, informative_text,
234                   details, buttons, default_button, exc_info, parent)
235
236
237def message_warning(text, title=None, informative_text=None, details=None,
238                    buttons=None, default_button=None, exc_info=False,
239                    parent=None):
240    """Show a warning message.
241    """
242    if not text:
243        import random
244        text_candidates = ["Death could come at any moment.",
245                           "Murphy lurks about. Remember to save frequently."
246                           ]
247        text = random.choice(text_candidates)
248
249    if title is not None:
250        title = "Warning"
251
252    return message(QMessageBox.Warning, text, title, informative_text,
253                   details, buttons, default_button, exc_info, parent)
254
255
256def message_information(text, title=None, informative_text=None, details=None,
257                        buttons=None, default_button=None, exc_info=False,
258                        parent=None):
259    """Show an information message box.
260    """
261    if title is None:
262        title = "Information"
263    if not text:
264        text = "I am not a number."
265
266    return message(QMessageBox.Information, text, title, informative_text,
267                   details, buttons, default_button, exc_info, parent)
268
269
270def message_question(text, title, informative_text=None, details=None,
271                     buttons=None, default_button=None, exc_info=False,
272                     parent=None):
273    """Show an message box asking the user to select some
274    predefined course of action (set by buttons argument).
275
276    """
277    return message(QMessageBox.Question, text, title, informative_text,
278                   details, buttons, default_button, exc_info, parent)
279
280
281def message(icon, text, title=None, informative_text=None, details=None,
282            buttons=None, default_button=None, exc_info=False, parent=None):
283    """Show a message helper function.
284    """
285    if title is None:
286        title = "Message"
287    if not text:
288        text = "I am neither a postman nor a doctor."
289
290    if buttons is None:
291        buttons = QMessageBox.Ok
292
293    if details is None and exc_info:
294        details = traceback.format_exc(limit=20)
295
296    mbox = QMessageBox(icon, title, text, buttons, parent)
297
298    if informative_text:
299        mbox.setInformativeText(informative_text)
300
301    if details:
302        mbox.setDetailedText(details)
303
304    if default_button is not None:
305        mbox.setDefaultButton(default_button)
306
307    return mbox.exec_()
Note: See TracBrowser for help on using the repository browser.