graphics_node_item.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. """
  2. QGraphics representation class for a node element.
  3. An object with a defined size (120x120) on screen which can either be
  4. an image file or a set of primitives.
  5. """
  6. from enum import Enum
  7. import base64
  8. from PyQt5.QtWidgets import QGraphicsItem, QStyleOptionGraphicsItem, QWidget
  9. from PyQt5.Qt import QRectF, QPainter, QFont, Qt, QBrush, QColor, QImage
  10. class IconType(Enum):
  11. IMAGE = 0
  12. PRIMITIVE = 1
  13. class GraphicsNodeItem(QGraphicsItem):
  14. def __init__(self, node_id, node_type="", consyn=None):
  15. QGraphicsItem.__init__(self)
  16. self.node_id = node_id
  17. self._type = node_type
  18. self._consyn = consyn
  19. self._icon_type = None
  20. self._font = QFont()
  21. self._font.setPixelSize(12)
  22. self.setZValue(1.0)
  23. def set_type(self, node_type):
  24. self._type = node_type
  25. self.update(self.boundingRect())
  26. def update_consyn(self, consyn):
  27. self._consyn = consyn
  28. self.update(self.boundingRect())
  29. def get_type(self):
  30. return self._type
  31. def boundingRect(self):
  32. bbox = QRectF(0, 0, 120, 120)
  33. return bbox
  34. def paint(self, painter, option, widget=None):
  35. # type: (QPainter, QStyleOptionGraphicsItem, QWidget) -> None
  36. # draw type text and bounding rectangle
  37. painter.setFont(self._font)
  38. painter.setBrush(QBrush(Qt.white))
  39. painter.drawRect(self.boundingRect())
  40. text_box = QRectF(0, 100, 120, 20)
  41. painter.drawRect(text_box)
  42. painter.setBrush(QBrush(QColor(0, 0, 0, 0)))
  43. painter.drawText(text_box, Qt.AlignCenter | Qt.TextDontClip, self._type)
  44. # draw concrete syntax
  45. if not self._consyn:
  46. # nothing to draw, so leave empty
  47. return
  48. # first, determine if we have an actual image file or a primitive group
  49. for item in self._consyn:
  50. if item["type"] == "Icon":
  51. if item["is_primitive"]:
  52. self._icon_type = IconType.PRIMITIVE
  53. else:
  54. self._icon_type = IconType.IMAGE
  55. break
  56. if not self._icon_type:
  57. print("Could not determine CS icon type for type {}".format(self._type))
  58. return
  59. if self._icon_type == IconType.IMAGE:
  60. # an actual image file, so load and display it
  61. img_data_b64 = None
  62. for item in self._consyn:
  63. if item["type"] == "Image":
  64. img_data_b64 = item["data"]
  65. break
  66. if not img_data_b64:
  67. print("Could not find image data for type {}".format(self._type))
  68. return
  69. img_data = base64.b64decode(img_data_b64)
  70. qimg = QImage.fromData(img_data)
  71. painter.drawImage(QRectF(0, 0, 100, 100), qimg)
  72. else:
  73. # a set of primitives
  74. for item in self._consyn:
  75. item_type = item["type"]
  76. # ignore the "useless" Icon class
  77. if item_type == "Icon":
  78. continue
  79. if item_type == "Rectangle":
  80. rect = QRectF(item["x"], item["y"], item["width"], item["height"])
  81. painter.drawRect(rect)
  82. elif item_type == "Ellipse":
  83. painter.drawEllipse(item["x"], item["y"], item["width"], item["height"])
  84. elif item_type == "Line":
  85. painter.drawLine(item["start_x"], item["start_y"], item["end_x"], item["end_y"])
  86. else:
  87. print("No paint implemented for primitive {}".format(item_type))