# -*- coding: utf-8 -*- # gui/components/model_view/_scenario_camera.py """Камерный сценарий — базовый слой, всегда активен. Обрабатывает ПКМ (вращение), СКМ (панорамирование), подавление ЛКМ drag. Политика камеры текущего доменного сценария определяет, работает ли этот слой. """ from __future__ import annotations from typing import TYPE_CHECKING from PySide6.QtCore import Qt from PySide6.QtGui import QGuiApplication from gui.components.model_view._interaction_scenario import ( CameraPolicy, InteractionScenario, ) from error_logger import log_exception if TYPE_CHECKING: # pragma: no cover from gui.components.model_view_widget import ModelViewWidget class CameraScenario(InteractionScenario): """Базовый камерный слой: вращение (ПКМ), панорамирование (СКМ).""" name = "camera" camera_policy = CameraPolicy.FREE def on_mouse_press(self, mv: "ModelViewWidget", event) -> bool: if event.button() == Qt.MouseButton.RightButton: # В режиме контура ПКМ передаётся PyVista (remove point) if mv._zone_selection_mode and mv.is_scenario_active("contour_edit"): return False mv._cam_rotate_active = True mv._cam_last_pos = (event.position().x(), event.position().y()) return True if event.button() == Qt.MouseButton.MiddleButton: mv._cam_pan_active = True mv._cam_last_pos = (event.position().x(), event.position().y()) return True return False def on_mouse_move(self, mv: "ModelViewWidget", event) -> bool: # Safeguard: если release-событие потерялось (после модалок/фокуса), # синхронизируем drag-флаги с реальным состоянием кнопок мыши. try: real_buttons = QGuiApplication.mouseButtons() except Exception as _exc: real_buttons = Qt.MouseButton.NoButton if mv._cam_rotate_active and not (real_buttons & Qt.MouseButton.RightButton): mv._cam_rotate_active = False mv._cam_last_pos = None if mv._cam_pan_active and not (real_buttons & Qt.MouseButton.MiddleButton): mv._cam_pan_active = False mv._cam_last_pos = None # Подавление ЛКМ drag (не конфликтует с click-сценариями) if hasattr(event, "buttons") and (event.buttons() & Qt.MouseButton.LeftButton): return True # ПКМ drag → вращение камеры if ( mv._cam_rotate_active and hasattr(event, "buttons") and (event.buttons() & Qt.MouseButton.RightButton) ): cx, cy = mv._cam_last_pos or (event.position().x(), event.position().y()) nx, ny = event.position().x(), event.position().y() dx, dy = float(nx - cx), float(ny - cy) mv._cam_last_pos = (nx, ny) try: cam = mv._plotter.camera cam.Azimuth(-dx * 0.35) cam.Elevation(dy * 0.35) cam.OrthogonalizeViewUp() if hasattr(mv, "_reset_camera_clipping_range"): mv._reset_camera_clipping_range() mv._safe_render(min_interval_s=1.0 / 75.0) except Exception as _exc: log_exception(__name__, "on_mouse_move", _exc) return True # СКМ drag → панорамирование if ( mv._cam_pan_active and hasattr(event, "buttons") and (event.buttons() & Qt.MouseButton.MiddleButton) ): cx, cy = mv._cam_last_pos or (event.position().x(), event.position().y()) nx, ny = event.position().x(), event.position().y() dx, dy = float(nx - cx), float(ny - cy) mv._cam_last_pos = (nx, ny) mv._pan_camera_by_pixels(dx, dy) try: if hasattr(mv, "_reset_camera_clipping_range"): mv._reset_camera_clipping_range() mv._safe_render(min_interval_s=1.0 / 75.0) except Exception as _exc: log_exception(__name__, "on_mouse_move", _exc) return True return False def on_mouse_release(self, mv: "ModelViewWidget", event) -> bool: if event.button() == Qt.MouseButton.RightButton: mv._cam_rotate_active = False mv._cam_last_pos = None return True if event.button() == Qt.MouseButton.MiddleButton: mv._cam_pan_active = False mv._cam_last_pos = None return True return False