Source code for controllers.control_main

"""
This module contains the Controller class, which serves as the main controller for the Moilapps application.
The Controller class initializes the user interface, connects signals to their corresponding slots,
handles keyboard and mouse events, and manages the application's view modes and settings.

The Controller class imports several other modules and classes to fulfill its functionality,
including UI elements, control classes for various features, and models for data management.
"""

# import necessary library you used here
import os
import webbrowser
from PyQt6 import QtCore, QtGui, QtWidgets
from PyQt6.QtCore import QTimer

from src.models.model_apps import ModelApps
from src.controllers.control_ui_animation import ControlPanelPage
from .control_setup_icon import ConfigIconUI
from .control_plugin_manager import PluginManager
from .control_github import ControllerGitHub
from .control_view_anypoint import AnypointConfig
from .control_view_panorama import PanoramaConfig
from .control_view_recenter import RecenterConfig

from .control_recent_project import RecentOpen
from .control_mouse_event import MouseEvent
from .control_theme_apps import ControlThemeApps
from .control_message_box import ControlMessageBox
from .control_config_main import AppConfigManager
from .control_view_zoom import ControlViewZoom
from .control_view_rotate import ControlViewRotate
from .control_media_player import VideoController
from .control_saving_media import SaveMedia
from .control_image_result import ControlImageResult
from .control_image_original import ControlImageOriginal
from .control_view_fisheye import ControlImageFisheye
from .control_stylesheet import ControlStyleSheet
from .control_view_fullscreen import ControlViewFullscreen
from .control_screen_record import ScreenRecord


