Added preliminary support for python 2.6
Fixed setup.py to automatically search for all sub-packages
This commit is contained in:
parent
c022f3a10f
commit
ca9d0ed147
@ -15,8 +15,8 @@ import os, sys
|
||||
|
||||
## check python version
|
||||
## Allow anything >= 2.7
|
||||
if sys.version_info[0] < 2 or (sys.version_info[0] == 2 and sys.version_info[1] < 7):
|
||||
raise Exception("Pyqtgraph requires Python version 2.7 (this is %d.%d)" % (sys.version_info[0], sys.version_info[1]))
|
||||
if sys.version_info[0] < 2 or (sys.version_info[0] == 2 and sys.version_info[1] < 6):
|
||||
raise Exception("Pyqtgraph requires Python version 2.6 or greater (this is %d.%d)" % (sys.version_info[0], sys.version_info[1]))
|
||||
|
||||
## helpers for 2/3 compatibility
|
||||
from . import python2_3
|
||||
|
@ -10,7 +10,7 @@ as it can be converted to/from a string using repr and eval.
|
||||
"""
|
||||
|
||||
import re, os, sys
|
||||
from collections import OrderedDict
|
||||
from pgcollections import OrderedDict
|
||||
GLOBAL_PATH = None # so not thread safe.
|
||||
from . import units
|
||||
from .python2_3 import asUnicode
|
||||
|
@ -9,7 +9,7 @@ else:
|
||||
from exampleLoaderTemplate_pyqt import Ui_Form
|
||||
|
||||
import os, sys
|
||||
from collections import OrderedDict
|
||||
from pyqtgraph.pgcollections import OrderedDict
|
||||
|
||||
examples = OrderedDict([
|
||||
('Command-line usage', 'CLIexample.py'),
|
||||
|
@ -14,7 +14,6 @@ import pyqtgraph as pg
|
||||
from pyqtgraph.Qt import QtCore, QtGui
|
||||
|
||||
|
||||
import collections
|
||||
app = QtGui.QApplication([])
|
||||
import pyqtgraph.parametertree.parameterTypes as pTypes
|
||||
from pyqtgraph.parametertree import Parameter, ParameterTree, ParameterItem, registerParameterType
|
||||
|
@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pyqtgraph.Qt import QtCore, QtGui, USE_PYSIDE
|
||||
from .Node import *
|
||||
from collections import OrderedDict
|
||||
from pyqtgraph.pgcollections import OrderedDict
|
||||
from pyqtgraph.widgets.TreeWidget import *
|
||||
|
||||
## pyside and pyqt use incompatible ui files.
|
||||
|
@ -3,7 +3,7 @@ from pyqtgraph.Qt import QtCore, QtGui
|
||||
from pyqtgraph.graphicsItems.GraphicsObject import GraphicsObject
|
||||
import pyqtgraph.functions as fn
|
||||
from .Terminal import *
|
||||
from collections import OrderedDict
|
||||
from pyqtgraph.pgcollections import OrderedDict
|
||||
from pyqtgraph.debug import *
|
||||
import numpy as np
|
||||
from .eq import *
|
||||
|
@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from collections import OrderedDict
|
||||
from pyqtgraph.pgcollections import OrderedDict
|
||||
import os, types
|
||||
from pyqtgraph.debug import printExc
|
||||
from ..Node import Node
|
||||
|
@ -42,7 +42,7 @@ class ArrowItem(QtGui.QGraphicsPathItem):
|
||||
def setStyle(self, **opts):
|
||||
self.opts = opts
|
||||
|
||||
opt = {k:self.opts[k] for k in ['headLen', 'tipAngle', 'baseAngle', 'tailLen', 'tailWidth']}
|
||||
opt = dict([(k,self.opts[k]) for k in ['headLen', 'tipAngle', 'baseAngle', 'tailLen', 'tailWidth']])
|
||||
self.path = fn.makeArrowPath(**opt)
|
||||
self.setPath(self.path)
|
||||
|
||||
|
@ -3,13 +3,14 @@ from pyqtgraph.python2_3 import sortList
|
||||
import pyqtgraph.functions as fn
|
||||
from .GraphicsObject import GraphicsObject
|
||||
from .GraphicsWidget import GraphicsWidget
|
||||
import weakref, collections
|
||||
import weakref
|
||||
from pyqtgraph.pgcollections import OrderedDict
|
||||
import numpy as np
|
||||
|
||||
__all__ = ['TickSliderItem', 'GradientEditorItem']
|
||||
|
||||
|
||||
Gradients = collections.OrderedDict([
|
||||
Gradients = OrderedDict([
|
||||
('thermal', {'ticks': [(0.3333, (185, 0, 0, 255)), (0.6666, (255, 220, 0, 255)), (1, (255, 255, 255, 255)), (0, (0, 0, 0, 255))], 'mode': 'rgb'}),
|
||||
('flame', {'ticks': [(0.2, (7, 0, 220, 255)), (0.5, (236, 0, 134, 255)), (0.8, (246, 246, 0, 255)), (1.0, (255, 255, 255, 255)), (0.0, (0, 0, 0, 255))], 'mode': 'rgb'}),
|
||||
('yellowy', {'ticks': [(0.0, (0, 0, 0, 255)), (0.2328863796753704, (32, 0, 129, 255)), (0.8362738179251941, (255, 255, 0, 255)), (0.5257586450247, (115, 15, 255, 255)), (1.0, (255, 255, 255, 255))], 'mode': 'rgb'} ),
|
||||
|
@ -35,7 +35,6 @@ from .. LabelItem import LabelItem
|
||||
from .. GraphicsWidget import GraphicsWidget
|
||||
from .. ButtonItem import ButtonItem
|
||||
from pyqtgraph.WidgetGroup import WidgetGroup
|
||||
import collections
|
||||
|
||||
__all__ = ['PlotItem']
|
||||
|
||||
|
@ -7,7 +7,7 @@ import numpy as np
|
||||
import scipy.stats
|
||||
import weakref
|
||||
import pyqtgraph.debug as debug
|
||||
from collections import OrderedDict
|
||||
from pyqtgraph.pgcollections import OrderedDict
|
||||
#import pyqtgraph as pg
|
||||
|
||||
__all__ = ['ScatterPlotItem', 'SpotItem']
|
||||
|
@ -9,7 +9,6 @@ from pyqtgraph.GraphicsScene import GraphicsScene
|
||||
import pyqtgraph
|
||||
import weakref
|
||||
from copy import deepcopy
|
||||
import collections
|
||||
|
||||
__all__ = ['ViewBox']
|
||||
|
||||
@ -111,12 +110,6 @@ class ViewBox(GraphicsWidget):
|
||||
}
|
||||
|
||||
|
||||
#self.exportMethods = collections.OrderedDict([
|
||||
#('SVG', self.saveSvg),
|
||||
#('Image', self.saveImage),
|
||||
#('Print', self.savePrint),
|
||||
#])
|
||||
|
||||
self.setFlag(self.ItemClipsChildrenToShape)
|
||||
self.setFlag(self.ItemIsFocusable, True) ## so we can receive key presses
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
from pyqtgraph.Qt import QtGui, QtCore
|
||||
import collections, os, weakref, re
|
||||
import os, weakref, re
|
||||
from pyqtgraph.pgcollections import OrderedDict
|
||||
from .ParameterItem import ParameterItem
|
||||
|
||||
PARAM_TYPES = {}
|
||||
@ -216,7 +217,7 @@ class Parameter(QtCore.QObject):
|
||||
|
||||
def getValues(self):
|
||||
"""Return a tree of all values that are children of this parameter"""
|
||||
vals = collections.OrderedDict()
|
||||
vals = OrderedDict()
|
||||
for ch in self:
|
||||
vals[ch.name()] = (ch.value(), ch.getValues())
|
||||
return vals
|
||||
@ -227,7 +228,7 @@ class Parameter(QtCore.QObject):
|
||||
The tree state may be restored from this structure using restoreState()
|
||||
"""
|
||||
state = self.opts.copy()
|
||||
state['children'] = collections.OrderedDict([(ch.name(), ch.saveState()) for ch in self])
|
||||
state['children'] = OrderedDict([(ch.name(), ch.saveState()) for ch in self])
|
||||
if state['type'] is None:
|
||||
global PARAM_NAMES
|
||||
state['type'] = PARAM_NAMES.get(type(self), None)
|
||||
@ -363,7 +364,7 @@ class Parameter(QtCore.QObject):
|
||||
most parameters will accept a common set of options: value, name, limits,
|
||||
default, readonly, removable, renamable, visible, and enabled.
|
||||
"""
|
||||
changed = collections.OrderedDict()
|
||||
changed = OrderedDict()
|
||||
for k in opts:
|
||||
if k == 'value':
|
||||
self.setValue(opts[k])
|
||||
|
@ -1,5 +1,5 @@
|
||||
from pyqtgraph.Qt import QtGui, QtCore
|
||||
import collections, os, weakref, re
|
||||
import os, weakref, re
|
||||
|
||||
class ParameterItem(QtGui.QTreeWidgetItem):
|
||||
"""
|
||||
|
@ -1,6 +1,6 @@
|
||||
from pyqtgraph.Qt import QtCore, QtGui
|
||||
from pyqtgraph.widgets.TreeWidget import TreeWidget
|
||||
import collections, os, weakref, re
|
||||
import os, weakref, re
|
||||
#import functions as fn
|
||||
|
||||
|
||||
|
@ -5,7 +5,8 @@ from .ParameterItem import ParameterItem
|
||||
from pyqtgraph.widgets.SpinBox import SpinBox
|
||||
from pyqtgraph.widgets.ColorButton import ColorButton
|
||||
import pyqtgraph as pg
|
||||
import os, collections
|
||||
import os
|
||||
from pyqtgraph.pgcollections import OrderedDict
|
||||
|
||||
class WidgetParameterItem(ParameterItem):
|
||||
"""
|
||||
@ -481,8 +482,6 @@ class ListParameterItem(WidgetParameterItem):
|
||||
|
||||
def limitsChanged(self, param, limits):
|
||||
# set up forward / reverse mappings for name:value
|
||||
#self.forward = collections.OrderedDict([('', None)]) ## name: value
|
||||
#self.reverse = collections.OrderedDict([(None, '')]) ## value: name
|
||||
|
||||
if len(limits) == 0:
|
||||
limits = [''] ## Can never have an empty list--there is always at least a singhe blank item.
|
||||
@ -507,8 +506,8 @@ class ListParameter(Parameter):
|
||||
itemClass = ListParameterItem
|
||||
|
||||
def __init__(self, **opts):
|
||||
self.forward = collections.OrderedDict() ## name: value
|
||||
self.reverse = collections.OrderedDict() ## value: name
|
||||
self.forward = OrderedDict() ## name: value
|
||||
self.reverse = OrderedDict() ## value: name
|
||||
|
||||
## Parameter uses 'limits' option to define the set of allowed values
|
||||
if 'values' in opts:
|
||||
@ -528,8 +527,8 @@ class ListParameter(Parameter):
|
||||
@staticmethod
|
||||
def mapping(limits):
|
||||
## Return forward and reverse mapping dictionaries given a limit specification
|
||||
forward = collections.OrderedDict() ## name: value
|
||||
reverse = collections.OrderedDict() ## value: name
|
||||
forward = OrderedDict() ## name: value
|
||||
reverse = OrderedDict() ## value: name
|
||||
if isinstance(limits, dict):
|
||||
for k, v in limits.items():
|
||||
forward[k] = v
|
||||
|
543
pgcollections.py
Normal file
543
pgcollections.py
Normal file
@ -0,0 +1,543 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
advancedTypes.py - Basic data structures not included with python
|
||||
Copyright 2010 Luke Campagnola
|
||||
Distributed under MIT/X11 license. See license.txt for more infomation.
|
||||
|
||||
Includes:
|
||||
- OrderedDict - Dictionary which preserves the order of its elements
|
||||
- BiDict, ReverseDict - Bi-directional dictionaries
|
||||
- ThreadsafeDict, ThreadsafeList - Self-mutexed data structures
|
||||
"""
|
||||
|
||||
import threading, sys, copy, collections
|
||||
#from debug import *
|
||||
|
||||
try:
|
||||
from collections import OrderedDict
|
||||
except:
|
||||
# Deprecated; this class is now present in Python 2.7 as collections.OrderedDict
|
||||
# Only keeping this around for python2.6 support.
|
||||
class OrderedDict(dict):
|
||||
"""extends dict so that elements are iterated in the order that they were added.
|
||||
Since this class can not be instantiated with regular dict notation, it instead uses
|
||||
a list of tuples:
|
||||
od = OrderedDict([(key1, value1), (key2, value2), ...])
|
||||
items set using __setattr__ are added to the end of the key list.
|
||||
"""
|
||||
|
||||
def __init__(self, data=None):
|
||||
self.order = []
|
||||
if data is not None:
|
||||
for i in data:
|
||||
self[i[0]] = i[1]
|
||||
|
||||
def __setitem__(self, k, v):
|
||||
if not self.has_key(k):
|
||||
self.order.append(k)
|
||||
dict.__setitem__(self, k, v)
|
||||
|
||||
def __delitem__(self, k):
|
||||
self.order.remove(k)
|
||||
dict.__delitem__(self, k)
|
||||
|
||||
def keys(self):
|
||||
return self.order[:]
|
||||
|
||||
def items(self):
|
||||
it = []
|
||||
for k in self.keys():
|
||||
it.append((k, self[k]))
|
||||
return it
|
||||
|
||||
def values(self):
|
||||
return [self[k] for k in self.order]
|
||||
|
||||
def remove(self, key):
|
||||
del self[key]
|
||||
#self.order.remove(key)
|
||||
|
||||
def __iter__(self):
|
||||
for k in self.order:
|
||||
yield k
|
||||
|
||||
def update(self, data):
|
||||
"""Works like dict.update, but accepts list-of-tuples as well as dict."""
|
||||
if isinstance(data, dict):
|
||||
for k, v in data.iteritems():
|
||||
self[k] = v
|
||||
else:
|
||||
for k,v in data:
|
||||
self[k] = v
|
||||
|
||||
def copy(self):
|
||||
return OrderedDict(self.items())
|
||||
|
||||
def itervalues(self):
|
||||
for k in self.order:
|
||||
yield self[k]
|
||||
|
||||
def iteritems(self):
|
||||
for k in self.order:
|
||||
yield (k, self[k])
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
return OrderedDict([(k, copy.deepcopy(v, memo)) for k, v in self.iteritems()])
|
||||
|
||||
|
||||
|
||||
class ReverseDict(dict):
|
||||
"""extends dict so that reverse lookups are possible by requesting the key as a list of length 1:
|
||||
d = BiDict({'x': 1, 'y': 2})
|
||||
d['x']
|
||||
1
|
||||
d[[2]]
|
||||
'y'
|
||||
"""
|
||||
def __init__(self, data=None):
|
||||
if data is None:
|
||||
data = {}
|
||||
self.reverse = {}
|
||||
for k in data:
|
||||
self.reverse[data[k]] = k
|
||||
dict.__init__(self, data)
|
||||
|
||||
def __getitem__(self, item):
|
||||
if type(item) is list:
|
||||
return self.reverse[item[0]]
|
||||
else:
|
||||
return dict.__getitem__(self, item)
|
||||
|
||||
def __setitem__(self, item, value):
|
||||
self.reverse[value] = item
|
||||
dict.__setitem__(self, item, value)
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
raise Exception("deepcopy not implemented")
|
||||
|
||||
|
||||
class BiDict(dict):
|
||||
"""extends dict so that reverse lookups are possible by adding each reverse combination to the dict.
|
||||
This only works if all values and keys are unique."""
|
||||
def __init__(self, data=None):
|
||||
if data is None:
|
||||
data = {}
|
||||
dict.__init__(self)
|
||||
for k in data:
|
||||
self[data[k]] = k
|
||||
|
||||
def __setitem__(self, item, value):
|
||||
dict.__setitem__(self, item, value)
|
||||
dict.__setitem__(self, value, item)
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
raise Exception("deepcopy not implemented")
|
||||
|
||||
class ThreadsafeDict(dict):
|
||||
"""Extends dict so that getitem, setitem, and contains are all thread-safe.
|
||||
Also adds lock/unlock functions for extended exclusive operations
|
||||
Converts all sub-dicts and lists to threadsafe as well.
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.mutex = threading.RLock()
|
||||
dict.__init__(self, *args, **kwargs)
|
||||
for k in self:
|
||||
if type(self[k]) is dict:
|
||||
self[k] = ThreadsafeDict(self[k])
|
||||
|
||||
def __getitem__(self, attr):
|
||||
self.lock()
|
||||
try:
|
||||
val = dict.__getitem__(self, attr)
|
||||
finally:
|
||||
self.unlock()
|
||||
return val
|
||||
|
||||
def __setitem__(self, attr, val):
|
||||
if type(val) is dict:
|
||||
val = ThreadsafeDict(val)
|
||||
self.lock()
|
||||
try:
|
||||
dict.__setitem__(self, attr, val)
|
||||
finally:
|
||||
self.unlock()
|
||||
|
||||
def __contains__(self, attr):
|
||||
self.lock()
|
||||
try:
|
||||
val = dict.__contains__(self, attr)
|
||||
finally:
|
||||
self.unlock()
|
||||
return val
|
||||
|
||||
def __len__(self):
|
||||
self.lock()
|
||||
try:
|
||||
val = dict.__len__(self)
|
||||
finally:
|
||||
self.unlock()
|
||||
return val
|
||||
|
||||
def clear(self):
|
||||
self.lock()
|
||||
try:
|
||||
dict.clear(self)
|
||||
finally:
|
||||
self.unlock()
|
||||
|
||||
def lock(self):
|
||||
self.mutex.acquire()
|
||||
|
||||
def unlock(self):
|
||||
self.mutex.release()
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
raise Exception("deepcopy not implemented")
|
||||
|
||||
class ThreadsafeList(list):
|
||||
"""Extends list so that getitem, setitem, and contains are all thread-safe.
|
||||
Also adds lock/unlock functions for extended exclusive operations
|
||||
Converts all sub-lists and dicts to threadsafe as well.
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.mutex = threading.RLock()
|
||||
list.__init__(self, *args, **kwargs)
|
||||
for k in self:
|
||||
self[k] = mkThreadsafe(self[k])
|
||||
|
||||
def __getitem__(self, attr):
|
||||
self.lock()
|
||||
try:
|
||||
val = list.__getitem__(self, attr)
|
||||
finally:
|
||||
self.unlock()
|
||||
return val
|
||||
|
||||
def __setitem__(self, attr, val):
|
||||
val = makeThreadsafe(val)
|
||||
self.lock()
|
||||
try:
|
||||
list.__setitem__(self, attr, val)
|
||||
finally:
|
||||
self.unlock()
|
||||
|
||||
def __contains__(self, attr):
|
||||
self.lock()
|
||||
try:
|
||||
val = list.__contains__(self, attr)
|
||||
finally:
|
||||
self.unlock()
|
||||
return val
|
||||
|
||||
def __len__(self):
|
||||
self.lock()
|
||||
try:
|
||||
val = list.__len__(self)
|
||||
finally:
|
||||
self.unlock()
|
||||
return val
|
||||
|
||||
def lock(self):
|
||||
self.mutex.acquire()
|
||||
|
||||
def unlock(self):
|
||||
self.mutex.release()
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
raise Exception("deepcopy not implemented")
|
||||
|
||||
|
||||
def makeThreadsafe(obj):
|
||||
if type(obj) is dict:
|
||||
return ThreadsafeDict(obj)
|
||||
elif type(obj) is list:
|
||||
return ThreadsafeList(obj)
|
||||
elif type(obj) in [str, int, float, bool, tuple]:
|
||||
return obj
|
||||
else:
|
||||
raise Exception("Not sure how to make object of type %s thread-safe" % str(type(obj)))
|
||||
|
||||
|
||||
class Locker:
|
||||
def __init__(self, lock):
|
||||
self.lock = lock
|
||||
self.lock.acquire()
|
||||
def __del__(self):
|
||||
try:
|
||||
self.lock.release()
|
||||
except:
|
||||
pass
|
||||
|
||||
class CaselessDict(OrderedDict):
|
||||
"""Case-insensitive dict. Values can be set and retrieved using keys of any case.
|
||||
Note that when iterating, the original case is returned for each key."""
|
||||
def __init__(self, *args):
|
||||
OrderedDict.__init__(self, {}) ## requirement for the empty {} here seems to be a python bug?
|
||||
self.keyMap = OrderedDict([(k.lower(), k) for k in OrderedDict.keys(self)])
|
||||
if len(args) == 0:
|
||||
return
|
||||
elif len(args) == 1 and isinstance(args[0], dict):
|
||||
for k in args[0]:
|
||||
self[k] = args[0][k]
|
||||
else:
|
||||
raise Exception("CaselessDict may only be instantiated with a single dict.")
|
||||
|
||||
#def keys(self):
|
||||
#return self.keyMap.values()
|
||||
|
||||
def __setitem__(self, key, val):
|
||||
kl = key.lower()
|
||||
if kl in self.keyMap:
|
||||
OrderedDict.__setitem__(self, self.keyMap[kl], val)
|
||||
else:
|
||||
OrderedDict.__setitem__(self, key, val)
|
||||
self.keyMap[kl] = key
|
||||
|
||||
def __getitem__(self, key):
|
||||
kl = key.lower()
|
||||
if kl not in self.keyMap:
|
||||
raise KeyError(key)
|
||||
return OrderedDict.__getitem__(self, self.keyMap[kl])
|
||||
|
||||
def __contains__(self, key):
|
||||
return key.lower() in self.keyMap
|
||||
|
||||
def update(self, d):
|
||||
for k, v in d.iteritems():
|
||||
self[k] = v
|
||||
|
||||
def copy(self):
|
||||
return CaselessDict(OrderedDict.copy(self))
|
||||
|
||||
def __delitem__(self, key):
|
||||
kl = key.lower()
|
||||
if kl not in self.keyMap:
|
||||
raise KeyError(key)
|
||||
OrderedDict.__delitem__(self, self.keyMap[kl])
|
||||
del self.keyMap[kl]
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
raise Exception("deepcopy not implemented")
|
||||
|
||||
def clear(self):
|
||||
OrderedDict.clear(self)
|
||||
self.keyMap.clear()
|
||||
|
||||
|
||||
|
||||
class ProtectedDict(dict):
|
||||
"""
|
||||
A class allowing read-only 'view' of a dict.
|
||||
The object can be treated like a normal dict, but will never modify the original dict it points to.
|
||||
Any values accessed from the dict will also be read-only.
|
||||
"""
|
||||
def __init__(self, data):
|
||||
self._data_ = data
|
||||
|
||||
## List of methods to directly wrap from _data_
|
||||
wrapMethods = ['_cmp_', '__contains__', '__eq__', '__format__', '__ge__', '__gt__', '__le__', '__len__', '__lt__', '__ne__', '__reduce__', '__reduce_ex__', '__repr__', '__str__', 'count', 'has_key', 'iterkeys', 'keys', ]
|
||||
|
||||
## List of methods which wrap from _data_ but return protected results
|
||||
protectMethods = ['__getitem__', '__iter__', 'get', 'items', 'values']
|
||||
|
||||
## List of methods to disable
|
||||
disableMethods = ['__delitem__', '__setitem__', 'clear', 'pop', 'popitem', 'setdefault', 'update']
|
||||
|
||||
|
||||
## Template methods
|
||||
def wrapMethod(methodName):
|
||||
return lambda self, *a, **k: getattr(self._data_, methodName)(*a, **k)
|
||||
|
||||
def protectMethod(methodName):
|
||||
return lambda self, *a, **k: protect(getattr(self._data_, methodName)(*a, **k))
|
||||
|
||||
def error(self, *args, **kargs):
|
||||
raise Exception("Can not modify read-only list.")
|
||||
|
||||
|
||||
## Directly (and explicitly) wrap some methods from _data_
|
||||
## Many of these methods can not be intercepted using __getattribute__, so they
|
||||
## must be implemented explicitly
|
||||
for methodName in wrapMethods:
|
||||
locals()[methodName] = wrapMethod(methodName)
|
||||
|
||||
## Wrap some methods from _data_ with the results converted to protected objects
|
||||
for methodName in protectMethods:
|
||||
locals()[methodName] = protectMethod(methodName)
|
||||
|
||||
## Disable any methods that could change data in the list
|
||||
for methodName in disableMethods:
|
||||
locals()[methodName] = error
|
||||
|
||||
|
||||
## Add a few extra methods.
|
||||
def copy(self):
|
||||
raise Exception("It is not safe to copy protected dicts! (instead try deepcopy, but be careful.)")
|
||||
|
||||
def itervalues(self):
|
||||
for v in self._data_.itervalues():
|
||||
yield protect(v)
|
||||
|
||||
def iteritems(self):
|
||||
for k, v in self._data_.iteritems():
|
||||
yield (k, protect(v))
|
||||
|
||||
def deepcopy(self):
|
||||
return copy.deepcopy(self._data_)
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
return copy.deepcopy(self._data_, memo)
|
||||
|
||||
|
||||
|
||||
class ProtectedList(collections.Sequence):
|
||||
"""
|
||||
A class allowing read-only 'view' of a list or dict.
|
||||
The object can be treated like a normal list, but will never modify the original list it points to.
|
||||
Any values accessed from the list will also be read-only.
|
||||
|
||||
Note: It would be nice if we could inherit from list or tuple so that isinstance checks would work.
|
||||
However, doing this causes tuple(obj) to return unprotected results (importantly, this means
|
||||
unpacking into function arguments will also fail)
|
||||
"""
|
||||
def __init__(self, data):
|
||||
self._data_ = data
|
||||
#self.__mro__ = (ProtectedList, object)
|
||||
|
||||
## List of methods to directly wrap from _data_
|
||||
wrapMethods = ['__contains__', '__eq__', '__format__', '__ge__', '__gt__', '__le__', '__len__', '__lt__', '__ne__', '__reduce__', '__reduce_ex__', '__repr__', '__str__', 'count', 'index']
|
||||
|
||||
## List of methods which wrap from _data_ but return protected results
|
||||
protectMethods = ['__getitem__', '__getslice__', '__mul__', '__reversed__', '__rmul__']
|
||||
|
||||
## List of methods to disable
|
||||
disableMethods = ['__delitem__', '__delslice__', '__iadd__', '__imul__', '__setitem__', '__setslice__', 'append', 'extend', 'insert', 'pop', 'remove', 'reverse', 'sort']
|
||||
|
||||
|
||||
## Template methods
|
||||
def wrapMethod(methodName):
|
||||
return lambda self, *a, **k: getattr(self._data_, methodName)(*a, **k)
|
||||
|
||||
def protectMethod(methodName):
|
||||
return lambda self, *a, **k: protect(getattr(self._data_, methodName)(*a, **k))
|
||||
|
||||
def error(self, *args, **kargs):
|
||||
raise Exception("Can not modify read-only list.")
|
||||
|
||||
|
||||
## Directly (and explicitly) wrap some methods from _data_
|
||||
## Many of these methods can not be intercepted using __getattribute__, so they
|
||||
## must be implemented explicitly
|
||||
for methodName in wrapMethods:
|
||||
locals()[methodName] = wrapMethod(methodName)
|
||||
|
||||
## Wrap some methods from _data_ with the results converted to protected objects
|
||||
for methodName in protectMethods:
|
||||
locals()[methodName] = protectMethod(methodName)
|
||||
|
||||
## Disable any methods that could change data in the list
|
||||
for methodName in disableMethods:
|
||||
locals()[methodName] = error
|
||||
|
||||
|
||||
## Add a few extra methods.
|
||||
def __iter__(self):
|
||||
for item in self._data_:
|
||||
yield protect(item)
|
||||
|
||||
|
||||
def __add__(self, op):
|
||||
if isinstance(op, ProtectedList):
|
||||
return protect(self._data_.__add__(op._data_))
|
||||
elif isinstance(op, list):
|
||||
return protect(self._data_.__add__(op))
|
||||
else:
|
||||
raise TypeError("Argument must be a list.")
|
||||
|
||||
def __radd__(self, op):
|
||||
if isinstance(op, ProtectedList):
|
||||
return protect(op._data_.__add__(self._data_))
|
||||
elif isinstance(op, list):
|
||||
return protect(op.__add__(self._data_))
|
||||
else:
|
||||
raise TypeError("Argument must be a list.")
|
||||
|
||||
def deepcopy(self):
|
||||
return copy.deepcopy(self._data_)
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
return copy.deepcopy(self._data_, memo)
|
||||
|
||||
def poop(self):
|
||||
raise Exception("This is a list. It does not poop.")
|
||||
|
||||
|
||||
class ProtectedTuple(collections.Sequence):
|
||||
"""
|
||||
A class allowing read-only 'view' of a tuple.
|
||||
The object can be treated like a normal tuple, but its contents will be returned as protected objects.
|
||||
|
||||
Note: It would be nice if we could inherit from list or tuple so that isinstance checks would work.
|
||||
However, doing this causes tuple(obj) to return unprotected results (importantly, this means
|
||||
unpacking into function arguments will also fail)
|
||||
"""
|
||||
def __init__(self, data):
|
||||
self._data_ = data
|
||||
|
||||
## List of methods to directly wrap from _data_
|
||||
wrapMethods = ['__contains__', '__eq__', '__format__', '__ge__', '__getnewargs__', '__gt__', '__hash__', '__le__', '__len__', '__lt__', '__ne__', '__reduce__', '__reduce_ex__', '__repr__', '__str__', 'count', 'index']
|
||||
|
||||
## List of methods which wrap from _data_ but return protected results
|
||||
protectMethods = ['__getitem__', '__getslice__', '__iter__', '__add__', '__mul__', '__reversed__', '__rmul__']
|
||||
|
||||
|
||||
## Template methods
|
||||
def wrapMethod(methodName):
|
||||
return lambda self, *a, **k: getattr(self._data_, methodName)(*a, **k)
|
||||
|
||||
def protectMethod(methodName):
|
||||
return lambda self, *a, **k: protect(getattr(self._data_, methodName)(*a, **k))
|
||||
|
||||
|
||||
## Directly (and explicitly) wrap some methods from _data_
|
||||
## Many of these methods can not be intercepted using __getattribute__, so they
|
||||
## must be implemented explicitly
|
||||
for methodName in wrapMethods:
|
||||
locals()[methodName] = wrapMethod(methodName)
|
||||
|
||||
## Wrap some methods from _data_ with the results converted to protected objects
|
||||
for methodName in protectMethods:
|
||||
locals()[methodName] = protectMethod(methodName)
|
||||
|
||||
|
||||
## Add a few extra methods.
|
||||
def deepcopy(self):
|
||||
return copy.deepcopy(self._data_)
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
return copy.deepcopy(self._data_, memo)
|
||||
|
||||
|
||||
|
||||
def protect(obj):
|
||||
if isinstance(obj, dict):
|
||||
return ProtectedDict(obj)
|
||||
elif isinstance(obj, list):
|
||||
return ProtectedList(obj)
|
||||
elif isinstance(obj, tuple):
|
||||
return ProtectedTuple(obj)
|
||||
else:
|
||||
return obj
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
d = {'x': 1, 'y': [1,2], 'z': ({'a': 2, 'b': [3,4], 'c': (5,6)}, 1, 2)}
|
||||
dp = protect(d)
|
||||
|
||||
l = [1, 'x', ['a', 'b'], ('c', 'd'), {'x': 1, 'y': 2}]
|
||||
lp = protect(l)
|
||||
|
||||
t = (1, 'x', ['a', 'b'], ('c', 'd'), {'x': 1, 'y': 2})
|
||||
tp = protect(t)
|
24
setup.py
24
setup.py
@ -1,4 +1,10 @@
|
||||
from distutils.core import setup
|
||||
import os
|
||||
|
||||
## generate list of all sub-packages
|
||||
subdirs = [['pyqtgraph'] + i[0].split(os.path.sep)[1:] for i in os.walk('.') if '__init__.py' in i[2]]
|
||||
subdirs = filter(lambda p: len(p) == 1 or p[1] != 'build', subdirs)
|
||||
all_packages = ['.'.join(p) for p in subdirs]
|
||||
|
||||
setup(name='pyqtgraph',
|
||||
version='',
|
||||
@ -8,24 +14,8 @@ setup(name='pyqtgraph',
|
||||
author='Luke Campagnola',
|
||||
author_email='luke.campagnola@gmail.com',
|
||||
url='',
|
||||
packages=['pyqtgraph', 'pyqtgraph.console', 'pyqtgraph.graphicsItems', 'pyqtgraph.widgets', 'pyqtgraph.metaarray', 'pyqtgraph.parametertree', 'pyqtgraph.flowchart', 'pyqtgraph.imageview', 'pyqtgraph.dockarea', 'pyqtgraph.examples', 'pyqtgraph.canvas', 'pyqtgraph.exporters', 'pyqtgraph.GraphicsScene', 'pyqtgraph.multiprocess', 'pyqtgraph.opengl'],
|
||||
packages=all_packages,
|
||||
package_dir = {'pyqtgraph': '.'},
|
||||
package_data={'pyqtgraph': ['graphicsItems/PlotItem/*.png']},
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
#Package: python-pyqtgraph
|
||||
#Version: 196
|
||||
#Section: custom
|
||||
#Priority: optional
|
||||
#Architecture: all
|
||||
#Essential: no
|
||||
#Installed-Size: 4652
|
||||
#Maintainer: Luke Campagnola <luke.campagnola@gmail.com>
|
||||
#Homepage: http://luke.campagnola.me/code/pyqtgraph
|
||||
#Depends: python (>= 2.7), python-qt4 | python-pyside, python-scipy
|
||||
#Suggests: python-opengl, python-qt4-gl
|
||||
#Description: Scientific Graphics and GUI Library for Python
|
||||
#PyQtGraph is a pure-python graphics and GUI library built on PyQt4 and numpy. It is intended for use in mathematics / scientific / engineering applications. Despite being written entirely in python, the library is very fast due to its heavy leverage of numpy for number crunching and Qt's GraphicsView framework for fast display.
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pyqtgraph.Qt import QtGui, QtCore
|
||||
from collections import OrderedDict
|
||||
from pyqtgraph.pgcollections import OrderedDict
|
||||
import types, traceback
|
||||
import numpy as np
|
||||
|
||||
|
@ -4,7 +4,6 @@ from .GraphicsView import GraphicsView
|
||||
from pyqtgraph.graphicsItems.GradientEditorItem import GradientEditorItem
|
||||
import weakref
|
||||
import numpy as np
|
||||
import collections
|
||||
|
||||
__all__ = ['TickSlider', 'GradientWidget', 'BlackWhiteSlider']
|
||||
|
||||
@ -53,525 +52,3 @@ class GradientWidget(GraphicsView):
|
||||
return getattr(self.item, attr)
|
||||
|
||||
|
||||
|
||||
#Gradients = collections.OrderedDict([
|
||||
#('thermal', {'ticks': [(0.3333, (185, 0, 0, 255)), (0.6666, (255, 220, 0, 255)), (1, (255, 255, 255, 255)), (0, (0, 0, 0, 255))], 'mode': 'rgb'}),
|
||||
#('flame', {'ticks': [(0.2, (7, 0, 220, 255)), (0.5, (236, 0, 134, 255)), (0.8, (246, 246, 0, 255)), (1.0, (255, 255, 255, 255)), (0.0, (0, 0, 0, 255))], 'mode': 'rgb'}),
|
||||
#('yellowy', {'ticks': [(0.0, (0, 0, 0, 255)), (0.2328863796753704, (32, 0, 129, 255)), (0.8362738179251941, (255, 255, 0, 255)), (0.5257586450247, (115, 15, 255, 255)), (1.0, (255, 255, 255, 255))], 'mode': 'rgb'} ),
|
||||
#('bipolar', {'ticks': [(0.0, (0, 255, 255, 255)), (1.0, (255, 255, 0, 255)), (0.5, (0, 0, 0, 255)), (0.25, (0, 0, 255, 255)), (0.75, (255, 0, 0, 255))], 'mode': 'rgb'}),
|
||||
#('spectrum', {'ticks': [(1.0, (255, 0, 255, 255)), (0.0, (255, 0, 0, 255))], 'mode': 'hsv'}),
|
||||
#('cyclic', {'ticks': [(0.0, (255, 0, 4, 255)), (1.0, (255, 0, 0, 255))], 'mode': 'hsv'}),
|
||||
#('greyclip', {'ticks': [(0.0, (0, 0, 0, 255)), (0.99, (255, 255, 255, 255)), (1.0, (255, 0, 0, 255))], 'mode': 'rgb'}),
|
||||
#])
|
||||
|
||||
|
||||
#class TickSlider(GraphicsView):
|
||||
#def __init__(self, parent=None, orientation='bottom', allowAdd=True, **kargs):
|
||||
#self.orientation = orientation
|
||||
#self.length = 100
|
||||
#self.tickSize = 15
|
||||
#self.ticks = {}
|
||||
#self.maxDim = 20
|
||||
#GraphicsView.__init__(self, parent, useOpenGL=False)
|
||||
#self.allowAdd = allowAdd
|
||||
##self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
|
||||
##self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
|
||||
##self.setTransformationAnchor(QtGui.QGraphicsView.NoAnchor)
|
||||
##self.setResizeAnchor(QtGui.QGraphicsView.AnchorViewCenter)
|
||||
#self.setRenderHints(QtGui.QPainter.Antialiasing | QtGui.QPainter.TextAntialiasing)
|
||||
#self.orientations = {
|
||||
#'left': (270, 1, -1),
|
||||
#'right': (270, 1, 1),
|
||||
#'top': (0, 1, -1),
|
||||
#'bottom': (0, 1, 1)
|
||||
#}
|
||||
|
||||
##self.scene = QtGui.QGraphicsScene()
|
||||
##self.setScene(self.scene)
|
||||
|
||||
#self.setOrientation(orientation)
|
||||
#self.setFrameStyle(QtGui.QFrame.NoFrame | QtGui.QFrame.Plain)
|
||||
#self.setBackgroundRole(QtGui.QPalette.NoRole)
|
||||
#self.setMouseTracking(True)
|
||||
|
||||
|
||||
#def keyPressEvent(self, ev):
|
||||
#ev.ignore()
|
||||
|
||||
#def setMaxDim(self, mx=None):
|
||||
#if mx is None:
|
||||
#mx = self.maxDim
|
||||
#else:
|
||||
#self.maxDim = mx
|
||||
|
||||
#if self.orientation in ['bottom', 'top']:
|
||||
#self.setFixedHeight(mx)
|
||||
#self.setMaximumWidth(16777215)
|
||||
#else:
|
||||
#self.setFixedWidth(mx)
|
||||
#self.setMaximumHeight(16777215)
|
||||
|
||||
#def setOrientation(self, ort):
|
||||
#self.orientation = ort
|
||||
#self.resetTransform()
|
||||
#self.rotate(self.orientations[ort][0])
|
||||
#self.scale(*self.orientations[ort][1:])
|
||||
#self.setMaxDim()
|
||||
|
||||
#def addTick(self, x, color=None, movable=True):
|
||||
#if color is None:
|
||||
#color = QtGui.QColor(255,255,255)
|
||||
#tick = Tick(self, [x*self.length, 0], color, movable, self.tickSize)
|
||||
#self.ticks[tick] = x
|
||||
#self.scene.addItem(tick)
|
||||
#return tick
|
||||
|
||||
#def removeTick(self, tick):
|
||||
#del self.ticks[tick]
|
||||
#self.scene.removeItem(tick)
|
||||
|
||||
#def tickMoved(self, tick, pos):
|
||||
##print "tick changed"
|
||||
### Correct position of tick if it has left bounds.
|
||||
#newX = min(max(0, pos.x()), self.length)
|
||||
#pos.setX(newX)
|
||||
#tick.setPos(pos)
|
||||
#self.ticks[tick] = float(newX) / self.length
|
||||
|
||||
#def tickClicked(self, tick, ev):
|
||||
#if ev.button() == QtCore.Qt.RightButton:
|
||||
#self.removeTick(tick)
|
||||
|
||||
#def widgetLength(self):
|
||||
#if self.orientation in ['bottom', 'top']:
|
||||
#return self.width()
|
||||
#else:
|
||||
#return self.height()
|
||||
|
||||
#def resizeEvent(self, ev):
|
||||
#wlen = max(40, self.widgetLength())
|
||||
#self.setLength(wlen-self.tickSize)
|
||||
#bounds = self.scene().itemsBoundingRect()
|
||||
#bounds.setLeft(min(-self.tickSize*0.5, bounds.left()))
|
||||
#bounds.setRight(max(self.length + self.tickSize, bounds.right()))
|
||||
##bounds.setTop(min(bounds.top(), self.tickSize))
|
||||
##bounds.setBottom(max(0, bounds.bottom()))
|
||||
#self.setSceneRect(bounds)
|
||||
#self.fitInView(bounds, QtCore.Qt.KeepAspectRatio)
|
||||
|
||||
#def setLength(self, newLen):
|
||||
#for t, x in self.ticks.items():
|
||||
#t.setPos(x * newLen, t.pos().y())
|
||||
#self.length = float(newLen)
|
||||
|
||||
#def mousePressEvent(self, ev):
|
||||
#QtGui.QGraphicsView.mousePressEvent(self, ev)
|
||||
#self.ignoreRelease = False
|
||||
#for i in self.items(ev.pos()):
|
||||
#if isinstance(i, Tick):
|
||||
#self.ignoreRelease = True
|
||||
#break
|
||||
##if len(self.items(ev.pos())) > 0: ## Let items handle their own clicks
|
||||
##self.ignoreRelease = True
|
||||
|
||||
#def mouseReleaseEvent(self, ev):
|
||||
#QtGui.QGraphicsView.mouseReleaseEvent(self, ev)
|
||||
#if self.ignoreRelease:
|
||||
#return
|
||||
|
||||
#pos = self.mapToScene(ev.pos())
|
||||
|
||||
#if ev.button() == QtCore.Qt.LeftButton and self.allowAdd:
|
||||
#if pos.x() < 0 or pos.x() > self.length:
|
||||
#return
|
||||
#if pos.y() < 0 or pos.y() > self.tickSize:
|
||||
#return
|
||||
#pos.setX(min(max(pos.x(), 0), self.length))
|
||||
#self.addTick(pos.x()/self.length)
|
||||
#elif ev.button() == QtCore.Qt.RightButton:
|
||||
#self.showMenu(ev)
|
||||
|
||||
|
||||
#def showMenu(self, ev):
|
||||
#pass
|
||||
|
||||
#def setTickColor(self, tick, color):
|
||||
#tick = self.getTick(tick)
|
||||
#tick.color = color
|
||||
#tick.setBrush(QtGui.QBrush(QtGui.QColor(tick.color)))
|
||||
|
||||
#def setTickValue(self, tick, val):
|
||||
#tick = self.getTick(tick)
|
||||
#val = min(max(0.0, val), 1.0)
|
||||
#x = val * self.length
|
||||
#pos = tick.pos()
|
||||
#pos.setX(x)
|
||||
#tick.setPos(pos)
|
||||
#self.ticks[tick] = val
|
||||
|
||||
#def tickValue(self, tick):
|
||||
#tick = self.getTick(tick)
|
||||
#return self.ticks[tick]
|
||||
|
||||
#def getTick(self, tick):
|
||||
#if type(tick) is int:
|
||||
#tick = self.listTicks()[tick][0]
|
||||
#return tick
|
||||
|
||||
#def mouseMoveEvent(self, ev):
|
||||
#QtGui.QGraphicsView.mouseMoveEvent(self, ev)
|
||||
##print ev.pos(), ev.buttons()
|
||||
|
||||
#def listTicks(self):
|
||||
#ticks = self.ticks.items()
|
||||
#ticks.sort(lambda a,b: cmp(a[1], b[1]))
|
||||
#return ticks
|
||||
|
||||
|
||||
#class GradientWidget(TickSlider):
|
||||
|
||||
#sigGradientChanged = QtCore.Signal(object)
|
||||
|
||||
#def __init__(self, *args, **kargs):
|
||||
#self.currentTick = None
|
||||
#self.currentTickColor = None
|
||||
#self.rectSize = 15
|
||||
#self.gradRect = QtGui.QGraphicsRectItem(QtCore.QRectF(0, -self.rectSize, 100, self.rectSize))
|
||||
#self.backgroundRect = QtGui.QGraphicsRectItem(QtCore.QRectF(0, -self.rectSize, 100, self.rectSize))
|
||||
#self.backgroundRect.setBrush(QtGui.QBrush(QtCore.Qt.DiagCrossPattern))
|
||||
#self.colorMode = 'rgb'
|
||||
#TickSlider.__init__(self, *args, **kargs)
|
||||
#self.colorDialog = QtGui.QColorDialog()
|
||||
#self.colorDialog.setOption(QtGui.QColorDialog.ShowAlphaChannel, True)
|
||||
#self.colorDialog.setOption(QtGui.QColorDialog.DontUseNativeDialog, True)
|
||||
|
||||
#self.colorDialog.currentColorChanged.connect(self.currentColorChanged)
|
||||
#self.colorDialog.rejected.connect(self.currentColorRejected)
|
||||
|
||||
##self.gradient = QtGui.QLinearGradient(QtCore.QPointF(0,0), QtCore.QPointF(100,0))
|
||||
#self.scene.addItem(self.backgroundRect)
|
||||
#self.scene.addItem(self.gradRect)
|
||||
|
||||
#self.setMaxDim(self.rectSize + self.tickSize)
|
||||
|
||||
##self.btn = QtGui.QPushButton('RGB')
|
||||
##self.btnProxy = self.scene.addWidget(self.btn)
|
||||
##self.btnProxy.setFlag(self.btnProxy.ItemIgnoresTransformations)
|
||||
##self.btnProxy.scale(0.7, 0.7)
|
||||
##self.btnProxy.translate(-self.btnProxy.sceneBoundingRect().width()+self.tickSize/2., 0)
|
||||
##if self.orientation == 'bottom':
|
||||
##self.btnProxy.translate(0, -self.rectSize)
|
||||
#self.rgbAction = QtGui.QAction('RGB', self)
|
||||
#self.rgbAction.setCheckable(True)
|
||||
#self.rgbAction.triggered.connect(lambda: self.setColorMode('rgb'))
|
||||
#self.hsvAction = QtGui.QAction('HSV', self)
|
||||
#self.hsvAction.setCheckable(True)
|
||||
#self.hsvAction.triggered.connect(lambda: self.setColorMode('hsv'))
|
||||
|
||||
#self.menu = QtGui.QMenu()
|
||||
|
||||
### build context menu of gradients
|
||||
#global Gradients
|
||||
#for g in Gradients:
|
||||
#px = QtGui.QPixmap(100, 15)
|
||||
#p = QtGui.QPainter(px)
|
||||
#self.restoreState(Gradients[g])
|
||||
#grad = self.getGradient()
|
||||
#brush = QtGui.QBrush(grad)
|
||||
#p.fillRect(QtCore.QRect(0, 0, 100, 15), brush)
|
||||
#p.end()
|
||||
#label = QtGui.QLabel()
|
||||
#label.setPixmap(px)
|
||||
#label.setContentsMargins(1, 1, 1, 1)
|
||||
#act = QtGui.QWidgetAction(self)
|
||||
#act.setDefaultWidget(label)
|
||||
#act.triggered.connect(self.contextMenuClicked)
|
||||
#act.name = g
|
||||
#self.menu.addAction(act)
|
||||
|
||||
#self.menu.addSeparator()
|
||||
#self.menu.addAction(self.rgbAction)
|
||||
#self.menu.addAction(self.hsvAction)
|
||||
|
||||
|
||||
#for t in self.ticks.keys():
|
||||
#self.removeTick(t)
|
||||
#self.addTick(0, QtGui.QColor(0,0,0), True)
|
||||
#self.addTick(1, QtGui.QColor(255,0,0), True)
|
||||
#self.setColorMode('rgb')
|
||||
#self.updateGradient()
|
||||
|
||||
#def showMenu(self, ev):
|
||||
#self.menu.popup(ev.globalPos())
|
||||
|
||||
#def contextMenuClicked(self, b):
|
||||
#global Gradients
|
||||
#act = self.sender()
|
||||
#self.restoreState(Gradients[act.name])
|
||||
|
||||
#def setColorMode(self, cm):
|
||||
#if cm not in ['rgb', 'hsv']:
|
||||
#raise Exception("Unknown color mode %s. Options are 'rgb' and 'hsv'." % str(cm))
|
||||
|
||||
#try:
|
||||
#self.rgbAction.blockSignals(True)
|
||||
#self.hsvAction.blockSignals(True)
|
||||
#self.rgbAction.setChecked(cm == 'rgb')
|
||||
#self.hsvAction.setChecked(cm == 'hsv')
|
||||
#finally:
|
||||
#self.rgbAction.blockSignals(False)
|
||||
#self.hsvAction.blockSignals(False)
|
||||
#self.colorMode = cm
|
||||
#self.updateGradient()
|
||||
|
||||
#def updateGradient(self):
|
||||
#self.gradient = self.getGradient()
|
||||
#self.gradRect.setBrush(QtGui.QBrush(self.gradient))
|
||||
#self.sigGradientChanged.emit(self)
|
||||
|
||||
#def setLength(self, newLen):
|
||||
#TickSlider.setLength(self, newLen)
|
||||
#self.backgroundRect.setRect(0, -self.rectSize, newLen, self.rectSize)
|
||||
#self.gradRect.setRect(0, -self.rectSize, newLen, self.rectSize)
|
||||
#self.updateGradient()
|
||||
|
||||
#def currentColorChanged(self, color):
|
||||
#if color.isValid() and self.currentTick is not None:
|
||||
#self.setTickColor(self.currentTick, color)
|
||||
#self.updateGradient()
|
||||
|
||||
#def currentColorRejected(self):
|
||||
#self.setTickColor(self.currentTick, self.currentTickColor)
|
||||
#self.updateGradient()
|
||||
|
||||
#def tickClicked(self, tick, ev):
|
||||
#if ev.button() == QtCore.Qt.LeftButton:
|
||||
#if not tick.colorChangeAllowed:
|
||||
#return
|
||||
#self.currentTick = tick
|
||||
#self.currentTickColor = tick.color
|
||||
#self.colorDialog.setCurrentColor(tick.color)
|
||||
#self.colorDialog.open()
|
||||
##color = QtGui.QColorDialog.getColor(tick.color, self, "Select Color", QtGui.QColorDialog.ShowAlphaChannel)
|
||||
##if color.isValid():
|
||||
##self.setTickColor(tick, color)
|
||||
##self.updateGradient()
|
||||
#elif ev.button() == QtCore.Qt.RightButton:
|
||||
#if not tick.removeAllowed:
|
||||
#return
|
||||
#if len(self.ticks) > 2:
|
||||
#self.removeTick(tick)
|
||||
#self.updateGradient()
|
||||
|
||||
#def tickMoved(self, tick, pos):
|
||||
#TickSlider.tickMoved(self, tick, pos)
|
||||
#self.updateGradient()
|
||||
|
||||
|
||||
#def getGradient(self):
|
||||
#g = QtGui.QLinearGradient(QtCore.QPointF(0,0), QtCore.QPointF(self.length,0))
|
||||
#if self.colorMode == 'rgb':
|
||||
#ticks = self.listTicks()
|
||||
#g.setStops([(x, QtGui.QColor(t.color)) for t,x in ticks])
|
||||
#elif self.colorMode == 'hsv': ## HSV mode is approximated for display by interpolating 10 points between each stop
|
||||
#ticks = self.listTicks()
|
||||
#stops = []
|
||||
#stops.append((ticks[0][1], ticks[0][0].color))
|
||||
#for i in range(1,len(ticks)):
|
||||
#x1 = ticks[i-1][1]
|
||||
#x2 = ticks[i][1]
|
||||
#dx = (x2-x1) / 10.
|
||||
#for j in range(1,10):
|
||||
#x = x1 + dx*j
|
||||
#stops.append((x, self.getColor(x)))
|
||||
#stops.append((x2, self.getColor(x2)))
|
||||
#g.setStops(stops)
|
||||
#return g
|
||||
|
||||
#def getColor(self, x, toQColor=True):
|
||||
#ticks = self.listTicks()
|
||||
#if x <= ticks[0][1]:
|
||||
#c = ticks[0][0].color
|
||||
#if toQColor:
|
||||
#return QtGui.QColor(c) # always copy colors before handing them out
|
||||
#else:
|
||||
#return (c.red(), c.green(), c.blue(), c.alpha())
|
||||
#if x >= ticks[-1][1]:
|
||||
#c = ticks[-1][0].color
|
||||
#if toQColor:
|
||||
#return QtGui.QColor(c) # always copy colors before handing them out
|
||||
#else:
|
||||
#return (c.red(), c.green(), c.blue(), c.alpha())
|
||||
|
||||
#x2 = ticks[0][1]
|
||||
#for i in range(1,len(ticks)):
|
||||
#x1 = x2
|
||||
#x2 = ticks[i][1]
|
||||
#if x1 <= x and x2 >= x:
|
||||
#break
|
||||
|
||||
#dx = (x2-x1)
|
||||
#if dx == 0:
|
||||
#f = 0.
|
||||
#else:
|
||||
#f = (x-x1) / dx
|
||||
#c1 = ticks[i-1][0].color
|
||||
#c2 = ticks[i][0].color
|
||||
#if self.colorMode == 'rgb':
|
||||
#r = c1.red() * (1.-f) + c2.red() * f
|
||||
#g = c1.green() * (1.-f) + c2.green() * f
|
||||
#b = c1.blue() * (1.-f) + c2.blue() * f
|
||||
#a = c1.alpha() * (1.-f) + c2.alpha() * f
|
||||
#if toQColor:
|
||||
#return QtGui.QColor(r, g, b,a)
|
||||
#else:
|
||||
#return (r,g,b,a)
|
||||
#elif self.colorMode == 'hsv':
|
||||
#h1,s1,v1,_ = c1.getHsv()
|
||||
#h2,s2,v2,_ = c2.getHsv()
|
||||
#h = h1 * (1.-f) + h2 * f
|
||||
#s = s1 * (1.-f) + s2 * f
|
||||
#v = v1 * (1.-f) + v2 * f
|
||||
#c = QtGui.QColor()
|
||||
#c.setHsv(h,s,v)
|
||||
#if toQColor:
|
||||
#return c
|
||||
#else:
|
||||
#return (c.red(), c.green(), c.blue(), c.alpha())
|
||||
|
||||
#def getLookupTable(self, nPts, alpha=True):
|
||||
#"""Return an RGB/A lookup table."""
|
||||
#if alpha:
|
||||
#table = np.empty((nPts,4), dtype=np.ubyte)
|
||||
#else:
|
||||
#table = np.empty((nPts,3), dtype=np.ubyte)
|
||||
|
||||
#for i in range(nPts):
|
||||
#x = float(i)/(nPts-1)
|
||||
#color = self.getColor(x, toQColor=False)
|
||||
#table[i] = color[:table.shape[1]]
|
||||
|
||||
#return table
|
||||
|
||||
|
||||
|
||||
#def mouseReleaseEvent(self, ev):
|
||||
#TickSlider.mouseReleaseEvent(self, ev)
|
||||
#self.updateGradient()
|
||||
|
||||
#def addTick(self, x, color=None, movable=True):
|
||||
#if color is None:
|
||||
#color = self.getColor(x)
|
||||
#t = TickSlider.addTick(self, x, color=color, movable=movable)
|
||||
#t.colorChangeAllowed = True
|
||||
#t.removeAllowed = True
|
||||
#return t
|
||||
|
||||
#def saveState(self):
|
||||
#ticks = []
|
||||
#for t in self.ticks:
|
||||
#c = t.color
|
||||
#ticks.append((self.ticks[t], (c.red(), c.green(), c.blue(), c.alpha())))
|
||||
#state = {'mode': self.colorMode, 'ticks': ticks}
|
||||
#return state
|
||||
|
||||
#def restoreState(self, state):
|
||||
#self.setColorMode(state['mode'])
|
||||
#for t in self.ticks.keys():
|
||||
#self.removeTick(t)
|
||||
#for t in state['ticks']:
|
||||
#c = QtGui.QColor(*t[1])
|
||||
#self.addTick(t[0], c)
|
||||
#self.updateGradient()
|
||||
|
||||
|
||||
|
||||
#class BlackWhiteSlider(GradientWidget):
|
||||
#def __init__(self, parent):
|
||||
#GradientWidget.__init__(self, parent)
|
||||
#self.getTick(0).colorChangeAllowed = False
|
||||
#self.getTick(1).colorChangeAllowed = False
|
||||
#self.allowAdd = False
|
||||
#self.setTickColor(self.getTick(1), QtGui.QColor(255,255,255))
|
||||
#self.setOrientation('right')
|
||||
|
||||
#def getLevels(self):
|
||||
#return (self.tickValue(0), self.tickValue(1))
|
||||
|
||||
#def setLevels(self, black, white):
|
||||
#self.setTickValue(0, black)
|
||||
#self.setTickValue(1, white)
|
||||
|
||||
|
||||
|
||||
|
||||
#class GammaWidget(TickSlider):
|
||||
#pass
|
||||
|
||||
|
||||
#class Tick(QtGui.QGraphicsPolygonItem):
|
||||
#def __init__(self, view, pos, color, movable=True, scale=10):
|
||||
##QObjectWorkaround.__init__(self)
|
||||
#self.movable = movable
|
||||
#self.view = weakref.ref(view)
|
||||
#self.scale = scale
|
||||
#self.color = color
|
||||
##self.endTick = endTick
|
||||
#self.pg = QtGui.QPolygonF([QtCore.QPointF(0,0), QtCore.QPointF(-scale/3**0.5,scale), QtCore.QPointF(scale/3**0.5,scale)])
|
||||
#QtGui.QGraphicsPolygonItem.__init__(self, self.pg)
|
||||
#self.setPos(pos[0], pos[1])
|
||||
#self.setFlags(QtGui.QGraphicsItem.ItemIsMovable | QtGui.QGraphicsItem.ItemIsSelectable)
|
||||
#self.setBrush(QtGui.QBrush(QtGui.QColor(self.color)))
|
||||
#if self.movable:
|
||||
#self.setZValue(1)
|
||||
#else:
|
||||
#self.setZValue(0)
|
||||
|
||||
##def x(self):
|
||||
##return self.pos().x()/100.
|
||||
|
||||
#def mouseMoveEvent(self, ev):
|
||||
##print self, "move", ev.scenePos()
|
||||
#if not self.movable:
|
||||
#return
|
||||
#if not ev.buttons() & QtCore.Qt.LeftButton:
|
||||
#return
|
||||
|
||||
|
||||
#newPos = ev.scenePos() + self.mouseOffset
|
||||
#newPos.setY(self.pos().y())
|
||||
##newPos.setX(min(max(newPos.x(), 0), 100))
|
||||
#self.setPos(newPos)
|
||||
#self.view().tickMoved(self, newPos)
|
||||
#self.movedSincePress = True
|
||||
##self.emit(QtCore.SIGNAL('tickChanged'), self)
|
||||
#ev.accept()
|
||||
|
||||
#def mousePressEvent(self, ev):
|
||||
#self.movedSincePress = False
|
||||
#if ev.button() == QtCore.Qt.LeftButton:
|
||||
#ev.accept()
|
||||
#self.mouseOffset = self.pos() - ev.scenePos()
|
||||
#self.pressPos = ev.scenePos()
|
||||
#elif ev.button() == QtCore.Qt.RightButton:
|
||||
#ev.accept()
|
||||
##if self.endTick:
|
||||
##return
|
||||
##self.view.tickChanged(self, delete=True)
|
||||
|
||||
#def mouseReleaseEvent(self, ev):
|
||||
##print self, "release", ev.scenePos()
|
||||
#if not self.movedSincePress:
|
||||
#self.view().tickClicked(self, ev)
|
||||
|
||||
##if ev.button() == QtCore.Qt.LeftButton and ev.scenePos() == self.pressPos:
|
||||
##color = QtGui.QColorDialog.getColor(self.color, None, "Select Color", QtGui.QColorDialog.ShowAlphaChannel)
|
||||
##if color.isValid():
|
||||
##self.color = color
|
||||
##self.setBrush(QtGui.QBrush(QtGui.QColor(self.color)))
|
||||
###self.emit(QtCore.SIGNAL('tickChanged'), self)
|
||||
##self.view.tickChanged(self)
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -120,6 +120,14 @@ class GraphicsView(QtGui.QGraphicsView):
|
||||
self.scaleCenter = False ## should scaling center around view center (True) or mouse click (False)
|
||||
self.clickAccepted = False
|
||||
|
||||
def setAntialiasing(self, aa):
|
||||
"""Enable or disable default antialiasing.
|
||||
Note that this will only affect items that do not specify their own antialiasing options."""
|
||||
if aa:
|
||||
self.setRenderHints(self.renderHints() | QtGui.QPainter.Antialiasing)
|
||||
else:
|
||||
self.setRenderHints(self.renderHints() & ~QtGui.QPainter.Antialiasing)
|
||||
|
||||
def setBackground(self, background):
|
||||
"""
|
||||
Set the background color of the GraphicsView.
|
||||
|
Loading…
Reference in New Issue
Block a user