visualization_widgets.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. """
  2. Visualization Widgets
  3. Reusable components for displaying analysis visualizations with click-to-enlarge functionality.
  4. """
  5. from typing import Optional, Callable
  6. from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QFrame
  7. from PyQt5.QtCore import Qt
  8. from PyQt5.QtGui import QPixmap, QFont, QCursor
  9. from ui.dialogs.image_preview_dialog import ImagePreviewDialog
  10. class ClickableImageWidget(QFrame):
  11. """
  12. A frame widget displaying an image that opens a preview dialog when clicked.
  13. Features:
  14. - Displays scaled image with aspect ratio preserved
  15. - Click to open full-size preview dialog
  16. - Visual indicator (cursor change, optional hover effect)
  17. - Configurable maximum dimensions
  18. """
  19. def __init__(self, pixmap: QPixmap, title: str, max_width: int = 500, parent: QWidget = None):
  20. """
  21. Initialize the clickable image widget.
  22. Args:
  23. pixmap: QPixmap to display
  24. title: Title for the preview dialog
  25. max_width: Maximum width in pixels for the scaled display image
  26. parent: Parent widget
  27. """
  28. super().__init__(parent)
  29. self.original_pixmap = pixmap # Store original for preview dialog
  30. self.title = title
  31. self.max_width = max_width
  32. # Setup widget styling
  33. self.setFrameStyle(QFrame.Box)
  34. self.setStyleSheet("background-color: white; border: 1px solid #bdc3c7;")
  35. # Create layout
  36. layout = QVBoxLayout(self)
  37. layout.setAlignment(Qt.AlignCenter)
  38. # Title label
  39. title_label = QLabel(f"<b>{title}</b>")
  40. title_label.setFont(QFont("Arial", 12))
  41. layout.addWidget(title_label)
  42. # Image label
  43. self.image_label = QLabel()
  44. self.image_label.setAlignment(Qt.AlignCenter)
  45. self.image_label.setCursor(Qt.PointingHandCursor)
  46. # Scale pixmap for display
  47. scaled_pixmap = self._scale_pixmap(pixmap, max_width)
  48. self.image_label.setPixmap(scaled_pixmap)
  49. self.image_label.setFixedSize(scaled_pixmap.width(), scaled_pixmap.height())
  50. # Connect click event
  51. self.image_label.mousePressEvent = self._on_image_clicked
  52. layout.addWidget(self.image_label, alignment=Qt.AlignCenter)
  53. layout.addStretch()
  54. def _scale_pixmap(self, pixmap: QPixmap, max_width: int) -> QPixmap:
  55. """Scale pixmap to fit max_width while preserving aspect ratio."""
  56. if pixmap.width() > max_width:
  57. return pixmap.scaledToWidth(max_width, Qt.SmoothTransformation)
  58. return pixmap
  59. def _on_image_clicked(self, event):
  60. """Handle image click to show preview dialog."""
  61. dialog = ImagePreviewDialog(self.original_pixmap, title=self.title, parent=self)
  62. dialog.exec_()
  63. class VisualizationPanel(QFrame):
  64. """
  65. A panel for displaying a single analysis visualization with metadata.
  66. Features:
  67. - Title and description
  68. - Clickable image
  69. - Optional metadata display
  70. """
  71. def __init__(self, title: str, description: str = "", parent: QWidget = None):
  72. """
  73. Initialize the visualization panel.
  74. Args:
  75. title: Panel title
  76. description: Optional description text
  77. parent: Parent widget
  78. """
  79. super().__init__(parent)
  80. self.setFrameStyle(QFrame.Box)
  81. self.setStyleSheet("background-color: white; border: 1px solid #bdc3c7;")
  82. layout = QVBoxLayout(self)
  83. layout.setAlignment(Qt.AlignCenter)
  84. # Title
  85. title_label = QLabel(f"<b>{title}</b>")
  86. title_label.setFont(QFont("Arial", 12))
  87. layout.addWidget(title_label)
  88. # Description (if provided)
  89. if description:
  90. desc_label = QLabel(description)
  91. desc_label.setStyleSheet("color: #7f8c8d; font-size: 10px;")
  92. layout.addWidget(desc_label)
  93. # Store reference to layout for adding image label later
  94. self.layout_ref = layout
  95. def add_image(self, pixmap: QPixmap, max_width: int = 500):
  96. """Add an image to the visualization panel."""
  97. # Scale image
  98. if pixmap.width() > max_width:
  99. scaled_pixmap = pixmap.scaledToWidth(max_width, Qt.SmoothTransformation)
  100. else:
  101. scaled_pixmap = pixmap
  102. # Create clickable image label
  103. image_label = QLabel()
  104. image_label.setPixmap(scaled_pixmap)
  105. image_label.setFixedSize(scaled_pixmap.width(), scaled_pixmap.height())
  106. image_label.setAlignment(Qt.AlignCenter)
  107. image_label.setCursor(Qt.PointingHandCursor)
  108. # Store pixmaps for click handler
  109. image_label.original_pixmap = pixmap
  110. image_label.title = self.layout_ref.itemAt(0).widget().text() if self.layout_ref.count() > 0 else "Image"
  111. # Add click handler
  112. def on_click(event):
  113. dialog = ImagePreviewDialog(image_label.original_pixmap, title=image_label.title, parent=self)
  114. dialog.exec_()
  115. image_label.mousePressEvent = on_click
  116. # Add to layout
  117. self.layout_ref.addWidget(image_label, alignment=Qt.AlignCenter)
  118. self.layout_ref.addStretch()