restructured to reduce circular dependencies

This commit is contained in:
Nils Nemitz 2021-03-11 02:45:02 +09:00
parent abda01c51d
commit 291c7c304c
10 changed files with 79 additions and 58 deletions

View File

@ -317,7 +317,7 @@ if QT_LIB in [PYQT5, PYQT6]:
loadUiType = uic.loadUiType
QtCore.Signal = QtCore.pyqtSignal
QtCore.Slot = QtCore.pyqtSlot
if QT_LIB == PYSIDE6:
# PySide6 6.0 has a missing binding

View File

@ -287,6 +287,7 @@ from .ThreadsafeTimer import *
from .namedPen import *
from .namedBrush import *
from .palette import *
from . import namedColorManager
##############################################################

View File

@ -28,6 +28,12 @@ from .metaarray import MetaArray
from collections import OrderedDict
from .python2_3 import asUnicode, basestring
# legacy color definitions:
# NamedColorManager now maintains the primary list of palette colors,
# accessible through functions.NAMED_COLOR_MANAGER.colors().
# For backwards compatibility, this dictionary is updated to contain the same information.
#
# For the user, colors and color palettes are most conveniently accessed through a Palette object.
Colors = {
'b': QtGui.QColor(0,0,255,255),
'g': QtGui.QColor(0,255,0,255),
@ -41,11 +47,9 @@ Colors = {
'l': QtGui.QColor(200,200,200,255),
's': QtGui.QColor(100,100,150,255)
}
# instantiate singleton NamedColorManager with a reference to Colors
print(' functions loaded, colors initiated.')
NAMED_COLOR_MANAGER = NamedColorManager( Colors )
# populates the Colors dictionary with default functional colors.
# print('updated(?) colors:', Colors)
print(' namedColorManager loaded, colors updated.')
SI_PREFIXES = asUnicode('yzafpnµm kMGTPEZY')
SI_PREFIXES_ASCII = 'yzafpnum kMGTPEZY'
@ -243,7 +247,7 @@ def parseNamedColorSpecification(*args):
return None # hexadecimal string not handled as NamedColor
if arg in Colors:
return (arg, None) # valid name, no alpha given
if isinstance(arg, tuple) or isinstance(arg, list):
if isinstance(arg, (tuple, list)):
args = arg # promote to top level
else:
return None #numerical values not handled as NamedColor
@ -350,7 +354,7 @@ def mkBrush(*args, **kargs):
| Calling mkBrush(None) returns an invisible brush.
"""
while ( # unravel single element sublists
( isinstance(args, tuple) or isinstance(args,list) )
isinstance(args, (tuple, list) )
and len(args) == 1
):
args = args[0]
@ -375,14 +379,14 @@ def mkBrush(*args, **kargs):
return QtGui.QBrush( QtCore.Qt.NoBrush ) # explicit None means "no brush"
if args == () or args == []:
print(' functions: returning default color NamedBrush')
qpen = NamedBrush( 'gr_fg' ) # default foreground color
qpen = NamedBrush( 'gr_fg', manager=NAMED_COLOR_MANAGER ) # default foreground color
else:
result = parseNamedColorSpecification(args)
if result is not None: # make a NamedBrush
name, alpha = result
if name == '':
return QtGui.QBrush( QtCore.Qt.NoBrush ) # empty string means "no brush"
qbrush = NamedBrush(name, alpha=alpha)
qbrush = NamedBrush(name, manager=NAMED_COLOR_MANAGER, alpha=alpha)
else: # make a QBrush
qcol = mkColor(args)
qbrush = QtGui.QBrush(qcol)
@ -404,7 +408,7 @@ def mkPen(*args, **kargs):
In these examples, *color* may be replaced with any arguments accepted by :func:`mkColor() <pyqtgraph.mkColor>` """
# print('mkPen called:',args,kargs)
while ( # unravel single element sublists
( isinstance(args, tuple) or isinstance(args,list) )
isinstance(args, (tuple, list) )
and len(args) == 1
):
args = args[0]
@ -429,14 +433,14 @@ def mkPen(*args, **kargs):
if args is None:
return QtGui.QPen( QtCore.Qt.NoPen ) # explicit None means "no pen"
if args == () or args == []:
qpen = NamedPen( 'gr_fg', width=width ) # default foreground color
qpen = NamedPen( 'gr_fg', manager=NAMED_COLOR_MANAGER, width=width ) # default foreground color
else:
result = parseNamedColorSpecification(args)
if result is not None: # make a NamedPen
name, alpha = result
if name == '':
return QtGui.QPen( QtCore.Qt.NoPen ) # empty string means "no pen"
qpen = NamedPen( name, alpha=alpha, width=width )
qpen = NamedPen( name, manager=NAMED_COLOR_MANAGER, alpha=alpha, width=width )
else: # make a QPen
qcol = mkColor(args)
qpen = QtGui.QPen(QtGui.QBrush(qcol), width)
@ -445,7 +449,8 @@ def mkPen(*args, **kargs):
width = kargs.get('width', 1) # collect remaining kargs to define properties
dash = kargs.get('dash', None)
cosmetic = kargs.get('cosmetic', True)
assert qpen is not None
if qpen is None:
raise ValueError('Failed to construct QPen from arguments '+str(args)+','+str(kargs) )
qpen.setCosmetic(cosmetic)
if style is not None:
qpen.setStyle(style)

View File

@ -54,7 +54,7 @@ class GraphicsObject(GraphicsItem, QtGui.QGraphicsObject):
# """ stub function called after Palette.apply(), specific reactions to palette redefinitions execute here """
# print('style change request:', self, type(color_dict))
@QT_CORE_SLOT()
@QtCore.Slot() # qt.py equates this to pyqtSlot for PyQt
def styleHasChanged(self):
""" called to trigger redraw after all named colors have been updated """
# self._boundingRect = None

View File

@ -64,7 +64,7 @@ class GraphicsWidget(GraphicsItem, QtGui.QGraphicsWidget):
#print "shape:", p.boundingRect()
return p
@QT_CORE_SLOT()
@QtCore.Slot() # qt.py equates this to pyqtSlot for PyQt
def styleHasChanged(self):
""" called to trigger redraw after all named colors have been updated """
# self._boundingRect = None

View File

@ -1,24 +1,26 @@
# from ..Qt import QtGui
from .Qt import QtGui, QtCore
from . import functions as fn
from .namedColorManager import NamedColorManager
__all__ = ['NamedBrush']
DEBUG = False
class NamedBrush(QtGui.QBrush):
""" Extends QPen to retain a functional color description """
def __init__(self, name, alpha=None ):
def __init__(self, name, manager=None, alpha=None ):
"""
Creates a new NamedBrush object.
'name' should be in 'functions.Colors'
'alpha' controls opacity which persists over palette changes
'name' should be in 'functions.Colors'
'manager' is a reference to the controlling NamedColorManager
'alpha' controls opacity which persists over palette changes
"""
if DEBUG: print(' NamedBrush created as',name,alpha)
super().__init__(QtCore.Qt.SolidPattern) # Initialize QBrush superclass
self._identifier = (name, alpha)
if manager is None or not isinstance(manager, NamedColorManager):
raise ValueError("NamedPen requires NamedColorManager to be provided in 'manager' argument!")
self._manager = manager
self._updateQColor(self._identifier)
fn.NAMED_COLOR_MANAGER.register( self ) # manually register for callbacks
self._manager.register( self ) # manually register for callbacks
def __eq__(self, other): # make this a hashable object
# return other is self
@ -51,13 +53,17 @@ class NamedBrush(QtGui.QBrush):
self._identifier = (self._identifier[0], alpha)
self._updateQColor(self._identifier)
def identifier(self):
""" return current color identifier """
return self._identifier
def _updateQColor(self, identifier, color_dict=None):
""" update super-class QColor """
name, alpha = identifier
if color_dict is None:
color_dict = fn.NAMED_COLOR_MANAGER.colors()
color_dict = self._manager.colors()
try:
qcol = fn.Colors[name]
qcol = color_dict[name]
except ValueError as exc:
raise ValueError("Color '{:s}' is not in list of defined colors".format(str(name)) ) from exc
if alpha is not None:
@ -65,10 +71,6 @@ class NamedBrush(QtGui.QBrush):
if DEBUG: print(' NamedBrush '+name+' updated to QColor ('+str(qcol.name())+', alpha='+str(alpha)+')')
super().setColor( qcol )
def identifier(self):
""" return current color identifier """
return self._identifier
def paletteChange(self, color_dict):
""" refresh QColor according to lookup of identifier in functions.Colors """
if DEBUG: print(' NamedBrush: style change request:', self, type(color_dict))

View File

@ -4,7 +4,7 @@ from .Qt import QtCore, QtGui
import weakref
__all__ = ['NamedColorManager']
DEBUG = True
DEBUG = False
DEFAULT_COLORS = {
'b': QtGui.QColor( 0, 0,255,255),
@ -18,7 +18,7 @@ DEFAULT_COLORS = {
'd': QtGui.QColor(150,150,150,255),
'l': QtGui.QColor(200,200,200,255),
's': QtGui.QColor(100,100,150,255),
'gr_acc':QtGui.QColor(200,200,100,255), # graphical accent color: pastel yellow
'gr_acc':QtGui.QColor(200,200,100,255), # graphical accent color: pastel yellow
'gr_reg':QtGui.QColor( 0, 0,255, 50) # graphical region marker: translucent blue
}
for key, col in [ # add functional colors
@ -35,8 +35,9 @@ for idx, col in enumerate( ( # twelve predefined plot colors
key = 'p{:X}'.format(idx)
DEFAULT_COLORS[key] = DEFAULT_COLORS[col]
# define and instantiate a SignalSource object to pass signals to all pyqtgraph elements
class NamedColorManager(QtCore.QObject): # this needs to emit QEvents
# An instantiated QObject is required to emit QSignals.
# functions.py initializes and maintains NAMED_COLOR_MANAGER for this purpose.
class NamedColorManager(QtCore.QObject):
"""
Singleton QObject that provides palette change signals
Instantiated by 'functions.py' and retrievable as functions.NAMED_COLOR_MANAGER

View File

@ -1,27 +1,30 @@
# from ..Qt import QtGui
from .Qt import QtGui, QtCore
from . import functions as fn
from .namedColorManager import NamedColorManager
__all__ = ['NamedPen']
DEBUG = False
class NamedPen(QtGui.QPen):
""" Extends QPen to retain a functional color description """
def __init__(self, name, width=1, alpha=None ):
def __init__(self, name, manager=None, width=1, alpha=None ):
"""
Creates a new NamedPen object.
'name' should be included in 'functions.Colors'
'width' specifies linewidth and defaults to 1
'alpha' controls opacity which persists over palette changes
'name' should be included in 'functions.Colors'
'manager' is a reference to the controlling NamedColorManager
'width' specifies linewidth and defaults to 1
'alpha' controls opacity which persists over palette changes
"""
if DEBUG: print(' NamedBrush created as',name,alpha)
if DEBUG: print(' NamedPen created as',name,alpha)
super().__init__(QtCore.Qt.SolidLine) # Initialize QPen superclass
super().setWidth(width)
super().setCosmetic(True)
self._identifier = (name, alpha)
if manager is None or not isinstance(manager, NamedColorManager):
raise ValueError("NamedPen requires NamedColorManager to be provided in 'manager' argument!")
self._manager = manager
self._updateQColor(self._identifier)
fn.NAMED_COLOR_MANAGER.register( self ) # manually register for callbacks
if self._manager is not None:
self._manager.register( self ) # manually register for callbacks
def __eq__(self, other): # make this a hashable object
# return other is self
@ -55,13 +58,17 @@ class NamedPen(QtGui.QPen):
self._identifier = (self._identifier[0], alpha)
self._updateQColor(self._identifier)
def identifier(self):
""" return current color identifier """
return self._identifier
def _updateQColor(self, identifier, color_dict=None):
""" update super-class QColor """
name, alpha = identifier
if color_dict is None:
color_dict = fn.NAMED_COLOR_MANAGER.colors()
color_dict = self._manager.colors()
try:
qcol = fn.Colors[name]
qcol = color_dict[name]
except ValueError as exc:
raise ValueError("Color '{:s}' is not in list of defined colors".format(str(name)) ) from exc
if alpha is not None:
@ -69,19 +76,24 @@ class NamedPen(QtGui.QPen):
if DEBUG: print(' NamedPen updated to QColor ('+str(qcol.name())+')')
super().setColor( qcol )
def paletteChange(self, color_dict):
""" refresh QColor according to lookup of identifier in functions.Colors """
if DEBUG: print(' NamedPen: style change request:', self, type(color_dict))
name, alpha = self._identifier
if color_dict is None: # manually retrieve color manager palette
color_dict = fn.NAMED_COLOR_MANAGER.colors()
try:
qcol = color_dict[name]
if DEBUG: print(' NamedPen: retrieved new QColor (', qcol.getRgb(), ') for name', name)
except ValueError as exc:
raise ValueError("Color {:s} is not in list of defined colors".format(str(name)) ) from exc
if alpha is not None:
qcol.setAlpha( alpha )
super().setColor(qcol)
self._updateQColor(self._identifier, color_dict=color_dict)
if DEBUG:
qcol = super().color()
name, alpha = self._identifier
print(' NamedPen: retrieved new QColor ('+str(qcol.name())+') '
+ 'for name '+str(name)+' ('+str(alpha)+')' )
# name, alpha = self._identifier
# if color_dict is None: # manually retrieve color manager palette
# color_dict = self._manager.colors()
# try:
# qcol = color_dict[name]
# if DEBUG: print(' NamedPen: retrieved new QColor (', qcol.getRgb(), ') for name', name)
# except ValueError as exc:
# raise ValueError("Color {:s} is not in list of defined colors".format(str(name)) ) from exc
# if alpha is not None:
# qcol.setAlpha( alpha )
# super().setColor(qcol)

View File

@ -1,6 +1,6 @@
from .Qt import QtGui, QtCore
from . import functions as fn
from . import functions as fn # namedColorManager
__all__ = ['Palette']

View File

@ -418,7 +418,7 @@ class GraphicsView(QtGui.QGraphicsView):
def dragEnterEvent(self, ev):
ev.ignore() ## not sure why, but for some reason this class likes to consume drag events
@QT_CORE_SLOT()
@QtCore.Slot() # qt.py equates this to pyqtSlot for PyQt
def styleHasChanged(self):
""" called to trigger redraw after all named colors have been updated """
self.setBackgroundBrush( self._bgBrush )