Last active
March 8, 2022 09:54
-
-
Save JustinPedersen/23aaf2d3b245444059ef4e382df69475 to your computer and use it in GitHub Desktop.
working implementation of gifs as tool tips for Maya
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Implementation of a gif as tool tip for Autodesk Maya. | |
Modified from: https://stackoverflow.com/questions/60521848/how-to-show-tooltip-image-when-hover-on-button-pyqt5 | |
""" | |
import sys | |
from PySide2 import QtCore | |
from PySide2 import QtGui | |
from PySide2 import QtWidgets | |
from shiboken2 import wrapInstance | |
import maya.OpenMayaUI as omui | |
def maya_main_window(): | |
""" | |
Return the Maya main window widget as a Python object | |
""" | |
main_window_ptr = omui.MQtUtil.mainWindow() | |
if sys.version_info.major >= 3: | |
return wrapInstance(int(main_window_ptr), QtWidgets.QWidget) | |
else: | |
return wrapInstance(long(main_window_ptr), QtWidgets.QWidget) | |
class ToolTipAnimation(QtWidgets.QLabel): | |
def __init__(self, file, width=None, height=None): | |
super(ToolTipAnimation, self).__init__(parent=maya_main_window()) | |
self.setMouseTracking(True) | |
# image loading doesn't happen immediately, as it could require some time; | |
# we store the information for later use | |
self._file = file | |
self._width = width | |
self._height = height | |
self._shown = False | |
# a timer that prevents the enterEvent to hide the tip immediately | |
self.showTimer = QtCore.QTimer(interval=100, singleShot=True) | |
# install an event filter for the application, so that we can be notified | |
# whenever the user performs any action | |
QtWidgets.QApplication.instance().installEventFilter(self) | |
def load(self): | |
movie = QtGui.QMovie(self._file) | |
if self._width and not self._height: | |
self._height = self._width | |
if self._width and self._height: | |
size = QtCore.QSize(self._width, self._height) | |
movie.setScaledSize(size) | |
else: | |
size = QtCore.QSize() | |
for f in range(movie.frameCount()): | |
movie.jumpToFrame(f) | |
size = size.expandedTo(movie.currentImage().size()) | |
self.setFixedSize(size) | |
self.setMovie(movie) | |
self._shown = True | |
def show(self, pos=None): | |
if not self._shown: | |
self.load() | |
if pos is None: | |
pos = QtGui.QCursor.pos() | |
# ensure that the tooltip is always shown within the screen geometry | |
for screen in QtWidgets.QApplication.screens(): | |
if screen.availableGeometry().contains(pos): | |
screen = screen.availableGeometry() | |
# add an offset so that the mouse cursor doesn't hide the tip | |
pos += QtCore.QPoint(2, 16) | |
if pos.x() < screen.x(): | |
pos.setX(screen.x()) | |
elif pos.x() + self.width() > screen.right(): | |
pos.setX(screen.right() - self.width()) | |
if pos.y() < screen.y(): | |
pos.setY(screen.y()) | |
elif pos.y() + self.height() > screen.bottom(): | |
pos.setY(screen.bottom() - self.height()) | |
break | |
self.move(pos) | |
super(ToolTipAnimation, self).show() | |
self.movie().start() | |
def maybeHide(self): | |
# if for some reason the tooltip is shown where the mouse is, we should | |
# not hide it if it's still within the parent's rectangle | |
if self.parent() is not None: | |
parent_pos = self.parent().mapToGlobal(QtCore.QPoint()) | |
rect = QtCore.QRect(parent_pos, self.parent().size()) | |
if rect.contains(QtGui.QCursor.pos()): | |
return | |
self.hide() | |
def eventFilter(self, source, event): | |
# hide the tip for any user interaction | |
if event.type() in (QtCore.QEvent.KeyPress, QtCore.QEvent.KeyRelease, | |
QtCore.QEvent.WindowActivate, QtCore.QEvent.WindowDeactivate, | |
QtCore.QEvent.FocusIn, QtCore.QEvent.FocusOut, | |
QtCore.QEvent.Leave, QtCore.QEvent.Close, | |
QtCore.QEvent.MouseButtonPress, QtCore.QEvent.MouseButtonRelease, | |
QtCore.QEvent.MouseButtonDblClick, QtCore.QEvent.Wheel): | |
self.hide() | |
return False | |
def mouseMoveEvent(self, event): | |
QtCore.QTimer.singleShot(100, self.hide) | |
def enterEvent(self, event): | |
# hide the tooltip when mouse enters, but not immediately, otherwise it | |
# will be shown right after from the parent widget | |
if not self.showTimer.isActive(): | |
QtCore.QTimer.singleShot(100, self.hide) | |
def showEvent(self, event): | |
self.showTimer.start() | |
def hideEvent(self, event): | |
if self.movie(): | |
self.movie().stop() | |
class ButtonIcon(QtWidgets.QPushButton): | |
toolTipAnimation = None | |
formats = tuple(str(fmt) for fmt in QtGui.QMovie.supportedFormats()) | |
def setToolTipImage(self, image, width=None, height=None): | |
if not image or self.toolTipAnimation: | |
self.toolTipAnimation.hide() | |
self.toolTipAnimation.deleteLater() | |
self.toolTipAnimation = None | |
self.setToolTip('') | |
if not image: | |
return | |
if image.endswith(self.formats): | |
self.toolTipAnimation = ToolTipAnimation(image, width, height) | |
else: | |
if width and not height: | |
height = width | |
if width and height: | |
self.setToolTip( | |
'<img src="{}" width="{}" height="{}">'.format( | |
image, width, height)) | |
else: | |
self.setToolTip('<img src="{}">'.format(image)) | |
def event(self, event): | |
if (event.type() == QtCore.QEvent.ToolTip and self.toolTipAnimation and | |
not self.toolTipAnimation.isVisible()): | |
self.toolTipAnimation.show(event.globalPos()) | |
return True | |
elif event.type() == QtCore.QEvent.Leave and self.toolTipAnimation: | |
self.toolTipAnimation.maybeHide() | |
return super(ButtonIcon, self).event(event) | |
class TestDialog(QtWidgets.QDialog): | |
def __init__(self, parent=maya_main_window()): | |
super(TestDialog, self).__init__(parent) | |
# ADD YOUR PATHS HERE | |
image_path = r'\clipart.png' | |
gif_path = r'\giphy.gif' | |
self.setWindowTitle("Test Dialog") | |
self.setMinimumWidth(200) | |
# Remove the ? from the dialog on Windows | |
self.setWindowFlags(self.windowFlags() ^ QtCore.Qt.WindowContextHelpButtonHint) | |
# Widgets | |
button_fixed = ButtonIcon('fixed image') | |
button_fixed.setToolTipImage(image_path) | |
button_animated = ButtonIcon('animated gif') | |
button_animated.setToolTipImage(gif_path, 200) | |
# Layouts | |
main_layout = QtWidgets.QVBoxLayout() | |
main_layout.addWidget(button_fixed) | |
main_layout.addWidget(button_animated) | |
self.setLayout(main_layout) | |
if __name__ == "__main__": | |
d = TestDialog() | |
d.show() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment