# -*- coding: utf-8 -*-
## Copyright 2019 Trevor van Hoof and Jan Pijpers.
## Licensed under the Apache License, Version 2.0
## Downloaded from https://janpijpers.com or https://gumroad.com/janpijpers
## See the license file attached or on https://www.janpijpers.com/script-licenses/
'''
Name: widgetUnderMouse
Description:
prints and highlights the widget under your mouse.
note that this is supppaaaaaaa hacky! And it will make any qt ui flash and slow down a lot!
But its helpfull when you want to find out what an object is called. I used this a lot in Maya to hack into the UI and add custom widgets.
If you click with the mouse buttons the overlay will stop.
'''
import sys
## Simple pyside 2 or 1 import check.
try:
PYSIDE_VERSION = 2
from PySide2.QtWidgets import *
from PySide2.QtGui import *#QFont, QIcon, QPixmap, QColor
from PySide2.QtCore import *
from PySide2.QtUiTools import *
from pyside2uic import compileUi
except:
from PySide.QtCore import *
from PySide.QtGui import *
def widgets_at(pos, topOnly = False ):
"""Return ALL widgets at `pos`
It uses the WA_TransparentForMouseEvents trick to find the underlying widgets.
Arguments:
pos (QPoint): Position at which to get widgets
"""
widgets = []
## Ask QT what widget is at this position
widget_at = QApplication.widgetAt(pos)
if topOnly:
return [widget_at]
while widget_at:
widgets.append(widget_at)
## Make widget invisible, so the next time we call the widgetAt function
## QT will return the underlying widget.
widget_at.setAttribute(Qt.WA_TransparentForMouseEvents)
widget_at = QApplication.widgetAt(pos)
# Restore attributes else nothing will respond to mouse clicks anymore.
for widget in widgets:
widget.setAttribute(Qt.WA_TransparentForMouseEvents, False)
return widgets
class Overlay(QWidget):
def __init__(self, parent=None):
'''
This is an overlay that sits across the entire UI.
This way its easier to track the mouse position and interact with the widgets below it.
:param parent:
'''
super(Overlay, self).__init__(parent)
self.setAttribute(Qt.WA_StyledBackground)
self.setStyleSheet("QWidget { background-color: rgba(0, 255, 0, 0) }")
self.setMouseTracking(True)
self._widgetsUnderMouse = set()
def mouseMoveEvent(self, event):
'''
For every 'pixel' we move our mouse this function is called.
:param event:
:return:
'''
## query the current position
pos = QCursor.pos()
## Find the widgets below the cursor.
currentWidgets = set( [ widgets_at(pos)[1] ] )
## If we have found new widgets.
if currentWidgets != self._widgetsUnderMouse:
## Remove the old outline of the widgets we had before
self._removeOutline(self._widgetsUnderMouse)
## Add a new outline to our new widgets
self._addOutline(currentWidgets)
## Print all widgets we have under our mouse now.
for w in currentWidgets:
n = w.objectName()
print "Name: ",n, "Widget: ", w
self._widgetsUnderMouse = currentWidgets
## Let qt do the rest of its magic.
return super(Overlay, self).mouseMoveEvent(event)
def mousePressEvent( self, event ):
'''
If we click with the left mouse button the overlay stops.
:param event:
:return:
'''
self.deleteLater()
return super(Overlay, self).mousePressEvent(event)
def _addOutline( self, wList ):
for w in wList:
n = w.objectName()
## SUUUPER HACK TRICK
## We force an object name on the object
w.setObjectName("AAAAAAA")
## Make the object have a red outline with a stylesheet
w.setStyleSheet('QWidget#AAAAAAA {border: 4px solid red;outline-offset: -2px;}')
## Restore the object name
w.setObjectName(n)
def _removeOutline( self, wList):
'''
Not the best idea because we remove all style info,
actually we should store the style sheet info before setting the outline buuuuuttt you get the idea :D
:param wList:
:return:
'''
for w in wList:
w.setStyleSheet("")
def _clearAll(self):
self._removeOutline(self._widgetsUnderMouse)
def __del__(self):
self._clearAll()
self._widgetsUnderMouse = set()
def get_maya_window():
for widget in QApplication.allWidgets():
try:
if widget.objectName() == "MayaWindow":
return widget
except:
pass
return None
window = get_maya_window()
app = None
if not window:
'''
If we are not in Maya, we just make an example window
'''
app = QApplication(sys.argv)
window = QWidget()
window.setObjectName("Window")
window.setFixedSize(200, 100)
button = QPushButton("Button 1", window)
button.setObjectName("Button 1")
button.move(10, 10)
button = QPushButton("Button 2", window)
button.setObjectName("Button 2")
button.move(50, 15)
overlay = Overlay(window)
overlay.setObjectName("Overlay")
overlay.setFixedSize(window.size())
overlay._clearAll()
overlay.show()
if app:
window.show()
app.exec_()