graphics_node_item.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  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._is_highlighted = False
  20. self._highlight_color = None
  21. self._icon_type = None
  22. self._font = QFont()
  23. self._font.setPixelSize(12)
  24. self.setZValue(1.0)
  25. def set_type(self, node_type):
  26. self._type = node_type
  27. self.update(self.boundingRect())
  28. def update_consyn(self, consyn):
  29. self._consyn = consyn
  30. self.update(self.boundingRect())
  31. def get_type(self):
  32. return self._type
  33. def boundingRect(self):
  34. bbox = QRectF(0, 0, 120, 120)
  35. return bbox
  36. def set_highlighted(self, highlight, color):
  37. self._is_highlighted = highlight
  38. self._highlight_color = color
  39. def paint(self, painter, option, widget=None):
  40. # type: (QPainter, QStyleOptionGraphicsItem, QWidget) -> None
  41. # draw type text and bounding rectangle
  42. painter.setFont(self._font)
  43. painter.setRenderHint(QPainter.SmoothPixmapTransform)
  44. # draw bounding rectangle
  45. painter.setBrush(QBrush(Qt.white))
  46. if self._is_highlighted:
  47. painter.setPen(self._highlight_color)
  48. painter.drawRect(self.boundingRect())
  49. text_box = QRectF(0, 100, 120, 20)
  50. painter.drawRect(text_box)
  51. painter.setPen(Qt.black)
  52. painter.setBrush(QBrush(QColor(0, 0, 0, 0)))
  53. painter.drawText(text_box, Qt.AlignCenter | Qt.TextDontClip, self._type)
  54. # draw concrete syntax
  55. if not self._consyn:
  56. # nothing to draw, so leave empty
  57. return
  58. # first, determine if we have an actual image file or a primitive group
  59. for item in self._consyn:
  60. if item["type"] == "Icon":
  61. if item["is_primitive"]:
  62. self._icon_type = IconType.PRIMITIVE
  63. else:
  64. self._icon_type = IconType.IMAGE
  65. break
  66. if not self._icon_type:
  67. print("Could not determine CS icon type for type {}".format(self._type))
  68. return
  69. if self._icon_type == IconType.IMAGE:
  70. # an actual image file, so load and display it
  71. img_data_b64 = None
  72. for item in self._consyn:
  73. if item["type"] == "Image":
  74. img_data_b64 = item["data"]
  75. break
  76. if not img_data_b64:
  77. print("Could not find image data for type {}".format(self._type))
  78. return
  79. img_data = base64.b64decode(img_data_b64)
  80. qimg = QImage.fromData(img_data)
  81. painter.drawImage(QRectF(5, 5, 95, 95), qimg)
  82. else:
  83. # a set of primitives
  84. for item in self._consyn:
  85. item_type = item["type"]
  86. # ignore the "useless" Icon class
  87. if item_type == "Icon":
  88. continue
  89. if item_type == "Rectangle":
  90. rect = QRectF(item["x"], item["y"], item["width"], item["height"])
  91. painter.drawRect(rect)
  92. elif item_type == "Ellipse":
  93. painter.drawEllipse(item["x"], item["y"], item["width"], item["height"])
  94. elif item_type == "Line":
  95. painter.drawLine(item["start_x"], item["start_y"], item["end_x"], item["end_y"])
  96. else:
  97. print("No paint implemented for primitive {}".format(item_type))