diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5ca3fbc --- /dev/null +++ b/.gitignore @@ -0,0 +1,71 @@ +# Python files +*.py[cod] + +# C extensions +*.so +*.dll +*.dylib + +# Compiled Static libraries +*.lai +*.la +*.a + +# Compiled Object files +*.os + +# Packages +*.egg +*.egg-info +dist +build +build-scons +eggs +.eggs +parts +bin +var +sdist +develop-eggs +.installed.cfg +lib +lib64 +__pycache__ +*.pth +*.bak + +# Installer logs +pip-log.txt +.amlog +.sconsign.dblite + +# Unit test / coverage reports +.coverage +.tox +nosetests.xml + +# Designer files +*visualea/src/visualea/ui_* + +# Translations +*.mo + +# Vim files +*.swp +*.*~ + +# Mr Developer +.mr.developer.cfg +.project +.pydevproject +.settings +.idea + +# svn +.svn + +# temporary files +*._icon.png + +# Mac dirs +.DS_Store \ No newline at end of file diff --git a/conda/meta.yaml b/conda/meta.yaml index 69574e5..e3128bd 100644 --- a/conda/meta.yaml +++ b/conda/meta.yaml @@ -1,16 +1,17 @@ -{% set version = "2.0.1" %} +{% set data = load_setup_py_data() %} package: name: openalea.grapheditor - version: {{ version }} + version: {{ data.get('version') }} source: path: .. build: + noarch: python preserve_egg_dir: True number: 0 - script: python setup.py install --prefix=$PREFIX + script: {{PYTHON}} setup.py install requirements: build: @@ -18,14 +19,14 @@ requirements: run: - openalea.deploy - openalea.core - - openalea.vpltk + - qtpy test: imports: - openalea.grapheditor about: - home: http://github.com/openalea/visualea + home: {{ data.get('url') }} license: Cecill-c License - summary: GraphEditor package for OpenAlea. + summary: {{ data.get('description') }} diff --git a/examples/networkx/conf.py b/examples/networkx/conf.py index 4047c02..e66ae2f 100644 --- a/examples/networkx/conf.py +++ b/examples/networkx/conf.py @@ -37,8 +37,8 @@ master_doc = 'index' # General information about the project. -project = u'NetworkX GraphEditor Strategy' -copyright = u'2010, Daniel Barbeau' +project = 'NetworkX GraphEditor Strategy' +copyright = '2010, Daniel Barbeau' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -172,8 +172,8 @@ # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ - ('index', 'NetworkXGraphEditorStrategy.tex', u'NetworkX GraphEditor Strategy Documentation', - u'Daniel Barbeau', 'manual'), + ('index', 'NetworkXGraphEditorStrategy.tex', 'NetworkX GraphEditor Strategy Documentation', + 'Daniel Barbeau', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of diff --git a/examples/networkx/__init__.py b/examples/networkx/nx_app.py similarity index 86% rename from examples/networkx/__init__.py rename to examples/networkx/nx_app.py index 5e02e5c..fc4f647 100644 --- a/examples/networkx/__init__.py +++ b/examples/networkx/nx_app.py @@ -7,10 +7,15 @@ them. """ +import weakref import networkx as nx + +from functools import cmp_to_key + from openalea.grapheditor.all import Observed, GraphAdapterBase -import weakref +def cmp(a, b): + return (id(a) > id(b)) - (id(a) < id(b)) class NxObservedVertex(Observed): @@ -23,18 +28,18 @@ def notify_position(self, pos): self.notify_listeners(("metadata_changed", "position", pos)) def notify_update(self, **kwargs): - for k, v in kwargs.iteritems(): + for k, v in kwargs.items(): self.notify_listeners(("metadata_changed", k, v)) - pos = self.g().node[self]["position"] + pos = self.g().nodes[self]["position"] self.notify_position(pos) def __setitem__(self, key, value): - self.g().node[self][key] = value + self.g().nodes[self][key] = value self.notify_update() def __getitem__(self, key): - return self.g().node[self][key] + return self.g().nodes[self][key] class NXObservedGraph( GraphAdapterBase, Observed ): """An adapter to networkx.Graph""" @@ -55,7 +60,7 @@ def add_vertex(self, vertex, **kwargs): if "position" not in kwargs : kwargs["position"] = [0., 0.] else: - kwargs["position"] = map(float, kwargs["position"]) + kwargs["position"] = list(map(float, kwargs["position"])) if "color" not in kwargs : kwargs["color"] = QtGui.QColor(0, 0, 0) @@ -71,7 +76,7 @@ def remove_vertex(self, vertex): def add_edge(self, src_vertex, tgt_vertex, **kwargs): edge = [src_vertex, tgt_vertex] - edge.sort(lambda x, y: cmp(id(x), id(y))) + edge.sort(key=cmp_to_key(cmp)) edge = tuple(edge) if self.graph.has_edge(*edge): return @@ -81,7 +86,7 @@ def add_edge(self, src_vertex, tgt_vertex, **kwargs): def remove_edge(self, src_vertex, tgt_vertex): edge = [src_vertex, tgt_vertex] - edge.sort(lambda x, y: cmp(id(x), id(y))) + edge.sort(key=cmp_to_key(cmp)) edge = tuple(edge) self.graph.remove_edge(edge[0], edge[1]) self.notify_listeners(("edge_removed", ("default",edge))) @@ -92,17 +97,17 @@ def remove_edges(self, edges): # -- not in the adapter interface (yet): -- def set_vertex_data(self, vertex, **kwargs): if vertex in self.graph: - for k, v in kwargs.iteritems(): - self.graph.node[vertex][k]=v + for k, v in kwargs.items(): + self.graph.nodes[vertex][k]=v def set_edge_data(self, edge_proxy, **kwargs): - #nothing right now" + #nothing right now pass #------------------------ # -- the graph qt view -- #------------------------ -from PyQt4 import QtGui, QtCore +from qtpy import QtGui, QtCore, QtWidgets from openalea.grapheditor.qt import (Vertex, View, mixin_method, QtGraphStrategyMaker, DefaultGraphicalEdge, @@ -112,8 +117,8 @@ def set_edge_data(self, edge_proxy, **kwargs): class GraphicalNode( DefaultGraphicalVertex ): def initialise_from_model(self): - self.setPos(QtCore.QPointF(*self.graph().graph.node[self.vertex()]["position"])) - color = self.graph().graph.node[self.vertex()]["color"] + self.setPos(QtCore.QPointF(*self.graph().graph.nodes[self.vertex()]["position"])) + color = self.graph().graph.nodes[self.vertex()]["color"] brush = QtGui.QBrush(color) self.setBrush(brush) @@ -121,7 +126,7 @@ def store_view_data(self, **kwargs): self.graph().set_vertex_data(self.vertex(), **kwargs) def get_view_data(self, key): - return self.graph().graph.node[self.vertex()][key] + return self.graph().graph.nodes[self.vertex()][key] class GraphicalView( View ): def __init__(self, parent): @@ -157,10 +162,10 @@ def removeElement(self, event): "floating-default":DefaultGraphicalFloatingEdge} ) #THE APPLICATION'S MAIN WINDOW -class MainWindow(QtGui.QMainWindow): +class MainWindow(QtWidgets.QMainWindow): def __init__(self, parent=None): """ """ - QtGui.QMainWindow.__init__(self, parent) + QtWidgets.QMainWindow.__init__(self, parent) self.setMinimumSize(800,600) @@ -181,9 +186,9 @@ def __init__(self, parent=None): if __name__=="__main__": - instance = QtGui.QApplication.instance() + instance = QtWidgets.QApplication.instance() if instance is None : - app = QtGui.QApplication([]) + app = QtWidgets.QApplication([]) else : app = instance diff --git a/metainfo.ini b/metainfo.ini deleted file mode 100644 index 7395134..0000000 --- a/metainfo.ini +++ /dev/null @@ -1,15 +0,0 @@ - -[metainfo] -version = 2.0.1 -release = 2.0 -project = openalea -name = OpenAlea.GraphEditor -namespace = openalea -pkg_name = openalea.graph_editor -package= grapheditor -description= GraphEditor package for OpenAlea. -long_description= An attempt at generalising the viewing and interacting of various sorts of graphs. -authors = Daniel Barbeau, Christophe Pradal -authors_email = christophe.pradal@cirad.fr -url = https://github.com/openalea/openalea -license = Cecill-C diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index f0ca5b2..0000000 --- a/setup.cfg +++ /dev/null @@ -1,49 +0,0 @@ -# Distutils parameters file -# Use this file to specify custom parameters to pass to setup.py script -# Uncomment necessary options - -[sdist] -#formats=gztar,zip - -#add automatic release number to your egg -[egg_info] -#tag_build = .dev -#tag_svn_revision = 1 - -[global] -# verbose=0 - - -[build_sphinx] -source-dir = doc/ -build-dir = doc/_build -all_files = 1 - - -[nosetests] -where=test -#with_coverage= -#cover_package=openalea.grapheditor -#cover_erase= -verbosity=2 - -[egg_upload] -package = OpenAlea.GraphEditor - -[upload_sphinx] -package = grapheditor -project = openalea - -[bdist_rpm] -requires = python >= 2.6 - python-OpenAlea.Deploy >= 0.9 - PyQt4 -build_requires = python >= 2.6 - python-devel >= 2.6 - python-setuptools >= 0.6 - python-OpenAlea.Deploy >= 0.9 -provides = %{name} = %{version} -obsoletes = %{name} < %{version} -doc_files = AUTHORS.txt ChangeLog.txt README.txt LICENSE.txt -python = /usr/bin/python -packager = OpenAlea Consortium diff --git a/setup.py b/setup.py index b1d0540..a6bc876 100644 --- a/setup.py +++ b/setup.py @@ -6,11 +6,20 @@ from setuptools import setup, find_packages -from openalea.deploy.metainfo import read_metainfo +name = "OpenAlea.GraphEditor" +description= "GraphEditor package for OpenAlea." +long_description= "An generic GGUI API for viewing and interacting with various sorts of graphs." +authors = "Daniel Barbeau, Christophe Pradal" +authors_email = "christophe.pradal@cirad.fr" +url = "https://github.com/openalea/grapheditor" +license = "Cecill-C" -metadata = read_metainfo('metainfo.ini', verbose=True) -for key,value in metadata.iteritems(): - exec("%s = '%s'" % (key, value)) + +# find version number in src/openalea/core/version.py +_version = {} +with open("src/openalea/core/version.py") as fp: + exec(fp.read(), _version) + version = _version["__version__"] namespace = 'openalea' packages=find_packages('src') @@ -19,7 +28,7 @@ setup_requires = ['openalea.deploy'] install_requires = [] # web sites where to find eggs -dependency_links = ['http://openalea.gforge.inria.fr/pi'] +dependency_links = [] # setup function call # @@ -40,8 +49,8 @@ package_dir= package_dir, # Namespace packages creation by deploy - namespace_packages=[namespace], - create_namespaces=True, + #namespace_packages=[namespace], + #create_namespaces=True, zip_safe=False, diff --git a/src/openalea/grapheditor/SimpleGraph/custom_graph_model.py b/src/openalea/grapheditor/SimpleGraph/custom_graph_model.py index 4b3a2d0..07e8532 100644 --- a/src/openalea/grapheditor/SimpleGraph/custom_graph_model.py +++ b/src/openalea/grapheditor/SimpleGraph/custom_graph_model.py @@ -31,10 +31,10 @@ def __init__(self): self.__edges = {} def simulate_construction_notifications(self): - for v in self.__vertices.values(): + for v in list(self.__vertices.values()): self.notify_listeners( ("vertex_added", ("vertex", v)) ) - for e in self.__edges.values(): - self.notify_listeners( ("edge_added", ("default", v)) ) + for e in list(self.__edges.values()): + self.notify_listeners( ("edge_added", ("default", e)) ) #todo : add this to the graph_adapter interface? def new_vertex(self, position=None): @@ -79,7 +79,7 @@ def get_vertex_output(self, vertex): return vertex #todo : add this to the graph_adapter interface? - def new_edge(src, dst): + def new_edge(self, src, dst): edge = Edge(src, dst) self.add_edge(src, dst, edge) diff --git a/src/openalea/grapheditor/SimpleGraph/custom_graph_view.py b/src/openalea/grapheditor/SimpleGraph/custom_graph_view.py index f28fc39..1d51b08 100644 --- a/src/openalea/grapheditor/SimpleGraph/custom_graph_view.py +++ b/src/openalea/grapheditor/SimpleGraph/custom_graph_view.py @@ -23,9 +23,9 @@ from openalea.grapheditor.qtutils import mixin_method, extend_qt_scene_event from openalea.grapheditor.qtgraphview import Vertex, Edge, FloatingEdge from openalea.grapheditor.edgefactory import LinearEdgePath -from openalea.vpltk.qt import QtGui, QtCore -from custom_graph_model import Graph as GraphType -from custom_graph_model import Vertex as VertexModel +from qtpy import QtGui, QtCore, QtWidgets +from openalea.grapheditor.SimpleGraph.custom_graph_model import Graph as GraphType +from openalea.grapheditor.SimpleGraph.custom_graph_model import Vertex as VertexModel @@ -34,19 +34,19 @@ # edges # ############################################################## -class SimpleVertex(QtGui.QGraphicsEllipseItem, Vertex): +class SimpleVertex(QtWidgets.QGraphicsEllipseItem, Vertex): __vertex_size__= QtCore.QSizeF(30.0, 30.0) __border_size__=5 def __init__(self, vertex, graph, parent=None): - QtGui.QGraphicsEllipseItem.__init__(self, 0.0, 0.0, + QtWidgets.QGraphicsEllipseItem.__init__(self, 0.0, 0.0, self.__vertex_size__.width(), self.__vertex_size__.height(), parent) Vertex.__init__(self, vertex, graph) self.setZValue(1.0) - #we choose the avocado colors + # We choose the avocado colors self.setBrush( QtGui.QBrush(QtCore.Qt.yellow) ) pen=QtGui.QPen(QtCore.Qt.darkGreen) pen.setWidth(self.__border_size__-2) @@ -66,11 +66,11 @@ def sizeHint(self, blop, blip): ################## # QtWorld-Events # ################## - mousePressEvent = mixin_method(Vertex, QtGui.QGraphicsEllipseItem, "mousePressEvent") - itemChange = mixin_method(Vertex, QtGui.QGraphicsEllipseItem, "itemChange") + mousePressEvent = mixin_method(Vertex, QtWidgets.QGraphicsEllipseItem, "mousePressEvent") + itemChange = mixin_method(Vertex, QtWidgets.QGraphicsEllipseItem, "itemChange") def contextMenuEvent(self, event): #called on right click on the vertex. - menu = QtGui.QMenu(event.widget()) + menu = QtWidgets.QMenu(event.widget()) action= menu.addAction("Delete vertex") action.connect(action, QtCore.SIGNAL("triggered()"), self.remove) menu.popup(event.screenPos()) @@ -80,7 +80,7 @@ def remove(self): self.graph().remove_vertex(self.vertex()) def paint(self, painter, painterOptions, widget): - QtGui.QGraphicsEllipseItem.paint(self, painter, painterOptions, widget) + QtWidgets.QGraphicsEllipseItem.paint(self, painter, painterOptions, widget) def store_view_data(self, key, value, notify=True): self.vertex().get_ad_hoc_dict().set_metadata(key, value, notify) @@ -96,16 +96,16 @@ def announce_view_data(self, exclusive=False): self.vertex().get_ad_hoc_dict().simulate_full_data_change) -class SimpleEdge(QtGui.QGraphicsPathItem, Edge): +class SimpleEdge(QtWidgets.QGraphicsPathItem, Edge): def __init__(self, edgeModel, graphadapter, vert1, vert2, parent=None): """ """ - QtGui.QGraphicsPathItem.__init__(self, parent) + QtWidgets.QGraphicsPathItem.__init__(self, parent) Edge.__init__(self, edgeModel, graphadapter, vert1, vert2) self.set_edge_path(LinearEdgePath()) self.initialise_from_model() def contextMenuEvent(self, event): - menu = QtGui.QMenu(self.scene().views()[0]) + menu = QtWidgets.QMenu(self.scene().views()[0]) action = menu.addAction("Delete edge") self.scene().connect(action, QtCore.SIGNAL("triggered()"), self.remove) menu.popup(event.screenPos()) @@ -133,10 +133,10 @@ def announce_view_data_dst(self, exclusive=False): self.dstBBox().get_ad_hoc_dict().simulate_full_data_change) -class SimpleFloatingEdge(QtGui.QGraphicsPathItem, FloatingEdge): +class SimpleFloatingEdge(QtWidgets.QGraphicsPathItem, FloatingEdge): def __init__(self, srcPoint, graph): """ """ - QtGui.QGraphicsPathItem.__init__(self, None) + QtWidgets.QGraphicsPathItem.__init__(self, None) FloatingEdge.__init__(self, srcPoint, graph) self.set_edge_path(LinearEdgePath()) self.setZValue(0.0) diff --git a/src/openalea/grapheditor/SimpleGraph/main.py b/src/openalea/grapheditor/SimpleGraph/main.py index e9be241..63c30eb 100644 --- a/src/openalea/grapheditor/SimpleGraph/main.py +++ b/src/openalea/grapheditor/SimpleGraph/main.py @@ -1,6 +1,6 @@ import sys -from openalea.vpltk.qt import QtGui +from qtpy import QtWidgets from openalea.grapheditor import qt from custom_graph_model import Graph @@ -33,10 +33,10 @@ def get_view_data(self, key): adapterType = None ) #THE APPLICATION'S MAIN WINDOW -class MainWindow(QtGui.QMainWindow): +class MainWindow(QtWidgets.QMainWindow): def __init__(self, parent=None): """ """ - QtGui.QMainWindow.__init__(self, parent) + QtWidgets.QMainWindow.__init__(self, parent) self.__graph = Graph() self.__graphView = SimpleGraph.create_view(self.__graph, parent=self) self.setCentralWidget(self.__graphView) @@ -44,8 +44,8 @@ def __init__(self, parent=None): #THE ENTRY POINT def main(args): - app = QtGui.QApplication(args) - QtGui.QApplication.processEvents() + app = QtWidgets.QApplication(args) + QtWidgets.QApplication.processEvents() win = MainWindow() win.show() return app.exec_() diff --git a/src/openalea/grapheditor/base.py b/src/openalea/grapheditor/base.py index 6b4b2bc..420aacf 100644 --- a/src/openalea/grapheditor/base.py +++ b/src/openalea/grapheditor/base.py @@ -142,8 +142,8 @@ class __GraphStrategy(object): __vertexWidgetMap__ = vertexWidgetMap __edgeWidgetMap__ = edgeWidgetMap __connectorTypes__ = connectorTypes - __graphViewInitialiser__ = staticmethod(graphViewInitialiser \ - if graphViewInitialiser \ + __graphViewInitialiser__ = staticmethod(graphViewInitialiser + if graphViewInitialiser else lambda x,y:x) __adapterType__ = adapterType @@ -167,9 +167,9 @@ def create_vertex_widget(cls, vtype, *args, **kwargs): @classmethod def create_edge_widget(cls, etype, *args, **kwargs): - VertexClass = cls.__edgeWidgetMap__.get(etype) - if(VertexClass): - return VertexClass(*args, **kwargs) + EdgeClass = cls.__edgeWidgetMap__.get(etype) + if(EdgeClass): + return EdgeClass(*args, **kwargs) else: raise Exception("etype not found") diff --git a/src/openalea/grapheditor/baselisteners.py b/src/openalea/grapheditor/baselisteners.py index cf3bc8d..a05a531 100644 --- a/src/openalea/grapheditor/baselisteners.py +++ b/src/openalea/grapheditor/baselisteners.py @@ -2,7 +2,7 @@ # # OpenAlea.Visualea: OpenAlea graphical user interface # -# Copyright 2006-2009 INRIA - CIRAD - INRA +# Copyright 2006-2023 INRIA - CIRAD - INRA # # File author(s): Daniel Barbeau # @@ -176,9 +176,10 @@ def set_graph(self, graph, adapter=None, observableGraph=None): self.__graph = graph #obtaining types from the strategy. cls = self.__strategyCls - self.__graphAdapter = adapter if adapter is not None else \ - (graph if cls.__adapterType__ is None \ - else cls.__adapterType__(graph)) + self.__graphAdapter = (adapter if adapter is not None + else (graph if cls.__adapterType__ is None + else cls.__adapterType__(graph)) + ) self.__observableGraph = graph if observableGraph is None else observableGraph if self.__observableGraph: self.__observableGraph.register_listener(self) @@ -321,7 +322,7 @@ def get_edge_types(self): def get_graphical_edges_connected_to(self, cmodel): edgeMap = self.__widgetmap.setdefault("edge",{}) retSet = set() - for edgeModel, graphicalEdges in edgeMap.iteritems(): + for edgeModel, graphicalEdges in edgeMap.items(): if hasattr(edgeModel, "__iter__") and cmodel in edgeModel: retSet |= graphicalEdges elif edgeModel == cmodel: #what??????? @@ -379,7 +380,9 @@ def _unregister_widget_from_model(self, widget, model): if(widgets is None): return toDiscard = None for widgetWeakRef in widgets: - if widgetWeakRef() == widget : toDiscard = widgetWeakRef; break + if widgetWeakRef() == widget : + toDiscard = widgetWeakRef + break if toDiscard: widgets.discard(toDiscard) @@ -392,8 +395,9 @@ def _widget_died(self, widgetWeakRef): if t is None: return model = self.__widgetmap.setdefault(t,{}).pop(widgetWeakRef, None) - if not model: return - # raise Exception("__widget_died without associated model") + if not model: + raise Exception("__widget_died without associated model") + return modelWidgets = self.__widgetmap.get(model, None) if not modelWidgets : return modelWidgets.discard(widgetWeakRef) @@ -408,7 +412,11 @@ def _is_creating_edge(self): return True if self.__newEdge else False def _new_edge_start(self, srcPt, etype="default", source=None): - self.__newEdge = self.__strategyCls.create_edge_widget("floating-"+etype, srcPt, self.get_graph()) + self.__newEdge = self.__strategyCls.create_edge_widget( + "floating-"+etype, + srcPt, + self.get_graph()) + self.__newEdge.add_to_view(self.get_scene()) if source: self.__newEdgeSource = source @@ -429,7 +437,7 @@ def _new_edge_end(self): if(self.__newEdge): try: self.__newEdge.consolidate(self.get_graph()) - except Exception, e : + except Exception as e : pass finally: self.__newEdge.remove_from_view(self.get_scene()) @@ -444,7 +452,7 @@ def _new_edge_end(self): -class BlackBoxModel(object): +class BlackBoxModel: """An object that allows to unify certain model (in the MVC meaning) operations calls, wether the model is an Observed instance or just any random class. diff --git a/src/openalea/grapheditor/edgefactory.py b/src/openalea/grapheditor/edgefactory.py index 9f43f2f..24ba53f 100644 --- a/src/openalea/grapheditor/edgefactory.py +++ b/src/openalea/grapheditor/edgefactory.py @@ -19,7 +19,7 @@ __license__ = "Cecill-C" __revision__ = " $Id$ " -from openalea.vpltk.qt import QtCore, QtGui +from qtpy import QtCore, QtGui # def EdgeFactory(): # try: @@ -36,7 +36,7 @@ # return SplineEdgePath() -class LinearEdgePath(object): +class LinearEdgePath: """ Draw edges as line. """ def __init__(self): self.p1 = QtCore.QPointF() diff --git a/src/openalea/grapheditor/interfaces.py b/src/openalea/grapheditor/interfaces.py index da37288..f81d054 100644 --- a/src/openalea/grapheditor/interfaces.py +++ b/src/openalea/grapheditor/interfaces.py @@ -31,7 +31,7 @@ def __new__(cls, name, bases, dict): newCls = type.__new__(cls, name, bases, dict) ###--CONTRACT CHECKING INFRASTRUCTURE--- - newCls.__interface_decl__ = [i for i in dict.keys()] + newCls.__interface_decl__ = [i for i in list(dict.keys())] for base in bases: if(hasattr(base, "__interface_decl__")): newCls.__interface_decl__ += base.__interface_decl__ @@ -74,12 +74,11 @@ def check(cls, obj): return not stop -class IGraphViewStrategies(object): +class IGraphViewStrategies(object, metaclass=IInterfaceMetaClass): """Define implementations of this trait class to define the behaviour of the graph. For example : DataFlowGraphViewTrait, TreeGraphViewTrait, NetworkGraphViewTrait...""" - __metaclass__ = IInterfaceMetaClass def get_graph_model_type(cls): @@ -125,9 +124,7 @@ def initialise_graph_view(cls, graphView, graphModel): #------*************************************************------# -class IGraphListener(object): - __metaclass__ = IInterfaceMetaClass - +class IGraphListener(object, metaclass=IInterfaceMetaClass): def vertex_added(self, vtype, vertexModel): raise NotImplementedError @@ -167,9 +164,7 @@ def initialise_from_model(self): #------*************************************************------# -class IGraphAdapter(object): - __metaclass__ = IInterfaceMetaClass - +class IGraphAdapter(object, metaclass=IInterfaceMetaClass): def add_vertex(self, *args, **kargs): NotImplementedError @@ -213,9 +208,8 @@ def get_edge_types(self): raise NotImplementedError #------*************************************************------# -class IGraphViewConnectable(object): +class IGraphViewConnectable(object, metaclass=IInterfaceMetaClass): """Interface for connectable objects""" - __metaclass__ = IInterfaceMetaClass def set_highlighted(self, *args, **kwargs): raise NotImplementedError @@ -224,9 +218,8 @@ def get_scene_center(self): raise NotImplementedError #------*************************************************------# -class IGraphViewElement(object): +class IGraphViewElement(object, metaclass=IInterfaceMetaClass): """Base class for elements in a GraphView""" - __metaclass__ = IInterfaceMetaClass def position_changed(self, *args): """Place the element's representation in @@ -291,10 +284,9 @@ def notify(self, sender, event): #------*************************************************------# -class IGraphViewFloatingEdge(object): +class IGraphViewFloatingEdge(object, metaclass=IInterfaceMetaClass): """Interface for edges to be drawn during creation time, ie while the user drags.""" - __metaclass__ = IInterfaceMetaClass def __init__(self, src): raise NotImplementedError diff --git a/src/openalea/grapheditor/observer.py b/src/openalea/grapheditor/observer.py index f96a58d..f59b166 100644 --- a/src/openalea/grapheditor/observer.py +++ b/src/openalea/grapheditor/observer.py @@ -108,8 +108,8 @@ def notify_listeners(self, event=None): if(not obs.is_notification_locked()): try: obs.call_notify(self, event) - except Exception, e: - print "Warning :", str(self), "notification of", str(obs), "failed", e + except Exception as e: + print("Warning :", str(self), "notification of", str(obs), "failed", e) traceback.print_exc() self.__isNotifying = False diff --git a/src/openalea/grapheditor/qtgraphview.py b/src/openalea/grapheditor/qtgraphview.py index 75626df..d8500d8 100644 --- a/src/openalea/grapheditor/qtgraphview.py +++ b/src/openalea/grapheditor/qtgraphview.py @@ -19,8 +19,7 @@ __revision__ = " $Id$ " import weakref, types, gc, warnings -from openalea.vpltk.qt import QtGui, QtCore -from openalea.vpltk.qt.compat import from_qvariant +from qtpy import QtGui, QtCore, QtWidgets from openalea.grapheditor import base, baselisteners, qtutils from openalea.grapheditor import edgefactory @@ -79,7 +78,7 @@ def position_changed(self, *args): self.setPos(point) def lock_position(self, val=True): - self.setFlag(QtGui.QGraphicsItem.ItemIsMovable, not val) + self.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, not val) def default_position(self): return [0.0, 0.0] @@ -163,10 +162,10 @@ class Vertex(Element): can override it completely in your subclass.""" - class InvisibleConnector(QtGui.QGraphicsEllipseItem, Connector): + class InvisibleConnector(QtWidgets.QGraphicsEllipseItem, Connector): size = 10 def __init__(self, parent, *args, **kwargs): - QtGui.QGraphicsEllipseItem.__init__(self, 0, 0 , self.size, self.size, None) + 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 @@ -185,7 +184,7 @@ def position_changed(self, *args): def paint(self, painter, options, widget): pass - itemChange = qtutils.mixin_method(Connector, QtGui.QGraphicsEllipseItem, + itemChange = qtutils.mixin_method(Connector, QtWidgets.QGraphicsEllipseItem, "itemChange") #################################### @@ -202,8 +201,8 @@ def __init__(self, vertex, graph, defaultCenterConnector=False): self.__defaultConnector = None self.setZValue(1.0) - self.setFlag(QtGui.QGraphicsItem.ItemIsMovable, True) - self.setFlag(QtGui.QGraphicsItem.ItemIsSelectable, True) + self.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, True) + self.setFlag(QtWidgets.QGraphicsItem.ItemIsSelectable, True) self.setFlag(qtutils.ItemSendsGeometryChanges) self.__paintStrategy = defaultPaint if defaultCenterConnector: @@ -211,8 +210,8 @@ def __init__(self, vertex, graph, defaultCenterConnector=False): vertex = baselisteners.GraphElementListenerBase.get_observed - def iter_connectors(self, filter=lambda x:True): - return (c for c in self.__connectors if filter(c)) + def iter_connectors(self, filter_fun=lambda x:True): + return (c for c in self.__connectors if filter_fun(c)) def get_scene_center(self): """retrieve the center of the widget on the scene""" @@ -270,12 +269,12 @@ def itemChange(self, change, value): if sc: sc.invalidate() - if change == QtGui.QGraphicsItem.ItemVisibleHasChanged: + if change == QtWidgets.QGraphicsItem.ItemVisibleHasChanged: self.notify_position_change() elif change == qtutils.ItemPositionHasChanged: self.deaf(True) - point = QtCore.QPointF(from_qvariant(value)) + point = QtCore.QPointF(value) self.store_view_data(position=[point.x(), point.y()]) self.deaf(False) self.notify_position_change() @@ -296,7 +295,7 @@ class Edge(Element): def __init__(self, edge=None, graph=None, src=None, dst=None): Element.__init__(self, edge, graph) - self.setFlag(QtGui.QGraphicsItem.ItemIsSelectable) + self.setFlag(QtWidgets.QGraphicsItem.ItemIsSelectable) self.setZValue(0.5) self.srcPoint = QtCore.QPointF() self.dstPoint = QtCore.QPointF() @@ -383,19 +382,17 @@ def remove(self): def shape(self): path = self.__edge_creator.shape() if not path: - return QtGui.QGraphicsPathItem.shape(self) + return QtWidgets.QGraphicsPathItem.shape(self) else: return path def itemChange(self, change, value): """ Callback when item has been modified (move...) """ # hack to update start and end points: - if change == QtGui.QGraphicsItem.ItemVisibleHasChanged: + if change == QtWidgets.QGraphicsItem.ItemVisibleHasChanged: try: - srcGraphical = filter(lambda x: isinstance(x(), Connector), - self.srcBBox().listeners)[0]() - dstGraphical = filter(lambda x: isinstance(x(), Connector), - self.dstBBox().listeners)[0]() + 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: @@ -405,7 +402,7 @@ def itemChange(self, change, value): # -other. pass - elif (change == QtGui.QGraphicsItem.ItemSelectedChange): + elif (change == QtWidgets.QGraphicsItem.ItemSelectedChange): if(bool(value)): color = QtCore.Qt.blue else: @@ -416,7 +413,7 @@ def itemChange(self, change, value): QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin)) - return QtGui.QGraphicsItem.itemChange(self, change, value) + return QtWidgets.QGraphicsItem.itemChange(self, change, value) class FloatingEdge(Edge): @@ -435,7 +432,7 @@ def consolidate(self, graph): if(srcVertex == None or dstVertex == None): return self.scene().add_edge(srcVertex, dstVertex) - except Exception, e: + except Exception as e: pass # print "consolidation failed :", type(e), e,\ # ". Are you sure you plugged the right ports?" @@ -463,13 +460,13 @@ def get_connections(self): #------*************************************************------# -class Scene(QtGui.QGraphicsScene, baselisteners.GraphListenerBase): +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(QtGui.QGraphicsScene, Element) + focusedItemChanged = QtCore.Signal(QtWidgets.QGraphicsScene, Element) @classmethod @@ -486,7 +483,7 @@ def make_scene(cls, graph, clone=False, parent=None): return Scene(parent) def __init__(self, parent): - QtGui.QGraphicsScene.__init__(self, parent) + QtWidgets.QGraphicsScene.__init__(self, parent) baselisteners.GraphListenerBase.__init__(self) self.__selectAdditions = False # select newly added items self.__views = set() @@ -552,8 +549,8 @@ 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. - # QtGui.QGraphicsScene.clear(self) - items = self.items() + # QtWidgets.QGraphicsScene.clear(self) + items = list(self.items()) for i in items: self.removeItem(i) # let gc do the rest. baselisteners.GraphListenerBase.clear(self) @@ -567,12 +564,12 @@ def mouseMoveEvent(self, event): pos = event.scenePos() pos = [pos.x(), pos.y()] self._new_edge_set_destination(*pos) - QtGui.QGraphicsScene.mouseMoveEvent(self, event) + QtWidgets.QGraphicsScene.mouseMoveEvent(self, event) def mouseReleaseEvent(self, event): if(self._is_creating_edge()): self._new_edge_end() - QtGui.QGraphicsScene.mouseReleaseEvent(self, event) + QtWidgets.QGraphicsScene.mouseReleaseEvent(self, event) ######################### # Other utility methods # @@ -590,7 +587,7 @@ 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 self.items() if + for item in list(self.items()) if (True if filterType is None else isinstance(item, filterType))] def get_selected_items(self, filterType=None, subcall=None): @@ -598,7 +595,7 @@ 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 self.items() if item.isSelected() and + for item in list(self.items()) if item.isSelected() and (True if filterType is None else isinstance(item, filterType))] def get_selection_center(self, selection=None): @@ -627,7 +624,7 @@ def deprecation_wrapper(self, *args, **kwargs): return deprecation_wrapper -class View(QtGui.QGraphicsView, baselisteners.GraphViewBase): +class View(QtWidgets.QGraphicsView, baselisteners.GraphViewBase): """A View implementing client customisation """ class AcceptEvent(object): @@ -635,19 +632,19 @@ def __init__(self): self.accept = False # A few signals that strangely enough don't exist in QWidget - closing = QtCore.Signal(QtGui.QGraphicsView, QtGui.QGraphicsScene) + closing = QtCore.Signal(QtWidgets.QGraphicsView, QtWidgets.QGraphicsScene) # Some other signals that can be useful - copyRequest = QtCore.Signal(QtGui.QGraphicsView, QtGui.QGraphicsScene, AcceptEvent) - cutRequest = QtCore.Signal(QtGui.QGraphicsView, QtGui.QGraphicsScene, AcceptEvent) - pasteRequest = QtCore.Signal(QtGui.QGraphicsView, QtGui.QGraphicsScene, AcceptEvent) - deleteRequest = QtCore.Signal(QtGui.QGraphicsView, QtGui.QGraphicsScene, AcceptEvent) + 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): - QtGui.QGraphicsView.__init__(self, parent) + QtWidgets.QGraphicsView.__init__(self, parent) self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) @@ -657,11 +654,11 @@ def __init__(self, parent): self.__releaseHotkeyMap = {} # ---Qt Stuff--- -# self.setCacheMode(QtGui.QGraphicsView.CacheBackground) +# self.setCacheMode(QtWidgets.QGraphicsView.CacheBackground) self.setRenderHint(QtGui.QPainter.Antialiasing) - self.setTransformationAnchor(QtGui.QGraphicsView.AnchorUnderMouse) - self.setResizeAnchor(QtGui.QGraphicsView.AnchorViewCenter) - self.setDragMode(QtGui.QGraphicsView.RubberBandDrag) + self.setTransformationAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse) + self.setResizeAnchor(QtWidgets.QGraphicsView.AnchorViewCenter) + self.setDragMode(QtWidgets.QGraphicsView.RubberBandDrag) def setScene(self, scene): """ Overload of QGraphicsView.setScene to correctly handle multiple views @@ -670,7 +667,7 @@ def setScene(self, scene): if scene is not None: scene.register_view(self) self.closing.connect(scene.unregister_view) - QtGui.QGraphicsView.setScene(self, scene) + QtWidgets.QGraphicsView.setScene(self, scene) def set_canvas(self, scene): self.setScene(scene) @@ -691,15 +688,21 @@ def set_default_drop_handler(self, handler): self.__defaultDropHandler = handler def wheelEvent(self, event): - delta = -event.delta() / 2400.0 + 1.0 - self.scale_view(delta) + # 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---- 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 self.__mimeHandlers.keys(): + for format in list(self.__mimeHandlers.keys()): if event.mimeData().hasFormat(format): return format return True if self.__defaultDropHandler else False @@ -727,7 +730,7 @@ def dropEvent(self, event): # as it does a "move" instead of a "copy" # and the item is deleted from where it was # dragged from : - # QtGui.QGraphicsView.dropEvent(self, event) + # QtWidgets.QGraphicsView.dropEvent(self, event) # ----hotkeys---- def keyPressEvent(self, event): @@ -736,7 +739,7 @@ def keyPressEvent(self, event): if(action): action(event) else: - QtGui.QGraphicsView.keyPressEvent(self, event) + QtWidgets.QGraphicsView.keyPressEvent(self, event) if not event.isAccepted(): key = event.key() @@ -762,7 +765,7 @@ def keyReleaseEvent(self, event): if(action): action(event) else: - QtGui.QGraphicsView.keyReleaseEvent(self, event) + QtWidgets.QGraphicsView.keyReleaseEvent(self, event) # ----low level and Qt-Related---- def closeEvent(self, evt): @@ -772,7 +775,7 @@ def closeEvent(self, evt): if self.testAttribute(QtCore.Qt.WA_DeleteOnClose): self.closing.emit(self, self.scene()) self.setScene(None) - return QtGui.QGraphicsView.closeEvent(self, evt) + return QtWidgets.QGraphicsView.closeEvent(self, evt) ######################### # Other utility methods # @@ -801,11 +804,16 @@ def show_entire_scene (self) : post_addition = deprecate("post_addition") notify = deprecate("notify") - - if __debug__: - import interfaces - interfaces.IGraphListener.check(Scene) +# This part of code raise a warning : +## UserWarning: Object + # does not belong to the Interface IGraphListener + # Unimplemented : + # __qualname__ + # from . import interfaces + # interfaces.IGraphListener.check(Scene) + pass + def QtGraphStrategyMaker(*args, **kwargs): _type = base.GraphStrategyMaker(*args, **kwargs) @@ -815,9 +823,9 @@ def QtGraphStrategyMaker(*args, **kwargs): ################################ # SOME DEFAULT IMPLEMENTATIONS # ################################ -class DefaultGraphicalEdge(Edge, QtGui.QGraphicsPathItem): +class DefaultGraphicalEdge(Edge, QtWidgets.QGraphicsPathItem): def __init__(self, edge=None, graph=None, src=None, dest=None): - QtGui.QGraphicsPathItem.__init__(self, None) + QtWidgets.QGraphicsPathItem.__init__(self, None) Edge.__init__(self, edge, graph, src, dest) self.set_edge_creator(edgefactory.LinearEdgePath()) @@ -825,23 +833,23 @@ def __init__(self, edge=None, graph=None, src=None, dest=None): get_view_data = None -class DefaultGraphicalFloatingEdge(QtGui.QGraphicsPathItem, FloatingEdge): +class DefaultGraphicalFloatingEdge(FloatingEdge, QtWidgets.QGraphicsPathItem): def __init__(self, srcPoint, graph): """ """ - QtGui.QGraphicsPathItem.__init__(self, None) + QtWidgets.QGraphicsPathItem.__init__(self, None) FloatingEdge.__init__(self, srcPoint, graph) self.set_edge_creator(edgefactory.LinearEdgePath()) -class DefaultGraphicalVertex(Vertex, QtGui.QGraphicsEllipseItem): +class DefaultGraphicalVertex(Vertex, QtWidgets.QGraphicsEllipseItem): circleSize = 10.0 * 2 def __init__(self, vertex, graph): - QtGui.QGraphicsEllipseItem .__init__(self, 0, 0, self.circleSize, self.circleSize, None) + QtWidgets.QGraphicsEllipseItem .__init__(self, 0, 0, self.circleSize, self.circleSize, None) Vertex.__init__(self, vertex, graph, defaultCenterConnector=True) - mousePressEvent = qtutils.mixin_method(Vertex, QtGui.QGraphicsEllipseItem, + mousePressEvent = qtutils.mixin_method(Vertex, QtWidgets.QGraphicsEllipseItem, "mousePressEvent") - itemChange = qtutils.mixin_method(Vertex, QtGui.QGraphicsEllipseItem, + itemChange = qtutils.mixin_method(Vertex, QtWidgets.QGraphicsEllipseItem, "itemChange") - paint = qtutils.mixin_method(QtGui.QGraphicsEllipseItem, None, + paint = qtutils.mixin_method(QtWidgets.QGraphicsEllipseItem, None, "paint") diff --git a/src/openalea/grapheditor/qtutils.py b/src/openalea/grapheditor/qtutils.py index 8ab3b84..fe64aea 100644 --- a/src/openalea/grapheditor/qtutils.py +++ b/src/openalea/grapheditor/qtutils.py @@ -2,7 +2,7 @@ # # OpenAlea.Visualea: OpenAlea graphical user interface # -# Copyright 2006-2009 INRIA - CIRAD - INRA +# Copyright 2006-2023 INRIA - CIRAD - INRA 1# # File author(s): Daniel Barbeau # @@ -10,7 +10,7 @@ # 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 +# OpenAlea WebSite : http://openalea.rtfd.io # ############################################################################### @@ -19,7 +19,7 @@ import weakref -from openalea.vpltk.qt import QtCore, QtGui +from qtpy import QtCore, QtGui, QtWidgets ################################################################################## @@ -36,24 +36,24 @@ __badsymbols = [] for f in unportableFlags+unportableEnums: try: - __dict__[f] = getattr(QtGui.QGraphicsItem, f) - except Exception, e: + __dict__[f] = getattr(QtWidgets.QGraphicsItem, f) + except Exception as e: __badsymbols.append(f) continue if len(__badsymbols): - print \ -""" -The following QtGui.QGraphicsItem enums and flags were not found. + print(""" +The following QtWidgets.QGraphicsItem enums and flags were not found. These are probably used by a graph view. They might exist but your version of PyQt is too old so openalea.grapheditor.qtutils will try to compensate them: %s -""" % (__badsymbols) +""" % (__badsymbols)) # if it's just the PyQt Version that is too old we have a hack as # the qt flag exists but is simply not exposed. # this is not bug free: if the Qt guys change the enum order, we're wrecked. +""" if hasattr(QtCore, 'PYQT_VERSION') and QtCore.PYQT_VERSION < 0x040703 and QtCore.PYQT_VERSION >= 0x040600: # -- flags -- ItemSendsGeometryChanges = 0x800 @@ -61,6 +61,8 @@ # -- enums -- ItemScenePositionHasChanged = 0x1b ItemPositionHasChanged = 0x9 +""" + ##################################################### @@ -80,29 +82,29 @@ def connect(self, callback): self.callbacks[callback] = callback def disconnect(self, callback=None): if callback is not None: - del self.callbacks[callbacks] + del self.callbacks[callback] else: self.callbacks.clear() def emit(self, *args): # TODO: do type checking? - callbacks = self.callbacks.values()[:] + callbacks = list(self.callbacks.values())[:] for c in callbacks: c(*args) ############################################### # A QGraphicsWidget that looks like a post-it # ############################################### -class MemoRects(QtGui.QGraphicsRectItem): +class MemoRects(QtWidgets.QGraphicsRectItem): __handleSize = 7.5 __defaultColor = QtGui.QColor(250, 250, 100) def __init__(self, rect, parent=None): - QtGui.QGraphicsRectItem.__init__(self, rect, parent) + QtWidgets.QGraphicsRectItem.__init__(self, rect, parent) self.__resizing = False self.__handlePoly = QtGui.QPolygonF([QtCore.QPointF(0, -self.__handleSize), QtCore.QPointF(0, 0), QtCore.QPointF(-self.__handleSize,0)]) - self.setFlag(QtGui.QGraphicsItem.ItemStacksBehindParent) + self.setFlag(QtWidgets.QGraphicsItem.ItemStacksBehindParent) # -- handle -- self.__handlePos = QtCore.QPointF(0,0) # -- header -- @@ -115,7 +117,7 @@ def __init__(self, rect, parent=None): self.setColor(self.__defaultColor.darker(110)) # -- optionnal cosmetics -- if safeEffects: - fx = QtGui.QGraphicsDropShadowEffect() + fx = QtWidgets.QGraphicsDropShadowEffect() fx.setOffset(2,2) fx.setBlurRadius(5) self.setGraphicsEffect(fx) @@ -157,7 +159,7 @@ def mousePressEvent(self, event): if self.__handlePoly.containsPoint(pos, QtCore.Qt.OddEvenFill): self.__resizing = True else: - QtGui.QGraphicsRectItem.mousePressEvent(self, event) + QtWidgets.QGraphicsRectItem.mousePressEvent(self, event) def mouseMoveEvent(self, event): if self.__resizing: @@ -171,13 +173,13 @@ def mouseMoveEvent(self, event): self.__headerContentRect.height()) self.__moveHandleBottomRightTo(newRect.bottomRight()) else: - QtGui.QGraphicsRectItem.mouseMoveEvent(self, event) + QtWidgets.QGraphicsRectItem.mouseMoveEvent(self, event) def mouseReleaseEvent(self, event): if self.__resizing: self.__resizing = False else: - QtGui.QGraphicsRectItem.mouseReleaseEvent(self, event) + QtWidgets.QGraphicsRectItem.mouseReleaseEvent(self, event) def paint(self, painter, paintOptions, widget): myRect = self.boundingRect() @@ -210,7 +212,7 @@ def paint(self, painter, paintOptions, widget): # A Vanishing GraphicsItem mixing. Appears on # # hover in and vanishes on hover out # ############################################### -class AleaQGraphicsVanishingMixin(object): +class AleaQGraphicsVanishingMixin: __baseOpacity = 0.01 __numFrames = 24 @@ -271,10 +273,10 @@ def disappear(self): state = self.__timer.state() self.__timer.setDuration(self.__vanishingTime) - if state == QtCore.QTimeLine.Running and \ - self.__timer.direction() == QtCore.QTimeLine.Forward: + if ((state == QtCore.QTimeLine.Running) and + (self.__timer.direction() == QtCore.QTimeLine.Forward)): self.__timer.setDirection(QtCore.QTimeLine.Backward) - elif state == QtCore.QTimeLine.NotRunning: + elif (state == QtCore.QTimeLine.NotRunning): self.__timer.setCurrentTime(self.__timer.duration()) self.__timer.setDirection(QtCore.QTimeLine.Backward) self.__timer.start() @@ -289,7 +291,7 @@ def appear(self): return state = self.__timer.state() - self.__timer.setDuration(self.__vanishingTime/2) + self.__timer.setDuration(self.__vanishingTime//2) if state == QtCore.QTimeLine.Running and \ self.__timer.direction() == QtCore.QTimeLine.Backward: self.__timer.setDirection(QtCore.QTimeLine.Forward) @@ -308,7 +310,7 @@ def hoverLeaveEvent(self, event): ########################################### # A button like mixin for qgraphics items # ########################################### -class AleaQGraphicsButtonMixin(object): +class AleaQGraphicsButtonMixin: def __init__(self, auto=True): self.setAcceptedMouseButtons(QtCore.Qt.LeftButton) self.pressed = AleaSignal() @@ -325,12 +327,12 @@ def mouseReleaseEvent(self, event): ######################## # A horizontal toolbar # ######################## -class AleaQGraphicsToolbar(QtGui.QGraphicsRectItem, AleaQGraphicsVanishingMixin): +class AleaQGraphicsToolbar(AleaQGraphicsVanishingMixin, QtWidgets.QGraphicsRectItem): def __init__(self, parent=None): - QtGui.QGraphicsRectItem.__init__(self, parent) + QtWidgets.QGraphicsRectItem.__init__(self, parent) AleaQGraphicsVanishingMixin.__init__(self) self.setPen(QtGui.QPen(QtCore.Qt.NoPen)) - self.setFlag(QtGui.QGraphicsItem.ItemIgnoresTransformations, True) + self.setFlag(QtWidgets.QGraphicsItem.ItemIgnoresTransformations, True) self.__layout = HorizontalLayout(parent=None, margins=(2.,2.,2.,2.), innerMargins=(1.,1.), center=True, mins=(20.,20.)) @@ -348,9 +350,9 @@ def addItem(self, item): ############################################################# # Customized Qt Classes that can be reused in other places. # ############################################################# -class AleaQGraphicsRoundedRectItem(QtGui.QGraphicsRectItem): +class AleaQGraphicsRoundedRectItem(QtWidgets.QGraphicsRectItem): def __init__(self, radius, cache=False, *args): - QtGui.QGraphicsRectItem.__init__(self, *args) + QtWidgets.QGraphicsRectItem.__init__(self, *args) self.__radius = radius self.__useCachedPath = cache self.__cachedPath = None @@ -382,8 +384,8 @@ def paint(self, painter, options, widget): painter.setBrush(self.brush()) painter.drawPath(self.shape()) -class AleaQGraphicsEmitingTextItem(QtGui.QGraphicsTextItem): - """A QtGui.QGraphicsTextItem that emits geometryModified whenever +class AleaQGraphicsEmitingTextItem(QtWidgets.QGraphicsTextItem): + """A QtWidgets.QGraphicsTextItem that emits geometryModified whenever its geometry can have changed.""" ###################### @@ -392,7 +394,7 @@ class AleaQGraphicsEmitingTextItem(QtGui.QGraphicsTextItem): geometryModified = QtCore.Signal(QtCore.QRectF) def __init__(self, *args, **kwargs): - QtGui.QGraphicsTextItem.__init__(self, *args, **kwargs) + QtWidgets.QGraphicsTextItem.__init__(self, *args, **kwargs) self.document().contentsChanged.connect(self.__onDocumentChanged) self.hoveredIn = AleaSignal() self.hoveredOut = AleaSignal() @@ -401,11 +403,11 @@ def __onDocumentChanged(self): self.geometryModified.emit(self.boundingRect()) def hoverEnterEvent(self, event): - QtGui.QGraphicsTextItem.hoverEnterEvent(self, event) + QtWidgets.QGraphicsTextItem.hoverEnterEvent(self, event) self.hoveredIn.emit(event) def hoverLeaveEvent(self, event): - QtGui.QGraphicsTextItem.hoverLeaveEvent(self, event) + QtWidgets.QGraphicsTextItem.hoverLeaveEvent(self, event) self.hoveredOut.emit(event) @@ -414,14 +416,14 @@ def hoverLeaveEvent(self, event): # Buttons # ########### -class AleaQGraphicsColorWheel(QtGui.QGraphicsEllipseItem, AleaQGraphicsVanishingMixin, AleaQGraphicsButtonMixin): - _stopHues = xrange(0,360,360/12) - _stopPos = [i*1.0/12 for i in xrange(12)] +class AleaQGraphicsColorWheel(AleaQGraphicsVanishingMixin, AleaQGraphicsButtonMixin, QtWidgets.QGraphicsEllipseItem): + _stopHues = range(0,360,360//12) + _stopPos = [i*1.0/12 for i in range(12)] ###################### # The Missing Signal # ###################### def __init__(self, radius=3.0, parent=None): - QtGui.QGraphicsEllipseItem.__init__(self, 0,0,radius*2, radius*2, parent) + QtWidgets.QGraphicsEllipseItem.__init__(self, 0,0,radius*2, radius*2, parent) AleaQGraphicsVanishingMixin.__init__(self) AleaQGraphicsButtonMixin.__init__(self) self.colorChanged = AleaSignal(QtGui.QColor) @@ -432,14 +434,14 @@ def __init__(self, radius=3.0, parent=None): self.setBrush(QtGui.QBrush(gradient)) def _onButtonPressed(self, event): - color = QtGui.QColorDialog.getColor(QtCore.Qt.white, event.widget()) + color = QtWidgets.QColorDialog.getColor(QtCore.Qt.white, event.widget()) if color.isValid(): self.colorChanged.emit(color) -class AleaQGraphicsFontButton(QtGui.QGraphicsSimpleTextItem, AleaQGraphicsButtonMixin): +class AleaQGraphicsFontButton(AleaQGraphicsButtonMixin, QtWidgets.QGraphicsSimpleTextItem): _fontSize=24 def __init__(self, parent=None): - QtGui.QGraphicsSimpleTextItem.__init__(self, "A", parent) + QtWidgets.QGraphicsSimpleTextItem.__init__(self, "A", parent) AleaQGraphicsButtonMixin.__init__(self) font = self.font() font.setPixelSize(self._fontSize) @@ -448,7 +450,7 @@ def __init__(self, parent=None): self.fontChanged = AleaSignal(QtGui.QFont) def _onButtonPressed(self, event): - font, ok = QtGui.QFontDialog.getFont(event.widget()) + font, ok = QtWidgets.QFontDialog.getFont(event.widget()) if ok: self.fontChanged.emit(font) @@ -465,14 +467,14 @@ def __init__(self, parent=None): self.setBrush(QtGui.QBrush(QtGui.QColor(255,0,0))) def _onButtonPressed(self, event): - color = QtGui.QColorDialog.getColor(QtCore.Qt.white, event.widget()) + color = QtWidgets.QColorDialog.getColor(QtCore.Qt.white, event.widget()) if color.isValid(): self.fontColorChanged.emit(color) ##################################### # Simple layouts for QGraphicsItems # ##################################### -class Layout(object): +class Layout: def __init__(self, parent=None, final=None, margins=(0.,0.,0.,0.), innerMargins=(0.,0.), center=False, mins=(0.,0.)): self._parent = parent @@ -531,7 +533,7 @@ def _boundingRect(self): def setPos(self, pos): raise NotImplementedError - def setMinimumSize(width=None, height=None): + def setMinimumSize(self, width=None, height=None): if width: self._minWidth = width if height: self._minHeight = height @@ -616,10 +618,10 @@ def setPos(self, pos): ######################################################################################################### -# class AleaQGraphicsLabelWidget(QtGui.QGraphicsWidget): # +# class AleaQGraphicsLabelWidget(QtWidgets.QGraphicsWidget): # # def __init__(self, label, parent=None): # -# QtGui.QGraphicsWidget.__init__(self, parent) # -# self.__label = QtGui.QGraphicsSimpleTextItem(self) # +# QtWidgets.QGraphicsWidget.__init__(self, parent) # +# self.__label = QtWidgets.QGraphicsSimpleTextItem(self) # # font = self.__label.font() # # font.setBold(True) # # self.__label.setText(label) # @@ -643,7 +645,7 @@ def setPos(self, pos): # def paint(self, painter, paintOpts, widget): # # self.__label.paint(painter, paintOpts, widget) # # # -# class AleaQGraphicsProxyWidget(QtGui.QGraphicsProxyWidget): # +# class AleaQGraphicsProxyWidget(QtWidgets.QGraphicsProxyWidget): # # """Embed a QWidget in a QGraphicsItem without the ugly background. # # # # When embedding for ex. a QLabel in a QGraphicsLayout using the normal # @@ -657,11 +659,11 @@ def setPos(self, pos): # Ctor. # # # # :Parameters: # -# - widget (QtGui.QWidget) - The QWidget to embed # -# - parent (QtGui.QGraphicsItem) - Reference to the parent. # +# - widget (QtWidgets.QWidget) - The QWidget to embed # +# - parent (QtWidgets.QGraphicsItem) - Reference to the parent. # # # # """ # -# QtGui.QGraphicsProxyWidget.__init__(self, parent) # +# QtWidgets.QGraphicsProxyWidget.__init__(self, parent) # # self.setWidget(widget) # # self.__noMouseEventForward = True # # # @@ -671,7 +673,7 @@ def setPos(self, pos): # if(event.type()==QtCore.QEvent.GraphicsSceneHoverMove and self.__noMouseEventForward): # # event.ignore() # # return True # -# return QtGui.QGraphicsProxyWidget.event(self, event) # +# return QtWidgets.QGraphicsProxyWidget.event(self, event) # # # # def setMouseEventForward(self, val): # # self.__noMouseEventForward = val # @@ -680,32 +682,32 @@ def setPos(self, pos): # widget.setBackgroundRole(QtGui.QPalette.Background) # # widget.setAutoFillBackground(True) # # widget.setStyleSheet("background-color: transparent") # -# QtGui.QGraphicsProxyWidget.setWidget(self, widget) # +# QtWidgets.QGraphicsProxyWidget.setWidget(self, widget) # ######################################################################################################### -class AleaQMenu(QtGui.QMenu): +class AleaQMenu(QtWidgets.QMenu): def __init__(self, arg1=None, arg2=None): - if isinstance(arg1, QtGui.QWidget): - QtGui.QMenu.__init__(self, arg1) + if isinstance(arg1, QtWidgets.QWidget): + QtWidgets.QMenu.__init__(self, arg1) else: - QtGui.QMenu.__init__(self, arg1, arg2) + QtWidgets.QMenu.__init__(self, arg1, arg2) def move(self, pos): rect = QtCore.QRect(pos, self.sizeHint()) #fix the position of the menu if it tries to popup too close to the lower & right edges. #bad fixing strategy probably: what if we were create arabian menus? #We should maybe sublcass QMenu to handle screen real estate and reuse it. - desktopGeom = QtGui.QApplication.desktop().availableGeometry(self.parent()) + desktopGeom = QtWidgets.QApplication.desktop().availableGeometry(self.parent()) contained, edges = qrect_contains(desktopGeom, rect, True) if not contained and edges.count(0) > 0: dx = edges[0] if edges[0] else edges[1] dy = edges[2] if edges[2] else edges[3] rect.translate(dx, dy) - QtGui.QMenu.move(self,rect.topLeft()) + QtWidgets.QMenu.move(self,rect.topLeft()) return else: - QtGui.QMenu.move(self, pos) + QtWidgets.QMenu.move(self, pos) def qrect_contains(r1, r2, proper): diff --git a/src/openalea/grapheditor/version.py b/src/openalea/grapheditor/version.py new file mode 100644 index 0000000..840cbfc --- /dev/null +++ b/src/openalea/grapheditor/version.py @@ -0,0 +1,15 @@ +""" +Maintain version for this package. +""" + +MAJOR = 2 +"""(int) Version major component.""" + +MINOR = 2 +"""(int) Version minor component.""" + +POST = 0 +"""(int) Version post or bugfix component.""" + +__version__ = ".".join([str(s) for s in (MAJOR, MINOR, POST)]) + diff --git a/test/__pycache__/test_grapheditor.cpython-36.pyc b/test/__pycache__/test_grapheditor.cpython-36.pyc new file mode 100644 index 0000000..ce3c0b1 Binary files /dev/null and b/test/__pycache__/test_grapheditor.cpython-36.pyc differ