ViewBox will now correctly auto-range when an item's position or transform changes.

This commit is contained in:
Luke Campagnola 2012-10-31 01:57:00 -04:00
parent 679de86509
commit 2c679dfbcc
3 changed files with 96 additions and 66 deletions

View File

@ -433,4 +433,18 @@ class GraphicsItem(object):
"""
Called whenever the transformation matrix of the view has changed.
"""
pass
pass
#def prepareGeometryChange(self):
#self._qtBaseClass.prepareGeometryChange(self)
#self.informViewBoundsChanged()
def informViewBoundsChanged(self):
"""
Inform this item's container ViewBox that the bounds of this item have changed.
This is used by ViewBox to react if auto-range is enabled.
"""
view = self.getViewBox()
if view is not None and hasattr(view, 'implements') and view.implements('ViewBox'):
view.itemBoundsChanged(self) ## inform view so it can update its range if it wants

View File

@ -11,10 +11,13 @@ class GraphicsObject(GraphicsItem, QtGui.QGraphicsObject):
_qtBaseClass = QtGui.QGraphicsObject
def __init__(self, *args):
QtGui.QGraphicsObject.__init__(self, *args)
self.setFlag(self.ItemSendsGeometryChanges)
GraphicsItem.__init__(self)
def itemChange(self, change, value):
ret = QtGui.QGraphicsObject.itemChange(self, change, value)
if change in [self.ItemParentHasChanged, self.ItemSceneHasChanged]:
self._updateView()
if change in [self.ItemPositionHasChanged, self.ItemTransformHasChanged]:
self.informViewBoundsChanged()
return ret

View File

@ -109,6 +109,7 @@ class ViewBox(GraphicsWidget):
'background': None,
}
self._updatingRange = False ## Used to break recursive loops. See updateAutoRange.
self.setFlag(self.ItemClipsChildrenToShape)
@ -340,6 +341,7 @@ class ViewBox(GraphicsWidget):
============= =====================================================================
"""
changes = {}
if rect is not None:
@ -471,6 +473,7 @@ class ViewBox(GraphicsWidget):
#if not enable:
#import traceback
#traceback.print_stack()
if enable is True:
enable = 1.0
@ -520,74 +523,84 @@ class ViewBox(GraphicsWidget):
self.updateAutoRange()
def updateAutoRange(self):
targetRect = self.viewRange()
if not any(self.state['autoRange']):
## Break recursive loops when auto-ranging.
## This is needed because some items change their size in response
## to a view change.
if self._updatingRange:
return
fractionVisible = self.state['autoRange'][:]
for i in [0,1]:
if type(fractionVisible[i]) is bool:
fractionVisible[i] = 1.0
childRange = None
order = [0,1]
if self.state['autoVisibleOnly'][0] is True:
order = [1,0]
args = {}
for ax in order:
if self.state['autoRange'][ax] is False:
continue
if self.state['autoVisibleOnly'][ax]:
oRange = [None, None]
oRange[ax] = targetRect[1-ax]
childRange = self.childrenBounds(frac=fractionVisible, orthoRange=oRange)
self._updatingRange = True
try:
targetRect = self.viewRange()
if not any(self.state['autoRange']):
return
else:
if childRange is None:
childRange = self.childrenBounds(frac=fractionVisible)
## Make corrections to range
xr = childRange[ax]
if xr is not None:
if self.state['autoPan'][ax]:
x = sum(xr) * 0.5
#x = childRect.center().x()
w2 = (targetRect[ax][1]-targetRect[ax][0]) / 2.
#childRect.setLeft(x-w2)
#childRect.setRight(x+w2)
childRange[ax] = [x-w2, x+w2]
else:
#wp = childRect.width() * 0.02
wp = (xr[1] - xr[0]) * 0.02
#childRect = childRect.adjusted(-wp, 0, wp, 0)
childRange[ax][0] -= wp
childRange[ax][1] += wp
#targetRect[ax][0] = childRect.left()
#targetRect[ax][1] = childRect.right()
targetRect[ax] = childRange[ax]
args['xRange' if ax == 0 else 'yRange'] = targetRect[ax]
#else:
### Make corrections to Y range
#if self.state['autoPan'][1]:
#y = childRect.center().y()
#h2 = (targetRect[1][1]-targetRect[1][0]) / 2.
#childRect.setTop(y-h2)
#childRect.setBottom(y+h2)
#else:
#hp = childRect.height() * 0.02
#childRect = childRect.adjusted(0, -hp, 0, hp)
fractionVisible = self.state['autoRange'][:]
for i in [0,1]:
if type(fractionVisible[i]) is bool:
fractionVisible[i] = 1.0
childRange = None
order = [0,1]
if self.state['autoVisibleOnly'][0] is True:
order = [1,0]
args = {}
for ax in order:
if self.state['autoRange'][ax] is False:
continue
if self.state['autoVisibleOnly'][ax]:
oRange = [None, None]
oRange[ax] = targetRect[1-ax]
childRange = self.childrenBounds(frac=fractionVisible, orthoRange=oRange)
#targetRect[1][0] = childRect.top()
#targetRect[1][1] = childRect.bottom()
#args['yRange'] = targetRect[1]
if len(args) == 0:
return
args['padding'] = 0
args['disableAutoRange'] = False
#self.setRange(xRange=targetRect[0], yRange=targetRect[1], padding=0, disableAutoRange=False)
self.setRange(**args)
else:
if childRange is None:
childRange = self.childrenBounds(frac=fractionVisible)
## Make corrections to range
xr = childRange[ax]
if xr is not None:
if self.state['autoPan'][ax]:
x = sum(xr) * 0.5
#x = childRect.center().x()
w2 = (targetRect[ax][1]-targetRect[ax][0]) / 2.
#childRect.setLeft(x-w2)
#childRect.setRight(x+w2)
childRange[ax] = [x-w2, x+w2]
else:
#wp = childRect.width() * 0.02
wp = (xr[1] - xr[0]) * 0.02
#childRect = childRect.adjusted(-wp, 0, wp, 0)
childRange[ax][0] -= wp
childRange[ax][1] += wp
#targetRect[ax][0] = childRect.left()
#targetRect[ax][1] = childRect.right()
targetRect[ax] = childRange[ax]
args['xRange' if ax == 0 else 'yRange'] = targetRect[ax]
#else:
### Make corrections to Y range
#if self.state['autoPan'][1]:
#y = childRect.center().y()
#h2 = (targetRect[1][1]-targetRect[1][0]) / 2.
#childRect.setTop(y-h2)
#childRect.setBottom(y+h2)
#else:
#hp = childRect.height() * 0.02
#childRect = childRect.adjusted(0, -hp, 0, hp)
#targetRect[1][0] = childRect.top()
#targetRect[1][1] = childRect.bottom()
#args['yRange'] = targetRect[1]
if len(args) == 0:
return
args['padding'] = 0
args['disableAutoRange'] = False
#self.setRange(xRange=targetRect[0], yRange=targetRect[1], padding=0, disableAutoRange=False)
self.setRange(**args)
finally:
self._updatingRange = False
def setXLink(self, view):
"""Link this view's X axis to another view. (see LinkView)"""