diff --git a/EyeTrackApp/camera_widget.py b/EyeTrackApp/camera_widget.py index 4a75f90..19cd0d8 100644 --- a/EyeTrackApp/camera_widget.py +++ b/EyeTrackApp/camera_widget.py @@ -115,20 +115,104 @@ class CameraWidget: self.capture_queue, ) + + + + self.hover = None + + # cartesian co-ordinates in widget space are used during selection + self.xy0 = None + self.xy1 = None + self.cartesian_needs_update = False + # polar co-ordinates from the image center are the canonical representation + self.cr, self.ca = None, None + self.roi_size = None + self.clip_size = None + self.clip_pos = None + self.padded_size = None + self.img_pos = None + self.roi_image_center = None + + self.is_mouse_up = True + self.hover_pos = None + self.in_roi_mode = False + self.movavg_fps_queue = deque(maxlen=120) + self.movavg_bps_queue = deque(maxlen=120) + + + + def get_widget_layout(self): + self.widget_layout = [ + [ + sg.Text("Camera Address", background_color="#424042"), + sg.InputText( + self.config.capture_source, + key=self.gui_camera_addr, + tooltip="Enter the IP address or UVC port of your camera. (Include the 'http://')", + ), + ], + [ + sg.Button( + "Save and Restart Tracking", + key=self.gui_save_tracking_button, + button_color="#6f4ca1", + ), + ], + [ + sg.Button( + "Tracking Mode", + key=self.gui_tracking_button, + button_color="#6f4ca1", + tooltip="Go here to track your eye.", + ), + sg.Button( + "Cropping Mode", + key=self.gui_roi_button, + button_color="#6f4ca1", + tooltip="Go here to crop out your eye.", + ), + ], + [ + sg.Text("Rotation", background_color="#424042"), + sg.Slider( + range=(0, 360), + default_value=self.config.rotation_angle, + orientation="h", + key=self.gui_rotation_slider, + background_color="#424042", + tooltip="Adjust the rotation of your cameras, make them level.", + ), + ], + [ + sg.Column( + self.tracking_layout, + key=self.gui_tracking_layout, + background_color="#424042", + ), + sg.Column( + self.roi_layout, + key=self.gui_roi_layout, + background_color="#424042", + visible=False, + ), + ], + ] + + def get_roi_layout(self): self.roi_layout = [ [ - # sg.Button( + # sg.Button( # "Mark Out", - # key=self.gui_mask_markup, - # button_color="#6f4ca1", - # tooltip="Mark out stuff that is not your eye.", - # ), - # sg.Button( - # "Lighten", - # key=self.gui_mask_lighten, - # button_color="#6f4ca1", - # tooltip="Lighten shadowed areas.", - # ), + # key=self.gui_mask_markup, + # button_color="#6f4ca1", + # tooltip="Mark out stuff that is not your eye.", + # ), + # sg.Button( + # "Lighten", + # key=self.gui_mask_lighten, + # button_color="#6f4ca1", + # tooltip="Lighten shadowed areas.", + # ), sg.Checkbox( "Camera Widget Padding", default=self.config.gui_rotation_ui_padding, @@ -151,6 +235,7 @@ class CameraWidget: ], ] + def get_tracking_layout(self): # Define the window's contents self.tracking_layout = [ [ @@ -208,82 +293,11 @@ class CameraWidget: ], ] - self.widget_layout = [ - [ - sg.Text("Camera Address", background_color="#424042"), - sg.InputText( - self.config.capture_source, - key=self.gui_camera_addr, - tooltip="Enter the IP address or UVC port of your camera. (Include the 'http://')", - ), - ], - [ - sg.Button( - "Save and Restart Tracking", - key=self.gui_save_tracking_button, - button_color="#6f4ca1", - ), - ], - [ - sg.Button( - "Tracking Mode", - key=self.gui_tracking_button, - button_color="#6f4ca1", - tooltip="Go here to track your eye.", - ), - sg.Button( - "Cropping Mode", - key=self.gui_roi_button, - button_color="#6f4ca1", - tooltip="Go here to crop out your eye.", - ), - ], - [ - sg.Text("Rotation", background_color="#424042"), - sg.Slider( - range=(0, 360), - default_value=self.config.rotation_angle, - orientation="h", - key=self.gui_rotation_slider, - background_color="#424042", - tooltip="Adjust the rotation of your cameras, make them level.", - ), - ], - [ - sg.Column( - self.tracking_layout, - key=self.gui_tracking_layout, - background_color="#424042", - ), - sg.Column( - self.roi_layout, - key=self.gui_roi_layout, - background_color="#424042", - visible=False, - ), - ], - ] - self.hover = None - - # cartesian co-ordinates in widget space are used during selection - self.xy0 = None - self.xy1 = None - self.cartesian_needs_update = False - # polar co-ordinates from the image center are the canonical representation - self.cr, self.ca = None, None - self.roi_size = None - self.clip_size = None - self.clip_pos = None - self.padded_size = None - self.img_pos = None - self.roi_image_center = None - - self.is_mouse_up = True - self.hover_pos = None - self.in_roi_mode = False - self.movavg_fps_queue = deque(maxlen=120) - self.movavg_bps_queue = deque(maxlen=120) + def update_layouts(self): + self.get_roi_layout() + self.get_tracking_layout() + self.get_widget_layout() def _movavg_fps(self, next_fps): self.movavg_fps_queue.append(next_fps) @@ -417,6 +431,7 @@ class CameraWidget: self.main_config.save() if event == self.gui_tracking_button: + self.get_tracking_layout() print("\033[94m[INFO] Moving to tracking mode\033[0m") self.in_roi_mode = False self.camera.set_output_queue(self.capture_queue) @@ -424,6 +439,7 @@ class CameraWidget: window[self.gui_tracking_layout].update(visible=True) if event == self.gui_roi_button: + self.get_roi_layout() print("\033[94m[INFO] Move to roi mode\033[0m") self.in_roi_mode = True self.camera.set_output_queue(self.roi_queue) diff --git a/EyeTrackApp/eyetrackapp.py b/EyeTrackApp/eyetrackapp.py index 50fb9f3..9df3fec 100644 --- a/EyeTrackApp/eyetrackapp.py +++ b/EyeTrackApp/eyetrackapp.py @@ -41,6 +41,8 @@ from utils.misc_utils import is_nt, resource_path import time import cv2 import numpy as np +import uuid + if is_nt: from winotify import Notification @@ -50,23 +52,159 @@ os.system("color") # init ANSI color # https://github.com/opencv/opencv/issues/17687 os.environ["OPENCV_VIDEOIO_MSMF_ENABLE_HW_TRANSFORMS"] = "0" WINDOW_NAME = "EyeTrackApp" -RIGHT_EYE_NAME = "-RIGHTEYEWIDGET-" -LEFT_EYE_NAME = "-LEFTEYEWIDGET-" -SETTINGS_NAME = "-SETTINGSWIDGET-" -ALGO_SETTINGS_NAME = "-ALGOSETTINGSWIDGET-" -VRCFT_MODULE_SETTINGS_NAME = "-VRCFTSETTINGSWIDGET-" -LEFT_EYE_RADIO_NAME = "-LEFTEYERADIO-" -RIGHT_EYE_RADIO_NAME = "-RIGHTEYERADIO-" -BOTH_EYE_RADIO_NAME = "-BOTHEYERADIO-" -SETTINGS_RADIO_NAME = "-SETTINGSRADIO-" -ALGO_SETTINGS_RADIO_NAME = "-ALGOSETTINGSRADIO-" -VRCFT_MODULE_SETTINGS_RADIO_NAME = "-VRCFTSETTINGSRADIO-" -GUIOFF_RADIO_NAME = "-GUIOFF-" + + page_url = "https://github.com/RedHawk989/EyeTrackVR/releases/latest" appversion = "EyeTrackApp 0.2.0 BETA 13" +class KeyManager: + def __init__(self): + self.update_keys() + + def update_keys(self): + unique_id = str(uuid.uuid4()) + self.RIGHT_EYE_NAME = f"-RIGHTEYEWIDGET{unique_id}-" + self.LEFT_EYE_NAME = f"-LEFTEYEWIDGET{unique_id}-" + self.SETTINGS_NAME = f"-SETTINGSWIDGET{unique_id}-" + self.ALGO_SETTINGS_NAME = f"-ALGOSETTINGSWIDGET{unique_id}-" + self.VRCFT_MODULE_SETTINGS_NAME = f"-VRCFTSETTINGSWIDGET{unique_id}-" + self.LEFT_EYE_RADIO_NAME = f"-LEFTEYERADIO{unique_id}-" + self.RIGHT_EYE_RADIO_NAME = f"-RIGHTEYERADIO{unique_id}-" + self.BOTH_EYE_RADIO_NAME = f"-BOTHEYERADIO{unique_id}-" + self.SETTINGS_RADIO_NAME = f"-SETTINGSRADIO{unique_id}-" + self.ALGO_SETTINGS_RADIO_NAME = f"-ALGOSETTINGSRADIO{unique_id}-" + self.VRCFT_MODULE_SETTINGS_RADIO_NAME = f"-VRCFTSETTINGSRADIO{unique_id}-" + self.GUIOFF_RADIO_NAME = f"-GUIOFF{unique_id}-" + +# Create an instance of the KeyManager +key_manager = KeyManager() + + +def create_window(config, settings, eyes): + + key_manager.update_keys() + + for eye in eyes: + eye.update_layouts() + + layout = [ + [ + sg.Radio( + "Left Eye", + "EYESELECTRADIO", + background_color="#292929", + default=(config.eye_display_id == EyeId.LEFT), + key=key_manager.LEFT_EYE_RADIO_NAME, + ), + sg.Radio( + "Right Eye", + "EYESELECTRADIO", + background_color="#292929", + default=(config.eye_display_id == EyeId.RIGHT), + key=key_manager.RIGHT_EYE_RADIO_NAME, + ), + sg.Radio( + "Both Eyes", + "EYESELECTRADIO", + background_color="#292929", + default=(config.eye_display_id == EyeId.BOTH), + key=key_manager.BOTH_EYE_RADIO_NAME, + ), + sg.Radio( + "Settings", + "EYESELECTRADIO", + background_color="#292929", + default=(config.eye_display_id == EyeId.SETTINGS), + key=key_manager.SETTINGS_RADIO_NAME, + ), + sg.Radio( + "Algo Settings", + "EYESELECTRADIO", + background_color="#292929", + default=(config.eye_display_id == EyeId.ALGOSETTINGS), + key=key_manager.ALGO_SETTINGS_RADIO_NAME, + ), + + ], + [ + sg.Radio( + "VRCFT Module Settings", + "EYESELECTRADIO", + background_color="#292929", + default=(config.eye_display_id == EyeId.VRCFTMODULESETTINGS), + key=key_manager.VRCFT_MODULE_SETTINGS_RADIO_NAME, + ), + sg.Radio( + "GUI OFF", + "EYESELECTRADIO", + background_color="#292929", + default=(config.eye_display_id == EyeId.GUIOFF), + key=key_manager.GUIOFF_RADIO_NAME, + ), + ], + [ + sg.Column( + eyes[1].widget_layout, + vertical_alignment="top", + key=key_manager.LEFT_EYE_NAME, + visible=(config.eye_display_id in [EyeId.LEFT, EyeId.BOTH]), + background_color="#424042", + ), + sg.Column( + eyes[0].widget_layout, + vertical_alignment="top", + key=key_manager.RIGHT_EYE_NAME, + visible=(config.eye_display_id in [EyeId.RIGHT, EyeId.BOTH]), + background_color="#424042", + ), + sg.Column( + settings[0].get_layout(), + vertical_alignment="top", + key=key_manager.SETTINGS_NAME, + visible=(config.eye_display_id in [EyeId.SETTINGS]), + background_color="#424042", + ), + sg.Column( + settings[1].get_layout(), + vertical_alignment="top", + key=key_manager.ALGO_SETTINGS_NAME, + visible=(config.eye_display_id in [EyeId.ALGOSETTINGS]), + background_color="#424042", + ), + sg.Column( + settings[2].get_layout(), + vertical_alignment="top", + key=key_manager.VRCFT_MODULE_SETTINGS_NAME, + visible=(config.eye_display_id in [EyeId.VRCFTMODULESETTINGS]), + background_color="#424042", + ), + ], + ] + + + if config.eye_display_id in [EyeId.LEFT, EyeId.BOTH]: + eyes[1].start() + if config.eye_display_id in [EyeId.RIGHT, EyeId.BOTH]: + eyes[0].start() + if config.eye_display_id in [EyeId.SETTINGS]: + settings[0].start() + if config.eye_display_id in [EyeId.ALGOSETTINGS]: + settings[1].start() + if config.eye_display_id in [EyeId.VRCFTMODULESETTINGS]: + settings[2].start() + + # the eye's needs to be running before it is passed to the OSC + # Create the window + return sg.Window( + f"{appversion}", + layout, + icon=resource_path("Images/logo.ico"), + background_color="#292929") + + + def main(): # Get Configuration config: EyeTrackConfig = EyeTrackConfig.load() @@ -147,279 +285,206 @@ def main(): osc_manager.start() - layout = [ - [ - sg.Radio( - "Left Eye", - "EYESELECTRADIO", - background_color="#292929", - default=(config.eye_display_id == EyeId.LEFT), - key=LEFT_EYE_RADIO_NAME, - ), - sg.Radio( - "Right Eye", - "EYESELECTRADIO", - background_color="#292929", - default=(config.eye_display_id == EyeId.RIGHT), - key=RIGHT_EYE_RADIO_NAME, - ), - sg.Radio( - "Both Eyes", - "EYESELECTRADIO", - background_color="#292929", - default=(config.eye_display_id == EyeId.BOTH), - key=BOTH_EYE_RADIO_NAME, - ), - sg.Radio( - "Settings", - "EYESELECTRADIO", - background_color="#292929", - default=(config.eye_display_id == EyeId.SETTINGS), - key=SETTINGS_RADIO_NAME, - ), - sg.Radio( - "Algo Settings", - "EYESELECTRADIO", - background_color="#292929", - default=(config.eye_display_id == EyeId.ALGOSETTINGS), - key=ALGO_SETTINGS_RADIO_NAME, - ), - - ], - [ - sg.Radio( - "VRCFT Module Settings", - "EYESELECTRADIO", - background_color="#292929", - default=(config.eye_display_id == EyeId.VRCFTMODULESETTINGS), - key=VRCFT_MODULE_SETTINGS_RADIO_NAME, - ), - sg.Radio( - "GUI OFF", - "EYESELECTRADIO", - background_color="#292929", - default=(config.eye_display_id == EyeId.GUIOFF), - key=GUIOFF_RADIO_NAME, - ), - ], - [ - sg.Column( - eyes[1].widget_layout, - vertical_alignment="top", - key=LEFT_EYE_NAME, - visible=(config.eye_display_id in [EyeId.LEFT, EyeId.BOTH]), - background_color="#424042", - ), - sg.Column( - eyes[0].widget_layout, - vertical_alignment="top", - key=RIGHT_EYE_NAME, - visible=(config.eye_display_id in [EyeId.RIGHT, EyeId.BOTH]), - background_color="#424042", - ), - sg.Column( - settings[0].get_layout(), - vertical_alignment="top", - key=SETTINGS_NAME, - visible=(config.eye_display_id in [EyeId.SETTINGS]), - background_color="#424042", - ), - sg.Column( - settings[1].get_layout(), - vertical_alignment="top", - key=ALGO_SETTINGS_NAME, - visible=(config.eye_display_id in [EyeId.ALGOSETTINGS]), - background_color="#424042", - ), - sg.Column( - settings[2].get_layout(), - vertical_alignment="top", - key=VRCFT_MODULE_SETTINGS_NAME, - visible=(config.eye_display_id in [EyeId.VRCFTMODULESETTINGS]), - background_color="#424042", - ), - ], - ] - - if config.eye_display_id in [EyeId.LEFT, EyeId.BOTH]: - eyes[1].start() - if config.eye_display_id in [EyeId.RIGHT, EyeId.BOTH]: - eyes[0].start() - if config.eye_display_id in [EyeId.SETTINGS]: - settings[0].start() - if config.eye_display_id in [EyeId.ALGOSETTINGS]: - settings[1].start() - if config.eye_display_id in [EyeId.VRCFTMODULESETTINGS]: - settings[2].start() - - # the eye's needs to be running before it is passed to the OSC - # Create the window - window = sg.Window( - f"{appversion}", - layout, - icon=resource_path("Images/logo.ico"), - background_color="#292929", - ) - + # window = create_window(config, settings, eyes) while True: - print('main loop') + if config.settings.gui_disable_gui: - timeout = 10 #TODO: test this on windows, on mac im not seeing a negitive side effect - layout = [[sg.Button("Enable GUI")]] + print('ee') + layoutg = [ + [sg.Button('Enable GUI')] + ] # Create the window - window = sg.Window("Simple Button", layout) + windowg = sg.Window('Simple Window', layoutg) - # Event loop to process events and get the values of the inputs + # Event loop while True: - event, values = window.read() - # If user closes window or clicks the button, break the loop - if event == sg.WINDOW_CLOSED: + eventg, valuesg = windowg.read() + + if eventg == sg.WINDOW_CLOSED: break - elif event == "Enable GUI": - print("Button clicked!") + elif eventg == 'Enable GUI': config.settings.gui_disable_gui = False config.save() + print('GUI Enabled') + break # Close the window - window.close() + windowg.close() + print('close') - else: - timeout = 1 - # GUI Render loop - while True: - # First off, check for any events from the GUI - event, values = window.read(timeout=timeout) # this higher timeout saves some cpu usage + # First off, check for any events from the GUI + window = create_window(config, settings, eyes) + print('new window') + while True: + event, values = window.read(timeout=1) # this higher timeout saves some cpu usage - # If we're in either mode and someone hits q, quit immediately - if event == "Exit" or event == sg.WIN_CLOSED: - for eye in eyes: - eye.stop() - cancellation_event.set() - osc_manager.shutdown() - print("\033[94m[INFO] Exiting EyeTrackApp\033[0m") - os._exit(0) # I do not like this, but for now this fixes app hang on close - return + # If we're in either mode and someone hits q, quit immediately + if event == "Exit" or event == sg.WIN_CLOSED and not config.settings.gui_disable_gui: + print(event == "Exit", event == sg.WIN_CLOSED, config.settings.gui_disable_gui) + for eye in eyes: + eye.stop() + cancellation_event.set() + osc_manager.shutdown() + print("\033[94m[INFO] Exiting EyeTrackApp\033[0m") + window.close() + os._exit(0) # I do not like this, but for now this fixes app hang on close + return - if values[RIGHT_EYE_RADIO_NAME] and config.eye_display_id != EyeId.RIGHT: - config.settings.gui_disable_gui = False - eyes[0].start() - eyes[1].stop() - settings[0].stop() - settings[1].stop() - settings[2].stop() - window[RIGHT_EYE_NAME].update(visible=True) - window[LEFT_EYE_NAME].update(visible=False) - window[SETTINGS_NAME].update(visible=False) - window[VRCFT_MODULE_SETTINGS_NAME].update(visible=False) - window[ALGO_SETTINGS_NAME].update(visible=False) - config.eye_display_id = EyeId.RIGHT - config.settings.tracker_single_eye = 2 - config.save() + if values[key_manager.RIGHT_EYE_RADIO_NAME] and config.eye_display_id != EyeId.RIGHT: + config.settings.gui_disable_gui = False + eyes[0].start() + eyes[1].stop() + settings[0].stop() + settings[1].stop() + settings[2].stop() + window[key_manager.RIGHT_EYE_NAME].update(visible=True) + window[key_manager.LEFT_EYE_NAME].update(visible=False) + window[key_manager.SETTINGS_NAME].update(visible=False) + window[key_manager.VRCFT_MODULE_SETTINGS_NAME].update(visible=False) + window[key_manager.ALGO_SETTINGS_NAME].update(visible=False) + config.eye_display_id = EyeId.RIGHT + config.settings.tracker_single_eye = 2 + config.save() - elif values[LEFT_EYE_RADIO_NAME] and config.eye_display_id != EyeId.LEFT: - config.settings.gui_disable_gui = False - settings[0].stop() - settings[1].stop() - settings[2].stop() - eyes[0].stop() - eyes[1].start() - window[RIGHT_EYE_NAME].update(visible=False) - window[LEFT_EYE_NAME].update(visible=True) - window[SETTINGS_NAME].update(visible=False) - window[VRCFT_MODULE_SETTINGS_NAME].update(visible=False) - window[ALGO_SETTINGS_NAME].update(visible=False) - config.eye_display_id = EyeId.LEFT - config.settings.tracker_single_eye = 1 - config.save() + elif values[key_manager.LEFT_EYE_RADIO_NAME] and config.eye_display_id != EyeId.LEFT: + config.settings.gui_disable_gui = False + settings[0].stop() + settings[1].stop() + settings[2].stop() + eyes[0].stop() + eyes[1].start() + window[key_manager.RIGHT_EYE_NAME].update(visible=False) + window[key_manager.LEFT_EYE_NAME].update(visible=True) + window[key_manager.SETTINGS_NAME].update(visible=False) + window[key_manager.VRCFT_MODULE_SETTINGS_NAME].update(visible=False) + window[key_manager.ALGO_SETTINGS_NAME].update(visible=False) + config.eye_display_id = EyeId.LEFT + config.settings.tracker_single_eye = 1 + config.save() - elif values[BOTH_EYE_RADIO_NAME] and config.eye_display_id != EyeId.BOTH: - config.settings.gui_disable_gui = False - settings[0].stop() - settings[1].stop() - settings[2].stop() - eyes[1].start() - eyes[0].start() - window[LEFT_EYE_NAME].update(visible=True) - window[RIGHT_EYE_NAME].update(visible=True) - window[SETTINGS_NAME].update(visible=False) - window[VRCFT_MODULE_SETTINGS_NAME].update(visible=False) - window[ALGO_SETTINGS_NAME].update(visible=False) - config.eye_display_id = EyeId.BOTH - config.settings.tracker_single_eye = 0 - config.save() + elif values[key_manager.BOTH_EYE_RADIO_NAME] and config.eye_display_id != EyeId.BOTH: + config.settings.gui_disable_gui = False + settings[0].stop() + settings[1].stop() + settings[2].stop() + eyes[1].start() + eyes[0].start() + window[key_manager.LEFT_EYE_NAME].update(visible=True) + window[key_manager.RIGHT_EYE_NAME].update(visible=True) + window[key_manager.SETTINGS_NAME].update(visible=False) + window[key_manager.VRCFT_MODULE_SETTINGS_NAME].update(visible=False) + window[key_manager.ALGO_SETTINGS_NAME].update(visible=False) + config.eye_display_id = EyeId.BOTH + config.settings.tracker_single_eye = 0 + config.save() - elif values[SETTINGS_RADIO_NAME] and config.eye_display_id != EyeId.SETTINGS: - config.settings.gui_disable_gui = False - eyes[0].stop() - eyes[1].stop() - settings[1].stop() - settings[0].start() - settings[2].stop() - window[RIGHT_EYE_NAME].update(visible=False) - window[LEFT_EYE_NAME].update(visible=False) - window[SETTINGS_NAME].update(visible=True) - window[VRCFT_MODULE_SETTINGS_NAME].update(visible=False) - window[ALGO_SETTINGS_NAME].update(visible=False) - config.eye_display_id = EyeId.SETTINGS - config.save() + elif values[key_manager.SETTINGS_RADIO_NAME] and config.eye_display_id != EyeId.SETTINGS: + config.settings.gui_disable_gui = False + eyes[0].stop() + eyes[1].stop() + settings[1].stop() + settings[0].start() + settings[2].stop() + window[key_manager.RIGHT_EYE_NAME].update(visible=False) + window[key_manager.LEFT_EYE_NAME].update(visible=False) + window[key_manager.SETTINGS_NAME].update(visible=True) + window[key_manager.VRCFT_MODULE_SETTINGS_NAME].update(visible=False) + window[key_manager.ALGO_SETTINGS_NAME].update(visible=False) + config.eye_display_id = EyeId.SETTINGS + config.save() - elif values[ALGO_SETTINGS_RADIO_NAME] and config.eye_display_id != EyeId.ALGOSETTINGS: - config.settings.gui_disable_gui = False - eyes[0].stop() - eyes[1].stop() - settings[0].stop() - settings[1].start() - settings[2].stop() - window[RIGHT_EYE_NAME].update(visible=False) - window[LEFT_EYE_NAME].update(visible=False) - window[SETTINGS_NAME].update(visible=False) - window[VRCFT_MODULE_SETTINGS_NAME].update(visible=False) - window[ALGO_SETTINGS_NAME].update(visible=True) - config.eye_display_id = EyeId.ALGOSETTINGS - config.save() + elif values[key_manager.ALGO_SETTINGS_RADIO_NAME] and config.eye_display_id != EyeId.ALGOSETTINGS: + config.settings.gui_disable_gui = False + eyes[0].stop() + eyes[1].stop() + settings[0].stop() + settings[1].start() + settings[2].stop() + window[key_manager.RIGHT_EYE_NAME].update(visible=False) + window[key_manager.LEFT_EYE_NAME].update(visible=False) + window[key_manager.SETTINGS_NAME].update(visible=False) + window[key_manager.VRCFT_MODULE_SETTINGS_NAME].update(visible=False) + window[key_manager.ALGO_SETTINGS_NAME].update(visible=True) + config.eye_display_id = EyeId.ALGOSETTINGS + config.save() - elif values[VRCFT_MODULE_SETTINGS_RADIO_NAME] and config.eye_display_id != EyeId.VRCFTMODULESETTINGS: - config.settings.gui_disable_gui = False - eyes[0].stop() - eyes[1].stop() - settings[0].stop() - settings[1].stop() - settings[2].start() - window[RIGHT_EYE_NAME].update(visible=False) - window[LEFT_EYE_NAME].update(visible=False) - window[SETTINGS_NAME].update(visible=False) - window[VRCFT_MODULE_SETTINGS_NAME].update(visible=True) - window[ALGO_SETTINGS_NAME].update(visible=False) - config.eye_display_id = EyeId.VRCFTMODULESETTINGS - config.save() - elif values[GUIOFF_RADIO_NAME] and config.eye_display_id != EyeId.GUIOFF: - config.settings.gui_disable_gui = True - # eyes[0].stop() - # eyes[1].stop() - settings[0].stop() - settings[1].stop() - settings[2].stop() - window[RIGHT_EYE_NAME].update(visible=False) - window[LEFT_EYE_NAME].update(visible=False) - window[SETTINGS_NAME].update(visible=False) - window[VRCFT_MODULE_SETTINGS_NAME].update(visible=False) - window[ALGO_SETTINGS_NAME].update(visible=False) - config.eye_display_id = EyeId.GUIOFF - config.save() - break + elif values[key_manager.VRCFT_MODULE_SETTINGS_RADIO_NAME] and config.eye_display_id != EyeId.VRCFTMODULESETTINGS: + config.settings.gui_disable_gui = False + eyes[0].stop() + eyes[1].stop() + settings[0].stop() + settings[1].stop() + settings[2].start() + window[key_manager.RIGHT_EYE_NAME].update(visible=False) + window[key_manager.LEFT_EYE_NAME].update(visible=False) + window[key_manager.SETTINGS_NAME].update(visible=False) + window[key_manager.VRCFT_MODULE_SETTINGS_NAME].update(visible=True) + window[key_manager.ALGO_SETTINGS_NAME].update(visible=False) + config.eye_display_id = EyeId.VRCFTMODULESETTINGS + config.save() + elif values[key_manager.GUIOFF_RADIO_NAME] and config.eye_display_id != EyeId.GUIOFF: + config.settings.gui_disable_gui = True + # eyes[0].stop() + # eyes[1].stop() + settings[0].stop() + settings[1].stop() + settings[2].stop() + window[key_manager.RIGHT_EYE_NAME].update(visible=False) + window[key_manager.LEFT_EYE_NAME].update(visible=False) + window[key_manager.SETTINGS_NAME].update(visible=False) + window[key_manager.VRCFT_MODULE_SETTINGS_NAME].update(visible=False) + window[key_manager.ALGO_SETTINGS_NAME].update(visible=False) + config.eye_display_id = EyeId.GUIOFF + config.save() + window.close() + break + + else: + + # Otherwise, render all + for eye in eyes: + if eye.started(): + eye.render(window, event, values) + for setting in settings: + if setting.started(): + setting.render(window, event, values) + + + + + # while True: + # print('main loop') + # if config.settings.gui_disable_gui: + # layoutg = [[sg.Button("Enable GUI")]] + + # Create the window + # windowc = sg.Window("Simple Button", layoutg) + + # Event loop to process events and get the values of the inputs + # while True: + # eventg, valuesg = windowc.read() +# + # If user closes window or clicks the button, break the loop + # if eventg == sg.WINDOW_CLOSED: + # break + # elif eventg == "Enable GUI": + # config.settings.gui_disable_gui = False + # config.save() + # break + + # Close the window + # windowc.close() + + + + # else: + # print('main loop') + # run_window(config, settings, eyes) - else: - # Otherwise, render all - for eye in eyes: - if eye.started(): - eye.render(window, event, values) - for setting in settings: - if setting.started(): - setting.render(window, event, values) if __name__ == "__main__": diff --git a/EyeTrackApp/settings/BaseSettings.py b/EyeTrackApp/settings/BaseSettings.py index 94b039a..85c4473 100644 --- a/EyeTrackApp/settings/BaseSettings.py +++ b/EyeTrackApp/settings/BaseSettings.py @@ -3,70 +3,32 @@ from typing import Iterable import PySimpleGUI as sg from colorama import Fore - -from config import EyeTrackConfig, EyeTrackSettingsConfig from threading import Event from eye import EyeId - +from config import EyeTrackConfig, EyeTrackSettingsConfig class BaseSettingsWidget: - def __init__( - self, - widget_id: EyeId, - main_config: EyeTrackConfig, - settings_modules: Iterable, - ): - # we put the last time an error was printed in the past so whenever a newone appears - self.last_error_printout = datetime.now() - timedelta(seconds=20) - self.error_printout_timeout = 2 - self.gui_general_settings_layout = f"-GENERALSETTINGSLAYOUT{widget_id}-" - self.reset_button_key = f"RESET_SETTINGS{widget_id}" - self.is_saving = False + def __init__(self, widget_id: EyeId, main_config: EyeTrackConfig, settings_modules: Iterable): + self.widget_id = widget_id self.main_config = main_config self.config = main_config.settings - + self.last_error_printout = datetime.now() - timedelta(seconds=20) + self.error_printout_timeout = 2 + self.reset_button_key = f"RESET_SETTINGS{widget_id}" + self.is_saving = False self.initialized_modules = self._initialize_modules(settings_modules=settings_modules, widget_id=widget_id) - - self.general_settings_layout = [] - for module in self.initialized_modules: - self.general_settings_layout.extend(module.get_layout()) - - self.widget_layout = [ - [ - sg.Column( - self.general_settings_layout, - key=self.gui_general_settings_layout, - background_color="#424042", - ), - ], - [ - sg.Text("", background_color="#424042"), - ], - [ - sg.Button( - "Reset settings to default", - key=self.reset_button_key, - button_color="#c40e23", - ) - ], - ] - - self.cancellation_event = ( - Event() - ) # Set the event until start is called, otherwise we can block if shutdown is called. + self.cancellation_event = Event() self.cancellation_event.set() def started(self): return not self.cancellation_event.is_set() def start(self): - # If we're already running, bail if not self.cancellation_event.is_set(): return self.cancellation_event.clear() def stop(self): - # If we're not running yet, bail if self.cancellation_event.is_set(): return self.cancellation_event.set() @@ -80,58 +42,47 @@ class BaseSettingsWidget: elapsed_seconds = (datetime.now() - self.last_error_printout).seconds if elapsed_seconds > self.error_printout_timeout: self.last_error_printout = now - - messages = [] - for module_errors in errors: - for error in module_errors: - messages.append(f"{Fore.RED}[ERROR]{Fore.RESET} {error['msg']} \n") + messages = [f"{Fore.RED}[ERROR]{Fore.RESET} {error['msg']} \n" for module_errors in errors for error in module_errors] print("".join(messages)) def render(self, window, event, values): validated_data, errors = {}, [] - # we might want to think about event driven architecture here eventually, validate only - # if anything changes instead of checking for changes for module in self.initialized_modules: module_validated_data = module.validate(values) if module_validated_data.changes: validated_data.update(module_validated_data.changes) if module_validated_data.errors: errors.append(module_validated_data.errors) - if not errors and validated_data and not self.is_saving: self.is_saving = True self._update_and_save_config(validated_data) - if errors: self._handle_errors(errors) - self.handle_events(event, window) def _initialize_modules(self, settings_modules, widget_id): - return [ - module( - config=self.config, - settings=self.main_config, - widget_id=widget_id, - ) - for module in settings_modules - ] + return [module(config=self.config, settings=self.main_config, widget_id=widget_id) for module in settings_modules] def get_layout(self) -> Iterable: - return self.widget_layout + general_settings_layout = [] + for module in self.initialized_modules: + general_settings_layout.extend(module.get_layout()) + widget_layout = [ + [sg.Column(general_settings_layout, key=f"-GENERALSETTINGSLAYOUT{self.widget_id}-", background_color="#424042")], + [sg.Text("", background_color="#424042")], + [sg.Button("Reset settings to default", key=self.reset_button_key, button_color="#c40e23")] + ] + return widget_layout def handle_events(self, event, window): if event == "__TIMEOUT__": return - if event == self.reset_button_key: self.reset_config(window) def reset_config(self, window): - default_values = {} base_settings = EyeTrackSettingsConfig() - print(f"\033[92m[INFO] Resetting config to defaults\033[0m") for module in self.initialized_modules: for key in module.get_key_for_panel_defaults(): @@ -140,5 +91,4 @@ class BaseSettingsWidget: default_values[key] = default_val window[widget_key].update(default_val) print(f"\033[92m[INFO] Config reset, saving\033[0m") - self._update_and_save_config(default_values)