Source code for mantidimaging.gui.windows.live_viewer.view
# Copyright (C) 2024 ISIS Rutherford Appleton Laboratory UKRI
# SPDX - License - Identifier: GPL-3.0-or-later
from __future__ import annotations
from pathlib import Path
from typing import TYPE_CHECKING
from PyQt5.QtCore import QSignalBlocker
from PyQt5.QtWidgets import QVBoxLayout
from PyQt5.Qt import QAction, QActionGroup
from mantidimaging.gui.mvp_base import BaseMainWindowView
from .live_view_widget import LiveViewWidget
from .presenter import LiveViewerWindowPresenter
import numpy as np
if TYPE_CHECKING:
from mantidimaging.gui.windows.main import MainWindowView # noqa:F401 # pragma: no cover
[docs]
class LiveViewerWindowView(BaseMainWindowView):
"""
Live Viewer window view class.
This class is responsible for handling user interaction with the window.
"""
imageLayout: QVBoxLayout
def __init__(self, main_window: MainWindowView, live_dir_path: Path) -> None:
super().__init__(None, 'gui/ui/live_viewer_window.ui')
self.setWindowTitle("Mantid Imaging - Live Viewer")
self.main_window = main_window
self.path = live_dir_path
self.presenter = LiveViewerWindowPresenter(self, main_window)
self.live_viewer = LiveViewWidget()
self.imageLayout.addWidget(self.live_viewer)
self.live_viewer.z_slider.valueChanged.connect(self.presenter.select_image)
self.filter_params: dict[str, dict] = {}
self.right_click_menu = self.live_viewer.image.vb.menu
operations_menu = self.right_click_menu.addMenu("Operations")
rotate_menu = operations_menu.addMenu("Rotate Image")
self.rotate_angles_group = QActionGroup(self)
allowed_angles = [0, 90, 180, 270]
for angle in allowed_angles:
action = QAction(str(angle) + "°", self.rotate_angles_group)
action.setCheckable(True)
rotate_menu.addAction(action)
action.triggered.connect(self.set_image_rotation_angle)
if angle == 0:
action.setChecked(True)
[docs]
def show(self) -> None:
"""Show the window"""
super().show()
self.activateWindow()
self.watch_directory()
[docs]
def show_most_recent_image(self, image: np.ndarray) -> None:
"""
Show the most recently modified image in the image view.
@param image: The image to show
"""
self.live_viewer.show_image(image)
[docs]
def watch_directory(self) -> None:
"""Show the most recent image arrived in the selected directory"""
self.presenter.set_dataset_path(self.path)
[docs]
def remove_image(self) -> None:
"""Remove the image from the view."""
self.live_viewer.handle_deleted()
[docs]
def set_image_range(self, index_range: tuple[int, int]) -> None:
"""Set the range on the z-slider, without triggering valueChanged signal"""
with QSignalBlocker(self.live_viewer.z_slider):
self.live_viewer.z_slider.set_range(*index_range)
[docs]
def set_image_index(self, index: int) -> None:
"""Set the position on the z-slider, triggering valueChanged signal once"""
with QSignalBlocker(self.live_viewer.z_slider):
self.live_viewer.z_slider.set_value(index)
self.live_viewer.z_slider.valueChanged.emit(index)
[docs]
def closeEvent(self, e) -> None:
"""Close the window and remove it from the main window list"""
self.main_window.live_viewer = None
self.presenter.close()
self.live_viewer.handle_deleted()
super().closeEvent(e)
self.presenter = None # type: ignore # View instance to be destroyed -type can be inconsistent
[docs]
def set_image_rotation_angle(self):
"""Set the image rotation angle which will be read in by the presenter"""
if self.rotate_angles_group.checkedAction().text() == "0°":
if "Rotate Stack" in self.filter_params:
del self.filter_params["Rotate Stack"]
else:
image_rotation_angle = int(self.rotate_angles_group.checkedAction().text().replace('°', ''))
self.filter_params["Rotate Stack"] = {"params": {"angle": image_rotation_angle}}
self.presenter.update_image_operation()