def _changeFrame(self, frame): """Internal helper for setFrame() / animatedTransition(); change self._frame and returns the differences between the current items and the new ones as (newGeometry, addItems, removeItems) tuple.""" self._resetAnimation() self._frame = frame newGeometry = QtCore.QRectF(p(self.pos), frame.sizeF()) addItems = {} removeItems = dict(self._items) for key, (layer, item) in self._frameItems(frame).iteritems(): try: del removeItems[key] except KeyError: parentItem = self._contentItem(layer) item.setParentItem(parentItem) addItems[key] = (layer, item) return newGeometry, addItems, removeItems
def _resetAnimation(self): if not self._animation: return self._animation.stop() self._removeItems(self._pendingRemove) # reset parent of all animated contents: for i in range(self._animation.animationCount()): anim = self._animation.animationAt(i) for item in p(anim.targetObject).childItems(): parentItem = self._staticParents[item] # custom items are special, because they're just # moved/reparented/hidden, but not created on the fly: origParent = self._originalCustomItemState.get(item) if origParent: item.setParentItem(origParent) else: item.setParentItem(parentItem) self._animation = None self._staticParents = {}
def animatedTransition(self, sourceFrame, targetFrame): """Set up child items for an animated transition from sourceFrame to targetFrame. Set rendered frame() to the targetFrame. Return animation (QAnimation instance).""" self.setFrame(sourceFrame) if targetFrame is sourceFrame: return None # raise? # sliding transition (left/right) if Slide changes: slide = cmp(targetFrame.slide().slideIndex(), sourceFrame.slide().slideIndex()) oldGeometry = QtCore.QRectF(p(self.pos), self._frame.sizeF()) newGeometry, addItems, removeItems = self._changeFrame(targetFrame) if oldGeometry != newGeometry: self._geometryAnimation = QtCore.QPropertyAnimation(self, 'geometry', self) self._geometryAnimation.setEndValue(newGeometry) self._geometryAnimation.setDuration(100) self._animation = QtCore.QParallelAnimationGroup() self._animation.finished.connect(self._resetAnimation) fadeOut = {} fadeIn = {} slideOut = {} slideIn = {} # decide which items to slide and which to fade out/in: if not slide: # within-Slide animation, no sliding here: fadeOut = dict(removeItems) fadeIn = addItems else: for oldKey, (oldLayer, oldItem) in removeItems.iteritems(): # always slide custom items: if oldKey is oldItem: slideOut[oldKey] = (oldLayer, oldItem) continue # always fade non-Patches (e.g. backgrounds, movies, ...) if not isinstance(oldKey, presentation.Patch): fadeOut[oldKey] = (oldLayer, oldItem) continue # always fade header & footer: if (isinstance(oldKey, presentation.Patch) and oldKey.flag(presentation.Patch.FLAG_HEADER | presentation.Patch.FLAG_FOOTER)): fadeOut[oldKey] = (oldLayer, oldItem) continue slideOut[oldKey] = (oldLayer, oldItem) for newKey, (newLayer, newItem) in addItems.iteritems(): # always slide custom items: if newKey is newItem: slideIn[newKey] = (newLayer, newItem) continue # always fade non-Patches (e.g. backgrounds, movies, ...) if not isinstance(newKey, presentation.Patch): fadeIn[newKey] = (newLayer, newItem) continue # always fade header & footer: if (isinstance(newKey, presentation.Patch) and newKey.flag(presentation.Patch.FLAG_HEADER | presentation.Patch.FLAG_FOOTER)): fadeIn[newKey] = (newLayer, newItem) continue # look for pairs (oldItem, newItem) of Patches where # newKey.isSuccessorOf(oldKey) => fade out/in changed = False for oldKey, (oldLayer, oldItem) in removeItems.iteritems(): if not isinstance(oldKey, presentation.Patch): continue if newKey.isSuccessorOf(oldKey): changed = True if oldKey in slideOut: del slideOut[oldKey] else: print "not found in slideOut (fadeOut: %s): %s" % (oldKey in fadeOut, oldKey) fadeOut[oldKey] = (oldLayer, oldItem) fadeIn[newKey] = (newLayer, newItem) break if not changed: slideIn[newKey] = (newLayer, newItem) # don't fade out items that are completely covered by items that fade in: for newKey, (newLayer, newItem) in fadeIn.iteritems(): coveredRect = _frameBoundingRect(newItem) for oldKey, (oldLayer, oldItem) in fadeOut.items(): if coveredRect.contains(_frameBoundingRect(oldItem)): del fadeOut[oldKey] offset = self._frame.sizeF().width() * slide # set up property animations for sliding/fading in/out: for items, contentName, duration, propName, startValue, endValue in ( (slideOut, 'slideOut', SLIDE_DURATION, 'pos', QtCore.QPoint(0, 0), QtCore.QPoint(-offset, 0)), (slideIn, 'slideIn', SLIDE_DURATION, 'pos', QtCore.QPoint(offset, 0), QtCore.QPoint(0, 0)), (fadeOut, 'fadeOut', FADE_DURATION, 'opacity', 1.0, 0.0), (fadeIn, 'fadeIn', FADE_DURATION, 'opacity', 0.0, 1.0), ): if items: parentItems = set() for key, (layer, item) in items.iteritems(): parentItem = self._contentItem("%s-%s" % (layer, contentName)) self._staticParents[item] = item.parentItem() item.setParentItem(parentItem) parentItems.add(parentItem) for parentItem in parentItems: anim = QtCore.QPropertyAnimation(parentItem, propName, self._animation) anim.setDuration(duration) anim.setStartValue(startValue) anim.setEndValue(endValue) self._items.update(addItems) self._pendingRemove = removeItems self._animation.start() return self._animation