Merge pull request #1385 from davvid/bindir
[git-cola.git] / qtpy / QtGui.py
blob8b3a0ba999e0903bfa36c2ebe8ded24103a10bf5
1 # -----------------------------------------------------------------------------
2 # Copyright © 2014-2015 Colin Duquesnoy
3 # Copyright © 2009- The Spyder Development Team
5 # Licensed under the terms of the MIT License
6 # (see LICENSE.txt for details)
7 # -----------------------------------------------------------------------------
9 """Provides QtGui classes and functions."""
11 from . import PYQT5, PYQT6, PYSIDE2, PYSIDE6, QtModuleNotInstalledError
12 from ._utils import getattr_missing_optional_dep, possibly_static_exec
14 _missing_optional_names = {}
16 _QTOPENGL_NAMES = {
17 "QOpenGLBuffer",
18 "QOpenGLContext",
19 "QOpenGLContextGroup",
20 "QOpenGLDebugLogger",
21 "QOpenGLDebugMessage",
22 "QOpenGLFramebufferObject",
23 "QOpenGLFramebufferObjectFormat",
24 "QOpenGLPixelTransferOptions",
25 "QOpenGLShader",
26 "QOpenGLShaderProgram",
27 "QOpenGLTexture",
28 "QOpenGLTextureBlitter",
29 "QOpenGLVersionProfile",
30 "QOpenGLVertexArrayObject",
31 "QOpenGLWindow",
35 def __getattr__(name):
36 """Custom getattr to chain and wrap errors due to missing optional deps."""
37 raise getattr_missing_optional_dep(
38 name,
39 module_name=__name__,
40 optional_names=_missing_optional_names,
44 if PYQT5:
45 from PyQt5.QtGui import *
47 # Backport items moved to QtGui in Qt6
48 from PyQt5.QtWidgets import (
49 QAction,
50 QActionGroup,
51 QFileSystemModel,
52 QShortcut,
53 QUndoCommand,
56 elif PYQT6:
57 from PyQt6 import QtGui
58 from PyQt6.QtGui import *
60 # Attempt to import QOpenGL* classes, but if that fails,
61 # don't raise an exception until the name is explicitly accessed.
62 # See https://github.com/spyder-ide/qtpy/pull/387/
63 try:
64 from PyQt6.QtOpenGL import *
65 except ImportError as error:
66 for name in _QTOPENGL_NAMES:
67 _missing_optional_names[name] = {
68 "name": "PyQt6.QtOpenGL",
69 "missing_package": "pyopengl",
70 "import_error": error,
73 QFontMetrics.width = lambda self, *args, **kwargs: self.horizontalAdvance(
74 *args,
75 **kwargs,
77 QFontMetricsF.width = lambda self, *args, **kwargs: self.horizontalAdvance(
78 *args,
79 **kwargs,
82 # Map missing/renamed methods
83 QDrag.exec_ = lambda self, *args, **kwargs: self.exec(*args, **kwargs)
84 QGuiApplication.exec_ = lambda *args, **kwargs: possibly_static_exec(
85 QGuiApplication,
86 *args,
87 **kwargs,
89 QTextDocument.print_ = lambda self, *args, **kwargs: self.print(
90 *args,
91 **kwargs,
94 # Allow unscoped access for enums inside the QtGui module
95 from .enums_compat import promote_enums
97 promote_enums(QtGui)
98 del QtGui
99 elif PYSIDE2:
100 from PySide2.QtGui import *
102 # Backport items moved to QtGui in Qt6
103 from PySide2.QtWidgets import (
104 QAction,
105 QActionGroup,
106 QFileSystemModel,
107 QShortcut,
108 QUndoCommand,
111 if hasattr(QFontMetrics, "horizontalAdvance"):
112 # Needed to prevent raising a DeprecationWarning when using QFontMetrics.width
113 QFontMetrics.width = (
114 lambda self, *args, **kwargs: self.horizontalAdvance(
115 *args,
116 **kwargs,
119 elif PYSIDE6:
120 from PySide6.QtGui import *
122 # Attempt to import QOpenGL* classes, but if that fails,
123 # don't raise an exception until the name is explicitly accessed.
124 # See https://github.com/spyder-ide/qtpy/pull/387/
125 try:
126 from PySide6.QtOpenGL import *
127 except ImportError as error:
128 for name in _QTOPENGL_NAMES:
129 _missing_optional_names[name] = {
130 "name": "PySide6.QtOpenGL",
131 "missing_package": "pyopengl",
132 "import_error": error,
135 # Backport `QFileSystemModel` moved to QtGui in Qt6
136 from PySide6.QtWidgets import QFileSystemModel
138 QFontMetrics.width = lambda self, *args, **kwargs: self.horizontalAdvance(
139 *args,
140 **kwargs,
142 QFontMetricsF.width = lambda self, *args, **kwargs: self.horizontalAdvance(
143 *args,
144 **kwargs,
147 # Map DeprecationWarning methods
148 QDrag.exec_ = lambda self, *args, **kwargs: self.exec(*args, **kwargs)
149 QGuiApplication.exec_ = lambda *args, **kwargs: possibly_static_exec(
150 QGuiApplication,
151 *args,
152 **kwargs,
155 if PYSIDE2 or PYSIDE6:
156 # PySide{2,6} do not accept the `mode` keyword argument in
157 # QTextCursor.movePosition() even though it is a valid optional argument
158 # as per C++ API. Fix this by monkeypatching.
160 # Notes:
162 # * The `mode` argument is called `arg__2` in PySide{2,6} as per
163 # QTextCursor.movePosition.__doc__ and __signature__. Using `arg__2` as
164 # keyword argument works as intended, so does using a positional
165 # argument. Tested with PySide2 5.15.0, 5.15.2.1 and 5.15.3 and PySide6
166 # 6.3.0; older version, down to PySide 1, are probably affected as well [1].
168 # * PySide2 5.15.0 and 5.15.2.1 silently ignore invalid keyword arguments,
169 # i.e. passing the `mode` keyword argument has no effect and doesn`t
170 # raise an exception. Older versions, down to PySide 1, are probably
171 # affected as well [1]. At least PySide2 5.15.3 and PySide6 6.3.0 raise an
172 # exception when `mode` or any other invalid keyword argument is passed.
174 # [1] https://bugreports.qt.io/browse/PYSIDE-185
175 movePosition = QTextCursor.movePosition
177 def movePositionPatched(
178 self,
179 operation: QTextCursor.MoveOperation,
180 mode: QTextCursor.MoveMode = QTextCursor.MoveAnchor,
181 n: int = 1,
182 ) -> bool:
183 return movePosition(self, operation, mode, n)
185 QTextCursor.movePosition = movePositionPatched
187 if PYQT5 or PYSIDE2:
188 # Part of the fix for https://github.com/spyder-ide/qtpy/issues/394
189 from qtpy.QtCore import QPointF as __QPointF
191 QNativeGestureEvent.x = lambda self: self.localPos().toPoint().x()
192 QNativeGestureEvent.y = lambda self: self.localPos().toPoint().y()
193 QNativeGestureEvent.position = lambda self: self.localPos()
194 QNativeGestureEvent.globalX = lambda self: self.globalPos().x()
195 QNativeGestureEvent.globalY = lambda self: self.globalPos().y()
196 QNativeGestureEvent.globalPosition = lambda self: __QPointF(
197 float(self.globalPos().x()),
198 float(self.globalPos().y()),
200 QEnterEvent.position = lambda self: self.localPos()
201 QEnterEvent.globalPosition = lambda self: __QPointF(
202 float(self.globalX()),
203 float(self.globalY()),
205 QTabletEvent.position = lambda self: self.posF()
206 QTabletEvent.globalPosition = lambda self: self.globalPosF()
207 QHoverEvent.x = lambda self: self.pos().x()
208 QHoverEvent.y = lambda self: self.pos().y()
209 QHoverEvent.position = lambda self: self.posF()
210 # No `QHoverEvent.globalPosition`, `QHoverEvent.globalX`,
211 # nor `QHoverEvent.globalY` in the Qt5 docs.
212 QMouseEvent.position = lambda self: self.localPos()
213 QMouseEvent.globalPosition = lambda self: __QPointF(
214 float(self.globalX()),
215 float(self.globalY()),
218 # Follow similar approach for `QDropEvent` and child classes
219 QDropEvent.position = lambda self: self.posF()
220 if PYQT6 or PYSIDE6:
221 # Part of the fix for https://github.com/spyder-ide/qtpy/issues/394
222 for _class in (
223 QNativeGestureEvent,
224 QEnterEvent,
225 QTabletEvent,
226 QHoverEvent,
227 QMouseEvent,
229 for _obsolete_function in (
230 "pos",
231 "x",
232 "y",
233 "globalPos",
234 "globalX",
235 "globalY",
237 if hasattr(_class, _obsolete_function):
238 delattr(_class, _obsolete_function)
239 QSinglePointEvent.pos = lambda self: self.position().toPoint()
240 QSinglePointEvent.posF = lambda self: self.position()
241 QSinglePointEvent.localPos = lambda self: self.position()
242 QSinglePointEvent.x = lambda self: self.position().toPoint().x()
243 QSinglePointEvent.y = lambda self: self.position().toPoint().y()
244 QSinglePointEvent.globalPos = lambda self: self.globalPosition().toPoint()
245 QSinglePointEvent.globalX = (
246 lambda self: self.globalPosition().toPoint().x()
248 QSinglePointEvent.globalY = (
249 lambda self: self.globalPosition().toPoint().y()
252 # Follow similar approach for `QDropEvent` and child classes
253 QDropEvent.pos = lambda self: self.position().toPoint()
254 QDropEvent.posF = lambda self: self.position()