mirror of https://gitlab.com/pamhyr/pamhyr2
Scenario: Continue adapt network window to scenario.
parent
b60b922fef
commit
abe7046d4f
|
|
@ -88,25 +88,3 @@ class NodeMenu(AbstractMenu):
|
||||||
else:
|
else:
|
||||||
if action == add_res:
|
if action == add_res:
|
||||||
self._parent.add_node_reservoir(node)
|
self._parent.add_node_reservoir(node)
|
||||||
|
|
||||||
|
|
||||||
class EdgeMenu(AbstractMenu):
|
|
||||||
def run(self):
|
|
||||||
it = self._items[0]
|
|
||||||
|
|
||||||
reverse = self._menu.addAction(self._trad["menu_rev_edge"])
|
|
||||||
delete = self._menu.addAction(self._trad["menu_del_edge"])
|
|
||||||
if self._parent.graph.is_enable_edge(it.edge):
|
|
||||||
enable = self._menu.addAction(self._trad["menu_dis_edge"])
|
|
||||||
is_enable = True
|
|
||||||
else:
|
|
||||||
enable = self._menu.addAction(self._trad["menu_ena_edge"])
|
|
||||||
is_enable = False
|
|
||||||
|
|
||||||
action = self._exec()
|
|
||||||
if action == delete:
|
|
||||||
self._parent.del_edge(it)
|
|
||||||
elif action == enable:
|
|
||||||
self._parent.enable_edge(it, is_enable)
|
|
||||||
elif action == reverse:
|
|
||||||
self._parent.reverse_edge(it)
|
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ from PyQt5.QtWidgets import (
|
||||||
|
|
||||||
from View.Scenarios.UndoCommand import *
|
from View.Scenarios.UndoCommand import *
|
||||||
from View.Scenarios.ContextMenu import (
|
from View.Scenarios.ContextMenu import (
|
||||||
DefaultMenu, NodeMenu, EdgeMenu,
|
DefaultMenu, NodeMenu,
|
||||||
)
|
)
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
@ -44,16 +44,17 @@ logger = logging.getLogger()
|
||||||
_translate = QCoreApplication.translate
|
_translate = QCoreApplication.translate
|
||||||
|
|
||||||
|
|
||||||
class ScenarioItem(QGraphicsItem):
|
class ScenarioItem(QGraphicsTextItem):
|
||||||
Type = QGraphicsItem.UserType + 1
|
Type = QGraphicsItem.UserType + 10
|
||||||
|
|
||||||
def __init__(self, node, graph_widget):
|
def __init__(self, scenario, graph_widget):
|
||||||
super(ScenarioItem, self).__init__()
|
super(ScenarioItem, self).__init__()
|
||||||
|
|
||||||
self.node = node
|
|
||||||
self.setPos(QPointF(self.node.pos.x, self.node.pos.y))
|
|
||||||
|
|
||||||
self.graph = graph_widget
|
self.graph = graph_widget
|
||||||
|
self.scenario = scenario
|
||||||
|
|
||||||
|
self.setPlainText(self.scenario.name)
|
||||||
|
self.setDefaultTextColor(Qt.black)
|
||||||
|
|
||||||
self.setFlag(QGraphicsItem.ItemIsMovable)
|
self.setFlag(QGraphicsItem.ItemIsMovable)
|
||||||
self.setFlag(QGraphicsItem.ItemSendsGeometryChanges)
|
self.setFlag(QGraphicsItem.ItemSendsGeometryChanges)
|
||||||
|
|
@ -61,339 +62,114 @@ class ScenarioItem(QGraphicsItem):
|
||||||
self.setZValue(1)
|
self.setZValue(1)
|
||||||
|
|
||||||
def type(self):
|
def type(self):
|
||||||
return NodeItem.Type
|
return ScenarioItem.Type
|
||||||
|
|
||||||
def boundingRect(self):
|
|
||||||
adjust = 2.0
|
|
||||||
return QRectF(-10 - adjust, -10 - adjust, 20 + adjust, 20 + adjust)
|
|
||||||
|
|
||||||
def shape(self):
|
|
||||||
path = QPainterPath()
|
|
||||||
if self.graph.graph._reservoir.get_assoc_to_node(self.node) is None:
|
|
||||||
path.addEllipse(-10, -10, 20, 20)
|
|
||||||
else:
|
|
||||||
path.addRect(-10, -10, 20, 20)
|
|
||||||
return path
|
|
||||||
|
|
||||||
@timer
|
|
||||||
def paint(self, painter, option, widget):
|
|
||||||
painter.setPen(Qt.NoPen)
|
|
||||||
|
|
||||||
# Select color in function of node position in graph and
|
|
||||||
# status
|
|
||||||
color = Qt.darkBlue
|
|
||||||
if self.graph.selected_new_edge_src_node() == self:
|
|
||||||
color = Qt.darkRed
|
|
||||||
elif self.graph.selected_item() == self:
|
|
||||||
color = Qt.red
|
|
||||||
elif not self.graph.graph.is_enable_node(self.node):
|
|
||||||
color = Qt.darkGray
|
|
||||||
elif self.graph.graph.is_upstream_node(self.node):
|
|
||||||
color = Qt.yellow
|
|
||||||
elif self.graph.graph.is_downstream_node(self.node):
|
|
||||||
color = Qt.green
|
|
||||||
|
|
||||||
painter.setBrush(QBrush(color))
|
|
||||||
if self.graph.graph._reservoir.get_assoc_to_node(self.node) is None:
|
|
||||||
painter.drawEllipse(-10, -10, 20, 20)
|
|
||||||
else:
|
|
||||||
painter.drawRect(-10, -10, 20, 20)
|
|
||||||
|
|
||||||
def itemChange(self, change, value):
|
|
||||||
if change == QGraphicsItem.ItemPositionHasChanged:
|
|
||||||
self.graph.node_change_position(value, self)
|
|
||||||
|
|
||||||
self.graph.update_edges(self)
|
|
||||||
return super(NodeItem, self).itemChange(change, value)
|
|
||||||
|
|
||||||
def mousePressEvent(self, event):
|
|
||||||
self.update()
|
|
||||||
if not self.graph._only_display:
|
|
||||||
super(NodeItem, self).mousePressEvent(event)
|
|
||||||
|
|
||||||
def mouseReleaseEvent(self, event):
|
|
||||||
self.update()
|
|
||||||
super(NodeItem, self).mouseReleaseEvent(event)
|
|
||||||
|
|
||||||
def mouseMoveEvent(self, event):
|
|
||||||
self.update()
|
|
||||||
if not self.graph._only_display:
|
|
||||||
super(NodeItem, self).mouseMoveEvent(event)
|
|
||||||
|
|
||||||
|
|
||||||
class EdgeItem(QGraphicsItem):
|
|
||||||
_arc_dist = 0.1
|
|
||||||
|
|
||||||
Type = QGraphicsItem.UserType + 2
|
|
||||||
|
|
||||||
def __init__(self, src_node_item, dest_node_item,
|
|
||||||
edge, graph_widget):
|
|
||||||
super(EdgeItem, self).__init__()
|
|
||||||
|
|
||||||
self.src_node = src_node_item
|
|
||||||
self.dest_node = dest_node_item
|
|
||||||
self.edge = edge
|
|
||||||
|
|
||||||
self.graph = graph_widget
|
|
||||||
self._ind = 1
|
|
||||||
|
|
||||||
geometry = self.compute_arc_two_point(
|
|
||||||
QPointF(
|
|
||||||
self.src_node.pos().x(),
|
|
||||||
self.src_node.pos().y()
|
|
||||||
),
|
|
||||||
QPointF(
|
|
||||||
self.dest_node.pos().x(),
|
|
||||||
self.dest_node.pos().y()
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
self._bound_rect = geometry['bound_rect']
|
|
||||||
self._arc = geometry['arc']
|
|
||||||
|
|
||||||
self.setAcceptedMouseButtons(Qt.NoButton)
|
|
||||||
|
|
||||||
def type(self):
|
|
||||||
return Edge.Type
|
|
||||||
|
|
||||||
def boundingRect(self):
|
|
||||||
# Rectangle of edge for display update
|
|
||||||
pen_width = 2.0
|
|
||||||
extra = 0 # (pen_width + 5) / 2.0
|
|
||||||
|
|
||||||
return self._bound_rect.normalized().adjusted(
|
|
||||||
-extra, -extra, extra, extra
|
|
||||||
)
|
|
||||||
|
|
||||||
def shape(self):
|
|
||||||
return self._arc
|
|
||||||
|
|
||||||
def paint(self, painter, option, widget):
|
|
||||||
# self.paint_line(painter, option, widget)
|
|
||||||
self.paint_arc(painter, option, widget)
|
|
||||||
|
|
||||||
@timer
|
|
||||||
def paint_line(self, painter, option, widget):
|
|
||||||
# Draw shape of the edge
|
|
||||||
# color = QColor(Qt.white)
|
|
||||||
# color.setAlpha(128)
|
|
||||||
# painter.setBrush(color)
|
|
||||||
# painter.drawPath(self.shape())
|
|
||||||
|
|
||||||
line = QLineF(self.src_node.pos(), self.dest_node.pos())
|
|
||||||
if line.length() == 0.0:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Select color
|
|
||||||
# color = Qt.darkBlue
|
|
||||||
color = Qt.black
|
|
||||||
if self.graph.selected_item() == self:
|
|
||||||
color = Qt.red
|
|
||||||
elif self.graph.current_edge() == self:
|
|
||||||
color = Qt.blue
|
|
||||||
elif not self.graph.graph.is_enable_edge(self.edge):
|
|
||||||
color = Qt.darkGray
|
|
||||||
|
|
||||||
painter.setPen(
|
|
||||||
QPen(
|
|
||||||
color, 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
painter.drawLine(line)
|
|
||||||
|
|
||||||
# Draw arrow
|
|
||||||
center = QPointF(
|
|
||||||
(self.src_node.pos().x() + self.dest_node.pos().x()) / 2,
|
|
||||||
(self.src_node.pos().y() + self.dest_node.pos().y()) / 2,
|
|
||||||
)
|
|
||||||
angle = math.acos(line.dx() / line.length())
|
|
||||||
if line.dy() >= 0:
|
|
||||||
angle = (math.pi * 2.0) - angle
|
|
||||||
|
|
||||||
self.paint_arrow(
|
|
||||||
painter, option, widget,
|
|
||||||
color, center, angle
|
|
||||||
)
|
|
||||||
|
|
||||||
@timer
|
|
||||||
def paint_arc(self, painter, option, widget):
|
|
||||||
line = QLineF(self.src_node.pos(), self.dest_node.pos())
|
|
||||||
if line.length() == 0.0:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Select color
|
|
||||||
# color = Qt.darkBlue
|
|
||||||
color = Qt.black
|
|
||||||
if self.graph.selected_item() == self:
|
|
||||||
color = Qt.red
|
|
||||||
elif self.graph.current_edge() == self:
|
|
||||||
color = Qt.blue
|
|
||||||
elif not self.graph.graph.is_enable_edge(self.edge):
|
|
||||||
color = Qt.darkGray
|
|
||||||
|
|
||||||
painter.setPen(
|
|
||||||
QPen(
|
|
||||||
color, 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
geometry = self.compute_arc_two_point(
|
|
||||||
QPointF(
|
|
||||||
self.src_node.pos().x(),
|
|
||||||
self.src_node.pos().y()
|
|
||||||
),
|
|
||||||
QPointF(
|
|
||||||
self.dest_node.pos().x(),
|
|
||||||
self.dest_node.pos().y()
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
self._bound_rect = geometry['bound_rect']
|
|
||||||
self._arc = geometry['arc']
|
|
||||||
|
|
||||||
painter.drawPath(self._arc)
|
|
||||||
|
|
||||||
line = geometry['line']
|
|
||||||
angle = math.acos(line.dx() / line.length())
|
|
||||||
if line.dy() >= 0:
|
|
||||||
angle = (math.pi * 2.0) - angle
|
|
||||||
|
|
||||||
self.paint_arrow(
|
|
||||||
painter, option, widget,
|
|
||||||
color, geometry['c'], angle,
|
|
||||||
)
|
|
||||||
|
|
||||||
def compute_arc_two_point(self, a, b):
|
|
||||||
# This function is a black magic spell for invoking an arc
|
|
||||||
# path between two points in Qt! (In fact, it's just cryptic
|
|
||||||
# trigonometry functions from stackoverflow:
|
|
||||||
# https://stackoverflow.com/questions/26901540/arc-in-qgraphicsscene)
|
|
||||||
c = self.compute_arc_p3(a, b)
|
|
||||||
|
|
||||||
line_ac = QLineF(a, c)
|
|
||||||
line_bc = QLineF(b, c)
|
|
||||||
line_ab = QLineF(a, b)
|
|
||||||
|
|
||||||
rad = abs(
|
|
||||||
line_bc.length() / (
|
|
||||||
2 * math.sin(
|
|
||||||
math.radians(
|
|
||||||
line_ac.angleTo(line_ab)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
bisector_bc = QLineF(line_bc.pointAt(0.5), line_bc.p2())
|
|
||||||
bisector_bc.setAngle(line_bc.normalVector().angle())
|
|
||||||
|
|
||||||
bisector_ab = QLineF(line_ab.pointAt(0.5), line_ab.p2())
|
|
||||||
bisector_ab.setAngle(line_ab.normalVector().angle())
|
|
||||||
|
|
||||||
center = QPointF(0, 0)
|
|
||||||
bisector_ab.intersect(bisector_bc, center)
|
|
||||||
|
|
||||||
circle = QRectF(
|
|
||||||
center.x() - rad,
|
|
||||||
center.y() - rad,
|
|
||||||
rad * 2, rad * 2
|
|
||||||
)
|
|
||||||
|
|
||||||
line_oa = QLineF(center, a)
|
|
||||||
line_ob = QLineF(center, b)
|
|
||||||
line_oc = QLineF(center, c)
|
|
||||||
|
|
||||||
start = line_ob
|
|
||||||
end = line_oa
|
|
||||||
|
|
||||||
w = 1
|
|
||||||
bounding_rect = circle.adjusted(
|
|
||||||
-w, -w, w, w
|
|
||||||
)
|
|
||||||
|
|
||||||
path = QPainterPath()
|
|
||||||
path.arcMoveTo(circle, start.angle())
|
|
||||||
path.arcTo(circle, start.angle(), start.angleTo(end))
|
|
||||||
|
|
||||||
return {
|
|
||||||
'bound_rect': bounding_rect,
|
|
||||||
'arc': path,
|
|
||||||
'c': c,
|
|
||||||
'line': line_ab,
|
|
||||||
}
|
|
||||||
|
|
||||||
def compute_arc_p3(self, p1, p2):
|
|
||||||
dist_p3 = self._ind * self._arc_dist
|
|
||||||
|
|
||||||
center_p1_p2 = QPointF(
|
|
||||||
(p1.x() + p2.x()) / 2,
|
|
||||||
(p1.y() + p2.y()) / 2
|
|
||||||
)
|
|
||||||
|
|
||||||
# u = (p2.x() - p1.x(), p2.y() - p1.y())
|
|
||||||
v = (p2.y() - p1.y(), p1.x() - p2.x())
|
|
||||||
p3 = QPointF(
|
|
||||||
center_p1_p2.x() + dist_p3 * v[0],
|
|
||||||
center_p1_p2.y() + dist_p3 * v[1]
|
|
||||||
)
|
|
||||||
|
|
||||||
return p3
|
|
||||||
|
|
||||||
def paint_arrow(self, painter, option, widget,
|
|
||||||
color, center, angle):
|
|
||||||
brush = QBrush()
|
|
||||||
brush.setColor(color)
|
|
||||||
brush.setStyle(Qt.SolidPattern)
|
|
||||||
|
|
||||||
size = 10.0
|
|
||||||
arrow_p1 = center + QPointF(
|
|
||||||
math.sin(angle - math.pi / 3) * size,
|
|
||||||
math.cos(angle - math.pi / 3) * size
|
|
||||||
)
|
|
||||||
arrow_p2 = center + QPointF(
|
|
||||||
math.sin(angle - math.pi + math.pi / 3) * size,
|
|
||||||
math.cos(angle - math.pi + math.pi / 3) * size
|
|
||||||
)
|
|
||||||
poly = QPolygonF([center, arrow_p1, arrow_p2])
|
|
||||||
path = QPainterPath()
|
|
||||||
path.addPolygon(poly)
|
|
||||||
|
|
||||||
painter.drawPolygon(poly)
|
|
||||||
painter.fillPath(path, brush)
|
|
||||||
|
|
||||||
|
|
||||||
class NodeText(QGraphicsTextItem):
|
|
||||||
def __init__(self, node_item):
|
|
||||||
super(NodeText, self).__init__()
|
|
||||||
|
|
||||||
self.item = node_item
|
|
||||||
self.setPlainText(self.item.node.name)
|
|
||||||
self.setDefaultTextColor(Qt.black)
|
|
||||||
self.set_custom_pos(self.item.pos())
|
|
||||||
self.setZValue(2)
|
|
||||||
|
|
||||||
def set_custom_pos(self, pos):
|
def set_custom_pos(self, pos):
|
||||||
x = pos.x()
|
x = pos.x()
|
||||||
y = pos.y() - 42 # Dont panic! The answer is 42
|
y = pos.y()
|
||||||
|
|
||||||
self.setPos(QPointF(x, y))
|
self.setPos(QPointF(x, y))
|
||||||
|
|
||||||
@timer
|
@timer
|
||||||
def paint(self, painter, option, widget):
|
def paint(self, painter, option, widget):
|
||||||
color = QColor(Qt.white)
|
color = QColor(Qt.white)
|
||||||
color.setAlpha(128)
|
|
||||||
|
|
||||||
# Draw text background
|
painter.setPen(Qt.NoPen)
|
||||||
painter.setBrush(color)
|
painter.setBrush(QBrush(color))
|
||||||
painter.drawRect(self.boundingRect())
|
painter.drawEllipse(self.boundingRect())
|
||||||
|
|
||||||
# Draw text
|
super(ScenarioItem, self).paint(painter, option, widget)
|
||||||
super(NodeText, self).paint(painter, option, widget)
|
|
||||||
|
|
||||||
def rename(self):
|
|
||||||
# Update the node text
|
class EdgeItem(QGraphicsItem):
|
||||||
self.setPlainText(self.item.node.name)
|
Type = QGraphicsItem.UserType + 11
|
||||||
|
|
||||||
|
def __init__(self, scenario_item, parent_item, graph_widget):
|
||||||
|
super(EdgeItem, self).__init__()
|
||||||
|
|
||||||
|
self.item = scenario_item
|
||||||
|
self.parent_item = parent_item
|
||||||
|
self.graph = graph_widget
|
||||||
|
|
||||||
|
self.setAcceptedMouseButtons(Qt.NoButton)
|
||||||
|
|
||||||
|
def type(self):
|
||||||
|
return EdgeItem.Type
|
||||||
|
|
||||||
|
def boundingRect(self):
|
||||||
|
pen_width = 2.0
|
||||||
|
extra = (pen_width + 5) / 2.0
|
||||||
|
|
||||||
|
return QRectF(
|
||||||
|
self.parent_item.pos(),
|
||||||
|
QSizeF(
|
||||||
|
self.item.pos().x() - self.parent_item.pos().x(),
|
||||||
|
self.item.pos().y() - self.parent_item.pos().y()
|
||||||
|
)
|
||||||
|
).normalized().adjusted(-extra, -extra, extra, extra)
|
||||||
|
|
||||||
|
def shape(self):
|
||||||
|
vec = self.item.pos() - self.parent_item.pos()
|
||||||
|
vec = vec * (5 / math.sqrt(QPointF.dotProduct(vec, vec)))
|
||||||
|
extra = QPointF(vec.y(), -vec.x())
|
||||||
|
|
||||||
|
result = QPainterPath(self.parent_item.pos() - vec + extra)
|
||||||
|
result.lineTo(self.parent_item.pos() - vec - extra)
|
||||||
|
result.lineTo(self.item.pos() + vec - extra)
|
||||||
|
result.lineTo(self.item.pos() + vec + extra)
|
||||||
|
result.closeSubpath()
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
@timer
|
||||||
|
def paint(self, painter, option, widget):
|
||||||
|
line = QLineF(self.parent_item.pos(), self.item.pos())
|
||||||
|
if line.length() == 0.0:
|
||||||
|
return
|
||||||
|
|
||||||
|
color = Qt.black
|
||||||
|
painter.setPen(
|
||||||
|
QPen(
|
||||||
|
color, 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin
|
||||||
|
)
|
||||||
|
)
|
||||||
|
# Draw the line
|
||||||
|
painter.drawLine(line)
|
||||||
|
|
||||||
|
arrow = self.get_arrow_path(line, color)
|
||||||
|
|
||||||
|
brush = QBrush()
|
||||||
|
brush.setColor(color)
|
||||||
|
brush.setStyle(Qt.SolidPattern)
|
||||||
|
|
||||||
|
path = QPainterPath()
|
||||||
|
path.addPolygon(arrow)
|
||||||
|
|
||||||
|
painter.drawPolygon(arrow)
|
||||||
|
painter.fillPath(path, brush)
|
||||||
|
|
||||||
|
def get_arrow_path(self, line, color):
|
||||||
|
line_center = QPointF(
|
||||||
|
(self.parent_item.pos().x() + self.item.pos().x()) / 2,
|
||||||
|
(self.parent_item.pos().y() + self.item.pos().y()) / 2,
|
||||||
|
)
|
||||||
|
|
||||||
|
angle = math.acos(line.dx() / line.length())
|
||||||
|
if line.dy() >= 0:
|
||||||
|
angle = (math.pi * 2.0) - angle
|
||||||
|
|
||||||
|
size = 10.0
|
||||||
|
arrow_p1 = line_center + QPointF(
|
||||||
|
math.sin(angle - math.pi / 3) * size,
|
||||||
|
math.cos(angle - math.pi / 3) * size
|
||||||
|
)
|
||||||
|
arrow_p2 = line_center + QPointF(
|
||||||
|
math.sin(angle - math.pi + math.pi / 3) * size,
|
||||||
|
math.cos(angle - math.pi + math.pi / 3) * size
|
||||||
|
)
|
||||||
|
poly = QPolygonF([line_center, arrow_p1, arrow_p2])
|
||||||
|
|
||||||
|
return poly
|
||||||
|
|
||||||
|
|
||||||
class GraphWidget(QGraphicsView):
|
class GraphWidget(QGraphicsView):
|
||||||
|
|
@ -407,20 +183,15 @@ class GraphWidget(QGraphicsView):
|
||||||
super(GraphWidget, self).__init__(parent=parent)
|
super(GraphWidget, self).__init__(parent=parent)
|
||||||
|
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
self._state = "move"
|
|
||||||
self._only_display = only_display
|
|
||||||
self._undo = undo
|
self._undo = undo
|
||||||
self._trad = trad
|
self._trad = trad
|
||||||
|
|
||||||
self.graph = graph
|
self.graph = graph
|
||||||
|
|
||||||
self._selected_item = None
|
self._selected_item = None
|
||||||
self._selected_new_edge_src_node = None
|
|
||||||
self._current_edge = None
|
|
||||||
self._current_moved_node = None
|
self._current_moved_node = None
|
||||||
self.tmp_line = None
|
|
||||||
|
|
||||||
self.node_items = []
|
self.scenarios_items = {}
|
||||||
self.edge_items = []
|
self.edge_items = []
|
||||||
self.texts = {}
|
self.texts = {}
|
||||||
|
|
||||||
|
|
@ -461,155 +232,22 @@ class GraphWidget(QGraphicsView):
|
||||||
Returns:
|
Returns:
|
||||||
Nothing
|
Nothing
|
||||||
"""
|
"""
|
||||||
self.node_items = []
|
self.scenarios_items = {}
|
||||||
self.edge_items = []
|
self.edge_items = []
|
||||||
self.texts = {}
|
|
||||||
|
|
||||||
for node in self.graph.nodes():
|
for scenar in self.graph.scenarios.lst:
|
||||||
inode = NodeItem(node, self)
|
iscenar = ScenarioItem(scenar, self)
|
||||||
self.texts[inode] = NodeText(inode)
|
self.scene().addItem(iscenar)
|
||||||
self.scene().addItem(self.texts[inode])
|
self.scenarios_items[scenar] = iscenar
|
||||||
self.scene().addItem(inode)
|
|
||||||
self.node_items.append(inode)
|
|
||||||
|
|
||||||
curr_edge = self.graph.current_reach()
|
if scenar.parent is not None:
|
||||||
|
iedge = EdgeItem(
|
||||||
iedges = []
|
self.scenarios_items[scenar],
|
||||||
multiple_edges = {}
|
self.scenarios_items[scenar.parent],
|
||||||
for edge in self.graph.edges():
|
self
|
||||||
n1 = next(
|
|
||||||
filter(
|
|
||||||
lambda n: n.node.name == edge.node1.name,
|
|
||||||
self.node_items
|
|
||||||
)
|
)
|
||||||
)
|
self.scene().addItem(iedge)
|
||||||
|
self.edge_items.append(iedge)
|
||||||
n2 = next(
|
|
||||||
filter(
|
|
||||||
lambda n: n.node.name == edge.node2.name,
|
|
||||||
self.node_items
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Multiple edges counter
|
|
||||||
if (n1, n2) not in multiple_edges:
|
|
||||||
ind = 1
|
|
||||||
else:
|
|
||||||
ind = multiple_edges[(n1, n2)] + 1
|
|
||||||
|
|
||||||
multiple_edges[(n1, n2)] = ind
|
|
||||||
|
|
||||||
iedge = EdgeItem(n1, n2, edge, self)
|
|
||||||
iedge._ind = ind
|
|
||||||
|
|
||||||
if edge == curr_edge:
|
|
||||||
self._current_edge = iedge
|
|
||||||
|
|
||||||
iedges.append(iedge)
|
|
||||||
|
|
||||||
for iedge in reversed(iedges):
|
|
||||||
self.scene().addItem(iedge)
|
|
||||||
self.edge_items.append(iedge)
|
|
||||||
|
|
||||||
def state(self, status):
|
|
||||||
"""Set the current status of draw widget
|
|
||||||
|
|
||||||
Set the current status of draw widget, like "move", "add" or
|
|
||||||
"del"
|
|
||||||
|
|
||||||
Args:
|
|
||||||
status: String of current status
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Nothing
|
|
||||||
"""
|
|
||||||
self._state = status
|
|
||||||
|
|
||||||
def add_node(self, pos):
|
|
||||||
"""Create a new node in graph and draw it
|
|
||||||
|
|
||||||
Args:
|
|
||||||
pos: The position of new node
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Nothing
|
|
||||||
"""
|
|
||||||
node = self.graph.create_node(pos.x(), pos.y())
|
|
||||||
self._undo.push(
|
|
||||||
AddNodeCommand(
|
|
||||||
self.graph, node
|
|
||||||
)
|
|
||||||
)
|
|
||||||
inode = NodeItem(node, self)
|
|
||||||
self.scene().addItem(inode)
|
|
||||||
self.node_items.append(inode)
|
|
||||||
self.texts[inode] = NodeText(inode)
|
|
||||||
self.scene().addItem(self.texts[inode])
|
|
||||||
|
|
||||||
self.changeNode.emit(self.sender())
|
|
||||||
|
|
||||||
def del_node(self, item):
|
|
||||||
"""Delete a node and update display
|
|
||||||
|
|
||||||
Args:
|
|
||||||
item: The node item to delete
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Nothing
|
|
||||||
"""
|
|
||||||
node = item.node
|
|
||||||
self._undo.push(
|
|
||||||
DelNodeCommand(
|
|
||||||
self.graph, node
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
self.scene().clear()
|
|
||||||
self.create_items()
|
|
||||||
self.changeNode.emit(self.sender())
|
|
||||||
self.changeEdge.emit(self.sender())
|
|
||||||
|
|
||||||
def rename_nodes(self):
|
|
||||||
"""Update all nodes item name in scene
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Nothing
|
|
||||||
"""
|
|
||||||
for i in self.texts:
|
|
||||||
if type(i) is NodeItem:
|
|
||||||
self.texts[i].rename()
|
|
||||||
|
|
||||||
def add_node_reservoir(self, node):
|
|
||||||
self.parent.add_node_reservoir(node)
|
|
||||||
self.display_update()
|
|
||||||
|
|
||||||
def del_node_reservoir(self, node):
|
|
||||||
self.parent.del_node_reservoir(node)
|
|
||||||
self.changeNode.emit(self.sender())
|
|
||||||
self.display_update()
|
|
||||||
|
|
||||||
def edit_node_reservoir(self, node):
|
|
||||||
self.changeNode.emit(self.sender())
|
|
||||||
self.parent.edit_node_reservoir(node)
|
|
||||||
|
|
||||||
def enable_edge(self, edge, prev):
|
|
||||||
self._undo.push(
|
|
||||||
EnableEdgeCommand(
|
|
||||||
edge.edge, not prev
|
|
||||||
)
|
|
||||||
)
|
|
||||||
self.changeEdge.emit(self.sender())
|
|
||||||
self.changeNode.emit(self.sender())
|
|
||||||
self.display_update()
|
|
||||||
|
|
||||||
def reverse_edge(self, edge):
|
|
||||||
self._undo.push(
|
|
||||||
ReverseEdgeCommand(
|
|
||||||
edge.edge
|
|
||||||
)
|
|
||||||
)
|
|
||||||
self.changeEdge.emit(self.sender())
|
|
||||||
self.display_update()
|
|
||||||
|
|
||||||
def display_update(self):
|
def display_update(self):
|
||||||
"""Clear the scene and redraw it
|
"""Clear the scene and redraw it
|
||||||
|
|
@ -620,18 +258,6 @@ class GraphWidget(QGraphicsView):
|
||||||
self.scene().clear()
|
self.scene().clear()
|
||||||
self.create_items()
|
self.create_items()
|
||||||
|
|
||||||
def keyPressEvent(self, event):
|
|
||||||
key = event.key()
|
|
||||||
|
|
||||||
if key == Qt.Key_Plus:
|
|
||||||
self.scaleView(1.2)
|
|
||||||
elif key == Qt.Key_Minus:
|
|
||||||
self.scaleView(1 / 1.2)
|
|
||||||
elif key == Qt.Key_Escape:
|
|
||||||
self.reset_selection()
|
|
||||||
else:
|
|
||||||
super(GraphWidget, self).keyPressEvent(event)
|
|
||||||
|
|
||||||
def drawBackground(self, painter, rect):
|
def drawBackground(self, painter, rect):
|
||||||
sceneRect = self.sceneRect()
|
sceneRect = self.sceneRect()
|
||||||
painter.fillRect(
|
painter.fillRect(
|
||||||
|
|
@ -654,160 +280,35 @@ class GraphWidget(QGraphicsView):
|
||||||
|
|
||||||
self.scale(scaleFactor, scaleFactor)
|
self.scale(scaleFactor, scaleFactor)
|
||||||
|
|
||||||
def mousePressEvent(self, event):
|
|
||||||
pos = self.mapToScene(event.pos())
|
|
||||||
self.clicked = True
|
|
||||||
|
|
||||||
if event.buttons() & Qt.RightButton:
|
|
||||||
self.update()
|
|
||||||
super(GraphWidget, self).mousePressEvent(event)
|
|
||||||
return
|
|
||||||
|
|
||||||
# Move item and select edge item
|
|
||||||
if self._state == "move":
|
|
||||||
self._selected_new_edge_src_node = None
|
|
||||||
|
|
||||||
items = self.items(event.pos())
|
|
||||||
if items and type(items[0]) is EdgeItem:
|
|
||||||
edge = items[0]
|
|
||||||
if edge:
|
|
||||||
self.set_current_edge(edge)
|
|
||||||
elif items and type(items[0]) is NodeItem:
|
|
||||||
self._mouse_origin_x = pos.x()
|
|
||||||
self._mouse_origin_y = pos.y()
|
|
||||||
self._current_moved_node = items[0]
|
|
||||||
|
|
||||||
# Add nodes and edges
|
|
||||||
elif self._state == "add":
|
|
||||||
items = self.items(event.pos())
|
|
||||||
nodes = list(filter(lambda i: type(i) is NodeItem, items))
|
|
||||||
if not nodes:
|
|
||||||
self.add_node(pos)
|
|
||||||
self.set_selected_new_edge_src_node(None)
|
|
||||||
else:
|
|
||||||
if self.selected_new_edge_src_node() is None:
|
|
||||||
self.set_selected_new_edge_src_node(nodes[0])
|
|
||||||
else:
|
|
||||||
self.add_edge(self.selected_new_edge_src_node(), nodes[0])
|
|
||||||
|
|
||||||
# Delete nodes and edges
|
|
||||||
elif self._state == "del":
|
|
||||||
self._selected_new_edge_src_node = None
|
|
||||||
items = list(
|
|
||||||
filter(
|
|
||||||
lambda i: type(i) is NodeItem or type(i) is EdgeItem,
|
|
||||||
self.items(event.pos())
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if len(items) > 0:
|
|
||||||
item = items[0]
|
|
||||||
if type(item) is NodeItem:
|
|
||||||
self.del_node(item)
|
|
||||||
elif type(item) is EdgeItem:
|
|
||||||
self.del_edge(item)
|
|
||||||
|
|
||||||
self.update()
|
|
||||||
super(GraphWidget, self).mousePressEvent(event)
|
|
||||||
|
|
||||||
def mouseReleaseEvent(self, event):
|
|
||||||
self.clicked = False
|
|
||||||
|
|
||||||
if self._only_display:
|
|
||||||
return
|
|
||||||
|
|
||||||
if self._state == "move":
|
|
||||||
if self._current_moved_node is not None:
|
|
||||||
pos = self.mapToScene(event.pos())
|
|
||||||
self._undo.push(
|
|
||||||
SetNodePosCommand(
|
|
||||||
self._current_moved_node,
|
|
||||||
(pos.x(), pos.y()),
|
|
||||||
(self._mouse_origin_x,
|
|
||||||
self._mouse_origin_y)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
self.update()
|
|
||||||
super(GraphWidget, self).mouseReleaseEvent(event)
|
|
||||||
|
|
||||||
def mouseMoveEvent(self, event):
|
|
||||||
pos = self.mapToScene(event.pos())
|
|
||||||
|
|
||||||
# Selecte item on the fly
|
|
||||||
items = self.items(event.pos())
|
|
||||||
selectable_items = list(
|
|
||||||
filter(
|
|
||||||
lambda i: (type(i) is NodeItem or type(i) is EdgeItem),
|
|
||||||
items
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
if selectable_items:
|
|
||||||
self.set_selected_item(selectable_items[0])
|
|
||||||
elif not self.clicked:
|
|
||||||
self.set_selected_item(None)
|
|
||||||
|
|
||||||
# Update temporary line
|
|
||||||
if self.selected_new_edge_src_node() is not None:
|
|
||||||
if self.tmp_line is None:
|
|
||||||
self.tmp_line = NewEdgeLine(
|
|
||||||
self.selected_new_edge_src_node().pos(),
|
|
||||||
pos
|
|
||||||
)
|
|
||||||
self.scene().addItem(self.tmp_line)
|
|
||||||
else:
|
|
||||||
self.tmp_line.dest = pos
|
|
||||||
self.tmp_line.update()
|
|
||||||
|
|
||||||
# If state is "move"
|
|
||||||
if self._state == "move":
|
|
||||||
# Move on scene
|
|
||||||
if not self.selected_item():
|
|
||||||
if event.buttons() & Qt.LeftButton:
|
|
||||||
old_p = self.mapToScene(
|
|
||||||
int(self.m_origin_x), int(self.m_origin_y)
|
|
||||||
)
|
|
||||||
new_p = self.mapToScene(event.pos())
|
|
||||||
translation = new_p - old_p
|
|
||||||
|
|
||||||
self.translate(translation.x(), translation.y())
|
|
||||||
|
|
||||||
self.m_origin_x = event.x()
|
|
||||||
self.m_origin_y = event.y()
|
|
||||||
|
|
||||||
# Propagate event
|
|
||||||
self.update()
|
|
||||||
super(GraphWidget, self).mouseMoveEvent(event)
|
|
||||||
|
|
||||||
# Contextual menu
|
# Contextual menu
|
||||||
|
|
||||||
def contextMenuEvent(self, event):
|
def contextMenuEvent(self, event):
|
||||||
if self._only_display:
|
if self._only_display:
|
||||||
return
|
return
|
||||||
|
|
||||||
pos = self.mapToScene(event.pos())
|
# pos = self.mapToScene(event.pos())
|
||||||
items = self.items(event.pos())
|
# items = self.items(event.pos())
|
||||||
|
|
||||||
# Select current menu
|
# # Select current menu
|
||||||
while len(items) > 0:
|
# while len(items) > 0:
|
||||||
if type(items[0]) in [NodeItem, EdgeItem]:
|
# if type(items[0]) in [NodeItem, EdgeItem]:
|
||||||
break
|
# break
|
||||||
else:
|
# else:
|
||||||
items = items[1:]
|
# items = items[1:]
|
||||||
|
|
||||||
if len(items) == 0:
|
# if len(items) == 0:
|
||||||
m_type = DefaultMenu
|
# m_type = DefaultMenu
|
||||||
elif type(items[0]) is NodeItem:
|
# elif type(items[0]) is NodeItem:
|
||||||
m_type = NodeMenu
|
# m_type = NodeMenu
|
||||||
elif type(items[0]) is EdgeItem:
|
# elif type(items[0]) is EdgeItem:
|
||||||
m_type = EdgeMenu
|
# m_type = EdgeMenu
|
||||||
else:
|
# else:
|
||||||
m_type = DefaultMenu
|
# m_type = DefaultMenu
|
||||||
|
|
||||||
# Create and exec menu
|
# # Create and exec menu
|
||||||
m = m_type(
|
# m = m_type(
|
||||||
event=event, pos=pos, items=items,
|
# event=event, pos=pos, items=items,
|
||||||
graph=self.graph, trad=self._trad, parent=self
|
# graph=self.graph, trad=self._trad, parent=self
|
||||||
)
|
# )
|
||||||
m.run()
|
# m.run()
|
||||||
self.clicked = False
|
# self.clicked = False
|
||||||
|
|
|
||||||
|
|
@ -81,18 +81,18 @@ class ScenariosWindow(PamhyrWindow):
|
||||||
self.setup_connections()
|
self.setup_connections()
|
||||||
|
|
||||||
def setup_graph(self):
|
def setup_graph(self):
|
||||||
# self._graph_widget = GraphWidget(
|
self._graph_widget = GraphWidget(
|
||||||
# self._study,
|
self._study,
|
||||||
# undo=self._undo_stack,
|
undo=self._undo_stack,
|
||||||
# trad=self._trad,
|
trad=self._trad,
|
||||||
# parent=self,
|
parent=self,
|
||||||
# )
|
)
|
||||||
|
|
||||||
self._graph_layout = self.find(
|
self._graph_layout = self.find(
|
||||||
QHBoxLayout, "horizontalLayout_graph"
|
QHBoxLayout, "horizontalLayout_graph"
|
||||||
)
|
)
|
||||||
|
|
||||||
# self._graph_layout.addWidget(self._graph_widget)
|
self._graph_layout.addWidget(self._graph_widget)
|
||||||
|
|
||||||
def setup_table(self):
|
def setup_table(self):
|
||||||
table = self.find(QTableView, "tableView_scenarios")
|
table = self.find(QTableView, "tableView_scenarios")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue