Mercurial > lcfOS
comparison python/other/diagramitems.py @ 390:b77f3290ac79
Added diagram editor tests
author | Windel Bouwman |
---|---|
date | Fri, 16 May 2014 10:12:16 +0200 |
parents | 534b94b40aa8 |
children | bb4289c84907 |
comparison
equal
deleted
inserted
replaced
388:e07c2a9abac1 | 390:b77f3290ac79 |
---|---|
1 """ | 1 """ |
2 Contains all blocks that can be used to build models. | 2 Contains all blocks that can be used to build models. |
3 """ | 3 """ |
4 | 4 |
5 from PyQt4.QtGui import * | 5 import sys |
6 from PyQt4.QtCore import * | 6 import json |
7 import base64 | |
8 import os | |
9 | |
10 sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'ide')) | |
11 | |
12 from qtwrapper import QtGui, QtCore, QtWidgets, pyqtSignal, get_icon | |
13 from qtwrapper import abspath, Qt | |
14 | |
7 | 15 |
8 def uniqify(name, names): | 16 def uniqify(name, names): |
9 newname, i = name, 1 | 17 newname, i = name, 1 |
10 while newname in names: newname, i = name + str(i), i + 1 | 18 while newname in names: newname, i = name + str(i), i + 1 |
11 return newname | 19 return newname |
20 | |
12 | 21 |
13 def enum(**enums): | 22 def enum(**enums): |
14 return type('Enum', (), enums) | 23 return type('Enum', (), enums) |
24 | |
15 | 25 |
16 Position = enum(TOP=0, TOP_RIGHT=1, RIGHT=2, BOTTOM_RIGHT=3, BOTTOM=4, BOTTOM_LEFT=5, LEFT=6, TOP_LEFT=7) | 26 Position = enum(TOP=0, TOP_RIGHT=1, RIGHT=2, BOTTOM_RIGHT=3, BOTTOM=4, BOTTOM_LEFT=5, LEFT=6, TOP_LEFT=7) |
17 | 27 |
28 | |
18 def buildPath(pts): | 29 def buildPath(pts): |
19 path = QPainterPath(pts[0]) | 30 path = QtGui.QPainterPath(pts[0]) |
20 for pt in pts[1:]: path.lineTo(pt) | 31 for pt in pts[1:]: path.lineTo(pt) |
21 return path | 32 return path |
22 | 33 |
23 def equalSpace(n, l, offset=15): | 34 def equalSpace(n, l, offset=15): |
24 if n == 1: | 35 if n == 1: |
25 return [l / 2] | 36 return [l / 2] |
26 elif n > 1: | 37 elif n > 1: |
27 return [offset + (l - offset*2)/(n - 1)*i for i in range(n)] | 38 return [offset + (l - offset*2)/(n - 1)*i for i in range(n)] |
28 return [] | 39 return [] |
29 | 40 |
30 class Connection(QGraphicsPathItem): | 41 |
42 class Connection(QtWidgets.QGraphicsPathItem): | |
31 """ A connection between blocks """ | 43 """ A connection between blocks """ |
32 def __init__(self, fromPort=None, toPort=None): | 44 def __init__(self, fromPort=None, toPort=None): |
33 super(Connection, self).__init__() | 45 super(Connection, self).__init__() |
34 self.pos2 = self.fromPort = self.toPort = None | 46 self.pos2 = self.fromPort = self.toPort = None |
35 self.setFlags(self.ItemIsSelectable | self.ItemClipsToShape) | 47 self.setFlags(self.ItemIsSelectable | self.ItemClipsToShape) |
36 pen = QPen(Qt.blue, 2, cap=Qt.RoundCap) | 48 pen = QtGui.QPen(Qt.blue, 2, cap=Qt.RoundCap) |
37 self.setPen(pen) | 49 self.setPen(pen) |
38 self.arrowhead = QGraphicsPathItem(self) | 50 self.arrowhead = QtGui.QGraphicsPathItem(self) |
39 self.arrowhead.setPath(buildPath([QPointF(0.0, 0.0), QPointF(-6.0, 10.0), QPointF(6.0, 10.0), QPointF(0.0, 0.0)])) | 51 self.arrowhead.setPath(buildPath([QPointF(0.0, 0.0), QPointF(-6.0, 10.0), QPointF(6.0, 10.0), QPointF(0.0, 0.0)])) |
40 self.arrowhead.setPen(pen) | 52 self.arrowhead.setPen(pen) |
41 self.arrowhead.setBrush(QBrush(pen.color())) | 53 self.arrowhead.setBrush(QtGui.QBrush(pen.color())) |
42 self.vias = [] | 54 self.vias = [] |
43 self.setFromPort(fromPort) | 55 self.setFromPort(fromPort) |
44 self.setToPort(toPort) | 56 self.setToPort(toPort) |
45 def getDict(self): | 57 def getDict(self): |
46 d = {} | 58 d = {} |
97 if pos1 is None or pos2 is None: | 109 if pos1 is None or pos2 is None: |
98 return | 110 return |
99 scene = self.scene() | 111 scene = self.scene() |
100 vias = [pos1 + QPointF(20, 0)] + self.vias + [pos2 + QPointF(-20, 0)] | 112 vias = [pos1 + QPointF(20, 0)] + self.vias + [pos2 + QPointF(-20, 0)] |
101 if scene: | 113 if scene: |
102 litem = QGraphicsLineItem() | 114 litem = QtGui.QGraphicsLineItem() |
103 litem.setFlags(self.ItemIsSelectable) | 115 litem.setFlags(self.ItemIsSelectable) |
104 scene.addItem(litem) | 116 scene.addItem(litem) |
105 for p1, p2 in zip(vias[:-1], vias[1:]): | 117 for p1, p2 in zip(vias[:-1], vias[1:]): |
106 line = QLineF(p1, p2) | 118 line = QLineF(p1, p2) |
107 litem.setLine(line) | 119 litem.setLine(line) |
113 self.arrowhead.setRotation(90) | 125 self.arrowhead.setRotation(90) |
114 p = buildPath(pts) | 126 p = buildPath(pts) |
115 self.setPath(p) | 127 self.setPath(p) |
116 """ Create a shape outline using the path stroker """ | 128 """ Create a shape outline using the path stroker """ |
117 s = super(Connection, self).shape() | 129 s = super(Connection, self).shape() |
118 pps = QPainterPathStroker() | 130 pps = QtGui.QPainterPathStroker() |
119 pps.setWidth(10) | 131 pps.setWidth(10) |
120 self.myshape = pps.createStroke(s).simplified() | 132 self.myshape = pps.createStroke(s).simplified() |
121 | 133 |
122 class PortItem(QGraphicsPathItem): | 134 class PortItem(QtWidgets.QGraphicsPathItem): |
123 """ Represents a port to a subsystem """ | 135 """ Represents a port to a subsystem """ |
124 def __init__(self, name, block): | 136 def __init__(self, name, block): |
125 super(PortItem, self).__init__(block) | 137 super(PortItem, self).__init__(block) |
126 self.textItem = QGraphicsTextItem(self) | 138 self.textItem = QtGui.QGraphicsTextItem(self) |
127 self.connection = None | 139 self.connection = None |
128 self.block = block | 140 self.block = block |
129 self.setCursor(QCursor(Qt.CrossCursor)) | 141 self.setCursor(QtGui.QCursor(Qt.CrossCursor)) |
130 self.setPen(QPen(Qt.blue, 2, cap=Qt.RoundCap)) | 142 self.setPen(QtGui.QPen(Qt.blue, 2, cap=Qt.RoundCap)) |
131 self.name = name | 143 self.name = name |
132 self.posCallbacks = [] | 144 self.posCallbacks = [] |
133 self.setFlag(self.ItemSendsScenePositionChanges, True) | 145 self.setFlag(self.ItemSendsScenePositionChanges, True) |
134 def getName(self): return self.textItem.toPlainText() | 146 def getName(self): return self.textItem.toPlainText() |
135 def setName(self, name): | 147 def setName(self, name): |
158 class InputPort(PortItem): | 170 class InputPort(PortItem): |
159 def __init__(self, name, block, d=10.0): | 171 def __init__(self, name, block, d=10.0): |
160 super(InputPort, self).__init__(name, block) | 172 super(InputPort, self).__init__(name, block) |
161 self.setPath(buildPath([QPointF(-d, -d), QPointF(0, 0), QPointF(-d, d)])) | 173 self.setPath(buildPath([QPointF(-d, -d), QPointF(0, 0), QPointF(-d, d)])) |
162 | 174 |
163 class Handle(QGraphicsEllipseItem): | 175 class Handle(QtWidgets.QGraphicsEllipseItem): |
164 """ A handle that can be moved by the mouse """ | 176 """ A handle that can be moved by the mouse """ |
165 def __init__(self, dx=10.0, parent=None): | 177 def __init__(self, dx=10.0, parent=None): |
166 super(Handle, self).__init__(QRectF(-0.5*dx,-0.5*dx,dx,dx), parent) | 178 super(Handle, self).__init__(QtCore.QRectF(-0.5*dx,-0.5*dx,dx,dx), parent) |
167 self.setBrush(QBrush(Qt.white)) | 179 self.setBrush(QtGui.QBrush(Qt.white)) |
168 self.setFlags(self.ItemIsMovable) | 180 self.setFlags(self.ItemIsMovable) |
169 self.setZValue(1) | 181 self.setZValue(1) |
170 self.setVisible(False) | 182 self.setVisible(False) |
171 self.setCursor(QCursor(Qt.SizeFDiagCursor)) | 183 self.setCursor(QtGui.QCursor(Qt.SizeFDiagCursor)) |
172 def mouseMoveEvent(self, event): | 184 def mouseMoveEvent(self, event): |
173 """ Move function without moving the other selected elements """ | 185 """ Move function without moving the other selected elements """ |
174 p = self.mapToParent(event.pos()) | 186 p = self.mapToParent(event.pos()) |
175 self.setPos(p) | 187 self.setPos(p) |
176 | 188 |
178 def __init__(self, position, block): | 190 def __init__(self, position, block): |
179 super(ResizeSelectionHandle, self).__init__(dx=12, parent=block) | 191 super(ResizeSelectionHandle, self).__init__(dx=12, parent=block) |
180 self.position = position | 192 self.position = position |
181 self.block = block | 193 self.block = block |
182 if position in [Position.TOP_LEFT, Position.BOTTOM_RIGHT]: | 194 if position in [Position.TOP_LEFT, Position.BOTTOM_RIGHT]: |
183 self.setCursor(QCursor(Qt.SizeFDiagCursor)) | 195 self.setCursor(QtGui.QCursor(Qt.SizeFDiagCursor)) |
184 elif position in [Position.TOP_RIGHT, Position.BOTTOM_LEFT]: | 196 elif position in [Position.TOP_RIGHT, Position.BOTTOM_LEFT]: |
185 self.setCursor(QCursor(Qt.SizeBDiagCursor)) | 197 self.setCursor(QCursor(Qt.SizeBDiagCursor)) |
186 elif position in [Position.TOP, Position.BOTTOM]: | 198 elif position in [Position.TOP, Position.BOTTOM]: |
187 self.setCursor(QCursor(Qt.SizeVerCursor)) | 199 self.setCursor(QCursor(Qt.SizeVerCursor)) |
188 elif position in [Position.LEFT, Position.RIGHT]: | 200 elif position in [Position.LEFT, Position.RIGHT]: |
189 self.setCursor(QCursor(Qt.SizeHorCursor)) | 201 self.setCursor(QtGui.QCursor(Qt.SizeHorCursor)) |
190 def mouseMoveEvent(self, event): | 202 def mouseMoveEvent(self, event): |
191 self.block.sizerMoveEvent(self, event.scenePos()) | 203 self.block.sizerMoveEvent(self, event.scenePos()) |
192 | 204 |
193 class Block(QGraphicsRectItem): | 205 class Block(QtWidgets.QGraphicsRectItem): |
194 """ Represents a block in the diagram. """ | 206 """ Represents a block in the diagram. """ |
195 def __init__(self, name='Untitled', parent=None): | 207 def __init__(self, name='Untitled', parent=None): |
196 super(Block, self).__init__(parent) | 208 super(Block, self).__init__(parent) |
197 self.selectionHandles = [ResizeSelectionHandle(i, self) for i in range(8)] | 209 self.selectionHandles = [ResizeSelectionHandle(i, self) for i in range(8)] |
198 # Properties of the rectangle: | 210 # Properties of the rectangle: |
199 self.setPen(QPen(Qt.blue, 2)) | 211 self.setPen(QtGui.QPen(Qt.blue, 2)) |
200 self.setBrush(QBrush(Qt.lightGray)) | 212 self.setBrush(QtGui.QBrush(Qt.lightGray)) |
201 self.setFlags(self.ItemIsSelectable | self.ItemIsMovable | self.ItemSendsScenePositionChanges) | 213 self.setFlags(self.ItemIsSelectable | self.ItemIsMovable | self.ItemSendsScenePositionChanges) |
202 self.setCursor(QCursor(Qt.PointingHandCursor)) | 214 self.setCursor(QtGui.QCursor(Qt.PointingHandCursor)) |
203 self.setAcceptHoverEvents(True) | 215 self.setAcceptHoverEvents(True) |
204 self.label = QGraphicsTextItem(name, self) | 216 self.label = QtWidgets.QGraphicsTextItem(name, self) |
205 self.name = name | 217 self.name = name |
206 # Create corner for resize: | 218 # Create corner for resize: |
207 button = QPushButton('+in') | 219 button = QtWidgets.QPushButton('+in') |
208 button.clicked.connect(self.newInputPort) | 220 button.clicked.connect(self.newInputPort) |
209 self.buttonItemAddInput = QGraphicsProxyWidget(self) | 221 self.buttonItemAddInput = QtWidgets.QGraphicsProxyWidget(self) |
210 self.buttonItemAddInput.setWidget(button) | 222 self.buttonItemAddInput.setWidget(button) |
211 self.buttonItemAddInput.setVisible(False) | 223 self.buttonItemAddInput.setVisible(False) |
212 button = QPushButton('+out') | 224 button = QtWidgets.QPushButton('+out') |
213 button.clicked.connect(self.newOutputPort) | 225 button.clicked.connect(self.newOutputPort) |
214 self.buttonItemAddOutput = QGraphicsProxyWidget(self) | 226 self.buttonItemAddOutput = QtWidgets.QGraphicsProxyWidget(self) |
215 self.buttonItemAddOutput.setWidget(button) | 227 self.buttonItemAddOutput.setWidget(button) |
216 self.buttonItemAddOutput.setVisible(False) | 228 self.buttonItemAddOutput.setVisible(False) |
217 # Inputs and outputs of the block: | 229 # Inputs and outputs of the block: |
218 self.inputs = [] | 230 self.inputs = [] |
219 self.outputs = [] | 231 self.outputs = [] |
327 self.setRect(0.0, 0.0, w, h) | 339 self.setRect(0.0, 0.0, w, h) |
328 rect = self.label.boundingRect() | 340 rect = self.label.boundingRect() |
329 self.label.setPos((w - rect.width()) / 2, (h - rect.height()) / 2) | 341 self.label.setPos((w - rect.width()) / 2, (h - rect.height()) / 2) |
330 self.updateSize() | 342 self.updateSize() |
331 | 343 |
344 | |
332 class CodeBlock(Block): | 345 class CodeBlock(Block): |
333 def __init__(self, name='Untitled', parent=None): | 346 def __init__(self, name='Untitled', parent=None): |
334 super(CodeBlock, self).__init__(name, parent) | 347 super(CodeBlock, self).__init__(name, parent) |
335 self.code = '' | 348 self.code = '' |
336 def setDict(self, d): | 349 |
337 super(CodeBlock, self).setDict(d) | 350 def setDict(self, d): |
338 self.code = d['code'] | 351 super(CodeBlock, self).setDict(d) |
339 def getDict(self): | 352 self.code = d['code'] |
340 d = super(CodeBlock, self).getDict() | 353 |
341 d['code'] = self.code | 354 def getDict(self): |
342 return d | 355 d = super(CodeBlock, self).getDict() |
343 def gencode(self): | 356 d['code'] = self.code |
357 return d | |
358 | |
359 def gencode(self): | |
344 c = ['def {0}():'.format(self.name)] | 360 c = ['def {0}():'.format(self.name)] |
345 if self.code: | 361 if self.code: |
346 c += indent(self.code.split('\n')) | 362 c += indent(self.code.split('\n')) |
347 else: | 363 else: |
348 c += indent(['pass']) | 364 c += indent(['pass']) |
349 return c | 365 return c |
350 | 366 |
367 | |
351 class DiagramBlock(Block): | 368 class DiagramBlock(Block): |
352 def __init__(self, name='Untitled', parent=None): | 369 def __init__(self, name='Untitled', parent=None): |
353 super(DiagramBlock, self).__init__(name, parent) | 370 super(DiagramBlock, self).__init__(name, parent) |
354 self.subModel = DiagramScene() | 371 self.subModel = DiagramScene() |
355 self.subModel.containingBlock = self | 372 self.subModel.containingBlock = self |
356 def setDict(self, d): | 373 |
357 self.subModel.Dict = d['submodel'] | 374 def setDict(self, d): |
358 def mouseDoubleClickEvent(self, event): | 375 self.subModel.Dict = d['submodel'] |
376 | |
377 def mouseDoubleClickEvent(self, event): | |
359 # descent into child diagram | 378 # descent into child diagram |
360 #self.editParameters() | 379 #self.editParameters() |
361 print('descent') | 380 print('descent') |
362 scene = self.scene() | 381 scene = self.scene() |
363 if scene: | 382 if scene: |
364 for view in scene.views(): | 383 for view in scene.views(): |
365 view.diagram = self.subModel | 384 view.diagram = self.subModel |
366 view.zoomAll() | 385 view.zoomAll() |
367 | 386 |
368 class DiagramScene(QGraphicsScene): | 387 |
388 class DiagramScene(QtWidgets.QGraphicsScene): | |
369 """ A diagram scene consisting of blocks and connections """ | 389 """ A diagram scene consisting of blocks and connections """ |
370 structureChanged = pyqtSignal() | 390 structureChanged = pyqtSignal() |
371 def __init__(self): | 391 def __init__(self): |
372 super(DiagramScene, self).__init__() | 392 super(DiagramScene, self).__init__() |
373 self.startedConnection = None | 393 self.startedConnection = None |