[docs] class Controller(QtWidgets.QMainWindow): """ The Controller class serves as the main controller for the Moilapps application. It initializes the user interface, connects signals to their corresponding slots, handles keyboard and mouse events, and manages the application's view modes and settings. Attributes: ui_object (object): An instance of the user interface object. model (object): An instance of the ModelApps class for data management. _stylesheet (object): An instance of the ControlStyleSheet class for managing stylesheets. cap (object): Video capture object for handling media files. image_original (object): Original image object. ctrl_panel_page (object): Instance of the ControlPanelPage class for managing panel pages. ctrl_stylesheet (object): Instance of the ControlStyleSheet class for managing stylesheets. ctrl_fullscreen (object): Instance of the ControlViewFullscreen class for managing fullscreen mode. ctrl_screen_record (object): Instance of the ScreenRecord class for managing screen recording. ctrl_icon (object): Instance of the ConfigIconUI class for configuring icons. ctrl_theme (object): Instance of the ControlThemeApps class for managing application themes. ctrl_message_box (object): Instance of the ControlMessageBox class for managing message boxes. ctrl_main_config (object): Instance of the AppConfigManager class for managing application configurations. ctrl_plugin (object): Instance of the PluginManager class for managing plugins. ctrl_github (object): Instance of the ControllerGitHub class for managing GitHub integration. ctrl_save_media (object): Instance of the SaveMedia class for managing saved media. ctrl_mouse_event (object): Instance of the MouseEvent class for managing mouse events. view_recenter (object): Instance of the RecenterConfig class for managing view recentering. view_fisheye (object): Instance of the ControlImageFisheye class for managing fisheye view. view_anypoint (object): Instance of the AnypointConfig class for managing anypoint view. view_panorama (object): Instance of the PanoramaConfig class for managing panorama view. view_zoom (object): Instance of the ControlViewZoom class for managing zoom view. view_rotate (object): Instance of the ControlViewRotate class for managing rotate view. ctrl_img_result (object): Instance of the ControlImageResult class for managing image results. ctrl_img_ori (object): Instance of the ControlImageOriginal class for managing original images. timer (object): QTimer object for managing timing events. ctrl_media_player (object): Instance of the VideoController class for managing media playback. ctrl_recent_project (object): Instance of the RecentOpen class for managing recent projects. Methods: __init__: Initializes the Controller object. connect_signals: Connects signals to their corresponding slots in the user interface. moveEvent: Moves the screen image worker to the position specified by the given event. onclick_change_state_debug: Toggles the debug mode state when the debug button is clicked. keyPressEvent: Handles key press events for keyboard shortcuts and special keys. escape_event: Handles the escape button keyboard event, returning the application to its default state. initial_setup_view: Sets up the initial view mode based on the moilapp's mode_view attribute. """
[docs] def __init__(self, ui_main_window, *args, **kwargs): try: QtWidgets.QMainWindow.__init__(self, *args, **kwargs) self.ui_object = ui_main_window # create instance for user interface object self.ui_object.setupUi(self) self.ui_object.frame_video_controller.hide() self.model = ModelApps() self._stylesheet = self.model.get_stylesheet self.cap = None self.image_original = None # initial open application self.setMouseTracking(True) self.showMaximized() self.setWindowTitle("Moilapps - V4.1.1") self.ctrl_panel_page = ControlPanelPage(self) self.ctrl_stylesheet = ControlStyleSheet(self) self.ctrl_fullscreen = ControlViewFullscreen(self) self.ctrl_screen_record = ScreenRecord(self) self.ctrl_icon = ConfigIconUI(self.ui_object) self.ctrl_icon.setup_icon_theme(self.model.theme_mode) self.ctrl_theme = ControlThemeApps(self) self.ctrl_theme.onclick_change_theme_apps() self.ctrl_message_box = ControlMessageBox(self) self.ctrl_main_config = AppConfigManager(self) self.ctrl_github = ControllerGitHub(self) self.ctrl_save_media = SaveMedia(self) self.ctrl_mouse_event = MouseEvent(self) # Initialize view zoom and rotate controllers self.view_recenter = RecenterConfig(self) self.view_fisheye = ControlImageFisheye(self) self.view_anypoint = AnypointConfig(self) self.view_panorama = PanoramaConfig(self) self.view_zoom = ControlViewZoom(self) self.view_rotate = ControlViewRotate(self) self.ctrl_img_result = ControlImageResult(self) self.ctrl_img_ori = ControlImageOriginal(self) # controller view self.timer = QTimer() self.timer.timeout.connect(self.media_next_frame_signal) self.ctrl_media_player = VideoController(self) self.ctrl_recent_project = RecentOpen(self) self.ctrl_plugin = PluginManager(self) self.processing_data_config() if self.model.main_config["Plugin_run"] is not None: self.ctrl_plugin.open_pinned_plugin(self.model.main_config["Plugin_run"]) self.ui_object.add_plugins_button.hide() if self.model.main_config["Github_config"]["origin_url"] is None: print("test here") # self.model.model_github.github_information() # self.model_apps.github_information() self.model.model_config.read_recent_config_path() self.ctrl_save_media.load_saved_image_list(True) self.onclick_change_state_debug() self.model.main_controller(self) self.connect_signals() except Exception as e: self.model.activity_logger.error(f"Controller.__init__(): Error: {str(e)}")
[docs] def connect_signals(self): """ Connects signals to their corresponding slots in the user interface. Signals include button clicks, key shortcuts, checkbox state changes, and menu toggling. Each signal is connected to a specific method or action to be performed in response. Returns: None """ try: self.ui_object.btn_open_media.clicked.connect(self.onclick_handle_open_media_button) self.ui_object.btn_open_media.setShortcut("Ctrl+O") self.ui_object.btn_form_params.clicked.connect(self.model.form_camera_parameter) self.ui_object.btn_form_params.setShortcut("Ctrl+C") self.ui_object.btn_change_theme.clicked.connect(self.ctrl_theme.onclick_change_theme_apps) self.ui_object.btn_change_theme.setShortcut("Ctrl+T") self.ui_object.btn_help.clicked.connect(self.onclick_help_button) self.ui_object.btn_help.setShortcut("Ctrl+H") self.ui_object.btn_read_the_docs.clicked.connect(self.read_the_documentation) self.ui_object.btn_read_the_docs.setShortcut("F1") self.ui_object.comboBox_resolution_sources.currentIndexChanged.connect(self.change_resolution_sources) self.ui_object.reset_view_button.clicked.connect(self.reset_view_back_to_original) self.ui_object.reset_view_button.setShortcut("F5") self.ui_object.btn_clear_ui.clicked.connect(self.onclick_clear_user_interface) self.ui_object.btn_clear_ui.setShortcut("Ctrl+Shift+Del") self.ui_object.check_draw_poligon.stateChanged.connect(self.ctrl_img_ori.create_image_original) self.ui_object.check_draw_poligon_pano.stateChanged.connect(self.ctrl_img_ori.create_image_original) # control panel page self.ui_object.btn_togle_menu.clicked.connect(lambda: self.ctrl_panel_page.button_menu(220, True)) self.ui_object.btn_setting.clicked.connect(lambda: self.onclick_button_setting_menu(0)) self.ui_object.btn_setting.setShortcut('Ctrl+Shift+S') self.ui_object.btn_recent_media.clicked.connect(lambda: self.onclick_button_setting_menu(1)) self.ui_object.btn_recent_media.setShortcut('Ctrl+Shift+R') self.ui_object.btn_about_us.clicked.connect(self.onclick_open_about_us) self.ui_object.btn_about_us.setShortcut('Ctrl+Shift+A') self.ui_object.extra_left_close_button.clicked.connect(self.ctrl_panel_page.close_setting_window) self.ui_object.btn_debug_mode.clicked.connect(self.onclick_change_state_debug) self.ui_object.btn_debug_mode.setShortcut('Ctrl+D') except Exception as e: self.model.activity_logger.error(f"Controller.connect_signals(): Error: {str(e)}")
[docs] def moveEvent(self, event): """ Moves the screen image worker to the position specified by the given event. Args: event: A PyQt event containing information about the new position of the screen image worker. Returns: The return value of the super() method for the same event. Raises: N/A """ try: if self.model.debug_mode: self.model.activity_logger.info("Controller: moveEvent(), " "Get position of windows on monitor (specially more than 1 monitor)") self.model.update_scree_image.worker.get_event(event.pos()) return super().moveEvent(event) except Exception as e: self.model.activity_logger.error(f"Controller.moveEvent(): Error: {str(e)}")
[docs] def onclick_change_state_debug(self): """ Toggles the debug mode state when the debug button is clicked. If the debug mode is active, debug logging is enabled, and the button text is set to "Debug ON". If the debug mode is inactive, debug logging is disabled, and the button text is set to "Debug OFF". Return: None """ try: if self.model.debug_mode: self.model.activity_logger.info("Controller: onclick_change_state_debug(), " "Click active Debug ON or Debug OFF") if self.ui_object.btn_debug_mode.isChecked(): self.ui_object.btn_debug_mode.setText("Debug ON") self.ui_object.btn_debug_mode.setStyleSheet(self._stylesheet.stylesheet_button_additional("remove")) self.model.debug_mode = True else: self.ui_object.btn_debug_mode.setText("Debug OFF") self.ui_object.btn_debug_mode.setStyleSheet(self._stylesheet.stylesheet_button_additional("install")) self.model.debug_mode = False except Exception as e: self.model.activity_logger.error(f"Controller.onclick_change_state_debug(): Error: {str(e)}")
[docs] def keyPressEvent(self, event): """ Handles key press events for keyboard shortcuts and special keys. Activates different actions based on the key pressed and any modifiers. Supported shortcuts include toggling fullscreen with F11, handling escape events, and displaying message boxes for saving images or accessibility information. Arg: event: The key press event object. Return: None """ try: if self.model.debug_mode: self.model.activity_logger.info("Controller: keyPressEvent(), " "Keyboard press event") if event.key() == QtCore.Qt.Key.Key_F11: self.showMaximized() elif event.key() == QtCore.Qt.Key.Key_Escape: self.escape_event() elif event.key() == QtCore.Qt.Key.Key_S and event.modifiers() == QtCore.Qt.KeyboardModifier.ControlModifier: self.ctrl_message_box.show_message_box_save_image() elif event.key() == QtCore.Qt.Key.Key_A and event.modifiers() == QtCore.Qt.KeyboardModifier.ControlModifier: self.ctrl_message_box.show_accessibility() except Exception as e: self.model.activity_logger.error(f"Controller.keyPressEvent(): Error: {str(e)}")
[docs] def escape_event(self): """ Handles the escape button keyboard event, returning the application to its default state. When the escape button is pressed, this method closes any open menus, resets the panel page, and exits the rubber band zoom mode if active. Return: None """ try: if self.model.debug_mode: self.model.activity_logger.info("Controller: escape_event(), " "Keyboard escape event") self.ctrl_panel_page.button_menu(70, True) width = self.ui_object.frame_additional_right.width() if width != 0: self.ctrl_panel_page.button_about_us() width = self.ui_object.frame_additional_left.width() if width != 0: self.ctrl_panel_page.setting_menu() if self.model.view_zoom_area.state_rubberband: self.model.view_zoom_area.state_rubberband = False self.display_image_to_ui() except Exception as e: self.model.activity_logger.error(f"Controller.escape_event(): Error: {str(e)}")
[docs] def initial_setup_view(self): """ Sets up the initial view mode based on the moilapp's mode_view attribute. Depending on the mode_view attribute, this method styles the corresponding button in the user interface to indicate the selected view mode. It then triggers the appropriate method to initialize the view settings and display the image accordingly. Return: None """ try: if self.model.debug_mode: self.model.activity_logger.info("Controller: initial_setup_view(), " "Initial setup view (FisheyeView, AnypointView, PanoramaView") if self.image_original is not None: if self.model.set_moildev.moildev_main is not None: if self.model.mode_view == "FisheyeView": self.ui_object.btn_fisheye_view.setStyleSheet(self.ctrl_stylesheet.set_style_selected_menu()) if self.model.mode_view == "AnypointView": self.view_anypoint.onclick_btn_anypoint() self.ui_object.btn_anypoint_view.setStyleSheet(self.ctrl_stylesheet.set_style_selected_menu()) elif self.model.mode_view == "PanoramaView": self.view_panorama.onclick_btn_panorama() self.ui_object.btn_panorama_view.setStyleSheet(self.ctrl_stylesheet.set_style_selected_menu()) else: self.model.mode_view = "FisheyeView" if self.model.mode_view == "FisheyeView": self.ui_object.btn_fisheye_view.setStyleSheet(self.ctrl_stylesheet.set_style_selected_menu()) except Exception as e: self.model.activity_logger.error(f"Controller.initial_setup_view(): Error: {str(e)}")
[docs] def onclick_handle_open_media_button(self): """ Prompts the user to select a media source and loads it into the app. If a file is selected, updates the model with the media source and parameter name, and updates the UI accordingly. If there is an existing result image, prompts the user for confirmation before changing the media source. """ try: if self.model.debug_mode: self.model.activity_logger.info("Controller: onclick_handle_open_media_button(), " "Click push button or keyboard open media") if self.image_original is None: self.load_media_source() else: self.prompt_change_media_source() except Exception as e: self.model.activity_logger.error(f"Controller.onclick_handle_open_media_button(): Error: {str(e)}")
[docs] def prompt_change_media_source(self): """ Prompts the user to confirm changing the media source. Displays a confirmation message to the user asking if they want to change the media source. If the user confirms, the method proceeds to load the new media source. Return: None """ try: if self.model.debug_mode: self.model.activity_logger.info("Controller: prompt_change_media_source(), " "Show prompt change media source") message = ("Your workspace already contains media, \n" "Are you sure want to change the media source?\n") reply = self.ctrl_message_box.display_ask_confirmation(message) if reply: self.load_media_source() except Exception as e: self.model.activity_logger.error(f"Controller.prompt_change_media_source(): Error: {str(e)}")
[docs] def load_media_source(self): """ Prompt the user to confirm changing the media source. Display a confirmation message to the user asking if they want to change the media source. If the user confirms, the method proceeds to load the new media source. Return: None """ try: if self.model.debug_mode: self.model.activity_logger.info("Controller: load_media_source(), " "Load media source") source_type, cam_type, source_media, parameter_name = self.model.select_media_source() if source_media is None: message = 'No media selected after clicking the "OPEN" button.' self.ctrl_message_box.display_message_box(message, "warning") if self.model.debug_mode: self.model.activity_logger.info( 'No media selected after clicking the "OPEN" button.') else: self.update_model_and_create_original_image(source_type, cam_type, source_media, parameter_name) except Exception as e: self.model.activity_logger.error(f"Controller.load_media_source(): Error: {str(e)}")
[docs] def update_model_and_create_original_image(self, source_type, cam_type, source_media, parameter_name): """ Updates the model configuration and creates the original image. Update the main configuration attributes with the provided parameters, saves the updated configuration, processes the data configuration, and retrieves the list of recent projects. Arg: source_type (str): The type of media source. cam_type (str): The type of camera. source_media (str): The path to the media source. parameter_name (str): The name of the parameter. Return: None """ try: if self.model.debug_mode: self.model.activity_logger.info("Controller: update_model_and_create_original_image(), " "Update model config and create original image") self.cap = None self.model.recenter_mode_view = False self.model.main_config["Source_type"] = source_type self.model.main_config["Cam_type"] = cam_type self.model.main_config["Media_path"] = source_media self.model.main_config["Parameter_name"] = parameter_name self.model.save_main_config_update() self.model.save_main_config_update() self.processing_data_config() self.ctrl_recent_project.get_list_recent_project() except Exception as e: self.model.activity_logger.error(f"Controller.update_model_and_create_original_image(): Error: {str(e)}") print(f"Controller.update_model_and_create_original_image(): Error: {str(e)}")
[docs] def processing_data_config(self): try: if self.model.debug_mode: self.model.activity_logger.info("Controller: processing_data_config(), " "Processing data config") media_path = self.model.main_config["Media_path"] source_type = self.model.main_config['Source_type'] self.model.set_moildev.create_moildev() if media_path is not None: if source_type == "Open Camera": self.cap = self.model.open_streaming_camera(media_path) success, self.image_original = self.cap.read() self.model.check_if_the_source_is_usable(self.cap) elif source_type == "Load Media": if media_path.endswith(('.mp4', '.MOV', '.avi')): self.cap = self.model.load_video_source(media_path) success, self.image_original = self.cap.read() self.model.check_if_the_source_is_usable(self.cap) elif media_path.endswith(('.jpeg', '.JPG', '.jpg', '.png', 'TIFF')): self.cap = None image = self.model.load_image_source(media_path) self.image_original = image self.model.check_if_the_source_is_usable(image) self.model.image_original = self.image_original self.model.set_moildev.calculate_resolution_option() self.adding_resolution_option() self.initial_setup_view() self.ui_object.doubleSpinBox_rotate_ori.setEnabled(True) self.ctrl_main_config.show_config_view_in_information() self.view_fisheye.set_initial_value_to_ui() self.view_rotate.set_initial_value_to_ui_rotate() self.model.change_resolution_image() if self.cap is not None and self.cap.isOpened(): self.ui_object.frame_video_controller.show() self.media_next_frame_signal() self.timer.start() self.ctrl_media_player.check_active_play_pause_button() else: self.timer.stop() self.ui_object.frame_video_controller.hide() self.display_image_to_ui() except Exception as e: self.model.activity_logger.error(f"Controller.processing_data_config(): Error: {str(e)}")
[docs] def adding_resolution_option(self): """ Add resolution options to the user interface. Retrieves resolution options from the Moildev instance and populates the resolution combo box in the user interface with the available options. Return: None """ if self.model.debug_mode: self.model.activity_logger.info("Controller: adding_resolution_option(), " "Adding resolution option to user interface") self.ui_object.comboBox_resolution_sources.blockSignals(True) self.ui_object.comboBox_resolution_sources.clear() if self.model.set_moildev.resolution_option: for item in self.model.set_moildev.resolution_option: self.ui_object.comboBox_resolution_sources.addItem(f"{str(item[0])} x {str(item[1])}") self.ui_object.comboBox_resolution_sources.blockSignals(False)
[docs] def change_resolution_sources(self): """ Change the resolution sources based on the selected option from the combo box. Updates the current resolution index in the Moildev instance, changes the resolution of the original image, recalculates label ratios, and updates the main configuration with the new resolution settings. It then performs the initial setup of the view. Return: None """ if self.model.debug_mode: self.model.activity_logger.info("Controller: change_resolution_sources(), " "Change resolution sources from selected combo box") if self.image_original is not None: try: self.model.set_moildev.current_resolution_index = self.ui_object.comboBox_resolution_sources.currentIndex() self.model.change_resolution_image() self.ctrl_mouse_event.calculate_ratio_label_ori() if self.model.mode_view == "AnypointView": if self.ui_object.radio_mode_1.isChecked(): self.model.main_config["Mode_1"]["alpha"] = 0 self.model.main_config["Mode_1"]["beta"] = 0 self.model.main_config["Mode_1"]["zoom"] = round(self.ui_object.doubleSpinBox_zoom.value(), 3) else: self.model.main_config["Mode_2"]["pitch"] = 0 self.model.main_config["Mode_2"]["yaw"] = 0 self.model.main_config["Mode_2"]["zoom"] = round(self.ui_object.doubleSpinBox_zoom.value(), 3) elif self.model.mode_view == "PanoramaView": if self.ui_object.radioButton_car.isChecked(): self.model.main_config["Pano_car"]["alpha"] = 0 self.model.main_config["Pano_car"]["beta"] = 0 self.model.save_main_config_update() self.initial_setup_view() except: message = 'The operation cant perform well, \n please try another resources!' self.ctrl_message_box.display_message_box(message, "warning")
[docs] def media_next_frame_signal(self): """ Proces the next frame for video processing. Reads the next frame from the video capture device, calculates frame information, updates the video player, creates the image result, and displays the image to the user interface. If recording is enabled, writes the frame to the output video file. Return: None """ if self.model.debug_mode: self.model.activity_logger.info("Controller: media_next_frame_signal(), " "Process next frame for video processing") if self.cap is not None: success, self.image_original = self.cap.read() if success: self.model.image_original = self.image_original # print(self.model.set_image_resize) if self.model.set_image_resize: self.model.resize_image_resolution() self.model.video_config.calculate_frame_video(self.cap) self.ctrl_media_player.set_slider_video_time_position() self.ctrl_media_player.show_timer_video_info() self.display_image_to_ui() if self.ctrl_save_media.video_writer is not None: if self.ctrl_save_media.record_option == "Original": self.ctrl_save_media.video_writer.write(self.image_original) else: self.ctrl_save_media.video_writer.write(self.model.image_result)
[docs] def display_image_to_ui(self): """ Display the image to the user interface. Create and display either the original image or the result image, depending on the current state of the application. Return: None """ if self.model.debug_mode: self.model.activity_logger.info("Controller: display_image_to_ui(), " "Display image to user interface Original or Result") if self.image_original is not None: self.ctrl_img_result.create_image_result() self.ctrl_img_ori.create_image_original()
[docs] def showing_new_window_full_screen(self): """ Display a new window in full-screen mode. Hide the current window, shows a new window maximized to full screen, sets the full-screen mode flag, and creates the image result. Return: None """ if self.model.debug_mode: self.model.activity_logger.info("Controller: showing_new_window_full_screen(), " "Display New window with full screen") self.hide() self.ctrl_fullscreen.new_window.showMaximized() self.ctrl_fullscreen.new_window.show() self.ctrl_fullscreen.full_screen_mode = True self.ctrl_img_result.create_image_result()
[docs] def onclick_button_setting_menu(self, index): """ Handle the click event of the setting menu button. If the setting menu is inactive, it displays the setting menu and switches the current index of the stacked widget to either the side view setting or recent project view. If the setting menu is active, it toggles between the current index of the stacked widget. Arg: index (int): The index of the stacked widget to switch to. Return: None """ if self.model.debug_mode: self.model.activity_logger.info("Controller: onclick_button_setting_menu(), " "Click push button for display side view setting or recent project") if not self.ctrl_panel_page.active_left: self.ctrl_panel_page.setting_menu() self.ui_object.stackedWidget_additional_left.setCurrentIndex(index) if index == 1: self.ctrl_recent_project.get_list_recent_project() else: if self.ui_object.stackedWidget_additional_left.currentIndex() != index: self.ui_object.stackedWidget_additional_left.setCurrentIndex(index) self.ctrl_recent_project.get_list_recent_project() else: self.ctrl_panel_page.setting_menu() if index == 1: self.ui_object.label_title_additional_left.setText("Recent Open") else: self.ui_object.label_title_additional_left.setText("Apps Settings")
[docs] def onclick_open_about_us(self): """ Handle the click event of the 'About Us' button. Display the 'About Us' page in the setting menu. Return: None """ if self.model.debug_mode: self.model.activity_logger.info("Controller: onclick_open_about_us(), " "Click push button about us (MoilApp)") self.ctrl_panel_page.button_about_us()
[docs] def back_to_home(self): """ Switch the content view to home screen and hides plugin buttons and sets the plugin index to None. """ if self.model.debug_mode: self.model.activity_logger.info("Controller: back_to_home(), " "Click push button back to home") self.ui_object.stackedWidget_2.setCurrentIndex(0) self.ui_object.widget_container_content.setCurrentIndex(0) self.ui_object.frame_btn_moilapp.show() self.ui_object.frame_button_view.show() self.ui_object.add_plugins_button.show() self.ui_object.delete_plugins_button.hide() self.ui_object.label_plugin_name.hide() self.ui_object.close_plugin_button.hide() self.ui_object.open_in_new_window_plugins.hide() self.model.main_config["Plugin_run"] = None self.ctrl_plugin.index = None if self.cap is not None: if not self.timer.isActive(): self.timer.start() self.model.save_main_config_update()
[docs] def onclick_help_button(self): """ Handle the click event of the help button. Display an informational message box indicating that the help menu is still under development. Return: None """ if self.model.debug_mode: self.model.activity_logger.info("Controller: onclick_help_button(), " "Click push button for help") webbrowser.open(r"https://perseverance-tech-tw.github.io/moilapp-doc/latest/usage.html#moilapp-of-usage", new=2)
[docs] def onclick_clear_user_interface(self): """ Reset the user interface to its default state. This method stop the timer, resets various model and UI attributes to their default values, and hides certain UI elements. It also clears the saved image list and resets the styles of specific UI buttons. """ self.timer.stop() self.model.model_config.reset_value_main_config() self.cap = None self.image_original = None self.model.image_original = None self.model.image_result = None self.model.image_ori_used = None self.model.image_recenter = None self.ctrl_theme.init_ui() self.ctrl_stylesheet.reset_style(self.ui_object.btn_fisheye_view) self.ctrl_stylesheet.reset_style(self.ui_object.btn_anypoint_view) self.ctrl_stylesheet.reset_style(self.ui_object.btn_panorama_view) self.ui_object.listWidget_saved_image.clear() self.ui_object.widget_mode_view.hide() self.ui_object.frame_recenter_image.hide() if self.ctrl_panel_page.active_left: self.ctrl_panel_page.setting_menu() self.ui_object.spinBox_icx.blockSignals(True) self.ui_object.spinBox_icy.blockSignals(True) self.ui_object.spinBox_icx.setValue(0) self.ui_object.spinBox_icy.setValue(0) self.ui_object.spinBox_icx.blockSignals(False) self.ui_object.spinBox_icy.blockSignals(False) self.ui_object.comboBox_resolution_sources.blockSignals(True) self.ui_object.comboBox_resolution_sources.clear() self.ui_object.comboBox_resolution_sources.blockSignals(False) self.ui_object.doubleSpinBox_alpha_rec.setEnabled(False) self.ui_object.doubleSpinBox_beta_rec.setEnabled(False)
[docs] def reset_view_back_to_original(self): """ Reset the view back to the original state. This method reset the view back to its original state, particularly when the user clicks on the "Back to Original" button. It hides certain UI elements and resets various attributes related to the view. """ self.ui_object.widget_mode_view.setEnabled(True) self.ui_object.widget_mode_view.hide() if self.image_original is not None: self.ctrl_stylesheet.reset_style(self.ui_object.btn_fisheye_view.objectName()) self.ui_object.btn_fisheye_view.setStyleSheet(self.ctrl_stylesheet.set_style_selected_menu()) if self.model.view_zoom_area.state_rubberband: self.model.view_zoom_area.state_rubberband = False if self.ui_object.checkBox_reverse_view.isChecked(): self.ui_object.checkBox_reverse_view.setChecked(False) self.model.mode_view = "FisheyeView" self.model.view_properties.zooming_size = self.round_to_nearest_100(self.ui_object.scrollArea.width()-40) self.model.view_properties.rotate_degree = 0 self.model.main_config['Image_original']['rotate'] = 0 self.view_rotate.set_initial_value_to_ui_rotate() self.ui_object.widget_mode_view.hide() self.ui_object.frame_recenter_image.hide() self.ui_object.spinBox_icx.setEnabled(False) self.ui_object.spinBox_icy.setEnabled(False) self.ui_object.doubleSpinBox_alpha_rec.setEnabled(False) self.ui_object.doubleSpinBox_beta_rec.setEnabled(False) self.display_image_to_ui() self.model.save_main_config_update()
[docs] def read_the_documentation(self): """ Open the HTML documentation for this project in a new browser tab. Returns: None """ if self.model.debug_mode: self.model.activity_logger.info("Controller: read_the_documentation(), " "Click the 'Read the Doc' Button") webbrowser.open(r'https://perseverance-tech-tw.github.io/moilapp-doc', new=2)
[docs] def closeEvent(self, event): if self.cap is not None: self.cap.release()
[docs] def resizeEvent(self, event: QtGui.QResizeEvent) -> None: """ Handle the resize event of the main window. Adjust the size of the image according to the window size. Arg: None Return: None """ if self.model.debug_mode: self.model.activity_logger.info("Controller: resizeEvent(), " "Resize image depend with windows") width = self.round_to_nearest_100(self.ui_object.scrollArea.width() - 40) if self.image_original is not None: try: self.model.view_properties.zooming_size = width self.ctrl_img_result.create_image_result() except: pass
[docs] @classmethod def round_to_nearest_100(cls, num): """ Round the given number to the nearest multiple of 20. Arg: num (int or float): The number to be rounded. Return: int: The rounded number. """ return round(num / 20) * 20