109 lines
3.9 KiB
Python
109 lines
3.9 KiB
Python
""" Defines miscellaneous Qt-related helper classes and functions.
|
|
"""
|
|
|
|
import inspect
|
|
|
|
from qtpy import QtCore, QtGui
|
|
|
|
from ipython_genutils.py3compat import iteritems
|
|
from traitlets import HasTraits, TraitType
|
|
|
|
#-----------------------------------------------------------------------------
|
|
# Metaclasses
|
|
#-----------------------------------------------------------------------------
|
|
|
|
MetaHasTraits = type(HasTraits)
|
|
MetaQObject = type(QtCore.QObject)
|
|
|
|
class MetaQObjectHasTraits(MetaQObject, MetaHasTraits):
|
|
""" A metaclass that inherits from the metaclasses of HasTraits and QObject.
|
|
|
|
Using this metaclass allows a class to inherit from both HasTraits and
|
|
QObject. Using SuperQObject instead of QObject is highly recommended. See
|
|
QtKernelManager for an example.
|
|
"""
|
|
def __new__(mcls, name, bases, classdict):
|
|
# FIXME: this duplicates the code from MetaHasTraits.
|
|
# I don't think a super() call will help me here.
|
|
for k,v in iteritems(classdict):
|
|
if isinstance(v, TraitType):
|
|
v.name = k
|
|
elif inspect.isclass(v):
|
|
if issubclass(v, TraitType):
|
|
vinst = v()
|
|
vinst.name = k
|
|
classdict[k] = vinst
|
|
cls = MetaQObject.__new__(mcls, name, bases, classdict)
|
|
return cls
|
|
|
|
def __init__(mcls, name, bases, classdict):
|
|
# Note: super() did not work, so we explicitly call these.
|
|
MetaQObject.__init__(mcls, name, bases, classdict)
|
|
MetaHasTraits.__init__(mcls, name, bases, classdict)
|
|
|
|
#-----------------------------------------------------------------------------
|
|
# Classes
|
|
#-----------------------------------------------------------------------------
|
|
|
|
def superQ(QClass):
|
|
""" Permits the use of super() in class hierarchies that contain Qt classes.
|
|
|
|
Unlike QObject, SuperQObject does not accept a QObject parent. If it did,
|
|
super could not be emulated properly (all other classes in the heierarchy
|
|
would have to accept the parent argument--they don't, of course, because
|
|
they don't inherit QObject.)
|
|
|
|
This class is primarily useful for attaching signals to existing non-Qt
|
|
classes. See QtKernelManagerMixin for an example.
|
|
"""
|
|
class SuperQClass(QClass):
|
|
|
|
def __new__(cls, *args, **kw):
|
|
# We initialize QClass as early as possible. Without this, Qt complains
|
|
# if SuperQClass is not the first class in the super class list.
|
|
inst = QClass.__new__(cls)
|
|
QClass.__init__(inst)
|
|
return inst
|
|
|
|
def __init__(self, *args, **kw):
|
|
# Emulate super by calling the next method in the MRO, if there is one.
|
|
mro = self.__class__.mro()
|
|
for qt_class in QClass.mro():
|
|
mro.remove(qt_class)
|
|
next_index = mro.index(SuperQClass) + 1
|
|
if next_index < len(mro):
|
|
mro[next_index].__init__(self, *args, **kw)
|
|
|
|
return SuperQClass
|
|
|
|
SuperQObject = superQ(QtCore.QObject)
|
|
|
|
#-----------------------------------------------------------------------------
|
|
# Functions
|
|
#-----------------------------------------------------------------------------
|
|
|
|
def get_font(family, fallback=None):
|
|
"""Return a font of the requested family, using fallback as alternative.
|
|
|
|
If a fallback is provided, it is used in case the requested family isn't
|
|
found. If no fallback is given, no alternative is chosen and Qt's internal
|
|
algorithms may automatically choose a fallback font.
|
|
|
|
Parameters
|
|
----------
|
|
family : str
|
|
A font name.
|
|
fallback : str
|
|
A font name.
|
|
|
|
Returns
|
|
-------
|
|
font : QFont object
|
|
"""
|
|
font = QtGui.QFont(family)
|
|
# Check whether we got what we wanted using QFontInfo, since exactMatch()
|
|
# is overly strict and returns false in too many cases.
|
|
font_info = QtGui.QFontInfo(font)
|
|
if fallback is not None and font_info.family() != family:
|
|
font = QtGui.QFont(fallback)
|
|
return font
|