Source code for openalea.grapheditor.qtgraphview

# -*- python -*-
#
#       OpenAlea.Visualea: OpenAlea graphical user interface
#
#       Copyright 2006-2009 INRIA - CIRAD - INRA
#
#       File author(s): Daniel Barbeau <daniel.barbeau@sophia.inria.fr>
#
#       Distributed under the Cecill-C License.
#       See accompanying file LICENSE.txt or copy at
#           http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.html
#
#       OpenAlea WebSite : http://openalea.gforge.inria.fr
#
###############################################################################
"""Generic Qt Graph Widget"""

__license__ = "Cecill-C"
__revision__ = " $Id$ "

import weakref, types, gc, warnings
from qtpy import QtGui, QtCore, QtWidgets
from openalea.grapheditor import base, baselisteners, qtutils
from openalea.grapheditor import edgefactory

from math import sqrt


#------*************************************************------#
[docs] class Element(baselisteners.GraphElementListenerBase): """Base class for elements in a qtgraphview.View. Implements basic listeners calls for elements of a graph. A listener call is the method that is called after the main listening method (self.notify) dispatches the events. They are specified by interfaces.IGraphViewElement. :Listener calls: * position_changed(self, (posx, posy)) * add_to_view(self, view) * remove_from_view(self, view) """ #################################### # ----Instance members follow---- # #################################### def __init__(self, observed=None, graph=None): """ :Parameters: - observed (openalea.core.observer.Observed) - The item to observe. - graph (ducktype) - The graph owning the item. """ baselisteners.GraphElementListenerBase.__init__(self, observed, graph) ################################# # IGraphViewElement realisation # #################################
[docs] def get_view(self): return self.scene()
[docs] def add_to_view(self, view): """An element adds itself to the given view""" view.addItem(self)
[docs] def remove_from_view(self, view): """An element removes itself from the given view""" view.removeItem(self)
[docs] def position_changed(self, *args): """Updates the item's **graphical** position from model notifications. """ point = QtCore.QPointF(args[0], args[1]) self.setPos(point)
[docs] def lock_position(self, val=True): self.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, not val)
[docs] def default_position(self): return [0.0, 0.0]
#------*************************************************------#
[docs] class Connector(Element): def __init__(self, *args, **kwargs): Element.__init__(self, *args, **kwargs) self.setFlag(qtutils.ItemSendsGeometryChanges) # self.setFlag(ItemSendsScenePositionChanges) self.setZValue(1.5) self.highlighted = False self.__makeConnectionMouseButton = QtCore.Qt.LeftButton self.__makeConnectionModifiers = QtCore.Qt.ControlModifier
[docs] def set_connection_button(self, button): self.__makeConnectionMouseButton = button
[docs] def set_connection_modifiers(self, modifiers): self.__makeConnectionModifiers = modifiers
[docs] def set_highlighted(self, val): self.highlighted = val self.update()
[docs] def get_scene_center(self): pos = self.sceneBoundingRect().center() return [pos.x(), pos.y()]
[docs] def notify_position_change(self, pos=None): obs = self.get_observed() if pos is None: pos = self.get_scene_center() edges = [] # the following line is quirky because it relies on core.observer.Observed.listeners if hasattr(obs, "listeners"): edges = [l() for l in obs.listeners if isinstance(l(), Edge)] elif hasattr(self, "fakeParent"): # I am a defaultConnector par = self.fakeParent scene = par.scene() if scene is None: return observers = scene.get_graphical_edges_connected_to(obs) if observers: edges = [l() for l in observers if l is not None] for e in edges: e.notify(obs, ("metadata_changed", "connectorPosition", pos))
##################### # ----Qt World---- # #####################
[docs] def itemChange(self, change, value): if change & (qtutils.ItemScenePositionHasChanged | qtutils.ItemPositionHasChanged): self.notify_position_change() return value
[docs] def mousePressEvent(self, event): scene = self.scene() if (scene and event.buttons() & self.__makeConnectionMouseButton and event.modifiers() == self.__makeConnectionModifiers): scene._new_edge_start(self.get_scene_center()) else: super(self.__class__, self).mousePressEvent(event)
#------*************************************************------#
[docs] def defaultPaint(owner, painter, paintOptions, widget): rect = owner.boundingRect() painter.drawEllipse(rect)
[docs] class Vertex(Element): """An abstract graphic item that represents a graph vertex. The actual implementation is done in the derived class. What this intermediate implementation does is that it provides the basics for handling edge creation from one node to the other. It also provides a state based pluggable painting system, meant to customize the painting from the application side. Of course, if it doesn't match your needs you can override it completely in your subclass."""
[docs] class InvisibleConnector(QtWidgets.QGraphicsEllipseItem, Connector): size = 10 def __init__(self, parent, *args, **kwargs): QtWidgets.QGraphicsEllipseItem.__init__(self, 0, 0 , self.size, self.size, None) Connector.__init__(self, *args, **kwargs) self.setBrush(QtGui.QBrush(QtCore.Qt.darkGreen)) # Needs to be visible or else won't receive events # we override paint in order to hide the item self.setVisible(True) self.fakeParent = parent
[docs] def position_changed(self, *args): """reimplemented to do nothing. otherwise caught position changes from the model and ignored the position it was forced to""" pass
[docs] def paint(self, painter, options, widget): pass
itemChange = qtutils.mixin_method(Connector, QtWidgets.QGraphicsEllipseItem, "itemChange")
#################################### # ----Instance members follow---- # #################################### def __init__(self, vertex, graph, defaultCenterConnector=False): """ :Parameters: - vertex - the vertex to observe. - graph - the owner of the vertex """ Element.__init__(self, vertex, graph) self.__connectors = [] self.__defaultConnector = None self.setZValue(1.0) self.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, True) self.setFlag(QtWidgets.QGraphicsItem.ItemIsSelectable, True) self.setFlag(qtutils.ItemSendsGeometryChanges) self.__paintStrategy = defaultPaint if defaultCenterConnector: self.__defaultConnector = Vertex.InvisibleConnector(self, vertex, graph) vertex = baselisteners.GraphElementListenerBase.get_observed
[docs] def iter_connectors(self, filter_fun=lambda x:True): return (c for c in self.__connectors if filter_fun(c))
[docs] def get_scene_center(self): """retrieve the center of the widget on the scene""" center = self.sceneBoundingRect().center() return [center.x(), center.y()]
[docs] def add_to_view(self, view): Element.add_to_view(self, view) if self.__defaultConnector: self.__defaultConnector.add_to_view(view)
[docs] def remove_from_view(self, view): Element.remove_from_view(self, view) if self.__defaultConnector: self.__defaultConnector.remove_from_view(view)
[docs] def set_highlighted(self, value): pass
[docs] def set_painting_strategy(self, strat): self.__paintStrategy = strat
[docs] def add_connector(self, connector): assert isinstance(connector, Connector) self.__connectors.append(connector)
[docs] def remove_connector(self, connector): assert isinstance(connector, Connector) self.__connectors.remove(connector)
[docs] def notify(self, sender, event): if event == "notify_position_change": self.notify_position_change() else: Element.notify(self, sender, event)
[docs] def notify_position_change(self): """ Triggers a visual refresh of anything that observes the position of the vertex. """ if self.__defaultConnector: center = self.sceneBoundingRect().center() self.__defaultConnector.setPos(center.x() - Vertex.InvisibleConnector.size / 2.0, center.y() - Vertex.InvisibleConnector.size / 2.0) self.__defaultConnector.notify_position_change() for c in self.__connectors: c.notify_position_change()
##################### # ----Qt World---- # #####################
[docs] def itemChange(self, change, value): """ Used mainly to capture position changes from the QGraphicsScene and store it in the model so that it can be saved. """ sc = self.scene() if sc: sc.invalidate() if change == QtWidgets.QGraphicsItem.ItemVisibleHasChanged: self.notify_position_change() elif change == qtutils.ItemPositionHasChanged: self.deaf(True) point = QtCore.QPointF(value) self.store_view_data(position=[point.x(), point.y()]) self.deaf(False) self.notify_position_change() return value
[docs] def paint(self, painter, option, widget): """Qt-specific call to paint things.""" if self.__paintStrategy is None: self.__paintStrategy = defaultPaint self.__paintStrategy(self, painter, option, widget)
#------*************************************************------#
[docs] class Edge(Element): """Base class for Qt based edges.""" def __init__(self, edge=None, graph=None, src=None, dst=None): Element.__init__(self, edge, graph) self.setFlag(QtWidgets.QGraphicsItem.ItemIsSelectable) self.setZValue(0.5) self.srcPoint = QtCore.QPointF() self.dstPoint = QtCore.QPointF() self.__edge_creator = self.set_edge_creator(edgefactory.LinearEdgePath()) self.setPen(QtGui.QPen(QtCore.Qt.black, 2, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin)) self.dstBBox = self.srcBBox = None if src is not None: self.set_observed_source(src) if dst is not None: self.set_observed_destination(dst) self.setPath(self.__edge_creator.get_path(self.srcPoint, self.dstPoint)) edge = baselisteners.GraphElementListenerBase.get_observed
[docs] def initialise_from_model(self): pass
[docs] def set_edge_creator(self, creator): self.__edge_creator = creator self.setPath(self.__edge_creator.get_path(self.srcPoint, self.dstPoint)) return creator
[docs] def change_observed(self, old, new): if old == self.srcBBox(): self.set_observed_source(new) elif old == self.dstBBox(): self.set_observed_destination(new) else: Element.change_observed(self, old, new) return
[docs] def set_observed_source(self, src): if self.srcBBox is None: self.srcBBox = baselisteners.BlackBoxModel(self, src) else: self.srcBBox.clear_observed() self.srcBBox(src)
[docs] def set_observed_destination(self, dst): if self.dstBBox is None: self.dstBBox = baselisteners.BlackBoxModel(self, dst) else: self.dstBBox.clear_observed() self.dstBBox(dst)
[docs] def clear_observed(self, *args): self.srcBBox.clear_observed() self.dstBBox.clear_observed() Element.clear_observed(self, *args)
[docs] def update_line_source(self, *pos): self.srcPoint = QtCore.QPointF(*pos) path = self.__edge_creator.get_path(self.srcPoint, self.dstPoint) self.setPath(path)
[docs] def update_line_destination(self, *pos): self.dstPoint = QtCore.QPointF(*pos) path = self.__edge_creator.get_path(self.srcPoint, self.dstPoint) self.setPath(path)
[docs] def notify(self, sender, event): if(event[0] == "metadata_changed"): if(event[1] == "connectorPosition"): pos = event[2] if(sender == self.srcBBox()): self.update_line_source(*pos) if(sender == self.dstBBox()): self.update_line_destination(*pos) elif(event[1] == "hide" and (sender == self.dstBBox() or sender == self.srcBBox())): if event[2]: self.setVisible(False) else: self.setVisible(True)
[docs] def remove(self): self.graph().remove_edge(self.srcBBox(), self.dstBBox())
############ # Qt World # ############
[docs] def shape(self): path = self.__edge_creator.shape() if not path: return QtWidgets.QGraphicsPathItem.shape(self) else: return path
[docs] def itemChange(self, change, value): """ Callback when item has been modified (move...) """ # hack to update start and end points: if change == QtWidgets.QGraphicsItem.ItemVisibleHasChanged: try: srcGraphical = [x for x in self.srcBBox().listeners if isinstance(x(), Connector)][0]() dstGraphical = [x for x in self.dstBBox().listeners if isinstance(x(), Connector)][0]() srcGraphical.notify_position_change() dstGraphical.notify_position_change() except: # possible errors : # -filter yielded an empty list: index out of range # -item 0 of list is a weakref whose refered object has died # -other. pass elif (change == QtWidgets.QGraphicsItem.ItemSelectedChange): if(bool(value)): color = QtCore.Qt.blue else: color = QtCore.Qt.black self.setPen(QtGui.QPen(color, 2, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin)) return QtWidgets.QGraphicsItem.itemChange(self, change, value)
[docs] class FloatingEdge(Edge): def __init__(self, srcPoint, graph): Edge.__init__(self, None, graph, None, None) self.srcPoint = QtCore.QPointF(*srcPoint) self.dstPoint = QtCore.QPointF(self.srcPoint)
[docs] def notify(self, sender, event): return
[docs] def consolidate(self, graph): try: srcVertex, dstVertex , sItem, dItem = self.get_connections() if(srcVertex == None or dstVertex == None): return self.scene().add_edge(srcVertex, dstVertex) except Exception as e: pass # print "consolidation failed :", type(e), e,\ # ". Are you sure you plugged the right ports?" return
[docs] def get_connections(self): # find the vertex items that were activated srcVertexItem = self.scene().find_closest_connectable(self.srcPoint, boxsize=2) dstVertexItem = self.scene().find_closest_connectable(self.dstPoint, boxsize=2) scene = self.scene() if(not scene.is_connectable(srcVertexItem) or not scene.is_connectable(dstVertexItem)): raise Exception("Non connectable types for : " + str(srcVertexItem) + " : " + \ str(dstVertexItem)) return None, None, None, None # if the input and the output are on the same vertex... if(srcVertexItem == dstVertexItem): raise Exception("Nonsense connection : plugging self to self.") return srcVertexItem.get_observed(), dstVertexItem.get_observed(), srcVertexItem, dstVertexItem
#------*************************************************------#
[docs] class Scene(QtWidgets.QGraphicsScene, baselisteners.GraphListenerBase): """A Qt implementation of GraphListenerBase""" __instanceMap__ = weakref.WeakKeyDictionary() # A few signals that strangely enough don't exist in QWidget focusedItemChanged = QtCore.Signal(QtWidgets.QGraphicsScene, Element)
[docs] @classmethod def make_scene(cls, graph, clone=False, parent=None): if graph is not None: # if the graph has already a qtgraphview.Scene GraphListener # reuse it: existingScene = cls.__instanceMap__.get(graph) if existingScene is None or clone is True: existingScene = Scene(parent) cls.__instanceMap__[graph] = existingScene return existingScene else: return Scene(parent)
def __init__(self, parent): QtWidgets.QGraphicsScene.__init__(self, parent) baselisteners.GraphListenerBase.__init__(self) self.__selectAdditions = False # select newly added items self.__views = set() # -- used by upper class to operate snapping to connectors. -- self._connector_types.add(Connector) ############################################################################# # Functions to correctly cooperate with the View class (reference counting) # #############################################################################
[docs] def register_view(self, view): self.__views.add(weakref.ref(view))
[docs] def unregister_view(self, view, scene): toDiscard = None for v in self.__views: if v() == view : toDiscard = v; break if toDiscard: self.__views.remove(toDiscard) try: self.get_graph().unregister_listener(view) except : pass if len(self.__views) == 0: # cleanup before suicide? self.clear()
################################# # IGraphListener implementation # #################################
[docs] def get_scene(self): return self
[docs] def find_closest_connectable(self, pos, boxsize=10.0): # creation of a square to find connectables inside. if isinstance(pos, QtCore.QPointF) : pos = pos.x(), pos.y() rect = QtCore.QRectF((pos[0] - boxsize / 2), (pos[1] - boxsize / 2), boxsize, boxsize) dstPortItems = self.items(rect) dstPortItems = [item for item in dstPortItems if self.is_connectable(item)] distance = float('inf') dstPortItem = None for item in dstPortItems: d = sqrt((item.boundingRect().center().x() - pos[0]) ** 2 + (item.boundingRect().center().y() - pos[1]) ** 2) if d < distance: distance = d dstPortItem = item return dstPortItem
[docs] def post_addition(self, element): if self.__selectAdditions: element.setSelected(True)
[docs] def rebuild(self): """ Build the scene with graphic vertex and edge""" g = self.get_graph() ga = self.get_adapter() go = self.get_observable_graph() self.clear() self.set_graph(g, ga, go) self.initialise_from_model()
[docs] def clear(self): """ Remove all items from the scene """ # do not use the following even though it is faster. # qt might just delete stuff that is owned by Python. # QtWidgets.QGraphicsScene.clear(self) items = list(self.items()) for i in items: self.removeItem(i) # let gc do the rest. baselisteners.GraphListenerBase.clear(self) gc.collect()
################## # QtWorld-Events # ##################
[docs] def mouseMoveEvent(self, event): if(self._is_creating_edge()): pos = event.scenePos() pos = [pos.x(), pos.y()] self._new_edge_set_destination(*pos) QtWidgets.QGraphicsScene.mouseMoveEvent(self, event)
[docs] def mouseReleaseEvent(self, event): if(self._is_creating_edge()): self._new_edge_end() QtWidgets.QGraphicsScene.mouseReleaseEvent(self, event)
######################### # Other utility methods # #########################
[docs] def select_added_elements(self, val): warnings.warn(DeprecationWarning("Please use self.%s instead" % ("select_added_items",)), stacklevel=2) self.select_added_items(val)
[docs] def select_added_items(self, val): self.__selectAdditions = val
[docs] def get_items(self, filterType=None, subcall=None): """ """ if filterType and not isinstance(filterType, tuple): filterType = filterType, return [ (item if subcall is None else subcall(item)) for item in list(self.items()) if (True if filterType is None else isinstance(item, filterType))]
[docs] def get_selected_items(self, filterType=None, subcall=None): """ """ if filterType and not isinstance(filterType, tuple): filterType = filterType, return [ (item if subcall is None else subcall(item)) for item in list(self.items()) if item.isSelected() and (True if filterType is None else isinstance(item, filterType))]
[docs] def get_selection_center(self, selection=None): """ """ items = None if selection: items = selection else: items = self.get_selected_items() l = len(items) if(l == 0) : return QtCore.QPointF(30, 30) sx = sum((i.pos().x() for i in items)) sy = sum((i.pos().y() for i in items)) return QtCore.QPointF(float(sx) / l, float(sy) / l)
#------*************************************************------#
[docs] def deprecate(methodName, newName=None): """create deprecation wrappers""" if newName is None : newName = methodName def deprecation_wrapper(self, *args, **kwargs): warnings.warn(DeprecationWarning("Please use self.scene().%s instead" % (newName,)), stacklevel=2) return getattr(self.scene(), newName)(*args, **kwargs) return deprecation_wrapper
[docs] class View(QtWidgets.QGraphicsView, baselisteners.GraphViewBase): """A View implementing client customisation """
[docs] class AcceptEvent(object): def __init__(self): self.accept = False
# A few signals that strangely enough don't exist in QWidget closing = QtCore.Signal(QtWidgets.QGraphicsView, QtWidgets.QGraphicsScene) # Some other signals that can be useful copyRequest = QtCore.Signal(QtWidgets.QGraphicsView, QtWidgets.QGraphicsScene, AcceptEvent) cutRequest = QtCore.Signal(QtWidgets.QGraphicsView, QtWidgets.QGraphicsScene, AcceptEvent) pasteRequest = QtCore.Signal(QtWidgets.QGraphicsView, QtWidgets.QGraphicsScene, AcceptEvent) deleteRequest = QtCore.Signal(QtWidgets.QGraphicsView, QtWidgets.QGraphicsScene, AcceptEvent) #################################### # ----Instance members follow---- # #################################### def __init__(self, parent): QtWidgets.QGraphicsView.__init__(self, parent) self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) self.__defaultDropHandler = None self.__mimeHandlers = {} self.__pressHotkeyMap = {} self.__releaseHotkeyMap = {} # ---Qt Stuff--- # self.setCacheMode(QtWidgets.QGraphicsView.CacheBackground) self.setRenderHint(QtGui.QPainter.Antialiasing) self.setTransformationAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse) self.setResizeAnchor(QtWidgets.QGraphicsView.AnchorViewCenter) self.setDragMode(QtWidgets.QGraphicsView.RubberBandDrag)
[docs] def setScene(self, scene): """ Overload of QGraphicsView.setScene to correctly handle multiple views of the same scene using reference counting. """ self.__scene = scene if scene is not None: scene.register_view(self) self.closing.connect(scene.unregister_view) QtWidgets.QGraphicsView.setScene(self, scene)
[docs] def set_canvas(self, scene): self.setScene(scene)
################## # QtWorld-Events # ##################
[docs] def set_mime_handler_map(self, mapping): self.__mimeHandlers.update(mapping)
[docs] def set_keypress_handler_map(self, mapping): self.__pressHotkeyMap.update(mapping)
[docs] def set_keyrelease_handler_map(self, mapping): self.__releaseHotkeyMap = mapping
[docs] def set_default_drop_handler(self, handler): self.__defaultDropHandler = handler
[docs] def wheelEvent(self, event): # delta = -event.pixelDelta() / 2400.0 + QtCore.QPoint(1, 1) # self.scale(delta.x(), delta.y()) delta = event.pixelDelta() max_delta = max(abs(delta.x()), abs(delta.y())) max_delta /= 1200 sign = -1 if ((delta.x()<0) or (delta.y() <0)) else 1 self.scale_view(1. + sign * max_delta)
# ----drag and drop----
[docs] def accept_drop(self, event): """ Return the format of the object if a handler is registered for it. If not, if there is a default handler, returns True, else returns False. """ for format in list(self.__mimeHandlers.keys()): if event.mimeData().hasFormat(format): return format return True if self.__defaultDropHandler else False
[docs] def dragEnterEvent(self, event): """While the user hasn't released the object, this method is called to tell qt if the view accepts the object or not.""" event.setAccepted(True if self.accept_drop(event) else False)
[docs] def dragMoveEvent(self, event): format = self.accept_drop(event) if (format): event.setDropAction(QtCore.Qt.MoveAction) event.accept() else: event.ignore()
[docs] def dropEvent(self, event): format = self.accept_drop(event) handler = self.__mimeHandlers.get(format) if(handler): handler(event) else: self.__defaultDropHandler(event)
# Do not call the basic implementation # as it does a "move" instead of a "copy" # and the item is deleted from where it was # dragged from : # QtWidgets.QGraphicsView.dropEvent(self, event) # ----hotkeys----
[docs] def keyPressEvent(self, event): combo = event.modifiers().__int__(), event.key() action = self.__pressHotkeyMap.get(combo) if(action): action(event) else: QtWidgets.QGraphicsView.keyPressEvent(self, event) if not event.isAccepted(): key = event.key() scene = self.scene() acceptEvent = View.AcceptEvent() if event.modifiers() == QtCore.Qt.ControlModifier: if key == QtCore.Qt.Key_C: self.copyRequest.emit(self, scene, acceptEvent) elif key == QtCore.Qt.Key_X: self.cutRequest.emit(self, scene, acceptEvent) elif key == QtCore.Qt.Key_V: self.pasteRequest.emit(self, scene, acceptEvent) else: if key == QtCore.Qt.Key_Delete: self.deleteRequest.emit(self, scene, acceptEvent) if acceptEvent.accept: event.accept()
[docs] def keyReleaseEvent(self, event): combo = event.modifiers().__int__(), event.key() action = self.__releaseHotkeyMap.get(combo) if(action): action(event) else: QtWidgets.QGraphicsView.keyReleaseEvent(self, event)
# ----low level and Qt-Related----
[docs] def closeEvent(self, evt): """a big hack to cleanly remove items from the view and delete the python objects so that they stop leaking on some operating systems""" if self.testAttribute(QtCore.Qt.WA_DeleteOnClose): self.closing.emit(self, self.scene()) self.setScene(None) return QtWidgets.QGraphicsView.closeEvent(self, evt)
######################### # Other utility methods # #########################
[docs] def scale_view(self, factor): self.scale(factor, factor)
[docs] def show_entire_scene (self) : """Scale the scene and center it in order to display the entire content without scrolling. """ self.fitInView(self.scene().itemsBoundingRect(), QtCore.Qt.KeepAspectRatio)
###################### # Deprecated methods # ###################### graph = deprecate("graph") set_graph = deprecate("set_graph") rebuild_scene = deprecate("rebuild") clear_scene = deprecate("clear") get_selected_items = deprecate("get_items") get_selected_items = deprecate("get_selected_items") get_selection_center = deprecate("get_selection_center") select_added_elements = deprecate("select_added_elements") post_addition = deprecate("post_addition") notify = deprecate("notify")
if __debug__: # This part of code raise a warning : ## UserWarning: Object <class 'openalea.grapheditor.qtgraphview.Scene'> # does not belong to the Interface IGraphListener # Unimplemented : # __qualname__ # from . import interfaces # interfaces.IGraphListener.check(Scene) pass
[docs] def QtGraphStrategyMaker(*args, **kwargs): _type = base.GraphStrategyMaker(*args, **kwargs) _type.__sceneType__ = Scene return _type
################################ # SOME DEFAULT IMPLEMENTATIONS # ################################
[docs] class DefaultGraphicalEdge(Edge, QtWidgets.QGraphicsPathItem): def __init__(self, edge=None, graph=None, src=None, dest=None): QtWidgets.QGraphicsPathItem.__init__(self, None) Edge.__init__(self, edge, graph, src, dest) self.set_edge_creator(edgefactory.LinearEdgePath()) store_view_data = None get_view_data = None
[docs] class DefaultGraphicalFloatingEdge(FloatingEdge, QtWidgets.QGraphicsPathItem): def __init__(self, srcPoint, graph): """ """ QtWidgets.QGraphicsPathItem.__init__(self, None) FloatingEdge.__init__(self, srcPoint, graph) self.set_edge_creator(edgefactory.LinearEdgePath())
[docs] class DefaultGraphicalVertex(Vertex, QtWidgets.QGraphicsEllipseItem): circleSize = 10.0 * 2 def __init__(self, vertex, graph): QtWidgets.QGraphicsEllipseItem .__init__(self, 0, 0, self.circleSize, self.circleSize, None) Vertex.__init__(self, vertex, graph, defaultCenterConnector=True) mousePressEvent = qtutils.mixin_method(Vertex, QtWidgets.QGraphicsEllipseItem, "mousePressEvent") itemChange = qtutils.mixin_method(Vertex, QtWidgets.QGraphicsEllipseItem, "itemChange") paint = qtutils.mixin_method(QtWidgets.QGraphicsEllipseItem, None, "paint")