from PySide6.QtWidgets import QGraphicsView, QGraphicsScene, QGraphicsPixmapItem, QApplication, QMainWindow, QWidget, QVBoxLayout, QSplitter, QStackedWidget, QPushButton, QLabel, QToolButton from PySide6.QtGui import QEnterEvent, QPixmap, QWheelEvent, QPainter, QBrush, QColor, QIcon from PySide6.QtCore import Qt, QSize, Signal, QEvent import sys from ui.widgets.placeholder_widget import PlaceholderWidget class ZoomableImageView(QGraphicsView): def __init__(self, parent=None): super().__init__(parent) # Scena i element obrazu self._scene = QGraphicsScene(self) self.setScene(self._scene) self._scene.setBackgroundBrush( QBrush(QColor(20, 20, 20))) # ciemne tło self._pixmap_item = QGraphicsPixmapItem() self._scene.addItem(self._pixmap_item) # Ustawienia widoku # przesuwanie myszą self.setDragMode(QGraphicsView.DragMode.ScrollHandDrag) self.setRenderHint(QPainter.RenderHint.Antialiasing) self.setRenderHint(QPainter.RenderHint.SmoothPixmapTransform) # Wyłączenie suwaków self.setHorizontalScrollBarPolicy( Qt.ScrollBarPolicy.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) # Parametry zoomu self._zoom_factor = 1.25 self._current_scale = 1.0 def set_image(self, pixmap: QPixmap): # pixmap = QPixmap(image_path) self._pixmap_item.setPixmap(pixmap) self._scene.setSceneRect(pixmap.rect()) # self.reset_transform() def reset_transform(self): """Resetuje skalowanie i ustawia 1:1""" self._current_scale = 1.0 self.setTransform(self.transform().fromScale(1, 1)) def wheelEvent(self, event: QWheelEvent): """Zoom kółkiem myszy""" if event.modifiers() & Qt.KeyboardModifier.ControlModifier: # zoom tylko z CTRL if event.angleDelta().y() > 0: zoom = self._zoom_factor else: zoom = 1 / self._zoom_factor self._current_scale *= zoom self.scale(zoom, zoom) else: return super().wheelEvent(event) # normalne przewijanie class CameraPlaceholder(QWidget): def __init__(self, parent=None): super().__init__(parent) self.setAutoFillBackground(True) self.setStyleSheet("background-color: #141414;") layout = QVBoxLayout(self) layout.setSpacing(20) self.camera_start_btn = QPushButton("Start Camera") self.camera_start_btn.setFixedSize(200, 50) style_sheet = """ QPushButton { /* --- Styl podstawowy --- */ background-color: transparent; border: 2px solid #CECECE; /* Grubość, styl i kolor obramowania */ border-radius: 25px; /* Kluczowa właściwość do zaokrąglenia rogów! */ color: #CECECE; padding: 10px 20px; /* Wewnętrzny margines */ font-size: 16px; } QPushButton:hover { /* --- Styl po najechaniu myszką --- */ color: #F0F0F0; border: 2px solid #F0F0F0; } QPushButton:pressed { /* --- Styl po naciśnięciu --- */ background-color: #e0e0e0; /* Ciemniejsze tło w momencie kliknięcia */ border: 2px solid #e0e0e0; /* Zmiana koloru ramki dla sygnalizacji akcji */ } """ self.camera_start_btn.setStyleSheet(style_sheet) self.info_label = QLabel("Kliknij, aby uruchomić kamerę") self.info_label.setStyleSheet( "background-color: transparent; color: #CECECE; font-size: 18px;") self.info_label.setAlignment(Qt.AlignmentFlag.AlignCenter) layout.addStretch() layout.addWidget(self.camera_start_btn, alignment=Qt.AlignmentFlag.AlignCenter) layout.addWidget(self.info_label) layout.addStretch() self.setLayout(layout) def set_info_text(self, text: str): self.info_label.setText(text) class ViewWithOverlay(QWidget): toggleOrientation = Signal() swapViews = Signal() rotateCW = Signal() rotateCCW = Signal() def __init__(self): super().__init__() layout = QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) self.viewer = ZoomableImageView() layout.addWidget(self.viewer) icon_size = QSize(32, 32) btn_size = (48, 48) btn_style = """ background-color: rgba(255, 255, 255, 0.5); border-radius: 8px; border: 2px solid #1f1f1f; """ self.cw_btn = QToolButton(self) self.cw_btn.setIcon(QIcon("ui/icons/rotate-cw-svgrepo-com.svg")) self.cw_btn.setIconSize(icon_size) self.cw_btn.setStyleSheet(btn_style) self.cw_btn.setFixedSize(*btn_size) move_x = self.cw_btn.width() + 10 self.cw_btn.move(self.width() - move_x, 10) self.cw_btn.clicked.connect(self.rotateCW) self.ccw_btn = QToolButton(self) self.ccw_btn.setIcon(QIcon("ui/icons/rotate-ccw-svgrepo-com.svg")) self.ccw_btn.setIconSize(icon_size) self.ccw_btn.setStyleSheet(btn_style) self.ccw_btn.setFixedSize(*btn_size) move_x += self.ccw_btn.width() + 10 self.ccw_btn.move(self.width() - move_x, 10) self.ccw_btn.clicked.connect(self.rotateCCW) self.flip_btn = QToolButton(self) # self.flip_btn.setIcon(QIcon("ui/icons/flip-vertical-svgrepo-com.svg")) self.flip_btn.setIconSize(icon_size) self.flip_btn.setStyleSheet(btn_style) self.flip_btn.setFixedSize(*btn_size) move_x += self.flip_btn.width() + 10 self.flip_btn.move(self.width() - move_x, 10) self.flip_btn.clicked.connect(self.swapViews) self.orient_btn = QToolButton(self) # self.orient_btn.setIcon(QIcon("ui/icons/horizontal-stacks-svgrepo-com.svg")) self.orient_btn.setIconSize(icon_size) self.orient_btn.setStyleSheet(btn_style) self.orient_btn.setFixedSize(*btn_size) move_x += self.orient_btn.width() + 10 self.orient_btn.move(self.width() - move_x, 10) self.orient_btn.clicked.connect(self.toggleOrientation) self.cw_btn.raise_() self.ccw_btn.raise_() self.flip_btn.raise_() self.orient_btn.raise_() self.toggle_orientation(Qt.Orientation.Vertical) def set_image(self, pixmap: QPixmap): self.viewer.set_image(pixmap) def resizeEvent(self, event): super().resizeEvent(event) # Aktualizacja pozycji przycisku przy zmianie rozmiaru move_x = self.cw_btn.width() + 10 self.cw_btn.move(self.width() - move_x, 10) move_x += self.ccw_btn.width() + 10 self.ccw_btn.move(self.width() - move_x, 10) move_x += self.flip_btn.width() + 10 self.flip_btn.move(self.width() - move_x, 10) move_x += self.orient_btn.width() + 10 self.orient_btn.move(self.width() - move_x, 10) def toggle_orientation(self, orientation): if orientation == Qt.Orientation.Vertical: self.flip_btn.setIcon(QIcon("ui/icons/flip-vertical-svgrepo-com.svg")) self.orient_btn.setIcon(QIcon("ui/icons/horizontal-stacks-svgrepo-com.svg")) else: self.flip_btn.setIcon(QIcon("ui/icons/flip-horizontal-svgrepo-com.svg")) self.orient_btn.setIcon(QIcon("ui/icons/vertical-stacks-svgrepo-com.svg")) def enterEvent(self, event: QEnterEvent) -> None: self.orient_btn.show() self.flip_btn.show() self.ccw_btn.show() self.cw_btn.show() return super().enterEvent(event) def leaveEvent(self, event: QEvent) -> None: self.orient_btn.hide() self.flip_btn.hide() self.ccw_btn.hide() self.cw_btn.hide() return super().leaveEvent(event) class SplitView(QSplitter): def __init__(self, parent=None): super().__init__(parent) print("Inicjalizacja SplitView2") self.setOrientation(Qt.Orientation.Vertical) self.widget_start = CameraPlaceholder() # self.widget_live = ZoomableImageView() self.widget_live = ViewWithOverlay() # self.widget_live = PlaceholderWidget("Camera View", "#750466") # self.widget_ref = ZoomableImageView() self.widget_ref = ViewWithOverlay() # self.widget_ref = PlaceholderWidget("Image View", "#007981") self.stack = QStackedWidget() self.stack.addWidget(self.widget_start) self.stack.addWidget(self.widget_live) self.stack.setCurrentWidget(self.widget_start) self.addWidget(self.stack) self.addWidget(self.widget_ref) self.setSizes([self.height(), 0]) pixmap = QPixmap("media/empty_guitar_h.jpg") # pixmap.fill(Qt.GlobalColor.lightGray) self.widget_live.set_image(pixmap) self.widget_live.toggleOrientation.connect(self.toggle_orientation) self.widget_ref.toggleOrientation.connect(self.toggle_orientation) self.widget_live.swapViews.connect(self.swap_views) self.widget_ref.swapViews.connect(self.swap_views) def toggle_orientation(self): if self.orientation() == Qt.Orientation.Vertical: self.setOrientation(Qt.Orientation.Horizontal) self.setSizes([self.width()//2, self.width()//2]) self.widget_live.toggle_orientation(Qt.Orientation.Horizontal) self.widget_ref.toggle_orientation(Qt.Orientation.Horizontal) else: self.setOrientation(Qt.Orientation.Vertical) self.setSizes([self.height()//2, self.height()//2]) self.widget_live.toggle_orientation(Qt.Orientation.Vertical) self.widget_ref.toggle_orientation(Qt.Orientation.Vertical) def swap_views(self): """Zamiana widoków miejscami""" index_live = self.indexOf(self.stack) index_ref = self.indexOf(self.widget_ref) sizes = self.sizes() self.insertWidget(index_live, self.widget_ref) self.insertWidget(index_ref, self.stack) self.setSizes(sizes) def set_live_image(self, pixmap: QPixmap): """Ustawienie obrazu na żywo""" self.widget_live.set_image(pixmap) if self.stack.currentWidget() != self.widget_live: self.stack.setCurrentWidget(self.widget_live) def set_reference_image(self, path_image: str): """Ustawienie obrazu referencyjnego""" pixmap = QPixmap(path_image) self.widget_ref.set_image(pixmap) def toglle_live_view(self): """Przełączanie widoku na żywo""" if self.stack.currentWidget() == self.widget_start: self.stack.setCurrentWidget(self.widget_live) else: self.stack.setCurrentWidget(self.widget_start)